In the project development, interface request is essential, in order to facilitate the use and maintenance, we will be the interface request method secondary encapsulation. The following xiaobian will share with you the methods used in interface encapsulation in my project, hoping to help you. If you like, give it a triple whammy before you go.

Currently, there are two commonly used front-end request methods: AXIos and Fetch. The following small make up on these two kinds of detailed introduction.

axios

Axios is an HTTP client based on Promise for browsers and NodeJS, which is essentially a wrapper around native XHR, except that it is an implementation of Promise that complies with the latest ES specification.

The characteristics of

  • Create an XMLHttpRequest from the browser
  • Supporting Promise API
  • Client support prevents CSRF
  • Provides some interfaces for concurrent requests (important, much easier to do)
  • Create HTTP requests from Node.js
  • Intercept requests and responses
  • Transform request and response data
  • Cancel the request
  • Automatically convert JSON data

Compatibility issues

Axios compatibility issues in PC browsers

Axios supports IE8+, but the principle is based on Promise, so there are issues of incompatibility with IE.

Vuex requires a Promise polyfill in this browser


Solution:

  • Install Babel – polyfill
npm  install  babel-polyfill -s
Copy the code
  • Once installed, babel-polyfill needs to be introduced in main.js

Entry in webpack.base.config.js is typically configured

module.exports = {
  context: path.resolve(__dirname, '.. / '),
  entry: {
    app: ["babel-polyfill"."./src/main.js"] 
    // app: './src/main.js'
 }, }  Copy the code
Axios works with lower Versions of Android

The wrapped AXIos request was found to be invalid on lower versions of Android phones, mainly because promise was not available on lower versions of Android phones

Solution:

  • Install the es6 – promise
npm  install  es6-promise -s
Copy the code
  • Introduce registered ES6-Promise

Be sure to register before AXIos

// Note: ES6-Promise must be registered before Axios
promise.polyfill()

or require('es6-promise').polyfill(); Copy the code

Secondary encapsulation of Axios

Set the baseUrl
axios.defaults.baseURL = baseUrl
Copy the code
Setting timeout
axios.defaults.timeout = 10000
Copy the code
Request to intercept

Axios provides request interception, where we can do some unified pre-request processing, such as tokens, etc.

// Request interceptionaxios.interceptors.request.use((config) => {
  NProgress.start()
  let token = sessionStorage.token
  if (token) {
 config.headers.x_access_token = token  }  return config }, function (error) {  return Promise.reject(error) }) Copy the code
The response to intercept

Axios provides response interception, where we can do some unified processing of the data after the response, such as an error message.

const errorCode = {
  '000': 'Operation too frequent, do not repeat request'.  '401': 'Current operation does not have permissions'.  '403': 'Current operation does not have permissions'.  '404': 'Resource does not exist'. '417': 'Unbound login account, please use password to log in and bind'. '423': 'Demo environment can not operate, if you need to know contact cold'. '426': 'User name does not exist or password is incorrect'. '428': 'Verification code error, please re-enter'. '429': 'Too many requests'. '479': 'Demo environment, no permission to operate'. 'default': 'System unknown error, please feedback to administrator'. '40006':'Login failed, please log in again' }   // Response interceptionaxios.interceptors.response.use(function (response) {  const status = Number(response.data.code) || 200  const msg = response.data.message || errorCode[status] || errorCode['default']  if(Response.data.code === 40006) {// Token is invalid/ /... return Promise.reject(msg)  }  if(response.status ! == 200 || response.data.code ! == 200) {// The interface displays an error message message.error(msg);  return Promise.reject(msg)  }  return response }, function (error) {  if (axios.isCancel(error)) {  requestList.length = 0  throw new axios.Cancel('cancel request')  } else {  message.error('Network request failed, please try again')  }  return Promise.reject(error) }) Copy the code
Global progress bar

In order to optimize the user experience, we can add a global progress bar to the interface when requested. I’m used to using NProgress.

  • The installation
npm i nprogress -S
Copy the code
  • Nprogress provides two apis: start() and done(); We add the request interceptor and the response interceptor, respectively, to the start and end methods.
