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);
}

 

posted @ 2020-02-07 18:06  Lyra李  阅读(1784)  评论(0编辑  收藏  举报