What is Axios?

Axios is a promise based web request library that works with Node.js and browsers. It is isomorphic (that is, the same set of code can run in the browser and node.js). On the server side it uses the native Node.js HTTP module, while on the client side it uses XMLHttpRequests.

features

  • Created from the browserXMLHttpRequests
  • fromnode.jscreatehttprequest
  • supportPromise API
  • Intercept requests and responses
  • Transform request data and response data
  • Cancel the request
  • Automatic conversion JSONdata
  • The client supports defenseXSRF

The basic use

The installation

npm install axios
bower install axios 
yarn add axios
// Use unpkg CDN
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
// Use jsDelivr CDN
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
Copy the code

The import

import axios from 'axios'
Copy the code

Send the request

axios({        
  url:'xxx'.// Set the address of the request
  method:"GET".// Set the request method
  params: {// Get requests use params for arguments, or data for post requests
    type: ' '.page: 1
  }
}).then(res= > {  
  // res is the data returned by the back end
  console.log(res);   
})
Copy the code

Use cases

Make a GET request

// Make a request to the user with the given ID
axios.get('/user? ID=12345')
  .then(function (response) {
    // Handle success
    console.log(response);
  })
  .catch(function (error) {
    // Handle error cases
    console.log(error);
  })
  .then(function () {
    // Always execute
  });

// The above request can also be completed as follows (optional)
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .then(function () {
    // Always execute
  });  

