Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

请求

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,
        
  • 后端接收

    • 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,
        
  • 后端接收

    • body 取数据直接拿到 json 对象,已经自动给你一一解析过了
      this.ctx.request.body;
      
      • 取 body,结果是{ x: '1', y: '2' }

【application/form-data】

  • 上传文件的 form 表单提交,需要指定 enctype 属性为multipart/form-data

    header: { '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--
      
      • 既可以上传多个文件,也可以上传多个键值对