fetch请求详解

最新更新时间:2019年06月04日16:18:30

《猛戳-查看个人博客地图-总有你意想不到的惊喜》

本文内容:fetch相关javascript

概述

位于 WorkerOrGlobalScope 这一个 mixin 中的 fetch() 方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。java

Window 和 WorkerGlobalScope 都实现了 WorkerOrGlobalScope。 ——这意味着基本在任何场景下只要你想获取资源,均可以使用 位于 WorkerOrGlobalScope 中的 fetch() 方法。web

Fetch API 提供了一个获取资源的接口(包括跨域请求),Fetch 是对 HTTP 接口的抽象,包括 Request,Response,Headers,Body。得益于 JavaScript 实现的这些抽象好的 HTTP 模块,其余接口可以很方便的使用这些功能。ajax

Fetch 提供了对 Request 和 Response (以及其余与网络请求有关的)对象的通用定义。它同时还为有关联性的概念,例如CORS和HTTP原生头信息,提供一种新的定义,取代它们原来那种分离的定义。json

fetch规范与jQuery.ajax()的两个不一样点

当接收到一个表明错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即便该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (可是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。跨域

默认状况下,fetch 不会从服务端发送或接收任何 cookies, 若是站点依赖于用户 session,则会致使未经认证的请求(要发送 cookies,必须设置 credentials 选项)。自从2017年8月25往后,默认的credentials政策变动为same-originFirefox也在61.0b13中改变默认值promise

兼容性方案

if(window.fetch) {
    // run my fetch request here
} else {
    // do something with XMLHttpRequest?
}

语法

//input 必填
//[, init] 选填
Promise<Response> fetch(input[, init]);

input 定义要获取的资源,能够是两种形式,以下简单请求的两种形式:url字符串 / Request对象cookie

可选的配置项对象,包括全部对请求的设置。可选的参数有:
method, headers, body, mode, credentials, cache, redirect, referer, referrerPolicy, integerity网络

简单的请求

//第一种形式
let url = 'http://www.wanshaobo.com/1.jpg';//必传
let options = {
      body: JSON.stringify(data),
      headers: new Headers({
        'Content-Type': 'application/json',//发送数据方式为json
        //'Content-Type': 'application/x-www-form-urlencoded',//发送数据方式为表单提交
      }),
      method: 'POST',
      cache: "default",//default, reload, no-cache
      credentials: 'same-origin',//omit 不携带 same-origin 同源请求携带 include 不管跨域仍是同源请求都会携带
      mode: 'cors'//cors, no-cors, same-origin, navigate
    };//可选
fetch(url, options).then(function(Response){
	//fetch方法建立的Promise对象 返回resolved状态的回调函数
	//Response对象详解见下表
},function(error){
	//fetch方法建立的Promise对象 返回rejected状态的回调函数
})
//第二种形式
let Request = new Request(url, {method: 'POST', body: '{"foo":"bar"}'});
fetch(Request).then(function(Response){
	//fetch方法建立的Promise对象 返回resolved状态的回调函数
	//Response对象详解见下表
},function(error){
	//fetch方法建立的Promise对象 返回rejected状态的回调函数
})
  • 属性
key value type
Response.headers 包含此Response所关联的Headers 对象 只读
Response.ok 包含了一个布尔值来标示该 Response 成功(状态码的范围在200-299) 只读
Response.redirected 表示该Response是否来自一个重定向,若是是的话,它的URL列表将会有多个entry 只读
Response.status 包含Response的状态码 只读
Response.statusText 包含了与该Response状态码一致的状态信息 (例如, OK对应 200) 只读
Response.type 包含Response的类型 (例如, basic, cors) 只读
Response.url 包含Response的URL 只读
Response.useFinalURL 包含了一个布尔值来标示这是不是该Response的最终URL -
Response.headers 包含此Response所关联的Headers 对象 只读
Response.headers 包含此Response所关联的Headers 对象 只读
  • 方法
key value type
Response.json() 读取 Response对象而且将它设置为已读(由于Responses对象被设置为了 stream 的方式,因此它们只能被读取一次) ,并返回一个被解析为JSON格式的promise对象。
Response.text() 读取 Response对象而且将它设置为已读(由于Responses对象被设置为了 stream 的方式,因此它们只能被读取一次) ,并返回一个被解析为USVString格式的promise对象。

图片的请求demo

//形式一
var myImage = document.querySelector('img');
var myRequest = new Request('flowers.jpg');
fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(response) {
  var objectURL = URL.createObjectURL(response);
  myImage.src = objectURL;
});