// Support async/await usage
async function getUser() {
  try {
    const response = await axios.get('/user? ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error); }}Copy the code

Make a POST request

axios.post('/user', {
    firstName: 'Fred'.lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
Copy the code

Initiate multiple concurrent requests

function getUserAccount() {
    return axios.get('/user/12345');
}

function getUserPermissions() {
    return axios.get('/user/12345/permissions');
}

 
axios.all([getUserAccount(), getUserPermissions()])
   // then((results) => {//
   // const acct = results[0];
   // const perm = results[1];
   // })
    .then(axios.spread((acct, perm) = >{}));/ / write 2
Copy the code

In notation 2, axios.spread takes a function as an argument and returns a new function. The argument to the received argument function is the response returned for each request in the axios.all method.

Two, why to encapsulate

The AXIos API is so friendly that you can easily use it directly in your project.

As the project scale, however, if each initiate a HTTP request, will put these such as set the timeout time, set the request header, which is used to judge according to the project environment request address, error handling, etc., all need to write it again, this kind of repeated labor is not only a waste of time, and make the code redundancy increase, it is difficult to maintain. To improve code quality, you should re-wrap AXIOS in your project and reuse it.

Here’s an example:

axios('http://localhost:3000/api', {
  // Configure the code
  method: 'GET'.timeout: 1000.withCredentials: true.headers: {
    'Content-Type': 'application/json'.Authorization: 'xxx',},transformRequest: [function (data, headers) {
    returndata; }].// Other request configuration...
})
.then((data) = > {
  // todo: start coding business logic code
  console.log(data);
}, (err) = > {
  // Error handling
  if (err.response.status === 401) {
  // handle authorization error
  }
  if (err.response.status === 403) {
  // handle server forbidden error
  }
  // Other error handling.....
  console.log(err);
});
Copy the code

If every page sent a similar request, it would be too tedious to write a lot of configuration and error handling.

At this point, we need to re-wrap AXIos to make it easier to use

Three, how to package

  • At the same time, you need to negotiate some conventions with the back end, request headers, status codes, request timeout……

  • Setting interface request prefixes: The prefixes need to be differentiated based on the development, test, pre-delivery, and production environments.

  • Request header: to achieve some specific business, must carry some parameters can be requested (such as: user information);

  • Status code: Performs different services according to the different status returned by the interface, which needs to be agreed with the back end.

  • Request method: according to get, POST and other methods for a re-encapsulation, more convenient to use

  • Request interceptor: Determines which requests are accessible based on the request header

  • Response interceptor: This is the execution of different services based on the status code returned from the back end

Set the interface request prefix

Node environment variables are used to distinguish between development, test, and production environments

if (process.env.NODE_ENV === 'development') {
  axios.defaults.baseURL = 'http://dev.xxx.com'
} else if (process.env.NODE_ENV === 'production') {
  axios.defaults.baseURL = 'http://prod.xxx.com'
  // Differentiate the online test, pre-release, and official environments according to the custom Node environment variables
}
Copy the code

Proxy configuration

In local debugging, the vue project also needs to configure devServer to implement proxy forwarding in the vue.config.js file, so as to achieve cross-domain.

devServer: {
    proxy: {
      '/proxyApi': {
        target: 'http://dev.xxx.com'.changeOrigin: true.pathRewrite: {
          '/proxyApi': ' '}}}}Copy the code

In the React project, you need to configure proxies in the setupproxy. js file.

const { createProxyMiddleware } = require('http-proxy-middleware');
 
const options = (path, targetUrl) = > {
  let devOptions = {
    target: targetUrl,
    changeOrigin: true.secure: true.// Set a proxy that supports HTTPS
  };
  // Whether to enable the local mock interface
  if (process.env.IS_MOCK === '1') {
    devOptions = Object.assign(devOptions, {
      target: process.env.MOCK_URL,
      pathRewrite: {[` ^${path}`] :`/mock/api/xxx${path}`,}}); }return devOptions;
};

module.exports = (app) = > {
  if (process.env.NODE_ENV === 'development') {
    if (process.env.IS_MOCK === '1') {
      app.use(
        '/',
        createProxyMiddleware(
          options('/', process.env.TEST_URL),
        ),
      );
    } else {
      app.use(
        '/api',
        createProxyMiddleware(
          options('/api', process.env.TEST_URL),
        ),
      );
     / /...}}};Copy the code

Set the request header and timeout

In most cases, the request header is basically fixed, and some special headers may be required, which is used as the base configuration. When a special request header is needed, it is passed in as a parameter, overwriting the underlying configuration. New http.js file:

import axios from 'axios';
import qs from 'qs';

const requestList = [];// Request list
const CancelToken = axios.CancelToken; // Cancel the list
const sources = {}; / / save the request
axios.defaults.timeout = 10000;
axios.defaults.headers.get['Content-Type'] = ContentType.FORM;
axios.defaults.headers.post['Content-Type'] = ContentType.JSON;
axios.defaults.baseURL = process.env.BASE_URL;
axios.defaults.withCredentials = true; 

Copy the code

Encapsulating request method

The encapsulated method is introduced and reencapsulated into a method exposed on the interface to be called

// Configuration typeinterface ConfigType { loading? : boolean;// Whether to display loadingisPubParam? : boolean;// Whether to take public parametersContentType? : string; } enum ContentType {JSON = 'application/json; charset=utf-8',
  FORM = 'application/x-www-form-urlencoded; charset=utf-8',}const request = function (url, params, config, method) {
  return new Promise((resolve, reject) = > {
    axios[method](url, params, Object.assign({}, config))
      .then(
        (response) = > {
          resolve(response.data);
        },
        (err) = > {
          if (err.Cancel) {
            console.log(err);
          } else {
            reject(err);
          }
        },
      )
      .catch((err) = > {
        reject(err);
      });
  });
};

export const post = (url, params, config: ConfigType = {}) = > {
 if(config.isPubParam) params = { ... pubParams, ... params }; params = qs.stringify(params);return request(url, params, config, 'post');
};

export const get = (url, params, config: ConfigType = {}) = > {
 if(config.isPubParam) params = { ... pubParams, ... params };return request(url, { params }, config, 'get');
};

Copy the code

Multi-domain case

// Set multiple domain names in different environments
const setBaseUrl = (options) = > {
  let baseURL = ' ',
    baseURL2 = ' ';
  if (process.env.NODE_ENV === 'production') {
    baseURL = process.env. ONLINE_URL;
    baseURL2 = process.env.ONLINE_URL_2;
  } else {
    baseURL = process.env. TEST_URL;
    baseURL2 = process.env. TEST_URL_2;
  }
  // Replace the corresponding interface domain name
  if (/^\/api\//.test(options.url)) {
    options.url = baseURL + options.url;
  } else if (/^\/base\/test\//.test(options.url)) { options.url = baseURL2 + options.url; }};Copy the code

Request interceptor

Request interceptors can add tokens to each request, which can be easily maintained after unified processing

  axios.interceptors.request.use(
  (config) = > {
    const request =
      JSON.stringify(config.url) + JSON.stringify(config.data || ' ');
 
    setBaseUrl(config); // Call the multi-domain case function
    // Check whether token exists before request, handle single sign-on case
    
    config.cancelToken = new CancelToken((cancel) = > {
      sources[request] = cancel;
    });

    if (requestList.includes(request)) {
      sources[request]('Cancel duplicate request');
    } else {
      requestList.push(request);
      if (config['loading'])
       // toast. show(' loading...... ')
    }

    return config;
  },
  function (error) {
    return Promise.reject(error); });Copy the code

Response interceptor

The response interceptor can perform a layer of operations after receiving the response, such as judging login status and authorization according to the status code. If multiple domain interfaces exist, it can also perform interception processing here to update the BaseURL of the current interface.


axios.interceptors.response.use(
  (response) = > {
    const request =
      JSON.stringify(response.config.url) +
      JSON.stringify(response.config.data);
    requestList.splice(
      requestList.findIndex((item) = > item === request),
      1,);if (requestList.length === 0) {
      Toast.clear();
    }
    if (response.status === 200) {
        switch (response.data.returncode) {
          case -5:
            Toast.show('Authentication failed, please log in again! ');
            break;
          case 102:
            Toast.show('Operation too fast, please try again later! ');
            break; }}else {
        return Promise.reject(response)
    }
    return response;
  },
  (error) = > {
    if (axios.isCancel(error)) {
      requestList.length = 0;
      Toast.clear();
      throw new axios.Cancel('cancel request');
    } else  {
        // Different return codes in failure cases are handled accordingly
        switch (error.response.status) {
           case 500:
             Toast.show('Network request failed! ');break; }}return Promise.reject(error); });Copy the code

application

Put all interfaces into the index.js file in the API directory

import { get, post } from './http'
export const getUser = (params = {}) => get('/api/getuser', params)
Copy the code

Next call to the page

import * as API from 'api/index'
API.getUser({ id: 200 }).then(res= > {
  console.log(res)
})
Copy the code

This does not put the API unified management, convenient maintenance and expansion after.

conclusion

  • Encapsulation is one of the polymorphisms in programming languages, simple pairaxiosEncapsulation, you can realize the infinite charm it brings.
  • A good solution is to encapsulate it according to the needs of the project and make it easy to use.

reference

  • Axois
  • Parse the Axois source code