fetch详解
window对象提供了一个fetch方法,用于实现基于promise的http请求。它取代了最早的XMLHttpRequest实现的ajax请求。
1. 基本内容
1. 基本语法
fetch方法返回一个promise对象。
const promise = fetch(url[, options]);
url--发起请求的路径
options--可选设置。可以设置method, headers, body等,method默认是"GET"。
2. options配置对象
1. 如果不设置options, method默认是GET方法。
fetch(url) // 相当于 fetch(url, { method: 'GET' })
其传参通过url传参
fetch(url+ 'a=1&b=2')
2. 当请求方法为POST/PUT/DELETE等方法时,需要传请求体body和对应的headers
const user = {name: "lyra"}; fetch(url, { method: 'POST', body: {// 请求体 user: JSON.stringify(user) }, headers: {// 请求头 Content-Type: "application/json;charset=utf-8" } })
其中请求体body可以接受的参数类型有:
- string 如:JSON格式, 其对应的请求头为application/json; charset=utf-8
- FormData对象 对应的Content-Type:form/multipart
- ArrayBuffer/ArrayBufferView/Blob 二进制
- URLSearchParams对象 对应的Content-Type:application/x-www-form-urlencoded
对于特殊的请求头,如application/json,需要手动进行设置。
headers: {// 请求头 Content-Type: "application/json;charset=utf-8" }
如果需要传递cookie的凭证,但是又存在跨域问题,则应该设置:
fetch(url, { // ⚠️ 此处的属性不是位于headers内部 credentials: "include" // 相当于xhr.withCredentials = true })
如果使用JWT的用户信息校验机制,则需要设置请求头
fetch(url, { headers: { // jwtToken是用户登录后,服务端返回的结果;一般存在localStorage中 authorization: `Bearer ${jwtToken}` } })
2. 响应对象
1. 获取响应对象response
fetch请求的返回结果是promise内置的Response类的实例。该类提供了很多数据处理方法。
获取response对象的方法有两种:
/***考虑响应失败,即promise的reject状态********** 1. 网络连接出现问题 2. 请求网址不存在 ****************************/ //1. async..await try { const response = await fetch(url, options) }catch(e) { //当fetch的结果是reject } // 2. then fetch(url, options).then(response =>{ // response为响应对象; 主要服务器有响应404, 500也属于resoloved状态 }, () => { // reject状态 })
2. response的属性
- response.ok 布尔值;状态码200-299时为true
- reponse.status http状态码
- response.body 可读流; 可以实时计算数据的下载量
// Step 1:启动 fetch 并赋值给 reader let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100'); const reader = response.body.getReader(); // Step 2:获取总长度(总块数) const contentLength = +response.headers.get('Content-Length'); // Step 3:读取数据 let receivedLength = 0; // 当前长度 let chunks = []; // 存放接收到的二进制块的数组(包括 body) while(true) { const {done, value} = await reader.read(); if (done) { break; } chunks.push(value); receivedLength += value.length; console.log(`Received ${receivedLength} of ${contentLength}`) } // Step 4:将块合并成单个 Uint8Array let chunksAll = new Uint8Array(receivedLength); // (4.1) let position = 0; for(let chunk of chunks) { chunksAll.set(chunk, position); // (4.2) position += chunk.length; } // Step 5:解码成字符串 let result = new TextDecoder("utf-8").decode(chunksAll); // 我们完成啦! let commits = JSON.parse(result); alert(commits[0].author.login);
- response.headers 响应头
response.headers是一个类型Map类型的对象,可以通过get获取内容
response.headers.get('Content-Type'); // 迭代所有的headers for(let [key, value] of headers) { // key, value }
3. response的方法
用于获取对应类型的响应内容;其调用方法后的返回结果也是一个promise对象
⚠️下面解析请求体的方式只能使用一种;同时使用多种,只有第一个起作用。
- response.json() 获取json对象
- response.text() 获取文本
- response.formData() 获取FromData对象
- response.blob()
- response.arraybuffer() 二进制形式
数据处理的形式也有两种:
// 1. async...await try { const response = await fetch(url, options); const data = await response.json(); } catch (e) { // } // 2. then fetch(url, options)
.then(response => response.json()) .then(data => { //data }).catch(e= > { // })
3. 简单封装
封装后实现,GET和POST等方式的请求体传参形式相同。
// GET方法需要将对象转为查询参数 function obj2Str(obj) { let arr=[]; for(let key in obj) { if (obj.hasOwnProperty(key)) { arr.push(`${key}=${obj[key]}`); } } return arr.join('&'); } // 传递参数 const data = { a: 1, b: 2 } async function requset(url, objData, method='GET', headers) { /**1,2只需要使用一个**/ const defaultOptions = { // 1. 如果后台使用session验证用户信息 "credentials": "include",// 相当于xhr.withCredentials = true, } const options = { ...defaultOptions, method, headers: { // 2. 如果后台使用JWT验证用户信息 "Authorization": `Bearer ${jwtToken}`, ...headers } }; if (method === 'GET') { // GET方法通过URL传参 url = `${url}?${obj2Str(objData)}`; } else { options = { ...options, headers: { "Content-Type": "application/json; charset=utf-8", ...options.headers }, body: JSON.stringify(data), } } // 发起请求 try { const response = await fetch(url, options); const data = await response.json(); return data; } catch(e) { // 网络问题或者URL不存在 } } function get(url, obj, headers) { return requset(url, obj, 'GET', headers); } function post(url, obj, headers) { return requset(url, obj, 'POST', headers); }