当前位置: 首页 > news >正文

网络协议——HTTP协议

目录

一、HTTP协议是什么

二、HTTP协议工作的过程

三、HTTP协议格式

(一)HTTP请求

(二)HTTP响应

四、HTTP请求格式

(一)认识URL

关于URL encode

(二)认识 "方法" (method)

使用Fiddler观察GET请求

使用Fiddler观察POST请求

GET和POST的区别

(三)认识请求报头(header)

Host

Content-Length

Content-Type

User-Agent(简称UA)

Referer

(四)请求正文(body)

五、HTTP响应状态码

200 OK

404 Not Found

403 Forbidden

405 Method Not Allowed

500 Internal Server Error

504 Gateway Timeout

302 Move temporarily

301 Moved Permanently

状态码小结

六、通过Java Socket构造HTTP请求


一、HTTP协议是什么

HTTP全称为“超文本传输协议”,是一种非常广泛的应用层协议

我们平时打开一个网站,就是通过HTTP协议来传输数据的。

当我们在浏览器中输入一个 搜狗搜索的 "网址" (URL) 时, 浏览器就给搜狗的服务器发送了一个 HTTP 请求, 搜狗的服务器返回了一个 HTTP 响应.

这个响应结果被浏览器解析之后, 就展示成我们看到的页面内容. (这个过程中浏览器可能会给服务器发送多个 HTTP 请求, 服务器会对应返回多个响应, 这些响应里就包含了页面 HTML, CSS, JavaScript, 图片, 字体等信息).

所谓 "超文本" 的含义, 就是传输的内容不仅仅是文本 (比如 html, css 这个就是文本), 还可以是一些其他的资源, 比如图片, 视频, 音频等二进制的数据.

二、HTTP协议工作的过程

当我们在浏览器中输入一个网址,此时浏览器就会对对应的服务器发送一个HTTP请求,服务器收到请求后,经过处理,就会返回一个HTTP响应。

事实上,当我们访问一个网站的时候,可能涉及不止一次的HTTP请求和响应。

