HTTP
🍉简介
HTTP 协议全称为超文本传输协议,超文本比文本更加强大,它不仅包含字符串,还可以携带一些图片、特殊格式等
HTTP 最主要的应用场景就是网站。浏览器和服务器、客户端和服务器之间传输数据的协议,很可能就是 HTTP
🍉抓包工具
抓包工具本质上是一个代理程序,能够获取到网络上传输的数据并显示出来,从而给程序员提供一些参考,在后面介绍 HTTP 报文格式的过程中,会频繁用到抓包工具,这里我们使用 fiddler,它专注于 HTTP 的抓包
打开一个网站,浏览器和服务器之间会进行多次 HTTP 交互,其中第一次交互拿到的是这个页面的 html
选中这个请求并双击,可以看到明细:
点击 RAW,可以查看 HTTP 请求的原始数据
下面是请求的原始数据
再来看下响应的原始数据
为了节省带宽,一般响应数据会被压缩,对上述响应解压缩得到:
🍉报文结构
🍌请求
HTTP 请求包含 4 个部分
- 首行
- 请求头:由若干个键值对组成,每个键值对占一行, 键和值之间使用 : 分割
- 空行:请求头的结束标记
- 正文(body):http 的
载荷
部分,有的 http 请求有 body,有的没有
🍌响应
HTTP 响应的基本格式也是分为四个部分
- 首行
- **响应头:这里是按照键值对的形式来组织内容
- 空行
- 响应正文(body):响应的载荷是 html**
🍌URL
URL 全称为唯一资源定位符,用来描述一个网络上资源的位置
一个 URL 的完整结构如下:
🥝URL encode
query string(查询字符串)里是自定义的键值对,而在 URL 中,有些特殊符号,比如 / : ? @ 等都是有特定的含义,如果 query string 中也包含同样的符号,可能会使服务器 / 浏览器解析失败,比较靠谱的方法就是对上述符号进行转义(就像 C语言中用 printf 打印一些特殊符号一样,需要转义)。
除了这些特殊符号,汉字也要进行转义,因为汉字的 utf8 / gbk 等编码值中可能某个字节恰好和某个符号的 ASCII 码值一致
下面举个例子,比如搜索 C++:
🍌方法
有两个典型的使用 POST 的场景:登录和上传
以登录为例,在一个网站输入账号密码登录后抓包得到的数据报的 body:
这里有一个比较经典的面试题:
GET 和 POST 有什么区别
GET 和 POST 本质上没有区别。使用 GET 的场景也可以替换为 POST;使用 POST 的场景也可以替换为 GET。这取决于代码是怎么写的,尤其是服务器和客户端都是自己实现的情况下
但是这两者在使用习惯上还是有区别的:
- GET 习惯于把数据放到 URL 的 query string 中;POST 习惯于把数据放到 body 中
- 语义上的区别。标准文档中,GET 的语义是用来获取数据;POST 的语义是给服务器传输数据。当然实际使用并不拘泥于上述要求
- 关于幂等性。标准文档中建议 GET 请求实现成幂等的;POST 则没有要求。当然 GET 在实际开发中也不一定得实现成幂等
这里的"幂等"源于数学术语,如果每次输入的内容一定,输出的结果也一定,那就是幂等;反之,若输入内容一定,但输出不一定,则不是幂等。在计算机中,如果某个操作是幂等的,那就可以进行缓存
🍌报文字段
🥝Host
表示服务器主机的地址和端口
🥝Content-Length & Content-Type
这两个字段分别表示 body 中数据的长度
和请求的 body 中的数据格式
HTTP 底层也是基于 TCP
。连续传输多个 HTTP 数据报的话,接收方这边的接收缓冲区里就会积累多个包的数据,应用程序在读取这些数据时需要明确包与包之间的边界
。通过长度可以解决粘包问题
🥝User-Agent(UA)
UA 描述了操作系统和浏览器的信息,这两个其实就是在描述用户使用什么样的设备上网
它里面包含了系统信息,这就可以判定系统是 PC 的系统,还是移动端的系统,此时可以根据这个信息来返回不同的页面
比如在手机浏览器的设置中手动把 UA 修改为 PC 的 UA,那么就可以访问电脑版的网页了
🥝Referer
描述当前这个页面从哪儿来,类似上层目录,所以直接在浏览器输入 URL 的路径或从收藏夹中打开的网页都是没有 referer 的
🥝Cookie
Cookie 是报头中一个非常重要的属性,它本质上是浏览器本地持久化存储数据
的机制
操作系统提供了 api 操作文件,浏览器作为电脑上的一个程序,可以调用这些 api 来读写本地磁盘文件。而浏览器上运行的网页,理论上也是可以通过浏览器提供的 api 来读写本地文件,但是为了保证安全性,浏览器禁止这种做法,也就是说它没有给网页提供这样的 api。不然有些不法分子搞一些恶意网站,你点进去之后它就会把你电脑上的文件删掉,这样势必会造成巨大损失!
不过有些网站需要把一些信息保存到浏览器这边,比如登录界面需要保存用户的身份信息。所以浏览器给网页提供了这样的 api:可以有限度地存储数据,但不能随意访问文件系统
Cookie 就是一种经典的存储数据的机制
,它将存储的数据按照键值对的形式存储起来,其中键值对是由程序员自定义的,和 query string 差不多,因此不同网站的 Cookie 都是不一样的
HTTP 请求中的 Cookie 字段就是把本地存储的 Cookie 信息发送到服务器。相应地,HTTP 响应中会有一个 Set-Cookie 字段,这个是服务器告诉浏览器要在本地保存哪些信息
通常在首次访问 / 登录成功之后服务器会把数据返回给浏览器,然后 Cookie 会以域名为维度
存储在浏览器本地主机的硬盘上,比如浏览器访问 Gitee,就有一组 Cookie,访问 B 站,又有一组 Cookie,这些 Cookie 之间互不冲突,后续每次访问服务器都会带上对应网站的 Cookie
不同的客户端保存的 Cookie 是不同的,即使是同一台主机,使用不同的浏览器,Cookie 大概率也是不同的
Cookie 用途就是在客户端保存数据,其中保存的数据最主要是用户的身份标识,这样服务器就可以通过标识来区分用户。它一般不会保存其他业务数据,这些数据存在服务器,通过 Cookie 中的身份标识可以找到这些数据
有个典型的场景:在某个页面登录之后,下次登录就不用再输入账号密码,因为首次输入账密后这些信息就会保存在磁盘,下次进入网页时就会先从本地读取磁盘拿到账密。发送 HTTP 请求后服务器收到 Cookie 中的用户信息后就通过身份验证了,所以不用再手动输入账密
补充:页游中的账号密码等信息一般不是放在 Cookie 中的,因为浏览器保存的密码都是明文密码,放到 Cookie 中不安全
🍉状态码
🍌类别
🍌常见状态码
- 200 OK
打开 Fiddler,放眼望去基本都是 200,它表示请求已经成功处理
- 404 Not Found
这个也很常见,Not found 表示访问的资源没找到,此处的资源指的是URL 中的路径
比如输入一个不存在的网址:
-
403 Forbidden
表示请求的资源没有权限访问
-
405 Method Not Allowed
如果你的服务器只支持 GET 请求,但是你发了一个 POST 请求,那就会出现这个状态码
-
500 Internal Server Error
表示服务器内部错误,遇到这种情况可能是服务器挂了
-
504 Gateway Timeout
访问服务器超时了,这可能是服务器挂了,也可能是网断了
-
302 Move temporarily
临时重定向,表示资源
临时移动到新的位置
。除了 302,301 也表示重定向,不过它是永久性的
。重定向的时间会影响浏览器的缓存,如果是永久性的,那么浏览器会把重定向的结果记录下来,后续再次访问就会直接访问重定向的目标地址,不用多一次跳转了;而如果是临时性的,那就不太方便缓存了重定向报文的响应中会有一个特殊的 header:Location,它描述了重定向的
目标地址
在哪儿