乐趣区

关于前端:react开发利器-之-fetch请求封装

Fetch

Fetch API 提供了一个 JavaScript 接口,用于拜访和操纵 HTTP 管道的一些具体局部,例如申请和响应。

它还提供了一个全局 fetch() 办法,该办法提供了一种简略,正当的形式来跨网络异步获取资源。

这种性能以前是应用 XMLHttpRequest 实现的。

Fetch 提供了一个更现实的代替计划,能够很容易地被其余技术应用,例如 Service Workers。

Fetch 还提供了 专门的逻辑空间来定义其余与 HTTP 相干的概念,例如 CORS 和 HTTP 的扩大。

请留神,fetch 标准 jQuery.ajax() 次要有以下的不同:

  • 当接管到一个代表谬误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject,即便响应的 HTTP 状态码是 404 或 500。相同,它会 将 Promise 状态标记为 resolve(如果响应的 HTTP 状态码不在 200 – 299 的范畴内,则设置 resolve 返回值的 ok 属性为 false),仅当 网络故障 时或 申请被阻止 时,才会标记为 reject
  • fetch 不会发送跨域 cookie,除非你应用了 credentials 的初始化选项

一个根本的 fetch 申请设置起来很简略。看看上面的代码:

fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data));

参考 fetch(),查看所有可选的配置和更多形容。

// Example POST method implementation:
async function postData(url = '', data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: 'follow', // manual, *follow, error
    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
    body: JSON.stringify(data) // body data type must match "Content-Type" header
  });
  return response.json(); // parses JSON response into native JavaScript objects}

