HTTP状态码
- 1xx 信息性状态码 websocket upgrade
- 2xx 成功状态码
- 200 服务器已成功处理了请求
- 204(没有响应体)
- 206(范围请求 暂停继续下载)
- 3xx 重定向状态码
- 301(永久) :请求的页面已永久跳转到新的url
- 302(临时) :允许各种各样的重定向,一般情况下都会实现为到
GET
的重定向,但是不能确保POST
会重定向为POST
- 303 只允许任意请求到
GET
的重定向 - 304 未修改:自从上次请求后,请求的网页未修改过
- 307:
307
和302
一样,除了不允许POST
到GET
的重定向
- 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 协议里的应答方,常用的有
Apache
和Nginx
; 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
和三层的TCP
,HTTP
在第四层;OSI
分为七层,基本对应TCP/IP
,TCP
在第四层,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
通常由scheme
、host:port
、path
和query
四个部分组成,有的可以省略;scheme
叫“方案名”或者“协议名”,表示资源应该使用哪种协议来访问;- “
host:port
”表示资源所在的主机名和端口号; path
标记资源所在的位置;query
表示对资源附加的额外要求;- 在
URI
里对“@&/
”等特殊字符和汉字必须要做编码,否则服务器收到HTTP
报文后会无法正确处理
6. HTTP实体数据
1. 数据类型与编码
- text:即文本格式的可读数据,我们最熟悉的应该就是
text/html
了,表示超文本文档,此外还有纯文本text/plain
、样式表text/css
等。 image
:即图像文件,有image/gif
、image/jpeg
、image/png
等。audio/video
:音频和视频数据,例如audio/mpeg
、video/mp4
等。application
:数据格式不固定,可能是文本也可能是二进制,必须由上层应用程序来解释。常见的有application/json
,application/javascript
、application/pdf
等,另外,如果实在是不知道数据是什么类型,像刚才说的“黑盒”,就会是application/octet-stream
,即不透明的二进制数据
但仅有
MIME type
还不够,因为HTTP
在传输时为了节约带宽,有时候还会压缩数据,为了不要让浏览器继续“猜”,还需要有一个“Encoding type”,告诉数据是用的什么编码格式,这样对方才能正确解压缩,还原出原始的数据。
比起 MIME type
来说,Encoding type
就少了很多,常用的只有下面三种
gzip
:GNU zip
压缩格式,也是互联网上最流行的压缩格式;deflate
:zlib
(deflate
)压缩格式,流行程度仅次于gzip
;br
:一种专门为HTTP
优化的新压缩算法(Brotli
)
2. 数据类型使用的头字段
有了 MIME type
和 Encoding type
,无论是浏览器还是服务器就都可以轻松识别出 body
的类型,也就能够正确处理数据了。
HTTP
协议为此定义了两个 Accept
请求头字段和两个 Content
实体头字段,用于客户端和服务器进行“内容协商”。也就是说,客户端用 Accept
头告诉服务器希望接收什么样的数据,而服务器用 Content
头告诉客户端实际发送了什么样的数据
Accept
字段标记的是客户端可理解的MIME
type,可以用“,”做分隔符列出多个类型,让服务器有更多的选择余地,例如下面的这个头:
Accept: text/html,application/xml,image/webp,image/png
这就是告诉服务器:“我能够看懂 HTML、XML 的文本,还有 webp
和 png
的图片,请给我这四类格式的数据”。
相应的,服务器会在响应报文里用头字段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
”来表示,这点需要特别注意。 - 例如,浏览器请求
GBK
或UTF-8
的字符集,然后服务器返回的是UTF-8
编码,就是下面这样
Accept-Charset: gbk, utf-8
Content-Type: text/html; charset=utf-8
不过现在的浏览器都支持多种字符集,通常不会发送 Accept-Charset
,而服务器也不会发送 Content-Language
,因为使用的语言完全可以由字符集推断出来,所以在请求头里一般只会有 Accept-Language
字段,响应头里只会有 Content-Type
字段
4. 内容协商的质量值
在 HTTP 协议里用 Accept
、Accept-Encoding
、Accept-Language
等请求头字段进行内容协商的时候,还可以用一种特殊的“q”参数表示权重来设定优先级,这里的“q”是“quality factor”的意思。
权重的最大值是 1,最小值是 0.01,默认值是 1,如果值是 0 就表示拒绝。具体的形式是在数据类型或语言代码后面加一个“;”,然后是“q=value”。
这里要提醒的是“;”的用法,在大多数编程语言里“;”的断句语气要强于“,”,而在 HTTP 的内容协商里却恰好反了过来,“;”的意义是小于“,”的。
例如下面的 Accept 字段: