HTTP 的前世今生

HTTP状态码

  • 1xx 信息性状态码 websocket upgrade
  • 2xx 成功状态码
    • 200 服务器已成功处理了请求
    • 204(没有响应体)
    • 206(范围请求 暂停继续下载)
  • 3xx 重定向状态码
    • 301(永久) :请求的页面已永久跳转到新的url
    • 302(临时) :允许各种各样的重定向,一般情况下都会实现为到 GET 的重定向,但是不能确保 POST 会重定向为 POST
    • 303 只允许任意请求到 GET 的重定向
    • 304 未修改:自从上次请求后,请求的网页未修改过
    • 307:307302 一样,除了不允许 POSTGET 的重定向
  • 4xx 客户端错误状态码
    • 400 客户端参数错误
    • 401 没有登录
    • 403 登录了没权限 比如管理系统
    • 404 页面不存在
    • 405 禁用请求中指定的方法
  • 5xx 服务端错误状态码
    • 500 服务器错误:服务器内部错误,无法完成请求
    • 502 错误网关:服务器作为网关或代理出现错误
    • 503 服务不可用:服务器目前无法使用
    • 504 网关超时:网关或代理服务器,未及时获取请求

1. HTTP前生今世

  • HTTP 协议始于三十年前蒂姆·伯纳斯 - 李的一篇论文
  • HTTP/0.9 是个简单的文本协议,只能获取文本资源;
  • HTTP/1.0 确立了大部分现在使用的技术,但它不是正式标准;
  • HTTP/1.1 是目前互联网上使用最广泛的协议,功能也非常完善;
  • HTTP/2 基于 Google 的 SPDY 协议,注重性能改善,但还未普及;
  • HTTP/3 基于 Google 的 QUIC 协议,是将来的发展方向

2. HTTP世界全览

  • 互联网上绝大部分资源都使用 HTTP 协议传输;
  • 浏览器是 HTTP 协议里的请求方,即 User Agent
  • 服务器是 HTTP 协议里的应答方,常用的有 ApacheNginx
  • CDN 位于浏览器和服务器之间,主要起到缓存加速的作用;
  • 爬虫是另一类 User Agent,是自动访问网络资源的程序。
  • TCP/IP 是网络世界最常用的协议,HTTP 通常运行在 TCP/IP 提供的可靠传输基础上
  • DNS 域名是 IP 地址的等价替代,需要用域名解析实现到 IP 地址的映射;
  • URI 是用来标记互联网上资源的一个名字,由“协议名 + 主机名 + 路径”构成,俗称 URL;
  • HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,为 HTTP 套了一个安全的外壳;
  • 代理是 HTTP 传输过程中的“中转站”,可以实现缓存加速、负载均衡等功能

3. HTTP分层


  • 第一层:物理层,TCP/IP 里无对应;
  • 第二层:数据链路层,对应 TCP/IP 的链接层;
  • 第三层:网络层,对应 TCP/IP 的网际层;
  • 第四层:传输层,对应 TCP/IP 的传输层;
  • 第五、六、七层:统一对应到 TCP/IP 的应用层

总结

  • TCP/IP 分为四层,核心是二层的 IP 和三层的 TCPHTTP 在第四层;
  • OSI 分为七层,基本对应 TCP/IPTCP 在第四层,HTTP 在第七层;
  • OSI 可以映射到 TCP/IP,但这期间一、五、六层消失了;
  • 日常交流的时候我们通常使用 OSI 模型,用四层、七层等术语;
  • HTTP 利用 TCP/IP协议栈逐层打包再拆包,实现了数据传输,但下面的细节并不可见

有一个辨别四层和七层比较好的(但不是绝对的)小窍门,“两个凡是”:凡是由操作系统负责处理的就是四层或四层以下,否则,凡是需要由应用程序(也就是你自己写代码)负责处理的就是七层

4. HTTP报文是什么样子的

HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成

  • 起始行(start line):描述请求或响应的基本信息;
  • 头部字段集合(header):使用 key-value 形式更详细地说明报文;
  • 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据

这其中前两部分起始行和头部字段经常又合称为“请求头”或“响应头”,消息正文又称为“实体”,但与“header”对应,很多时候就直接称为“body”。

一个完整的 HTTP 报文就像是下图的这个样子,注意在 header 和 body 之间有一个“空行”


5. HTTP之URL

  • URI 是用来唯一标记服务器上资源的一个字符串,通常也称为 URL;
  • URI 通常由 schemehost:portpathquery 四个部分组成,有的可以省略;
  • scheme 叫“方案名”或者“协议名”,表示资源应该使用哪种协议来访问;
  • host:port”表示资源所在的主机名和端口号;
  • path 标记资源所在的位置;
  • query 表示对资源附加的额外要求;
  • URI 里对“@&/”等特殊字符和汉字必须要做编码,否则服务器收到 HTTP报文后会无法正确处理

6. HTTP实体数据

