这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天
HTTP协议简介
HTTP 全称 Hyper Text Transfer Protocol 超文本传输协议
默认端口:80
http报文的结构:由起始行、首部、主体组成。
首部下面的空行是用来隔离请求头部和请求数据
请求方法
- GET: 向服务器获取数据;
- POST:将实体提交到指定的资源,通常会造成服务器资源的修改;
- PUT:上传文件,更新数据;
- DELETE:删除服务器上的对象;
- HEAD:获取报文首部,与GET相比,不返回报文主体部分;
- OPTIONS:询问支持的请求方法,用来跨域请求,嗅探请求;
- CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信;
- TRACE: 回显服务器收到的请求,主要⽤于测试或诊断。
分类
- 安全Safe:不会修改服务器的数据的方法:
GETHEADOPTIONS - 幂等Idempontent:同样的请求被执行一次与连续执行多次的效果时一样的,服务器的状态也是一样的,所有safe的方法都是idempotent的:
GETHEADOPTIONSPUTDELETE
http状态码
- 2xx:成功
- 3xx:重定向
- 4xx:客户端错误
- 5xx:服务器错误
常见状态码及含义
| 状态码 | 含义 |
|---|---|
| 200 OK | 客户端请求成功 |
| 301 Moved Permanently | 资源(网页等)被永久转移到其它URL |
| 302 Found | 临时跳转 |
| 304 | 表示可以使用缓存的内容;(不应该认为时一种错误,而是对客户端有缓存情况下服务端的一种响应。) |
| 401 Unauthorized | 请求未经授权 |
| 404 Not Found | 请求资源不存在,可能是输入了错误的URL |
| 500 Internal Server Error | 服务器内部发生了不可预期的错误 |
| 504 Gateway Timeout | 网关或者代理的服务器无法在规定的时间内获得想要的响应 |
一些问题
HTTP 1.0 和 HTTP 1.1 之间有哪些区别?
HTTP 1.0和 HTTP 1.1 有以下区别:
- 连接方面,http1.0 默认使用非持久连接,而 http1.1 默认使用持久连接。http1.1 通过使用持久连接来使多个 http 请求复用同一个 TCP 连接,以此来避免使用非持久连接时每次需要建立连接的时延。
- 资源请求方面,在 http1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 缓存方面,在 http1.0 中主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供选择的缓存头来控制缓存策略。
- http1.1 中新增了 host 字段,用来指定服务器的域名。http1.0 中认为每台服 务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。因此有了 host 字段,这样就可以将请求发往到同一台服务器上的不同网站。
- http1.1 相对于 http1.0 还新增了很多请求方法,如 PUT、HEAD、OPTIONS 等。
HTTP 1.1 和 HTTP 2.0 的区别
- 二进制协议:HTTP/2 是一个二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为 "帧" ,可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。
帧是HTTP/2 通信的最小单位
- 多路复用: HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"【1】的问题。
- 数据流: HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
- 头信息压缩: HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
- 服务器推送: HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是 http2 下服务器主动推送的是静态资源,和 WebSocket 以及使用 SSE 等方式向客户端发送即时数据的推送是不同的。
【1】队头堵塞:
队头阻塞是由 HTTP 基本的“请求 - 应答”模型所导致的。HTTP 规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。队列里的请求是没有优先级的,只有入队的先后顺序,排在最前面的请求会被最优先处理。如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本,造成了队头堵塞的现象。
请求头
Header首部和请求方法配合工作,共同决定了客户端和服务器能做什么事情。
| 请求头 | 说明 |
|---|---|
| Accept | 接收类型,表示浏览器支持的MIME类型(对标服务端返回的Content-Type) |
| Content-Type | 客户端发送出去实体内容的类型 |
| Cache-Control | 指定请求和响应遵循的缓存机制,如no-cache |
| If-Modified-Since | 对应服务端的Last-Modified,用来匹配看文件是否变动,只能精确到1s之内 |
| Expires | 缓存控制,在这个时间内不会请求,直接使用缓存,服务端时间 |
| Max-age | 代表资源在本地缓存多少秒,有效时间内不会请求,而是使用缓存 |
| If-None-Match | 对应服务端的ETag,用来匹配文件内容是否改变(非常精确) |
| Cookie | 有cookie并且同域访问时会自动带上 |
| Referer | 该页面的来源URL(适用于所有类型的请求,会精确到详细页面地址,csrf拦截常用到这个字段) |
| Origin | 最初的请求是从哪里发起的(只会精确到端口),Origin比Referer更尊重隐私 |
| User-Agent | 用户客户端的一些必要信息,如UA头部等 |
响应头
| 响应头 | 说明 |
|---|---|
| Content-Type | 服务端返回的实体内容的类型 |
| Cache-Control | 指定请求和响应遵循的缓存机制,如no-cache |
| Last-Modified | 请求资源的最后修改时间 |
| Expires | 应该在什么时候认为文档已经过期,从而不再缓存它 |
| Max-age | 客户端的本地资源应该缓存多少秒,开启了Cache-Control后有效 |
| ETag | 资源的特定版本的标识符,Etags类似于指纹 |
| Set-Cookie | 设置和页面关联的cookie,服务器通过这个头部把cookie传给客户端 |
| Server | 服务器的一些相关信息 |
| Access-Control-Allow-Origin | 服务器端允许的请求Origin头部(譬如为*) |
HTTP缓存
减少了服务器和客户端之间的通信次数,降低网络延迟,加速页面加载,提高用户体验等 HTTP缓存就是HTTP协议规定缓存时如何工作,如何储存和各种类型等等事情
HTTP缓存的运作方式
- 浏览器请求资源,先看自己有没有缓存,没有就向服务器发起请求,有就执行下一步
- 查看缓存是否过期,若没有过期,则返回;若过期,
- 和服务器进行验证,若服务器告知未过期,那就继续使用;若过期,就返回新的资源作为新的缓存
缓存相关首部
- Cache-Control常见设置:
- max-age:保存为缓存的最长时间(单位:秒)
- no-cache:可以进行缓存,但每次使用前都要和服务器进行确认,同时代理服务器也不能对资源进行缓存。(不会走强缓存了,每次请求都回询问服务端缓存是否新鲜)
- no-store:禁止缓存,每次都要向服务器请求资源。
- must-revalidete:在缓存过期前可以使用,在缓存过期后必须向服务器验证
- etage/If-None-Match:hash码,资源的标识
- expires:缓存的过期时间
- last-modified/If-Modified-since:表示资源最后修改时间
HTTP缓存的分类:
根据是否需要重新向服务器发起请求:强制缓存、协商缓存。
根据是否可以被单个或者多个用户来分类,可分为:私有缓存、共享缓存
强缓存
强制缓存在缓存数据未失效的情况下(即Cache-Control的max-age没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。
优点:强制缓存生效时,http状态码为200。这种方式页面的加载速度是最快的,性能也是很好的。
缺点:但是在这期间,如果服务器端的资源修改了,页面上是拿不到的,因为它不会再向服务器发请求了。
协商缓存
协商缓存不管是否生效,都需要与服务器发送交互 怎么设置协商缓存? response header里面的设置:
- etage:标识
- last-modified:表示资源最后修改时间
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT
步骤:
每次请求返回来 response header 中的 etag和 last-modified,在下次请求时在 request header 就把这两个带上(If-None-Match和If-Modified-since),服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源,和更新对应的response header的标识etag、last-modified。如果资源没有变,那就不变etag、last-modified。
如果资源没更改,返回304,浏览器读取本地缓存。 如果资源有更改,返回200,返回最新的资源。
cookie
前面说过HTTP是无状态的协议,如何让他保持状态呢?就需要设置我们的cookie
Set-Cookie - response
| 标题 | 说明 |
|---|---|
| Name=value | 各种cookie的名称和值 |
| Expires=Date | Cookie 的有效期,缺省时Cookie仅在浏览器关闭之前有效 |
| Path=Path | 限制指定Cookie 的发送范围的文件目录,默认为当前 |
| Domain=domain | 限制cookie生效的域名,默认为创建cookie的服务域名 |
| secure | 仅在HTTPS 安全连接时,才可以发送Cookie |
| HttpOnly | JavaScript 脚本无法获得Cookie |
SameSite=[None/Strict/Lax] | None:同站、跨站请求都可发送 Strict:仅在同站发送 Lax:允许与级导航一起发送,并将与第三方网站发起的GET请求一起发送 |