关于前端: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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理