0%

Fetch API

Fetch API 介绍

基本用法

fetch() 与 经典的 XMLHttpRequest 基本相同,但有以下三个差异

  • fetch 使用 Promise,不使用回调函数,更加符合现代编码式样
  • fetch 采用模块化设计,API分散在多个对象上,Response、Request、Headers,相比 XMLHttpRequest 设计更合理
  • fetch 通过数据流 Stream 处理数据,可以分块读取,减少内存占用,而 XMLHttpRequest 不支持数据流,所有数据必须放在缓存里,必须要全部获取后再一次读出来
1
2
3
4
fetch('https://api.github.com/users/ruanyf')
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.log('Request Failed', err));

上面示例中,fetch 接收到的 response 是一个 Stream 对象,response.json()是一个异步操作,取出所有内容,并将其转为 JSON 对象

Response 对象

fetch 请求成功以后,得到的是一个 Response 对象。它对应服务器的 HTTP 回应。
前面说过,Response 包含的数据通过 Stream 接口异步读取,但是它还包含一些同步属性,对应 HTTP 回应的标头信息(Headers),可以立即读取。

  • Response.ok属性返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。
  • Response.status属性返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求)
  • Response.statusText属性返回一个字符串,表示 HTTP 回应的状态信息(例如请求成功以后,服务器返回”OK”)

fetch()发出请求以后,有一个很重要的注意点:只有网络错误,或者无法连接时,fetch()才会报错,其他情况都不会报错,而是认为请求成功。
这就是说,即使服务器返回的状态码是 4xx 或 5xx,fetch()也不会报错(即 Promise 不会变为 rejected状态)。
只有通过Response.status属性,得到 HTTP 回应的真实状态码,才能判断请求是否成功。

读取内容的办法

Response对象根据服务器返回的不同类型的数据,提供了不同的读取方法

  • response.text():得到文本字符串
  • response.json():得到 JSON 对象
  • response.blob():得到二进制 Blob 对象
  • response.formData():得到 FormData 表单对象
  • response.arrayBuffer():得到二进制 ArrayBuffer 对象
    上面5个读取方法都是异步的,返回的都是 Promise 对象。必须等到异步操作结束,才能得到服务器返回的完整数据

response.blob()

response.blob()用于获取二进制文件

1
2
3
4
5
6
const response = await fetch('flower.jpg');
const myBlob = await response.blob();
const objectURL = URL.createObjectURL(myBlob);

const myImage = document.querySelector('img');
myImage.src = objectURL;

response.arrayBuffer()

response.arrayBuffer()主要用于获取流媒体文件

1
2
3
4
5
6
7
8
9
10
const audioCtx = new window.AudioContext();
const source = audioCtx.createBufferSource();

const response = await fetch('song.ogg');
const buffer = await response.arrayBuffer();

const decodeData = await audioCtx.decodeAudioData(buffer);
source.buffer = buffer;
source.connect(audioCtx.destination);
source.loop = true;

定制请求

fetch()的第一个参数是 URL,还可以接受第二个参数,作为配置对象,定制发出的 HTTP 请求

1
fetch(url, optionObj)

optionObj 配置对象用到了三个属性

  • method:HTTP 请求的方法,POST、DELETE、PUT都在这个属性设置
  • headers:一个对象,用来定制 HTTP 请求的标头
  • body:POST 请求的数据体

提交JSON

标头Content-Type要设成’application/json;charset=utf-8’。因为默认发送的是纯文本,Content-Type的默认值是’text/plain;charset=UTF-8’

1
2
3
4
5
6
7
8
const user =  { name:  'John', surname:  'Smith'  };
const response = await fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});

提交表单

1
2
3
4
5
6
const form = document.querySelector('form');

const response = await fetch('/users', {
method: 'POST',
body: new FormData(form)
})

文件上传

1
2
3
4
5
6
7
8
9
10
const input = document.querySelector('input[type="file"]');

const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');

fetch('/avatars', {
method: 'POST',
body: data
});

直接上传二进制

1
2
3
4
5
6
7
8
let blob = await new Promise(resolve =>   
canvasElem.toBlob(resolve, 'image/png')
);

let response = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});

取消 fetch 请求

fetch()请求发送以后,如果中途想要取消,需要使用AbortController对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let controller = new AbortController();
let signal = controller.signal;

fetch(url, {
signal: controller.signal
});

signal.addEventListener('abort',
() => console.log('abort!')
);

controller.abort(); // 取消

console.log(signal.aborted); // true