初识 HTTP#
输入 url -> browser 进程处理输入信息 -> 浏览器内核向服务器发起请求 -> 浏览器内核读取响应 -> 浏览器内核进行渲染 -> browser 进程页面加载完成
-
Hyper Text Transfer Protocol (HTTP)超文本传输协议
-
他是应用层协议,基于传输层的 TCP 协议
-
请求、响应
-
简单可扩展(可以自定义请求头,只要客户端服务端之间可以理解)
-
无状态
协议分析#
发展历程#
报文结构#
HTTP/1.1#
如图,可以看到请求和响应的请求头、返回的状态码、等等
Method | 说明 |
---|---|
GET | 请求一个指定资源的表示形式,使用 GET 的请求应该只用于获取数据 |
POST | 用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用 |
PUT | 用请求有效载荷替换目标资源的所有当前表示 |
DELETE | 删除指定的资源 |
HEAD | 请求一个与 GET 请求的响应相同的响应,但没有响应体(用的比较少) |
CONNECT | 建立一个到由目标资源标识的服务器的隧道。(用的比较少) |
OPTIONS | 用于描述目标资源的通信选项。 |
TRACE | 沿着到目标资源的路径执行一个消息环回测试。(用的比较少) |
PATCH | 用于对资源应用部分修改。 |
-
Safe(安全的):不会修改服务器数据的方法,如读数据 GET、HEAD、OPTIONS 等
-
Idempotent(幂等):同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的,所有 safe 的方法都是 Idempotent 的 如 GET、HEAD、OPTIONS、PUT、DELETE 等
状态码#
- 200 OK - 客户端请求成功
- 301 - 资源(网页等)被永久转移到了其它 URL
- 302 - 临时跳转
- 401 - Unauthorized - 请求未经授权
- 404 - 请求资源不存在,可能是输入了错误的 URL
- 500 - 服务器内部发生了不可预期的错误
- 504 Gateway Timeout - 网关或者代理的服务器无法在规定的时间内获得想要的响应
RESTful API#
一种 API 设计风格:REST - Representational State Transfer
- 每一个 URI 代表 — 种资源
- 客户端和服务器之间,传递这种资源的某种表现层
- 客户端通过 HTTP method,对服务器端资源进行操作,实现 "表现层状态转化"。
请求 | 返回码 | 含义 |
---|---|---|
GET /zoos | 200 OK | 列出所有动物园,服务器成功返回了 |
POST /zoos | 201 CREATED | 新建一个动物园,服务器创建成功 |
PUT /zOos/ID | 400 INVALID REQUEST | 更新某个指定动物园的信息 (提供该动物园的全部信息); 用户发出的请求有错误,服务器没有进行新建或修改数据的操作 |
DELETE /zoos/ID | 204 NO CONTENT | 删除某个动物园,删除数据成功 |
常用请求头#
请求头 | 说明 |
---|---|
Accept | 接收类型,表示浏览器支持的 MIME 类型 **(对标服务端返回的 Content-Type)** |
Content-Type | 客户端发送出去实体内容的类型 |
Cache-Control | 指定请求和响应遵循的缓存机制,如 no-cache |
lf-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 头部 (如为 *) |
缓存#
强缓存
本地有了直接用就好了
- Expires(到期时间),时间戳
- Cache-Control
- 可缓存性
- no-cache:协商缓存验证
- no-store:不使用任何缓存
- public、private 等
- 到期
- max-age:单位是秒,存储的最大生存周期,相对于请求的时间
- 重新验证 * 重新加载
- must-revalidate:一旦资源过期,在成功向原始服务器验证之前,不能使用)()
- 可缓存性
协商缓存
与 Server 端要通信,再确定要不要用它
- Etag/If-None-Match:资源的特定版本的标识符,类似于指纹
- Last-Modified/If-Modified-Since:最后的修改时间。(绝对的)
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 仅在同站发送 ;允许与顶级导航一起发送,并将与第三方网站发起的 GET 请求一起发送 |
发展#
HTTP/2 概述:更快、更稳定、更简单
-
帧 (frame)
-
HTTP/2 通信的最小单位,每个帧都包含帧头,至少也会标识出当前帧所属的数据流。
-
1.0 传输的是文本,而 2 中传的则是二进制数据,效率更高。并有新的压缩算法。
-
-
-
消息:与逻辑请求或响应消息对应的完整的一系列帧。
-
数据流:已建立的连接内的双向字节流,可以承载一条或多条消息。
-
交错发送,接受方重组织。
-
-
HTTP/2 连接都是永久的,而且仅需要每个来源一个连接
-
流控制:阻止发送方向接收方发送大量数据的机制
-
服务器推送
HTTPS 概述#
-
HTTPS : Hypertext Transfer Protocol Secure
-
经过 TSL/SSL 加密
-
对称加密:加密和解密都是使用同一个密钥
-
非对称加密:加密和解密需要使用两个不同的密钥:公钥(public key)和私钥(private key)
常见场景分析#
静态资源#
以 今日头条 为例,打开网络面板查看其请求,找到 css 文件的请求。
可以看到返回的状态码为 200,那么是不是真的发起了请求呢(旁边的括号就说了,从磁盘缓存)
由上图响应头,可以看出:
- 缓存策略?
- 强缓存(max-age=xxxxx)
- Cache-control:换算一下,1 年
- 强缓存(max-age=xxxxx)
- 其他信息?
- 允许所有域名访问(access-control-allow-origin)
- 资源类型:css(content-type)
静态资源方案:缓存 + CDN + 文件名 hash
- CDN:Content Delivery Network
- 通过用户就近性和服务器负载的判断,CDN 确保内容以一种极为高效的方式为用户的请求提供服务
那么缓存期那么久,怎么保证用户拿到的内容是最新的呢?
文件名 hash,当文件内容有变化时文件名变换 / 加上版本号,这样缓存中的文件就无法 match,就只能重新请求了。
登陆 - 跨域#
跨域问题,导致了请求方法为 OPTION
协议、主机名、端口任意一者不同都会出现跨域问题(HTTP 的默认端口号 443)
解决跨域问题#
-
跨源资源共享(CORS)( Cross-Origin Resource Sharing )
-
跨源资源共享
(CORS)(或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的 "预检" 请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。 例如,
XMLHttpRequest
和 Fetch API 遵循同源策略。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。 -
预请求:获知服务端是否允许该跨源请求(复杂请求)
-
相关协议头
- access-control-....
-
-
代理服务器
- 同源策略是浏览器的安全策略,不是 HTTP 的
-
Iframe 诸多不便
如上图,登陆时向什么地址做了什么动作?
- 使用了 post 方法
- 目标域名:https://sso.toutiao.com
- 目标为:path/quick_login/v2/
携带了哪些信息,返回了哪些信息?
- 携带信息
- Post body,数据格式为 form
- 希望获取的数据格式为 json
- 已有的 cookie
- 返回信息
- 数据格式 json
- 种 cookie 的信息
那么下一次进入页面的时候,为什么能够记住登陆态呢?
鉴权#
- Session + cookie (大部分这种门户网站)
- 用户发起提交请求给服务器,包括用户名密码等等
- 服务器处理,鉴别其正确性,若正确则返回 Session 将其种到 cookie(Set-Cookie = ......)
- 用户再发送时:GET Cookie=....
- 服务器处理鉴别后返回一些登陆信息的
- JWT(JSON web token)
- 服务器本地不会存储
- 返回的 token 唯一性,登陆时间短等
- SSO:单点登录(Single Sign On)
如图,讲解的很清楚。
实际应用#
XMLHttpRequest - Web API 接口参考 | MDN (mozilla.org)
AJAX之XHR#
- XHR: XMLHttpRequest
- readyState
0 | UNSENT | 代理被创建,但尚未调用 open () 方法。 |
1 | OPENED | open () 方法已经被调用。 |
2 | HEADERS_RECEIVED | send () 方法已经被调用,并且头部和状态已经可获得。 |
3 | LOADING | 下载中;responseText 属性已经包含部分数据。 |
4 | DONE | 下载操作已完成。 |
AJAX 之 Fetch#
- XMLHttpRequet 的升级版
- 使用 Promise
- 模块化设计,Response,Request,Header 对象
- 通过数据流处理对象,支持分块读取
node 中标准库: HTTP/HTTPS#
- 默认模块,无需安装其他依赖
功能有限 / 不是十分友好
常用的请求库: axios#
- 起步 | Axios 中文文档
- 支持浏览器、nodejs 环境
- 丰富的拦截器
//全局配置
axios.defaults.baseURL = "https://api.example.com";
//添加请求拦截器
axios.interceptors.request.use(function (config) {
//在发送请求之前做些什么
return config;
},function (error) {
//对请求错误做些什么
return Promise.reject(error );
});
//发送请求
axios( {
method: 'get',
url: 'http://test.com',
responseType: 'stream
}).then( function(response) {
response.data.pipe( fs.createWriteStream('ada_lovelace.jpg'))
});
网络优化#
-
HTTP/2 - A Real-World Performance Test and Analysis | CSS-Tricks - CSS-Tricks
-
预解析、预连接等
-
重试是保证稳定的有效手段,但要防止其加剧恶劣情况(比如网络连接就是断开了)。
-
缓存合理使用,作为最后一道防线。
了解更多#
不止 HTTP 协议一个选择#
扩展 - 通信方式#
WebSocket#
- 浏览器与服务器进行全双工通讯的网络技术
- 典型场景:实时性要求高,例如聊天室
- URL 使用 **ws://** 或 wss:// 等开头
UDP#
QUIC:Quick UDP Internet Connection 基于 UDP
- 0-RTT 建联(首次建联除外)。
- 类似 TCP 的可靠传输。
- 类似 TLS 的加密传输,支持完美前向安全。
- 用户空间的拥塞控制,最新的 BBR 算法。
- 支持 h2 的基于流的多路复用,但没有 TCP 的 HOL 问题。
- 前向纠错 FEC。
- 类似 MPTCP 的 Connection migration。
- 应用暂不多
总结感想#
今天讲师小姐姐声音超温柔的介绍了 HTTP 及其常见协议分析、报文结构、缓存策略分析,还讲解了其具体的业务场景使用。
本文引用的内容大部分来自杨超男老师的课 ——HTTP 实用指南