HTTP实用指南(下) | 青训营笔记
🍏前言
这是我参与「第四届青训营」笔记创作活动的的第9天😺
由于笔记篇幅较长,所以将HTTP实用指南笔记调整为上下两部分分开发布。HTTP实用指南(下)承接了上部分的内容,继续介绍了HTTP协议的常见场景、实际应用以及拓展。
👨🏭常见场景
静态资源
状态码200 === 一定发起了请求?
在谷歌浏览器中打开开发者工具(快捷键F12),切换到“网络”,随后在浏览器中输入juejin.cn并前往:
我们观察到“状态”一栏的值全为200。随后在资源类型栏选择“CSS”,点击其中的一个文件:
可以看到状态代码“200”后跟随着一条StatusMessage (来自内存缓存);而观察响应头,由 cache-control: max-age=31536000 可知,这里的缓存策略采用的是强缓存,且缓存的最大周期时间为一年(31536000s)。
在缓存存在且强缓存未过期的情况下,不发起请求,而是直接读取缓存中的资源。所以当观察到状态码等于200时,并不意味着浏览器发起了请求。
除此之外,我们还可以在响应头中读取到其他更多的信息。比如由access-control-allow-origin:*可知,该资源允许所有域名访问;而由content-type:text/css;charset=utf-8可知,资源类型为CSS文件,字符集采用的是utf-8。
CDN
CDN (Content Delivery Network,内容分发网络)
CDN通过将内容缓存在终端用户附近,缩短网络资源的传递时延。通过用户就近性和服务器负载的判断,其确保内容以一种极为高效的方式为用户的请求提供服务。
静态资源方案:缓存 + CDN + 文件名hash
登录
跨域
常见的登陆方式有账号密码登录,以及扫码登陆。我们以账号密码登录为例,进行分析:
- 进入toutiao.com并点击登录,打开开发者工具,选择“网络”;
- 勾选“保留日志(preserve log)”,并过滤“quick_login”;
- 登录,并观察请求:
在观察到的两项请求中,存在一个方法为OPTIONS的请求。那么为什么会存在这一请求呢?
由前述知识可知,OPTIONS请求用于描述目标资源的通信选项。换言之,OPTIONS请求就是预检请求,可用于检测服务器允许的http方法。
以下引用块内容来自:HTTP协议中的OPTIONS方法是什么?有什么用_bksqmy的博客-CSDN博客_http option
它用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET, POST”。
观察控制台中的结果,确实可以在响应头中发现这一信息:access-control-allow-methods: POST
所以对于OPTIONS请求的出现,原因在于发生了跨域(cross-origin)。在进行跨域资源共享(CORS, Cross-Origin Resource Sharing)之前,需要通过一个预请求来获知服务端是否允许该跨源请求(复杂请求),该预请求即为OPTIONS请求。
⚠️关于跨域:协议(protocol)、域名(domain)、端口(port)不同即为跨域。在这个例子中,我们进入的网页(域名)为toutiao.com,而观察请求报文中的请求网址则可知域名为sso.toutiao.com。两者域名不同,所以说这里发生了跨域。
相关协议头如下:
如何解决跨域问题?
跨域问题其实由同源策略导致。需要了解的是,同源策略是浏览器的一种安全策略,并不来源于HTTP。
来自MDN官网:
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
由于同源策略的存在,跨域时便会出现报错。那么如何解决跨域问题?
以下引用块内容来自:10 种跨域解决方案(附终极方案) - 知乎 (zhihu.com)
1. CORS
跨域资源共享(CORS)是一种机制,它使用额外的HTTP头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
2. 代理服务器
原理:把不同的域名转换为相同的,即消除了跨域
3. iframe
结合iframe标签的src属性来解决跨域。
鉴权
下一次进入页面时,为什么还能记住登录态?
观察前述例子在控制台得到的结果,我们发现存在两个请求。一个为已经分析过的OPTIONS请求,另一个即为POST请求。
在这个 发起POST请求 / 请求得到响应的过程中,请求报文携带的信息有
- post body,数据格式为form
- 希望获取的数据格式为json
- 已有的cookie
🍊需要注意的是,这个“已有的cookie”是由预请求OPTIONS请求的响应报文返回的。
(请求报文携带的长长的已有cookie)
响应报文返回的信息有
- 数据格式json
- 种cookie的信息
下一次进入页面会存在一个鉴权的过程,即对当前用户的权限进行检查。可以采用session+cookie 和 token两种方式。
session + cookie
JWT (JSON web token)
以前述例子为例,浏览器在登陆后已经获得了一个能代表用户身份权限的cookie,下次再发起请求时只需要带上这个cookie,即可完成身份认证,从而实现记住登录态。 这也与web安全有关。相关内容见笔记:WEB开发的安全之旅 (防御篇) | 青训营笔记 - 掘金 (juejin.cn)
SSO
SSO (Single Sign On,单点登录)
用户只需要登陆一次,其他多个互相信任的系统也可以感知到用户的登陆状态。
👨🚒实际应用
浏览器
AJAX (Asynchronous JavaScript and XML)
Asynchronous JavaScript + XML(异步 JavaScript 和 XML), 其本身不是一种新技术,而是一个在 2005 年被 Jesse James Garrett 提出的新术语,用来描述一种使用现有技术集合的‘新’方法,包括:HTML或XHTML,CSS,JavaScript,DOM,XML,XSLT, 以及最重要的XMLHttpRequest。当使用结合了这些技术的 AJAX 模型以后, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。这使得程序能够更快地回应用户的操作。尽管 X 在 Ajax 中代表 XML,但由于JSON的许多优势,比如更加轻量以及作为 Javascript 的一部分,目前 JSON 的使用比 XML 更加普遍。JSON 和 XML 都被用于在 Ajax 模型中打包信息。
AJAX - XHR
XHR (XMLHttpRequest)
TheXMLHttpRequestobject is an API for fetching resources.The name
XMLHttpRequestis historical and has no bearing on its functionality.
可以根据readyState属性的值来判断请求资源的操作位于哪个阶段:
| 属性值 | 所处阶段 | 具体含义 |
|---|---|---|
| 0 | UNSENT | 代理被创建,但尚未调用open()方法 |
| 1 | OPENED | open()方法已被调用 |
| 2 | HEADERS_RECEIVED | send()方法已经被调用,并且头部和状态已经可以获得 |
| 3 | LOADING | 下载中;responseText属性已经包含部分数据 |
| 4 | DONE | 下载操作已经完成 |
示例代码片段:
(开头处省略了部分代码,此处主要展示XHR中对应HTTP的内容)
if(option.method === 'GET'){
option.url += location.search.length === 0 ? ''.concat('?',option.data) : ''.concat('&',option.data);
}
对xhr实体的readyState属性的值进行检查,如果该值等于4,则说明资源的获取操作已经完成,接下来还要对http响应报文的statusCode(即xhr实体的status属性值)进行检查,当该值等于200时说明资源获取成功,进行下一步的操作。
var xhr = new XMLHttpRequest();
xhr.responseType = option.responseType || 'json';
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status === 200){
if(option.success && typeof option.success === 'function'){
option.success(xhr.response);
}
} else{
if(option.error && typeof option.error === 'function'){
option.error();
}
}
}
}
xhr.open(option.method,option.url,true);
if(option.method === 'POST') {
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
}
xhr.send(option.method === 'POST' ? option.data : null);
AJAX - Fetch
- XMLHttpRequest的升级版
- 使用promise
- 模块化设计,Response/Request/Header对象
- 通过数据流处理对象,支持分块读取
postData('http://example.com/answer',{answer:42})
.then(data => console.log(date)) // JSON from `response.json()` call
.catch(error => console.error(error))
function postData(url,data) {
return fetch(url,{
body:JSON.stringify(data), //must match 'Content-Type' header
cache:'no-cache',
credentials:'same-origin',
headers:{
'user-agent':'Mozilla/4.0 MDN Example',
'content-type':'application/json'
},
method:'POST',
mode:'cors',
redirect:'follow',
referrer:'no-referrer'
}).then(response => response.json());
}
关于是 referer 还是 referrer :Referrer 还是 Referer? | JerryQu 的小站 (imququ.com)
node
标准库:HTTP/HTTPS
- 默认模块,无需安装其他依赖
- 功能有限/不是十分友好
const https = require('https');
https.get('https://test.com?api_key=DEMO_KEY' , (resp)=>{
let data = '';
// a chunk of data has been received.
resp.on('data',(chunk)=>{
data += chunk;
});
//the whole response has been received, print out the result.
resp.on('end',()=>{
console.log(JSON.parse(data).explanation);
});
}).on("error",(err)=>{
console.log("Error: "+err.message);
});
常用的请求库:axios
- 支持浏览器、node.js环境
- 丰富的拦截器
//全局配置
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'))
});
用户体验
网络优化
预解析和预连接:
<link rel="dns-prefetch" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>
稳定性
- 重试是保证稳定的有效手段,但要防止恶劣情况
- 缓存合理使用,作为最后一道防线
👨💻了解更多
WebSocket
- 浏览器与服务器进行全双工通讯的网络技术
- 典型场景:实时性要求高,例如聊天室
- URL使用
ws://或wss://等开头
HTTP 对比 WebSocket
QUIC (Quick UDP Internet Connection)
- 0-RTT建联(首次建联除外)
- 类似TCP的可靠传输
- 类似TLS的加密传输,支持完美前向安全
- 用户空间的拥塞控制,最新的BBR算法
- 支持h2的基于流的多路复用,但没有TCP的HOL问题
- 前向纠错FEC
- 类似MPTCP的Connection migration
🍎小结
HTTP实用指南(上) 与 HTTP实用指南(下)对HTTP协议相关内容进行了介绍,并拓展了一些其他的通讯技术。对于学习这方面的内容,还是需要掌握一些计算机网络相关的基础知识,并且多记忆和理解。💨
2022/8/2