共计 6509 个字符,预计需要花费 17 分钟才能阅读完成。
前言
关于 HTTP 的知识比较繁杂,也比较零散,于是想要通过这篇文章对常用知识点进行总结,一些知识点描述是从网上搜集而来,如有侵权,可以联系我进行修改。
提出问题
Http 的报文结构。
Http request 的几种类型。
Http 的状态码含义。
Http1.1 和 Http1.0 的区别,以及缓存原理
Http 长连接 keep-alive。
Cookie 与 Session 的作用于原理。
电脑上访问一个网页,整个过程是怎么样的:DNS、HTTP、TCP、OSPF、IP、ARP。
解答
1. Http 的报文结构
http 协议的请求报文和响应报文都是由以下 4 部分组成:
请求行
请求头
空行 CR + LF,回车 + 换行
请求体
2. Http request 的几种类型
请求行
Request
格式:【方法 URL HTTP 版本】例如:GET /csrfToken HTTP/1.1
HTTP 版本:目前有 HTTP/1.0、HTTP/1.1、HTTP/2.0 版本,其中 HTTP1.1 版本使用较广泛
方法
说明
支持 HTTP 协议版本
GET
获取资源
1.0、1.1
POST
传输实体主体
1.0、1.1
PUT
传输文件
1.0、1.1
HEAD
获得报文首部
1.0、1.1
DELETE
删除资源
1.0、1.1
OPTIONS
询问支持的方法
1.1
TRACE
追踪路径
1.1
CONNECT
要求用隧道协议连接代理
1.1
LINK
建立和资源之间的联系
1.0
UNLINK
断开连接关系
1.0
Response
格式:【HTTP 版本 状态码 描述】例如:HTTP/1.1 200 OK、HTTP/1.1 404 NOT FOUND
类别
原因短语
1xx
Informational(信息性状态码)
接收的请求正在处理
2xx
Success(成功状态码)
请求正常处理完毕
3xx
Redirection(重定向状态码)
需要进行附加操作以完成请求
4xx
Client Error(客户端错误状态码)
服务器无法处理请求
5xx
Server Error(服务器错误状态码)
服务器处理请求出错
3. Http 的状态码含义
常用状态码
200:OK,请求被正常处理
204:No Content,请求被受理但没有资源可以返回,返回 204 响应,浏览器显示的页面不发生更新
206:Partial Content,客户端进行范围请求,服务器成功执行了这部分的 GET 请求,响应报文中包含由 Content-Range 指定范围的实体内容
301:Moved Permanently,永久性重定向,比如访问 http://test.zhixue.com/zbptadmin,服务器会返回 301,response 的 headers 中会包含一个字段:Location: http://test.zhixue.com/zbptadmin/,浏览器会按照这个地址重新请求,并且如果用户保存了书签,浏览器会自动按照 Location 更新书签
302:Found,临时性重定向,和 301 类似,但是浏览器不会更新书签
303:See Other,和 302 类似,但 303 明确表示客户端应该使用 GET 方法获取 Location 资源
备注:当 301,302,303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送。301,302 标准是禁止将 POST 方法改成 GET 方法的,但实际使用时浏览器厂商都会这么做。
304:Not Modified,发送附带条件的请求时,(附带条件的请求是指采用 GET 方法的请求报文中包含 If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since 中任一首部),条件不满足返回 304,可直接使用客户端缓存,与重定向无关
307:Temporary Redirect,临时重定向,与 302 类似,只是强制要求使用 POST 方法
400:Bad Request,请求报文中存在语法错误,服务器无法识别
401:Unauthorized,请求需要认证
403:Forbidden,请求对应的资源禁止被访问
404:Not Found,服务器无法找到对应资源
500:Internal Server Error,服务器内部错误
503:Service Unavailable,服务器正忙
常见 HTTP 首部字段
通用首部字段(请求报文与响应报文都会使用的首部字段)
Date:创建报文的时间
Connection:连接的管理
Cache-Control:缓存的控制
Transfer-Encoding:报文主题的传输编码方式
请求首部字段(请求报文会使用的首部字段)
Host:请求资源所在的服务器
Accept:可处理的媒体类型
Accept-Charset:可接收的字符集
Accept-Encoding:可接收的内容编码
Accept-Language:可接收的自然语言
响应首部字段(响应报文会使用的首部字段)
Accept-Range:可接收的字节范围
Location:让客户端重定向到的 URI
Server:HTTP 服务器的安装信息
实体首部字段(请求报文与响应报文的实体部分使用的首部字段)
Allow:资源可支持的 HTTP 方法
Content-Type:实体主类的类型
Content-Encoding:实体主体适用的编码方式
Content-Language:实体主体的自然语言
Content-Length:实体主体的字节数
Content-Range:实体主体的位置范围,一般用于发出部分请求时使用
4. HTTP1.0、HTTP1.1、HTTP2.0 区别
HTTP1.0 和 HTTP1.1 主要区别
长连接
HTTP1.0 需要使用 keep-alive 参数告知服务器要建立一个长连接,而 HTTP1.1 默认支持长连接
HTTP 是基于 TCP/IP 协议的,创建一个 TCP 连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响。因此最好能维持一个长连接,可以用这个长连接来发送多个请求
节约带宽
HTTP1.1 支持只发送 header 信息,也就是 HTTP 的 HEAD Method,如果服务器认为客户端有权限请求服务器,则返回 100,否则返回 401。客户端如果接收到 100,才开始把请求体 body 发送到服务器。
这样,当服务器返回 401 的时候,客户端就可以不用发送请求体了,节约了带宽
HTTP1.1 支持分块传输,比如 206 状态码,由 Content-Range 指定传输内容,这是支持文件断点续传的基础。
HOST 域
现在一台服务器上可以有多个虚拟主机,这些虚拟站点可以共享同一个 ip 和端口,HTTP1.0 是没有 host 域的,HTTP1.1 才支持这个参数
HTTP1.1 和 HTTP2.0 的区别
多路复用
HTTP2.0 使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比 HTTP1.1 大了好几个数量级
当然 HTTP1.1 也可以多建立几个 TCP 连接,来支持处理更多并发的请求,但是创建 TCP 连接本身也是有开销的
TCP 连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立的连接,并且这个连接可以支持瞬时并发的请求
HTTP/1.1,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某个请求超时,后续请求只能被阻塞,也就是人们常说的线头阻塞
HTTP/2.0,多个请求可同时在一个连接上并行执行,某个任务耗时严重,不会影响到其他连接的正常执行
数据压缩
HTTP1.1 不支持 header 数据的压缩,HTTP2.0 使用 HPACK 算法对 header 的数据进行压缩,这样数据体积小了,在网络上传输就会更快
服务器推送
当我们对 HTTP2.0 的 web server 请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器获取。这种方式非常适合加载静态资源。
服务器推送的这些资源其实存在客户端的某个地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然快很多。
HTTP 缓存
缓存分类
强缓存
浏览器在加载资源时,先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器,此时状态码是 200,但是看 Size 项是 from memory cache 或 from disk cache
协商缓存
当强缓存没有命中时,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些 http header 验证这个资源是否命中协商缓存,如果命中,服务器会将这个请求返回 304,但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;如果没有命中,则将资源返回客户端,状态为 200,浏览器同时依据 response header 中的相关项更新本地缓存数据
from memory cache 和 from disk cache
区别
from memory cache 是从内存中读取缓存资源,很快,关闭浏览器后,内存中的资源就消失了
from disk cache 是从磁盘中读取缓存资源,要比 from memory cache 慢,但是持久化,关闭浏览器后仍然存在
哪些资源存在 memory,哪些资源存在 disk
看了一些文章,大部分观点是说:
资源在 disk 和 memory 中都会存
当关闭浏览器,再打开那个页面的时候,从 disk cache 中获取缓存资源,同时将缓存资源存在了内存中,当再次刷新页面的时候,就从 memory cache 中读取,因为这样会更快一些
我自己试了一些页面,再次刷新还是有的 from disk cache,有的 from memory cache,所以这个持保留观点
还有的文章说 css 文件存在 disk 中,js 等脚本存在 memory 中,个人认为这个不太靠谱,因为 memory 中的缓存在关闭浏览器就消失了,如果 js 只存在 memory,就起不到缓存的作用了
强缓存相关 http header
Expires
Expires 的值是服务端返回的到期时间,用 GMT 格式的字符串表示,如:Expires: Thu, 31 Dec 2016 23:55:55 GMT。即下一次请求时,请求时间小于服务器返回的到期时间,直接使用缓存数据。不过 Expires 是 HTTP1.0 的东西,现在浏览器默认使用 HTTP1.1,所以它的作用基本忽略。另一个问题是,到期时间是由服务器生成的,但是客户端时间可能和服务器时间有偏差,这就会导致缓存命中的误差。所以 HTTP1.1 的版本中,使用 Cache-Control 替代。
Cache-Control
Cache-Control 是最重要的规则。常见的取值有:
– “`private“`:客户端可以缓存
– “`public“`:客户端和代理服务器都可以缓存
– “`max-age=xxx“`:缓存的内容将在 xxx 秒后失效,单位是秒
– “`no-cache“`:需要使用 ** 协商缓存 ** 来验证缓存数据
– “`no-store“`:不缓存
协商缓存相关 http header
第 1 组:Last-Modified/If-Modified—Since
Last-Modified:第一次请求资源时,服务器返回的 http header,告诉浏览器资源的最后修改时间,为 GMT 格式,如 Last-Modified: Thu, 24 Jan 2017 23:55:55 GMT
If-Modified-Since:再次请求服务器资源时,浏览器设置在请求 header 中,值 为该资源第一次请求时服务器设置的 Last-Modified` 值,如 If-Modified-Since: Thu, 24 Jan 2017 23:55:55 GMT,服务器收到请求后发现 request header 中有 If-Modified-Since,则与被请求资源的最后修改时间进行比对。若资源的最后修改时间大于 If-Modified-Since,说明资源又被改动过,则返回资源内容,状态码 200,同时浏览器依据相应 response header 更新缓存资源;若资源的最后修改时间小于或等于 If-Modified-Since,说明资源无新修改,则返回状态码 304,但是不返回资源,告知浏览器继续使用所保存的 cache
第 2 组:Etag/If-None-Match
Etag:服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器确定),如 Etag: W/”5886c231-8d9″
If-None-Match:再次请求服务器时,通过此字段告知服务器该资源的唯一标识,如 If-None-Match: W/”5886c231-8d9″,服务器收到请求后发现 request header 中有 If-None-Match,则与被请求资源的唯一标识进行比对,若不同,说明资源又被改动过,则返回资源内容,状态码 200,同时浏览器依据相应 response header 更新缓存资源;若相同,则说明资源无更改,返回 304,告知浏览器继续使用所保存的缓存资源
为什么要有 Etag?
Last-Modified 颗粒度是秒,只能记录秒级的修改,比如 1s 内修改了 N 次,If-Modified-Since 就无法判断了,所以要引入 Etag。
总结
先执行强缓存策略,服务器通知浏览器一个缓存有效时间,在有效时间内,下次请求时直接使用缓存,不发起 http 请求,缓存从 from memory cache 或 from disk cache 中读取,若超过了有效时间,则执行协商缓存策略
对于协商缓存,将缓存信息中的 Etag 和 Last-Modified 的值通过 If-None-Match 和 If-Modified-Since 发送给服务器,由服务器进行校验,若资源无更改,返回 304,浏览器继续使用缓存,若资源被更改,则返回资源,状态码 200,同时浏览器更新缓存
流程图
浏览器第一次请求:
浏览器第二次请求:
5. Http 长连接 keep-alive
三个概念
短连接
所谓短连接,就是每次请求一个资源就建立连接,请求完成后立马关闭。每次请求都经过“创建 TCP 连接 -> 请求资源 -> 响应资源 -> 释放连接”。
长连接
所谓长连接(persistent connection),就是只建立一次 TCP 连接,多次 HTTP 请求都复用该连接。
并行连接
所谓并行连接(multiple connection),其实就是并发的短连接。
keep-alive
在 HTTP/1.0 里,为了实现 client 到 web-server 能支持长连接,必须在 HTTP 请求头里显式指定 Connection: keep-alive
在 HTTP/1.1 里,就默认开启了 keep-alive,要关闭 keep-alive 必须在 HTTP 请求头里显式指定 Connection: close
现在大多数浏览器都默认是使用 HTTP/1.1,所以 keep-alive 都是默认打开的。一旦 client 和 server 达成协议,那么长连接就建立好了。
keepalive_timeout
Httpd 守护进程,一般都提供了 keep-alive timeout 时间设置参数。比如 nginx 的 keepalive_timeout,和 Apache 的 KeepAliveTimeout。这个 keepalive_timout 时间值意味着:一个 http 产生的 tcp 连接在传送完最后一个响应后,还需要 hold 住 keepalive_timeout 秒后,才开始关闭这个连接。Nginx 配置中的 keepalive_timeout 默认为 75s,
6. cookie 与 Session
这个重点在于理解,这里就不赘述了。
7. 网页经历了什么
这个东西很多,后面会专门写一篇文章来进行说明。
参考文章:
HTTP1.0、HTTP1.1 和 HTTP2.0 的区别
彻底弄懂 HTTP 缓存机制及原理
What is the difference between memory cache and disk cache in Chrome?
理解 HTTP 之 keep-alive