可以通过抓包工具以Fiddler为例(下载地址: https://www.telerik.com/fiddler/)

查看这个交互过程:

  • 左侧窗口显示了所有的 HTTP请求/响应,可以选中某个请求查看详情.
  • 右侧上方显示了 HTTP 请求的报文内容.(切换到 Raw 标签页可以看到详细的数据格式) 
  • 右侧下方显示了 HTTP 响应的报文内容.(切换到 Raw 标签页可以看到详细的数据格式)

抓包工具的原理:

Fiddler相当于是一个“代理”。

浏览器访问sougou.com的时候,会把HTTP请求先发送给Fiddler,Fiddler再把请求发送给服务器,当服务器返回数据的时候,Fiddler拿到返回的数据,再把数据交给浏览器。

三、HTTP协议格式

(一)HTTP请求

  • 首行:[方法] + [url] + [版本]
  • Header:请求的属性,冒号分割的键值对;每组属性之间使用 \n 分隔;遇到空行表示 Header 部分结束
  • Body:空行后面的内容都是 Body。Body 允许为空字符串。如果 Body 存在,则在 Header 中会有一个 Content-Length 属性来标识 Body 的长度;

(二)HTTP响应

  • 首行:[版本号] + [状态码] + [状态码解释]
  • Header:请求的属性,冒号分割的键值对;每组属性之间使用 \n 分隔;遇到空行表示 Header 部分结束
  • Body:空行后面的内容都是 Body。Body 允许为空字符串。如果 Body 存在,则在 Header 中会有一个 Content-Length 属性来标识 Body 的长度;如果服务器返回了一个 html 页面,那么 html 页面内容就是在 body 中。

为什么HTTP报文中要存在“空行”?

1.因为HTTP协议中并没有规定报头部分的键值对有多少个,空行就是报头部分结束的标记,或者是用来分割报头与正文。

2.HTTP协议是依赖于TCP协议,TCP协议是面向字节流的,如果没有这个空行,就会出现“粘包问题”。

四、HTTP请求格式

(一)认识URL

URL是描述网络上唯一资源的位置的。

例如在jdbc:mysql://127.0.0.1:3306/java113?characterEncoding=utf8&useSSL=false#ch1中:

URL的部分含义
jdbc:mysql://协议名称
127.0.0.1要访问的服务器域名或者ip地址
:3306端口号,区分服务器上的哪个应用程序
/java113带有层次结构的路径,想要访问的是某个主机上某个程序的某个资源
?characterEncoding=utf8&useSSL=false用?与路径隔开,标识查询字符串Query String,对要访问的资源补充说明,是键值对结构,键与值之间用=分割,键值对之间用&分割
#ch1片段标识符,常见于文档类网页

URL 中可省略部分:

  • 协议名:可省略,省略后默认 `http://` 
  • ip 地址/域名:HTML 里(如 `img`、`link` 等标签 `src`/`href` 属性)可省略,省略后默认与当前 HTML 所属 ip/域名一致 
  • 端口号:可省略,`http` 协议默认 80 端口,`https` 协议默认 443 端口 
  • 带层次的文件路径:可省略,省略后相当于 `/`,部分服务器遇 `/` 会自动访问 `/index.html` 
  • 查询字符串:可省略 
  • 片段标识:可省略 

关于URL encode

像 / ?:等这样的字符,已经被url当做特殊意义理解了,因此这些字符在url中不能随意出现,比如某个参数中需要或者可能带有这类特殊字符,就必须对特殊字符进行转义处理。

URl encode的转义规则是:将需要转义的字符转为16进制,然后从右到左,取4位,每两位做一位,前面加上%,编码成%XY的格式。

    例如:

    当我们在浏览器中搜索C++时,+就被转义成了%2B

    分享一个URL encode工具:UrlEncode编码/UrlDecode解码 - 站长工具

    (二)认识 "方法" (method)

    方法说明
    GET获取资源
    POST传输实体主体
    PUT传输文件
    DELETE删除文件
    HEAD获取报文首部
    POTIONS询问支持的方法
    TRACE追踪路径
    CONNECT要求用隧道协议连接代理
    LINK建立和资源之间的联系
    UNLINK断开连接关系

    在这些方法中,GET和POST方法是最常见的请求,从语义上来说

    • GET是获取浏览器上的某个资源
    • POST多用于提交用户输入的数据给服务器(例如登陆页面)

    但是实际开发的时候,不一定严格按照语义来进行区分,GET也可以用于提交数据,POST也可以用于获取数据。

    使用Fiddler观察GET请求

    打开Fiddler,访问搜狗主页,观察抓包结果。

    使用Fiddler观察POST请求

    打开Fiddler,在gitee登录界面登录,就可以看到POST请求。

    GET和POST的区别

    • 语义不同: GET 一般用于获取数据, POST 一般用于提交数据.
    • GET 的 body 一般为空, 需要传递的数据通过 query string 传递, POST 的 query string 一般为空, 需要传递的数据通过 body 传递
    • GET 请求一般是幂等的, POST 请求一般是不幂等的. (如果多次请求得到的结果一样, 就视为请求是幂等的).
    • GET 可以被缓存, POST 不能被缓存. (这一点也是承接幂等性)

    至于PUT和DELETE方法,也使用于Restful api设计。

    POST
    DELETE
    GET
    PUT

    (三)认识请求报头(header)

    header的格式是键值对结构,每个键值对占一行,键与值之间使用分号加空格分割。

    介绍常用的报头

    Host

    表示服务器主机的IP地址(或者域名)和端口号。

    大部分情况下,host中的地址与url中的地址是一样的,如果使用了代理,可以通过host来获取到最原始的目标是什么。

    Content-Length

    表示body中的数据长度,单位是字节。

    HTTP协议,就是把字符串构建成HTTP约定好的格式,基于TCP实现的。

    TCP将这些字符串写入到TCP Socket中,对于一个TCP来说,一个连接上可以发送多个请求,服务器在收到这些数据的时候就要区分一下,从哪里到哪里是一个完整的请求。

    • 如果是没有body的http数据,读到空行就可以认为结束了。
    • 如果是有body的http数据,先解析header中Content-length的值,读到空行后,再读取固定字节的长度。

    Content-Type

    表示请求的body中的数据格式,提示了接收方如何解析body中的数据。

    数据类型格式
    HTMLtext/html
    CSStext/css
    JSapplication/javascript
    JSONapplication/json
    图片

    image/png

    image/jpg

    User-Agent(简称UA)

    里面表示了用户使用的设备的浏览器和操作系统的情况。

    例如:

    作用是通过UA中的浏览器版本/操作系统版本,区分出当前用户的设备,最多都支持哪些特性从而返回不同版本的页面。

    Referer

    描述了当前页面的来源,表示当前这个页面是从哪个页面跳转过来的。

    搜索页跳转到广告页,广告页的referer:

    Cookie是浏览器允许网页在本地磁盘存储数据的一种机制。

    网页不能直接操作设备上的其他数据,但可以通过浏览器,在其允许的范围内创建、读取、修改Cookie(这些Cookie仅由浏览器管理,且通常与特定网站绑定)。

    简单说,当你访问网站时,网站通过浏览器在你的设备上留下Cookie(小型文本文件),这些文件就存放在浏览器的指定存储位置,属于本地设备上的数据,而非网站服务器上的数据。浏览器会在你后续访问该网站时,自动携带这些Cookie信息,方便网站识别你的状态和偏好。

    Cookie是按照键值对的方式进行存储数据的,里面的数据都是程序员自定义的。

    Cookie有一个典型的应用场景:登录和用户认证。

    下面是登录的流程:

    (四)请求正文(body)

    body中的数据格式与报头中Conent-Type密切相关。

    五、HTTP响应状态码

    200 OK

    这是最常见的状态码,表示访问网页成功。

    404 Not Found

    表示访问的资源没有找到。

    当我们输入一个URL进行访问,URL中的ip定位到服务器主机,port定位到程序,path定位到程序管理的资源,出现404表示访问的资源在服务器上没有。

    403 Forbidden

    表示访问被拒绝,有的页面通常需要用户具有一定的权限才能访问(登陆后才能访问),如果用户没有登陆就直接访问,就容易见到403.

    405 Method Not Allowed

    表示请求的方法和服务器这边声明的注解不匹配,就会出现405。

    500 Internal Server Error

     表示服务器内部出现错误,处理逻辑的代码中抛出异常,但是没有catch到。 

    504 Gateway Timeout

    当服务器负载较大的时候,服务器处理单条请求时消耗的时间就会变长,就可能导致超时的情况。

    302 Move temporarily

    表示临时重定向,在登陆页面中经常会见到 302,用于实现登陆成功后自动跳转到主页。

    响应报文的 header 部分会包含一个 Location字段,表示要跳转到哪个页面。

    301 Moved Permanently

    永久重定向. 当浏览器收到这种响应时,后续的请求都会被自动改成新的地址。

    状态码小结

    状态码类别原因
    1XX信息性状态码接收的请求正在处理
    2XX成功状态码请求正常处理完毕
    3XX重定向状态码需要进行附加操作以完成请求
    4XX客户端错误状态码服务器无法处理请求
    5XX服务器错误状态码服务器处理请求出错

    六、通过Java Socket构造HTTP请求

    所谓的 "发送 HTTP 请求",本质上就是按照 HTTP 的格式往 TCP Socket 中写入一个字符串。
    所谓的 "接受 HTTP 响应", 本质上就是从 TCP Socket 中读取一个字符串, 再按照 HTTP 的格式来解析。

    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;public class HttpClient {private Socket socket;private String ip;private int port;public HttpClient(String ip,int port) throws IOException {this.ip=ip;this.port=port;this.socket=new Socket(ip,port);}
    //get报头public String get(String url)throws IOException{StringBuilder request=new StringBuilder();//构造首行request.append("GET "+url+" HTTP/1.1\n");//构造headerrequest.append("host: "+ip+':'+port+'\n');//构造空行request.append('\n');//发送请求OutputStream outputStream=socket.getOutputStream();//将request转为字节数组outputStream.write(request.toString().getBytes());//接收响应InputStream inputStream=socket.getInputStream();byte[]buffer=new byte[1024*1024];int n=inputStream.read(buffer);return new String(buffer,0,n,"utf-8");}
    //post报头public String post(String url,String body)throws IOException{StringBuilder request=new StringBuilder();//构造首行request.append("POST "+url+" HTTP/1.1\n");//构造headerrequest.append("host: "+ip+':'+port+'\n');request.append("Content-Length: "+body.getBytes().length+'\n');request.append("Content-Type: text/plain"+'\n');//构造空行request.append('\n');//构造bodyrequest.append(body);//发送请求OutputStream outputStream=socket.getOutputStream();//将request转为字节数组outputStream.write(request.toString().getBytes());//接收响应InputStream inputStream=socket.getInputStream();byte[]buffer=new byte[1024*1024];int n=inputStream.read(buffer);return new String(buffer,0,n,"utf-8");}public static void main(String[] args) throws IOException {HttpClient httpClient = new HttpClient("www.baidu.com", 80);String resp = httpClient.get("/");System.out.println(resp);}
    }
    

    构造方法 HttpClient(String ip, int port) 负责连接服务器(主机和端口),而 get(String url) 方法的参数仅负责指定资源路径,这样拆分更符合 HTTP 协议的逻辑。

    运行结果:

    http://www.xdnf.cn/news/1289737.html

    相关文章:

  • Linux服务:Apache 虚拟主机配置指南:多站点部署三种方式详解
  • 【超详细!题解|两种做法】洛谷P3196 [HNOI2008] 神奇的国度[MCS算法]
  • 深入剖析 React 合成事件:透过 onClick 看本质
  • 过程设计工具深度解析-软件工程之详细设计(补充篇)
  • Nginx 高级配置
  • 【后端】Spring @Resource和@Autowired的用法和区别
  • 通用同步/异步收发器USART串口
  • excel-随笔记
  • [ 数据结构 ] 时间和空间复杂度
  • Python初学者笔记第二十二期 -- (JSON数据解析)
  • VGG改进(2):基于Local Attention的模型优化
  • 【图像算法 - 13】基于 YOLO12 与 OpenCV 的实时目标点击跟踪系统(系统介绍 + 源码详细)
  • 获取数组,字符串,集合的长度
  • C++——高性能组件
  • 算法打卡力扣第88题:合并两个有序数组(easy)
  • 解释 Spring MVC 的工作原理
  • _init__.py的作用
  • 智能装配线cad【8张】三维图+设计说明书
  • linux 执行ls命令文件夹显示全白色
  • Langchain入门:文本摘要
  • 多轮问答与指代消解
  • 一维数组的创建、初始化与使用指南
  • “生成式UI革命”:Tambo AI如何让你的应用“开口说话、动手搭界面” | 全面深剖、案例实践与未来展望
  • Python函数篇:从零到精通
  • ubuntu24下keychorn键盘连接不了的改建页面的问题修复
  • 每日任务day0812:小小勇者成长记之挤牛奶
  • 10-docker基于dockerfile自动制作镜像
  • 熟悉并使用Spring框架 - 注解篇
  • golang的继承
  • 【Python办公】Mermaid代码转图片工具 - Tkinter GUI版本