HTTP 报文格式 HTTP 报文由请求行、首部、实体组成,首部和实体之间由 CRLF(回车换行符) 分隔开。
请求报文格式:
<method> <request-URL> <version>
<headers>
<entity-body>
GET /2.app.js HTTP/1.1
Host: 118.190.217.8:3389
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
Accept: *\/*
Referer: http://118.190.217.8:3389/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
响应报文格式:
<version> <status> <reason-phrase>
<headers>
<entity-body>
HTTP/1.1 200 OK
X-Powered-By: Express
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Sat, 07 Mar 2020 03:52:30 GMT
ETag: W/"253e-170b31f7de7"
Content-Type: application/javascript; charset=UTF-8
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Fri, 15 May 2020 05:38:05 GMT
Connection: keep-alive
Transfer-Encoding: chunked
幂等和非幂等
- 幂等:果一个请求不管执行多少次,其执行的副作用都是一样的,这个请求就是幂等的(如:get、head)
- 非幂等:post(如相同url都是执行新增的操作)
- POST和PUT很容易让人混淆,之前我总是简单的认为:POST表示创建资源,PUT表示更新资源;但是实际上它们都可用于创建和更新资源,只不过本质的差别就在于幂等性上。POST所对应的URI并非创建资源的本身,而是「资源的接收者」。例如:POST http://lindaidai.wang/articles的语义是在http://lindaidai.wang/articles下创建一篇帖子,HTTP响应中应包含帖子的创建状态以及帖子的URI。两次相同的POST请求会在服务器端创建两份资源,它们具有不同的URI,所以POST是「非幂等」的。
- PUT方法所对应的URI是要创建或者更新「资源本身」。这点很容易让人误会它不是幂等的,但其实它是「幂等」的。例如:PUT http://lindaidai.wang/accout/321 的语义是创建或者更新ID为321的帖子。第一次PUT方法执行之后,其在服务器上生成的资源,不能被后续的PUT方法更改,所以对同一URI进行多次PUT的副作用和一次PUT是相同的,因而它是「幂等」的。
请求方法
-
HEAD:只从服务器获取文档的头部不获取资源,幂等操作 -
PUT:PUT 方法的语义就是让服务器用请求的主体部分来创建一个由所请求的 URL 命名的新文档。 如果那个文档已存在,就覆盖它,幂等操作 -
PATCH:对资源进行局部更新,非幂等操作 -
POST:通常用来向服务器发送表单数据。创建或更新资源,非幂等操作 -
TRACE:客户端发起一个请求时,这个请求可能要穿过路由器、防火墙、代理、网关等。每个中间节点都可能会修改原始的 HTTP 请求,TRACE 方法允许客户端在最终发起请求时,看看它变成了什么样子。幂等操作
- TRACE 请求会在目的服务器端发起一个“环回”诊断。行程最后一站的服务器会弹回一条 TRACE 响应,并在响应主体中携带它收到的原始请求报文。 这样客户端就可以查看在所有中间 HTTP 应用程序组成的请求/响应链上,原始报文是否被毁坏或修改过。
首部报文
- 多个字段值用,号连接:Keep-Alive: timeout=15, max=100
- 若是字段值有可选参数且是多个则用;号连接:Accept: text/html, q=1; application/xml, q=0.8
- 当有多个字段值的时候,可以指定字段 q 来作为权重,权重范围 0~1。
通用报文:
- Connection:允许客户端和服务器指定与请求/响应连接有关的选项
- Date:提供日期和时间标志,说明报文是什么时间创建的
- MIME-version:给出了发送端使用的MIME版本
- Trailer:如果报文采用了分块传输编码(chunked transfer encoding)方式,就可以用这个首部列出位于报文拖挂(trailer)部分的首部集合
- Transfer-Encoding:告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式
- Update:给出了发送端可能想要“升级”使用的新版本或协议
- via:显示了报文经过的中间节点(代理、网关)
请求报文:
- client-IPR:提供了运行客户端的机器的IP地址
- From:提供了客户端用户的E-mail地址
- Host:给出了接收请求的服务器的主机名和端口号,使用场景:如果一台服务器托管了多个域名,因为它们部署在同一个服务器上,当使用DNS解析的时候会得到相同的IP地址,因此需要在HTTP请求时在Host首部内完整指定主机名或域名的URl
- Accept:客户端或者代理能够处理的媒体类型
- Accept-Encoding:优先可处理的编码格式
- Accept-Language:优先可处理的自然语言
- Accept-Charset:优先可以处理的字符集
- Referer:告诉服务器该请求是从哪个URI上来的
- User-Agent:将发起请求的应用程序名称告知服务器
- Authorization:web的认证信息
- lf-Match:值是资源的唯一标识,它的值和ETag一致时服务器才会处理该请求
- lf-None-Match:与ETag字段配合达到协商缓存的作用,值是资源的唯一标识,它的值和ETag不一致时服务器才会处理该请求,值和ETag不一致时表明服务器的资源被改过了那么本地的缓存就需要更新服务器最新的资源
- lf-Modified-Since:与Last-Modified字段配合达到协商缓存的作用,值是请求资源的过期时间,它的值和服务器资源的修改时间比较只有不一致时才会处理该请求
- lf-Unmodified-Since:作用和If-Modified-Since相反
- lf-Range:它告知服务器如果lf-Range的值(ETag或者时间)的值和服务器资源ETag或者时间一致则作为范围请求处理,也就是返回Range字段中的部分资源;否则就返回整个资源,如果没有指定If-Range而只指定了Range那么则需要进行两次处理
- Range:获取资源的某个范围的部分用于断点续传,值为某个范围,例如:Range: bytes=5001-10000,响应报文状态行返回206状态码和Partial,响应头中HTTP/1.1 206 Partial Content,Content-Range: bytes 5001-10000/10000,若是无法处理则返回200 OK以及整个资源
- UA-Color:提供了与客户端显示器的显示颜色有关的信息
- UA-CPU:给出了客户端CPU的类型或制造商
- UA-Disp:提供了与客户端显示器(屏幕)能力有关的信息
- UA-OS:给出了运行在客户端机器上的操作系统名称及版本
- UA-Pixels:提供了客户端显示器的像素信息
响应报文:
- Accept-Ranges:用来告知客户端服务器能否处理范围请求,值有两种:Accept-Ranges: bytes;Accept-Ranges: none
- Age:告知客户端服务器在多久前创建了响应,若是创建该响应的是缓存服务器则表示缓存后的响应再次发起认证到认证完成的时间值,值的单位是秒:Age: 600
- vary:代理服务器的缓存信息
- Location:用于指定重定向之后的URI,—般配合3XX状态码告知客户端需要重定向到Location上
- Server: 告知客户端当前服务器上安装的HTTP服务器应用程序的信息,server: nginx
- ETag: 告知客户端资源的实体标识,也就是资源的唯一标识,配合If-None-Match做协商缓存用,强ETag值:无论资源发生了多么细微的改变ETag都会变ETag: “usagi-12234”,弱ETag值:只会用于提示资源是否发生改变,只有资源发生根本改变ETag才会变,若是发生了根本改变:ETag: W/“usagi-12234”
实体首部报文:
- Content-Type:实体媒体类型,实体媒体类型
- Content-Range:针对范围请求,告诉客户端当前返回的是实体的哪个范围的部分,Content-Range: bytes 5001-10000/10000
- Content-Length: 表明了实体主体部分的大小单位是字节,当使用了内容编码的时候,也就是Accept-Encoding: gzip,不能再使用Content-Length,Content-Length: 6000
- Content-Encoding:实体的编码格式,配合Accept-Encoding
- Content-Language:实体的自然语言,配合Accept-Language
- Allow:告知客户端服务器能够支持的HTTP方法,Allow: GET, POST,HEAD,当服务端收到不支持的方法时会返回405 Method Not Allowed,并且会把所有支持的方法写入响应报文首部字段Allow中返回
- Last-Modified:资源的最后修改时间,配合lf-Modified-Since失效协商缓存,Last-Modified: Wed, Nov 11 2020 08:00:00 GMT
- Expires:强缓存的一种方式,设置资源缓存的失效日期,要从原始的源端再次获取此实体的日期和时间,Expires: Wed, Nov 11 2020 08:00:00 GMT
- Last-Modified:这个实体最后一次被修改的日期和时间
非标准首部字段
- x-XSS-Protection:属于响应首部,针对跨站脚本攻击(XSS)的一种对策略
- X-Frame-Options:属于响应首部,用于控制网站内容在其它Web网站的Frame标签内的显示问题。主要目的是为了防止点击挟持。
- 协议中对X-前缀的废除:之前是用×-开头来区分是否是非标准的字段但是后来被废除了这个做法。但是对于已经存在的X-开头的字段来说就让它存在吧。
- Cookie: 客户端传递给服务端的Cookie信息
- Set-Cookie: 在响应报文首部设置要传递给客户端生成的Cookie信息
范围请求
- 接收方(请求):lf-Range和Range
lf-Range: “usage-12234” Range: bytes=5001-10000 - 发送方(响应):Accept-Ranges和Content-Range
HTTP/1.1 206 Partial Content Accept-Ranges: bytes Content-Range: bytes 5001-10000/10000
指定字符集
- 接收方(请求): Accept-Chartset
- 发送方(响应): Content-Type
数据格式
- 接收方(请求):Accept
- 发送方(响应):Content-Type
- 字段值: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
压缩方式
- 接收方(请求):Accept-Encoding
- 发送方(响应):Content-Encoding
- 字段值:gzip:当今最流行的压缩格式,deflate:使用zlib的格式压缩,br:—种专门为HTTP发明的压缩算法,compress:实体采用Unix的文件压缩程序,identity:不对实体进行编码。当没有Content-Encoding首部的时候,就默认这种情况
内容编码的具体过程主要是:
- 服务器生成原始响应报文,其中有原始的Content-Type和Content-Length首部字段
- 接着将原始的响应报文经过内容编码服务器创建编码后的报文。这个编码后的报文同样有Content-Type和Content-Length两个字段,只不过Content-Length是有可能变的,例如主体经过了压缩,那么它的值肯定就变小了。
- 在编码后的报文中增加Content-Encoding首部,这样收到的应用程序就可以进行解码了。
- 接收程序收到编码后的报文再进行解码,获得原始报文。
传输编码
-
在非长连接的情况下浏览器可以通过连接是否关闭来界定请求或者响应的边界;而对于建立了长连接的情况,也就是设置了Connection: keep-alive这个头部,浏览器没法判断这次的数据是否传输完了,这时候就得计算「实体的长度」,并通过头部告诉浏览器,也就是使用Content-Length这个首部字段。 -
Content-Length如果比实际的长度短,就会造成内容被截断,甚至会影响下一次的请求;如果比实际的长度长,则会造成pending,这个请求一直在等待中直到超时。 -
因此Content-Length的计算显得尤为重要,它必须真实的反应实体长度。但又由于很多时候实体长度并没有那么容易获得,例如实体来自于网络文件,或者由动态语言生成。而这时候如果需要等待Content-Length的计算的话,无疑会影响到TTFB(Time To First Byte),也就是从客户端发出请求到收到响应的第一个字节所花费的时间。越短的TTFB则能让用户更早的看到页面内容,体验越好。 -
所以这就是Transfer-Encoding: chunked产生的原因,它解决了:不依赖头部的长度信息,也能知道实体的边界。 -
设置了此首部之后,表明这是一次分块传输,可以将报文实体改为用一系列分块来传输 -
每个分块会有两部分内容:十六进制的长度和数据(例如a\r\n表示的就是长度为10,因为a是十六进制中的10;后面的0123456789就表示数据) -
长度值独占一行,长度不包括它结尾的CRLF(\r\n),也不包括分块数据结尾的CRLF。 -
最后一个分块的长度值必须是0,且对应分块数据没有内容,它表示的是实体结束。
支持语言
- 接收方(请求):Accept-Language
- 发送方(响应):Content-Language
- 字段值:zh-CN, zh, en
图片或文本文件等上传
- Content-Type: multipart/form-data;
- Content-Type: multipart/byteranges;状态码206(Partial Content, 部分内容)响应报文包含了多个范围的内容时使用。
状态码
- 200 OK :请求成功,通常返回的数据中带有响应体。
- 204 No Content:意思和200一样,不过返回的数据中不带有响应体。
- 206 Partial Content:客户端进行了范围请求且服务端正常处理,响应报文的首部应该还有Content-Range字段指定实体的范围。使用场景为HTTP分块下载和断点续传。
- 301 Moved Permanently:永久重定向,最新的URI为响应报文首部的 Location 字段。场景是:例如你的网站换了地址了,之前的地址不用了,若用户还是从之前的地址进的话则会返回301且在Location中带上最新的URI。且浏览器默认会做缓存优化,减少服务器压力,在第二次访问的时候自动访问重定向的那个地址。
- 302 Found:临时重定向,和301不同,它表示请求的资源临时被移动到了别的URI上,因为是暂时的,所以不会被缓存
- 303 See Other:临时重定向,请求的资源临时被移动到了别的URI上,但是明确表示客户端应该使用GET方法获取资源。
- 304 Not Modefied:协商缓存成功就会返回304 Not Modefied,表示请求的资源在服务器上并未发送改变,告诉请求者可以使用缓存
- 307 Temprary Redirect:临时重定向,但是比302更加明确,重定向的请求方法和实体都不允许变动。场景例如:HSTS协议,强制客户端使用https建立连接,比如你的网站从HTTP升级到了HTTPS,而你还是通过http://xxx访问的话,就会返回307 Internal Redirect
- 400 Bad Request:请求报文中存在语法错误,但是没有具体指出是哪里。
- 401 Unauthorized:需要有通过HTTP认证的认证信息或者表示用户认证失败。
- 403 Forbidden:请求资源被拒绝,原因是:比如法律禁止、信息敏感。
- 404 Not Found:请求资源未找到,表示没在服务器上找到相应的资源。
- 500 Internal Server Error:服务器内部错误,但是没有具体指出是哪里,和400有点像。
- 501 Not Implemented:表示客户端请求的功能还不支持
- 502 Bad GateWay:服务器自身是正常的,但是代理服务器无法获取到合法响应
- 503 Service Unavailable:服务器内部处于超负载状态或进行停机维护
|