import NProgress from 'nprogress'// Introduce the nprogress pluginimport 'nprogress/nprogress.css'// This nprogress style must be introduced
// Request interceptionaxios.interceptors.request.use((config) => {
 NProgress.start()  let token = sessionStorage.token  if (token) {  config.headers.x_access_token = token  }  return config }, function (error) {  return Promise.reject(error) })  // Response interceptionaxios.interceptors.response.use(function (response) {  NProgress.done()  const status = Number(response.data.code) || 200  const msg = response.data.message || errorCode[status] || errorCode['default']  if(Response.data.code === 40006) {// Token is invalid/ /... return Promise.reject(msg)  }  if(response.status ! == 200 || response.data.code ! == 200) {// The interface displays an error message message.error(msg);  return Promise.reject(msg)  }  return response }, function (error) {  if (axios.isCancel(error)) {  requestList.length = 0  throw new axios.Cancel('cancel request')  } else {  message.error('Network request failed, please try again')  }  return Promise.reject(error) }) Copy the code
Using encapsulation

For ease of use, we can encapsulate the use method of AXIos so that it is easy to use in the project. Encapsulation method is as follows:

const request = function ({ url, params, config, method }) {
// If it is a GET request, concatenation parameters are required  let str = ' '
  if (method === 'get' && params) {
    Object.keys(params).forEach(item => {
 str += `${item}=${params[item]}& ` })  }  return new Promise((resolve, reject) => {  axios[method](str ? (url + '? ' + str.substring(0, str.length - 1)) : url, params, Object.assign({}, config)).then(response => {  resolve(response.data)  }, err => {  if (err.Cancel) {  } else {  reject(err)  }  }).catch(err => {  reject(err)  })  }) } export default request Copy the code

So when we use it, we just need to pass the corresponding parameter.

Use the sample

import request from '.. /.. /utils/axios'
import {api} from '.. /.. /utils/env'
export function login (params) {
  return request({
    url: api+'user/login'. method: 'post'. params: params  }) } Copy the code

Fetch

The characteristics of

  • Syntax concise, more semantic
  • Support async/await based on standard Promise implementation
  • XHR is a new implementation in the ES specification
  • More low-level, rich API (request, response)
  • ==isomorphic-fetch== can facilitate synchronization

disadvantage

  • Fetch is a low-level API that you can think of as native XHR, so it’s not as comfortable to use and needs to be wrapped
  • The FETCH only reports an error to the network request, and considers 400,500 as a successful request. The server does not reject the 400,500 error code. The FETCH is rejected only when the request cannot be completed due to network errors
  • Fetch (URL, {credentials: ‘include’})
  • Fetch does not support abort and timeout control. The timeout control implemented by setTimeout and Promise.reject cannot prevent the request process from continuing to run in the background, resulting in waste of traffic
  • Fetch has no way of natively monitoring the progress of requests, whereas XHR does

Compatibility issues

Fetch is a relatively new technology, so there will be some browser compatibility problems. Next, we illustrate the compatibility of FETCH in various browsers by using a picture of Can I Use.


Compatible with older browsers

Fetch is not compatible with older browsers because older browsers do not support Proimse.

Solution: Manually write a file to introduce a Pinkie promise, determine if there is currently a Window. promise, and if not, use the one I introduced as window. promise.

Steps:

  • Install the whatwg – fetch
npm install whatwg-fetch -save
Copy the code
  • Since the WHATWG-FETCH module does not have pinkie- promises, they need to be introduced in the module
cd /node_modules/whatwg-fetch

npm install pinkie-fetch --save
Copy the code
  • The introduction of the module

Introduce modules in the FETCH request file

import 'whatwg-fetch'
Copy the code

Secondary packaging

The following small editor provides a small editor of its own, which is the SECONDARY fetch based on TS.

