JS

JS-Fetch

Posted by Youzi on February 3, 2021

Fetch API

Fetch提供了获取资源的接口,可以用于跨域请求,可以看做是 XHR 的替代;实际上手用了一段时间之后呢,感觉和 XHR 差异不是很大,因为前端在 XHR 这块也封装了许多插件,像 axios 这些,都可以实现异步promise返回了,如果考虑兼容性肯定还是 XHR 更好一些,但是毕竟 fetch 不需要引入其他的包,更方便快捷,易用性也很强。

核心概念

fetch及其衍生的 API,提供了对请求以及相应的通用定义;还为 CORS / HTTP 原生头信息提供了新的定义;并且fetch方法不止在window对象上,在workerGlobalScope上也有,所以在 nodejs 环境下也可以用这个方法;fetch方法必须参数为资源路径,返回promise,相对于原生的 XHR 更方便了。

目前除了 IE 全面不兼容fetch API以外,其他主流浏览器兼容性较好,但是实验性的一些方法除外。

request | response

request

构造函数:new Request(input[, init])

  • input:定义需要fetch的资源,可以是URL,也可以是另一个request对象;
  • init:可选参数,包括一系列自定义选项:
    • method:请求方法,大写字符串GET | POST ...
    • headers:请求头,一个作为请求头的Headers对象,或者其内部值为ByteString的对象字面量;
    • body:任何需要加入到请求中的 body,blob | formdata | URLSearchParams | USVString对象,注意GET | HEAD方法没有 body;
    • mode:请求模式(是否跨域),可选项cors | no-cors | same-origin | navigate,默认使用 cors;
    • credentials:和 XHR 的withCredentials类似,标记了cookie如何发送,omit | same-origin | include,分别表示不发送 cookie,仅发送同源 cookie,发送所有 cookie
    • cache:请求的缓存模式,可选项default | no-store | reload | no-cache | force-cache | only-if-cached
    • redirect:重定向模式,当服务器返回 300+时该请求的后续动作,可选项:follow自动重定向,error重定向自动终止并抛出错误,manual手动处理重定向;
    • referrerhttp请求中referrer指定了跳转到新链接时,头部referrer携带的信息,可选项no-referrer | client | 指定的 URL
    • referrerPolicy:指定http头部referrer字段的值,可选项:no-referrer | no-referrer-when-downgrade | origin | origin-when-cross-origin | unsafe-url
    • integrity:包括请求的subresource integrity值;

response

可以用构造函数来创建一个response对象,但更多的情况是从其他 API 返回了一个response对象;这里主要就介绍下调用fetch之后返回的 response 对象;

实例对象包含的属性有:

  • headers:响应头;
  • ok:响应状态,布尔值,为truehttp状态码在 200-299 之间;
  • redirected:是否来自重定向的响应,如果是,响应的 URL 列表会有多个条目;
  • status:响应状态码;
  • statusText:与状态码一致的状态信息;
  • type:响应的类型,如basic | cors
  • url:响应的 url;
  • useFinalURL:表示响应是否是最终的 url;
  • body:响应体,后面会单独介绍;
  • bodyUsed:布尔值,标记 body 是否被读取过;

实例方法:

  • clone:创建实例对象的克隆;
  • error:该方法返回一个绑定了网络错误的新的相应对象;
  • redirect:用另一个 URL 创建新的response对象;
  • body的所有方法,由于 response 实现了 body 接口,所以也实现了所有方法;

body

bodyfetch API中代表了请求/响应的正文部分,允许手动声明请求或响应的内容类型以及如何处理;body提供了一个相关联的主体(字节流),已使用的标志位,MIME 类型;

属性:

  • body:主体内容,只读属性,一个readableStream类型;
  • bodyUsed:布尔值,只读属性,是否已被读取;

方法,以下的读取方法都返回一个promise对象,其resolve的参数类型都是方法对应的读取类型:

  • arrayBuffer
  • blob
  • formData
  • json
  • text

实例

由于在request | response都实现了这些方法和属性,所以可以来看个实例了;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 服务端 nodejs,express
// post method
router.post('/', (req, res, next) => {
  // inspect(req);
  console.warn(req);
  try {
    readFile('./test/img/img01.png', (err, data) => {
      console.log(data);
      if (err) {
        throw new Error(err);
      }
      res.set('Content-Type', 'application/json');
      let formdata = {
        para1: req.body,
        img: data
      };
      res.send(formdata);
    });
  } catch (err) {
    console.error(err);
  }
});

// 客户端
function getUser(params) {
  let url = '/user';
  let param = {
    usercode: '123456',
    password: '123456'
  };
  let p = fetch(url, {
    method: 'POST',
    headers: {
      'content-type': 'application/json'
    },
    body: JSON.stringify(param)
  });
  p.then(res => {
    console.warn(res);
    if (!res.ok) {
      throw new Error('net work error');
    }
    return res.json();
  })
    .then(res => {
      console.warn(res.para1, res.img);
      // let fr = new FileReader();
      let i8 = new Uint8Array(res.img.data);
      let blob = new Blob([i8], {
        type: 'image/png'
      });
      console.warn(blob);
      let img = document.querySelector('#img');
      img.src = URL.createObjectURL(blob);
      img.onload = function (e) {
        URL.revokeObjectURL(this.src);
      };
    })
    .catch(err => {
      console.error(err);
    });
}