请求
1. 请求过程
简单版
-
在 web 栏输入网址
-
对网址进行 DNS 解析,得到 IP 地址
-
根据 IP 找到对应服务器,发起 TCP 的三次握手
-
建立 TCP 后,发起针对 HTTPS 的 TLS 握手
-
服务器响应 HTTPS 请求,浏览器得到 HTML 代码
-
浏览器解析 HTML 代码,并请求代码中需要的资源(包括 js,css,图片)
-
对页面进行渲染,呈现给用户
-
服务器关闭 TCP 连接,四次挥手
关于 DNS 解析
域名的 IP 采用递归查询方式
-
先找浏览器内部的 DNS 缓存(这里面大概会存 1000 条,保持时间 1 分钟)
-
再找系统自身的 DNS 缓存
-
再找 HOSTS 文件(在 C 盘的 Windows/System32/drivers/etc 里面,格式是一行一行写的,每一行包括“IP 域名”,会把后面的域名按照此 IP 解析)
-
再找根域名服务器
-
再找下一级根域名服务器
2. 异步请求
XMLHttpRequest
-
较古老的标准浏览器实现,用于进行 http 请求
-
例子
var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onreadystatechange = function () { if (this.readyState !== 4) return; if (this.status === 200) { console.log(this.response); } else { console.log(this.status); console.log(this.statusText); } }; xhr.onerror = function () { console.log("error"); }; xhr.responseType = "json"; xhr.setRequestHeader("Accept", "application/json"); xhr.send();
fetch
-
是新一代的 http 请求工具,是 XMLHttpRequest 的升级版,属于浏览器提供的底层 API
-
优点:
-
语法简介,更语义化
-
基于 Promise 实现,支持 async/await,基本用法为:
fetch(url, option) .then(response => { }) .catch(...)let response = await fetch(url, option); -
通过数据流(Stream 对象)处理数据,可以分块读取
-
更加底层,提供的 API 丰富
-
脱离了 XHR,是 ES 规范里新的实现方式,由 WHATWG 提出,成为了 W3C 的规范
-
-
缺点
- 用起来没那么舒服,需要封装
- 只会对存在网络问题的请求报错,对 400/500 都当作成功(并不会 reject)
- 默认不会带 cookie,需要添加配置项 fetch(url,{credentials:'include'})
- 不支持 abort,不支持超时控制
- 没办法原生监测请求的进度
- 上传大文件时,无法显示进度条
- 需要手动处理返回的数据
3. 响应压缩
-
引入一组 Header
accept-encoding- 客户端发起请求时使用,表明自己支持的解压方式
- 一般可取
gzip,deflate,br
content-encoding- 服务端返回响应时使用,表明传输内容的压缩方式
- 基于客户端请求来决定
-
两种主流压缩格式
gzip- 最常见的方式
- 压缩速度快,但压缩率一般
br- 谷歌提出的更高效的压缩方式
- 压缩率更高,但压缩慢
-
两种压缩方式
- 实时压缩
- 借助 Nginx 返回时做 gzip 压缩
- 离线压缩
- 对于静态文件,可以在 build 时提前做 br 压缩,再托管到静态服务器上
- 实时压缩
3. POST 请求常用的三种格式
【application/json】
-
按 JSON 格式提交
header: { 'content-type': 'application/json' } -
前端发送
- data 的值是
json对象 - 不用自己序列化,内部会自动序列化后再给你传
- 定义 json 对象
const body = { favoriteIdArray: [1, 2, 3], }; - 赋值给 data
data: body,
- 定义 json 对象
- data 的值是
-
后端接收
- body 取数据直接拿到 json 对象
- 不用自己反序列化,因为内部会自动反序列化再给你
const idArray = this.ctx.request.body.favoriteIdArray- 取数据中的数组,结果是
[1,2,3]
- 取数据中的数组,结果是
【application/x-www-form-urlencoded】
-
按
普通的 form 表单提交,不指定 enctype 属性时,会默认用这种方式header: { 'content-type': 'application/x-www-form-urlencoded' } -
前端发送
- data 的值是
字符串,只能上传键值对,如果不是 form 自动组装,则需要自己用&去连接再赋值给 data- 定义字符串
const body = "x=1&y=2"; - 赋值给 data
data: body,
- 定义字符串
- data 的值是
-
后端接收
- body 取数据直接拿到 json 对象,已经自动给你一一解析过了
this.ctx.request.body;- 取 body,结果是{ x: '1', y: '2' }
- body 取数据直接拿到 json 对象,已经自动给你一一解析过了
【application/form-data】
-
按
上传文件的 form 表单提交,需要指定 enctype 属性为multipart/form-dataheader: { 'content-type': 'application/form-data' } -
前端发送
-
会在 Content-Type 中指定 boundary,用作后续隔离
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="filekey"; filename="" ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="textkey" tttttt ------WebKitFormBoundary7MA4YWxkTrZu0gW--- 既可以上传多个文件,也可以上传多个键值对
-