Define constants
/ * ** Define the back-end interface status code* /const codeStatus = {
    _SUCCESS_:'200'// The request was successful _TOKEN_INVALID_:'40006', / / token expires} const codeMessage:any = {  200: 'The server successfully returned the requested data. '. 201: 'Creating or modifying data succeeded. '. 202: 'A request has been queued in the background (asynchronous task). '. 204: 'Deleting data succeeded. '. 400: The server did not create or modify data. '. 401: 'User has no permissions (wrong token, username, password). '. 403: 'The user is authorized, but access is forbidden. '. 404: 'Access path error'. 406: 'Requested format not available. '. 410: 'The requested resource is permanently deleted and will not be retrieved. '. 422: 'A validation error occurred while creating an object. '. 500: 'Server error, please check server. '. 502: 'Gateway error. '. 503: 'Service unavailable, server temporarily overloaded or maintained. '. 504: 'Gateway timed out. '.}  Copy the code
Status code processing

Fetch returns resolve for all response codes, including 200X, 300X, 400X, 500X, etc. Only when an exception is thrown, it will go into the catch. This function distinguishes non-200x requests as reject. Uniformly handled in catch.

const checkHttpStatus = (response:any) => {
    if (response.status >= 200 && response.status < 300) {
        return response;
    }
    const errortext = codeMessage[response.status] || response.statusText;
// A prompt message is required, which will be completed after the prompt component is completed BaseNormalToast(errortext,{duration:5000})  const error = new Error(errortext);  error.name = response.status;  throw error; };    / * ** Unified processing of the code returned by the back-end interface* @param {*} Response The data returned by the back end* /const checkCodeStatus = (response:any) => {  if(response.code == codeStatus._SUCCESS_){   }else if(response.code == codeStatus._TOKEN_INVALID_){ // A series of processing of token invalidation BaseNormalToast('Token invalid, please log in again!! ',{duration:5000})  }else{// Other common error codesBaseNormalToast('${response.code}, error message:${response.message}`,{duration:5000})  }  return response };  Copy the code
Timeout handling
/ * ** Let fetch also timeout* timeout does not mean a connection timeout. It means the response time of the request, including the connection time of the request, the server processing time, and the server response timeEven if the timeout occurs, the fetch request is not abort. It is still sent to the server in the background, but the content of the response is discarded* @param {Promise} fetch_PROMISE fetch The Promise returned by the request* @param {number} [timeout=10000] Unit: ms, set the default timeout period to 10 seconds * @returnReturn to the Promise* /function timeout_fetch(fetch_promise:any,timeout = 10000) {  let timeout_fn:any = null; // This is a reject promise let timeout_promise = new Promise(function(resolve, reject) {  timeout_fn = function() {  reject('timeout promise');  };  });  // Promise.race is used here to pass in the fastest resolve or reject callbacks for subsequent bindings let abortable_promise = Promise.race([  fetch_promise,  timeout_promise  ]);   setTimeout(function() {  timeout_fn();  }, timeout);   return abortable_promise ; }  Copy the code
Using encapsulation
/ * ** @param {string} URL Interface address* @param {string} method Request methods: GET, POST * @param {JSON} [params=' '] body request parameter, null by default* @param {JSON} headers Headers parameter, default {}* @param {Boolean} loading Whether global loading is required * @returnReturn to the Promise* /interface Options {  url : string;  method : string; params ? : any;headers ? : object;} interface FetchOptions {  method : string;  headers : any; body ? : any;} function BaseFetch(options:Options){  let {url, method, params = ' ',headers = {}} = options  let header = {  Accept: 'application/json'. "Content-Type": "application/json; charset=UTF-8". "x_access_token": sessionstorage. token, // The token returned after the user logs in. Some interfaces involving user data need to add the token to the header. headers };  method = method.toUpperCase();  let data = params  let options:FetchOptions = {  method: method,  headers: header,  }  if(params ! =' '){// If the network request has parameters if(method=='GET') { let paramsArray:any[] = []  Object.keys(params).forEach(key => paramsArray.push(key + '=' + encodeURIComponent(params[key])))  if(url.search(/\? /) = = = 1) { typeof (params) === 'object' ? url += '? ' + paramsArray.join('&') : url  } else {  url += '&' + paramsArray.join('&')  }  }  if(method == 'POST' || method == 'PUT' || method == 'DELETE') { if(! (params instanceof FormData)) { data = JSON.stringify(params);  } else { / / is formdata params delete header["Content-Type"]  }  options = {  method: method,  headers: header,  body:data  }  }   }  return new Promise(function (resolve, reject) {  timeout_fetch(fetch(url, options))  .then(checkHttpStatus)  .then((response) => response.json())  .then(checkCodeStatus)  .then((responseData) => {  resolve(responseData);  })  .catch( (err) => {  reject(err);  });  });  }  export default BaseFetch  Copy the code

Use the sample

import { BaseFetch } from "./Fetch";

/ * ** Request server function to request data* @param {*} Params is a parameter that needs to be passed when requesting data* /export async function login(params: any) {  return BaseFetch({  url: 'login'. method: "POST". params  }); }  Copy the code

That’s a little bit of understanding and encapsulation of interface requests, and AXIos is recommended.

I am Monkeysoft, your [three] is monkeysoft creation of the biggest power, if this article has any mistakes and suggestions, welcome to leave a message!

The article continues to update, you can wechat search [little monkey’s Web growth path] pay attention to the public number for the first time to read, after paying attention to the background reply knowledge system, more can receive xiaobian carefully prepared front-end knowledge system, future learning is no longer confused, more can join the technology group exchange and discussion.


This article is formatted using MDNICE