postData('https://example.com/answer', { answer: 42})
  .then(data => {console.log(data); // JSON data parsed by `data.json()` call});

留神:mode: “no-cors” 仅容许应用一组无限的 HTTP 申请头:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type 容许应用的值为:application/x-www-form-urlencodedmultipart/form-datatext/plain

MDN 地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Us…

qs 简介

一个带有一些附加 安全性 查问字符串解析 字符串化 库。

次要维护者:Jordan Harband

最后创建者和维护者:TJ Holowaychuk

npmjs 仓库地址:https://www.npmjs.com/package/qs

react 应用 qs

装置

npm install qs

import qs from'qs'

qu.stringify()和 qs.parse()

  • qu.stringify() : 将 对象序列化成 url 的模式 ;以& 进行拼接
  • qs.parse(): 将 url 解析成对象模式;

1、qs.parse() 将 URL 解析成对象的模式

import  Qs from 'qs';
let url = 'method=query_sql_dataset_d<a style="color:transparent"> 起源 gao*daima.com 搞 @代 #码网 </a>ata&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0';
Qs.parse(url);
console.log(Qs.parse(url));

输入后果

{
    method:'query_sql_dataset_data',
    projectId:'85',
    appToken:'7d22e38e-5717-11e7-907b-a6006ad3dba0'
}

2、qs.stringify()将对象序列化成 URL 的模式,以 & 进行拼接(可用于发送查问条件)

import  Qs from 'qs';
let obj= {
     method: "query_sql_dataset_data",
     projectId: "85",
     appToken: "7d22e38e-5717-11e7-907b-a6006ad3dba0",
     datasetId: "12564701"
   };
Qs.stringify(obj);
console.log(Qs.stringify(obj));

输入的是:

method=query_sql_dataset_data&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0&datasetId=%12564701

JSON.stringify(param) VS Qs.stringify(param)

JSON 中同样存在 stringify办法,然而和 Qs.stringify 之间的区别是很显著的

// JSON.stringify(param) 
{"uid":"cs11","pwd":"000000als","username":"cs11","password":"000000als"}

// Qs.stringify(param)
uid=cs11&pwd=000000als&username=cs11&password=000000als

封装 fetch

为什么封装 Fetch 申请

  • 申请的中央代码更少。
  • 公共的谬误对立一个中央增加即可。
  • 申请定制的谬误还是申请本人也能够解决。
  • 扩展性好,增加性能只须要改一个中央。

总结起来一句话:简略,好用

封装 Fetch 申请(次要文件)

“./fetchUtil”

import qs from 'qs';
import {message} from 'antd';

const {stringify, parse} = qs;

const checkStatus = res => {if (200 >= res.status < 300) {return res;}
  message.error(` 网络申请失败,${res.status}`);
  const error = new Error(res.statusText);
  error.response = error;
  throw error;
};

/**
 *  捕捉胜利登录过期状态码等
 * @param res
 * @returns {*}
 */
const judgeOkState = async res => {const cloneRes = await res.clone().json(); 
  
  //TODO: 能够在这里管控全局申请
  if (!!cloneRes.code && cloneRes.code !== 200) {message.error(`11${cloneRes.msg}${cloneRes.code}`);
  }
  return res;
};

/**
 * 捕捉失败
 * @param error
 */
const handleError = error => {if (error instanceof TypeError) {message.error(` 网络申请失败啦!${error}`);
  }
  return {   // 避免页面解体,因为每个接口都有判断 res.code 以及 data
    code: -1,
    data: false,
  };
};

class http {
  /**
   * 动态的 fetch 申请通用办法
   * @param url
   * @param options
   * @returns {Promise<unknown>}
   */
  static async staticFetch(url = '', options = {}) {

    const defaultOptions = {
      /* 容许携带 cookies*/
      credentials: 'include',
      /* 容许跨域 **/
      mode: 'cors',
      headers: {
        token: null,
        Authorization: null,
        // 当申请办法是 POST,如果不指定 content-type 是其余类型的话,默认为如下,要求参数传递款式为 key1=value1&key2=value2,但理论场景以 json 为多
        // 'content-type': 'application/x-www-form-urlencoded',
      },
    };
    if (options.method === 'POST' || 'PUT') {defaultOptions.headers['Content-Type'] = 'application/json; charset=utf-8';
    }
    const newOptions = {...defaultOptions, ...options};
    console.log('newOptions', newOptions);
    return fetch(url, newOptions)
      .then(checkStatus)
      .then(judgeOkState)
      .then(res => res.json())
      .catch(handleError);
  }

  /**
   *post 申请形式
   * @param url
   * @returns {Promise<unknown>}
   */
  post(url, params = {}, option = {}) {const options = Object.assign({ method: 'POST'}, option);
    // 个别咱们罕用场景用的是 json,所以须要在 headers 加 Content-Type 类型
    options.body = JSON.stringify(params);

    // 能够是上传键值对模式,也能够是文件,应用 append 发明键值对数据
    if (options.type === 'FormData' && options.body !== 'undefined') {let params = new FormData();
      for (let key of Object.keys(options.body)) {params.append(key, options.body[key]);
      }
      options.body = params;
    }
    return http.staticFetch(url, options); // 类的静态方法只能通过类自身调用
  }

  /**
   * put 办法
   * @param url
   * @returns {Promise<unknown>}
   */
  put(url, params = {}, option = {}) {const options = Object.assign({ method: 'PUT'}, option);
    options.body = JSON.stringify(params);
    return http.staticFetch(url, options); // 类的静态方法只能通过类自身调用
  }

  /**
   * get 申请形式
   * @param url
   * @param option
   */
  get(url, option = {}) {const options = Object.assign({ method: 'GET'}, option);
    return http.staticFetch(url, options);
  }
}

const requestFun = new http(); //new 生成实例
export const {post, get, put} = requestFun;
export default requestFun;

定义接口文件,导出 fetch

utils/api

import requestFun from "./fetchUtil"; // 引入
import qs from "qs";

const {stringify} = qs;
const {post, get} = requestFun;

//get 形式
export async function fetchData1(params) {return get(`/api/bbb?${stringify(params)}`);
}

//post 形式
export async function fetchData2(params) {return post(`/api/aaa`, params);
}
 
export async function fetchGetComments(params) {return get(`http://localhost:8001/comments`, params);
}

组件内应用

home.js

import {fetchGetComments} from '../../utils/api'

// 获取数据
const loadData = async ()=> {const commentData = await fetchGetComments();
    console.log('commentData')
    console.log(commentData) 
}

延申问题

如果要扩大 fetch 的 delete 和 patch,该如何做?

如果自定义 header 的话,该如何做?

如果 post 后端须要 formdata 构造数据又该如何做?

感兴趣的小伙伴,能够自行脑补一下。

参考文档

  • https://www.jianshu.com/p/a6573cd68ae6
退出移动版