1. 数据类型与编码

  • text:即文本格式的可读数据,我们最熟悉的应该就是 text/html 了,表示超文本文档,此外还有纯文本 text/plain、样式表 text/css 等。
  • image:即图像文件,有 image/gifimage/jpegimage/png 等。
  • audio/video:音频和视频数据,例如 audio/mpegvideo/mp4 等。
  • application:数据格式不固定,可能是文本也可能是二进制,必须由上层应用程序来解释。常见的有 application/jsonapplication/javascriptapplication/pdf 等,另外,如果实在是不知道数据是什么类型,像刚才说的“黑盒”,就会是 application/octet-stream,即不透明的二进制数据

但仅有 MIME type 还不够,因为 HTTP 在传输时为了节约带宽,有时候还会压缩数据,为了不要让浏览器继续“猜”,还需要有一个“Encoding type”,告诉数据是用的什么编码格式,这样对方才能正确解压缩,还原出原始的数据。

比起 MIME type 来说,Encoding type 就少了很多,常用的只有下面三种

  • gzipGNU zip 压缩格式,也是互联网上最流行的压缩格式;
  • deflatezlibdeflate)压缩格式,流行程度仅次于 gzip
  • br:一种专门为 HTTP 优化的新压缩算法(Brotli

2. 数据类型使用的头字段

有了 MIME typeEncoding type,无论是浏览器还是服务器就都可以轻松识别出 body 的类型,也就能够正确处理数据了。

HTTP 协议为此定义了两个 Accept 请求头字段和两个 Content 实体头字段,用于客户端和服务器进行“内容协商”。也就是说,客户端用 Accept 头告诉服务器希望接收什么样的数据,而服务器用 Content 头告诉客户端实际发送了什么样的数据

img

Accept字段标记的是客户端可理解的 MIME type,可以用“,”做分隔符列出多个类型,让服务器有更多的选择余地,例如下面的这个头:

Accept: text/html,application/xml,image/webp,image/png

这就是告诉服务器:“我能够看懂 HTML、XML 的文本,还有 webppng 的图片,请给我这四类格式的数据”。

相应的,服务器会在响应报文里用头字段Content-Type告诉实体数据的真实类型:

Content-Type: text/html
Content-Type: image/png

这样浏览器看到报文里的类型是“text/html”就知道是 HTML 文件,会调用排版引擎渲染出页面,看到“image/png”就知道是一个 PNG 文件,就会在页面上显示出图像。

Accept-Encoding字段标记的是客户端支持的压缩格式,例如上面说的 gzip、deflate 等,同样也可以用“,”列出多个,服务器可以选择其中一种来压缩数据,实际使用的压缩格式放在响应头字段Content-Encoding

Accept-Encoding: gzip, deflate, br
Content-Encoding: gzip

不过这两个字段是可以省略的,如果请求报文里没有 Accept-Encoding 字段,就表示客户端不支持压缩数据;如果响应报文里没有 Content-Encoding 字段,就表示响应数据没有被压缩

3. 语言类型使用的头字段

同样的,HTTP 协议也使用 Accept 请求头字段和 Content 实体头字段,用于客户端和服务器就语言与编码进行“内容协商”。

Accept-Language字段标记了客户端可理解的自然语言,也允许用“,”做分隔符列出多个类型,例如:

Accept-Language: zh-CN, zh, en

这个请求头会告诉服务器:“最好给我 zh-CN 的汉语文字,如果没有就用其他的汉语方言,如果还没有就给英文”。

相应的,服务器应该在响应报文里用头字段Content-Language告诉客户端实体数据使用的实际语言类型

Content-Language: zh-CN
  • 字符集在 HTTP 里使用的请求头字段是Accept-Charset,但响应头里却没有对应的 Content-Charset,而是在Content-Type字段的数据类型后面用“charset=xxx”来表示,这点需要特别注意。
  • 例如,浏览器请求 GBKUTF-8 的字符集,然后服务器返回的是 UTF-8 编码,就是下面这样
Accept-Charset: gbk, utf-8
Content-Type: text/html; charset=utf-8

不过现在的浏览器都支持多种字符集,通常不会发送 Accept-Charset,而服务器也不会发送 Content-Language,因为使用的语言完全可以由字符集推断出来,所以在请求头里一般只会有 Accept-Language 字段,响应头里只会有 Content-Type字段

img

4. 内容协商的质量值

在 HTTP 协议里用 AcceptAccept-EncodingAccept-Language 等请求头字段进行内容协商的时候,还可以用一种特殊的“q”参数表示权重来设定优先级,这里的“q”是“quality factor”的意思。

权重的最大值是 1,最小值是 0.01,默认值是 1,如果值是 0 就表示拒绝。具体的形式是在数据类型或语言代码后面加一个“;”,然后是“q=value”。

这里要提醒的是“;”的用法,在大多数编程语言里“;”的断句语气要强于“,”,而在 HTTP 的内容协商里却恰好反了过来,“;”的意义是小于“,”的。

例如下面的 Accept 字段:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小码哥・Martin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值