1 HTTP基本概念
- HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写。
- HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
- HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。
- HTTP协议是一种应用层的传输协议,用于客户端和服务器之间的通信。
2 HTTP常用方法
方法 | 作用 | 说明 | 支持版本 |
---|---|---|---|
GET | 获取资源 | GET方法用来请求URL指定的资源。指定的资源经服务器端解析后返回响应内容 | 1.0/1.1 |
POST | 传输实体主体 | POST方法用来传输实体的主体 | 1.0/1.1 |
PUT | 传输文件 | 就像FTP协议的文件上传一样,要求在请求报文主体中包含文件的内容,然后保存到请求URL指定的位置。不太常用。 | 1.0/1.1 |
HEAD | 获得报文首部 | HEAD方法和GET方法一样,只是不返回报文主体部分。用于确认URL的有效性及资源更新的日期时间等。 | 1.0/1.1 |
DELETE | 删除文件 | DELETE方法用来删除文件,是PUT的相反方法。DELETE方法按请求URL删除指定的资源。也不常用 | 1.0/1.1 |
OPTIONS | 询问支持的方法 | OPTIONS方法用来查询针对请求URL指定的资源支持的方法 | 1.1 |
TRACE | 追踪路径 | TRACE方法是让Web服务器端将之前的请求通信环回给客户端方法。客户端可以用TRACE方法查询发送出去的请求时怎样被加工修改的。不常用,还容易引发XST攻击 | 1.1 |
CONNECT | 要求用隧道协议链接代理 | CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL和TSL协议把通信内容加密后经网络隧道传输 | 1.1 |
2.1 OPTIONS方法详解
OPTIONS请求即预检请求,可用于检测服务器允许的http方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起OPTIONS请求,即CORS预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
满足以下条件属于简单请求
- 请求方式只能是GET、POST、HEAD
- HTTP请求头限制这几种字段(Accept、Accept-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width)
- Content-Type:只能取application/x-www-form-urlencoded、multipart/form-data、text/plain
- 请求中的任意XMLHttpRequestUpload对象均没有注册任何事件监听器;XMLHttpRequestUpload对象可以使用
- 请求中没有使用ReadableStream对象
3 请求报文与响应报文
3.1 请求报文
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成,下图给出了请求报文的一般格式。
1.请求行
请求行分为三个部分:请求方法、请求地址和协议版本
2.请求头部
请求头部为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔。
常见请求头如下:
请求头 | 说明 |
---|---|
Accept | 可接受的响应内容类型(Content-Types ) |
Accept-Encoding | 可接受的字符集 |
Accept-Language | 可接受的响应内容的编码方式 |
Cache-Control | 用来指定当前的请求/回复中的,是否使用缓存机制。 |
Connection | 由之前服务器通过Set-Cookie (见下文)设置的一个HTTP协议Cookie |
Cookie | 表示服务器的域名以及服务器所监听的端口号。如果所请求的端口是对应的服务的标准端口(80),则端口号可以省略。 |
Host | 表示服务器的域名以及服务器所监听的端口号。如果所请求的端口是对应的服务的标准端口(80),则端口号可以省略。 |
Referer | 表示浏览器所访问的前一个页面,可以认为是之前访问页面的链接将浏览器带到了当前页面。Referer 其实是Referrer 这个单词,但RFC制作标准时给拼错了,后来也就将错就错使用Referer 了。 |
User-Agent | 浏览器的身份标识字符串 |
3.请求数据
可选部分,比如GET请求就没有请求数据。
而一个POST方法就会有请求体
响应报文
HTTP响应报文主要由状态行、响应头部、空行以及响应数据组成。
1.状态行
由3部分组成,分别为:协议版本,状态码,状态码描述。(状态码会在后面介绍)
2.响应头部
与请求头部类似,为响应报文添加了一些附加信息
常见响应头部如下:
响应头 | 说明 |
---|---|
Access-Control-Allow-Origin | 指定哪些网站可以跨域源资源共享 |
Age | 响应对象在代理缓存中存在的时间,以秒为单位 |
Cache-Control | 通知从服务器到客户端内的所有缓存机制,表示它们是否可以缓存这个对象及缓存有效时间。其单位为秒 |
Connection | 针对该连接所预期的选项 |
Content-Type | 当前内容的MIME 类型 |
Location | 用于在进行重定向,或在创建了某个新资源时使用。 |
Status | 通用网关接口的响应头字段,用来说明当前HTTP连接的响应状态。 |
4响应状态码
和请求报文相比,响应报文多了一个“响应状态码”,它以“清晰明确”的语言告诉客户端本次请求的处理结果。
HTTP的响应状态码由5段组成:
1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急...
- 100 Continue — 服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求。
- 101 Switching Protocols — 服务器转换协议:服务器将遵从客户的请求转换到另外一种协议。
- 102 Processing — 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。
2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息.
- 200 OK: 请求成功
- 201 Created: 常用于POST,PUT 请求,表明请求已经成功,并新建了一个资源。并在响应体中返回路径。
- 202 Accepted: 请求已经接收到,但没有响应,稍后也不会返回一个异步请求结果。 该状态码适用于等待其他进程处理或者批处理的场景
- 203 No-Authoritative Information: 表明响应返回的元信息(meta-infomation)和最初的服务器不同,而是从本地或者第三方获取的。主要用于其他资源的镜像和备份。除了前面的情况,首选还是200
- 204 No Content: 请求没有数据返回,但是头信息有用。用户代理(浏览器)会更新缓存的头信息。
- 205 Reset Content: 告诉用户代理(浏览器)重置发送该请求的文档。
- 206 Partical Content: 当客户端使用Range请求头时,返回该状态码。
3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
- 301 永久性重定向
- 302 临时性重定向
- 304 Not Modified: 资源未变更。
4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
- 400 Bad Request: 请求语法有问题,服务器无法识别。没有host请求头字段,或者设置了超过一个的host请求头字段。
- 401 UnAuthorized: 客户端未授权该请求。缺乏有效的身份认证凭证,一般可能是未登陆。登陆后一般都解决问题。
- 403 Forbidden: 服务器拒绝响应。权限不足。
- 404 Not Found: URL无效或者URL有效但是没有资源。
- 405 Method Not Allowed: 请求方式Method不允许。但是GET和HEAD属于强制方式,不能返回这个状态码。
- 406 Not Acceptable: 资源类型不符合服务器要求。
- 407 Proxy Authorization Required: 需要代理授权。
- 408 Request Timeout:服务器将不再使用的连接关闭。响应头会有Connection: close。
- 426 Upgrade Required: 告诉客户端需要升级通信协议。
5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。
- 500 Internal Server Error: 服务器内部错误,未捕获。
- 502 Bad Gateway: 服务器作为网关使用时,收到上游服务器返回的无效响应。
- 503 Service Unavailable: 无法服务。一般发生在因维护而停机或者服务过载。一般还会伴随着返回一个响应头Retry-After: 说明恢复服务的估计时间。
- 504 Gateway Timeout: 网关超时。服务器作为网关或者代理,不能及时从上游服务器获取响应返回给客户端。
- 505 Http Version Not Supported: 发出的请求http版本服务器不支持。如果请求通过http2发送,服务器不支持http2.0,就会返回该状态码。
5 浏览器缓存机制
我们根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分,分别是强制缓存和协商缓存 。
5.1强制缓存
强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程,强制缓存的情况主要有三种(暂不分析协商缓存过程),如下:
- 不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致)
- 存在该缓存结果和缓存标识,但是结果已经失效,强制缓存失效,则使用协商缓存(暂不分析)
- 存在该缓存结果和缓存标识,且该结果没有还没有失效,强制缓存生效,直接返回该结果
当浏览器向服务器发送请求的时候,服务器会将缓存规则放入HTTP响应的报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Conctrol的优先级比Expires高
2.1.2Cache-Control
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private:所有内容只有客户端可以缓存,Cache-Control的默认取值
- no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
5.2协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
- 协商缓存生效,返回304
- 协商缓存失败,返回200和请求结果
协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的,控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。
2.2.1Last-Modified / If-Modified-Since
- Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间
- If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件
Etag / If-None-Match
- Etag是服务器响应请求时,返回当前资源文件的一个唯一标识
- If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200
6 版本对比
http协议目前有4个版本,其中1.0、1.1版本在互联网上被广泛使用,2.0版本目前开始逐步得到应用,是新一代的http协议。
- http/0.9版本:1991年,原型版本,功能简陋,只有一个命令GET,只支持纯文本内容,该版本已过时。
- http/1.0版本: 1996年5月,支持cache, MIME, method等。
- http/1.1版本: 1997年1月,默认建立持久连接,并能很好地配合代理服务器工作。还支持以管道方式在同时发送多个请求,以便降低线路负载,提高传输速度。
- http/2 版本: 2015年5月作为互联网标准正式发布,头部信息和数据体都是二进制,引入头信息压缩机制等。
http1.0版本
- 任何格式的内容都可以发送,这使得互联网不仅可以传输文字,还能传输图像、视频、二进制等文件。
- 除了GET命令,还引入了POST命令和HEAD命令。
- http请求和回应的格式改变,除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。
http1.1版本
- http1.1是目前最为主流的http协议版本,从1997年发布至今,仍是主流的http协议版本。
- 引入了持久连接( persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。
- 引入了管道机制( pipelining),即在同一个TCP连接里,客户端可以同时发送多个请求,进一步改进了HTTP协议的效率。
- 新增方法:PUT、 PATCH、 OPTIONS、 DELETE。
- http协议不带有状态,每次请求都必须附上所有信息。请求的很多字段都是重复的,浪费带宽,影响速度。
http2版本
为了解决1.1版本利用率不高的问题,提出了HTTP/2.0版本。增加双工模式,即不仅客户端能够同时发送多个请求,服务端也能同时处理多个请求,解决了队头堵塞的问题(HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级);HTTP请求和响应中,状态行和请求/响应头都是些信息字段,并没有真正的数据,因此在2.0版本中将所有的信息字段建立一张表,为表中的每个字段建立索引,客户端和服务端共同使用这个表,他们之间就以索引号来表示信息字段,这样就避免了1.0旧版本的重复繁琐的字段,并以压缩的方式传输,提高利用率。另外也增加服务器推送的功能,即不经请求服务端主动向客户端发送数据。
二进制协议
HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。
多工
HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。
举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
这样双向的、实时的通信,就叫做多工(Multiplexing)。
数据流
因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM
帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
头信息压缩
HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie
和User Agent
,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip
或compress
压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
服务器推送
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。
意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。
服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。
常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。