//形式二
var myImage = document.querySelector('img');
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');
var init = { method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' };
var myRequest = new Request('flowers.jpg');
fetch(myRequest,init).then(function(response) {
  ... 
});

//形式三
var myRequest = new Request('flowers.jpg',myInit);
var init = { 
				method: 'GET',
				headers: { 'Content-Type': 'image/jpeg' },
				mode: 'cors',
				cache: 'default'
            };
var myRequest = new Request('flowers.jpg', init);
fetch(myRequest).then(function(response) {
  ... 
});

完整的应用方案一

没有对fetch进行Promise包装,login方法的then回调是Response.json()返回的Promise实例
优势:代码简洁
缺点:不能在request方法体中作全局的res.code状态码统一处理,只能在login方法的then回调中作每个请求的单独处理session

//实际的方法调用
let requestData = {}
login(requestData).then(res => {
        console.log('/abc 接口的返回值',res);// JSON from `response.json()` call
      }).catch(e => {
        console.log(e);
      })
      
//业务的方法
function login(obj) {//登陆
  return request('/abc',obj)
}

//fetch的包装
function request(url,data) {
  return fetch(baseURL + url, {
    body: JSON.stringify(data),
    headers: new Headers({'Content-Type': 'application/json'}),
    method: 'POST',
    cache: "default",
    credentials: 'include',//'same-origin' 'include'
  }).then(Response => Response.json(),err => {}).catch((e)=>{})
}

完整的应用方案二

对fetch进行Promise包装,在request方法体中作全局的res.code状态码统一处理,login方法的then回调是包装的Promise的返回值。

//实际的方法调用
let requestData = {}
login(requestData).then(res => {
		//Promise对象resolved
        console.log('/abc 接口的返回值',res.data);
      },err => {
      	//Promise对象rejecetd
        console.log(err)
      }).catch(e => {
        //catch方法处理 Promise 内部发生的错误,捕获两种错误:
        //一、then方法指定的两个回调函数,若是运行中抛出错误,会被catch方法捕获;
        //二、rejected状态也会被catch方法捕获
        //catch方法返回的仍是一个 Promise 对象
        console.log(e);
      })
      
//业务的方法
function login(obj) {//登陆
  return request('/abc',obj)
}

//fetch的包装
import {message} from "antd";
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
function request(url,data) {
  return new Promise((resolve,reject)=>{
    fetch(baseURL + url, {
      body: JSON.stringify(data),
      headers: new Headers({'Content-Type': 'application/json'}),
      method: 'POST',
      cache: "default",
      credentials: 'same-origin'
    }).then((Response)=>{
      //fetch请求返回resolved状态的回调函数
      let data = Response.json()//res是一个json文件,使用 json() 读取并解析数据,返回一个被解析为JSON格式的promise对象
      data.then((res,rej)=>{
        if(res.code == 100){
          resolve(res)
        }else if(res.code == 11115){
          //用户登陆失效,token失效,跳转到登陆页面
          history.replace('/login')
        }else{
          message.destroy()
          message.error(res.message);
        }
      })
    },err => {
      //fetch请求返回rejected状态的回调函数
      //fetch请求 网络故障时或请求被阻止时,标记为 reject
      reject(err)
    }).catch((e)=>{
      reject(e)
    })
  })
}

完整的应用方案三:FormData() 和fetch()上传文件

body使用FromData对象,主要用于序列化表单以及建立与表单格式相同的数据
经过HTML元素,FormData() 和fetch()上传文件。

var formData = new FormData();
var fileField = document.querySelector("input[type='file']");
formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);
function request(url,data) {
  return new Promise((resolve,reject)=>{
    fetch(url, {
      body: formData,
      method: 'PUT',
    }).then((Response)=>{
      let data = Response.json()
      data.then((res,rej)=>{
      
      })
    })
  })
}

完整的应用方案四:FormData() 和fetch()上传多个文件

能够经过HTML元素,FormData() 和fetch()上传文件。

var formData = new FormData();
var photos = document.querySelector("input[type='file'][multiple]");
formData.append('title', 'My Vegas Vacation');
formData.append('photos', photos.files);
function request(url,data) {
  return new Promise((resolve,reject)=>{
    fetch(url, {
      body: formData,
      method: 'PUT',
    }).then((Response)=>{
      let data = Response.json()
      data.then((res,rej)=>{
      
      })
    })
  })
}

参考资料

感谢阅读,欢迎评论^-^

打赏我吧^-^