• In addition to pure static display page in front-end daily development, it is essential to do some interface requests fromXMLHttpRequestAnd to thejQuerytheajaxAnd then the nextFetchandAxios.

Why chooseAxios

  • Create XMLHttpRequests from the browser
  • Create HTTP requests from Node.js
  • Supporting Promise API
  • Intercept requests and responses
  • Transform request data and response data
  • Cancel the request
  • Automatically convert JSON data
  • The client supports XSRF defense

Why not?Fetch

  • Fetchtch reports errors only for network requests, and considers all 400,500 successful requests to be wrapped and processed
  • Fetch does not carry cookies by default, configuration items need to be added (Axios also needs to)
  • Fetch does not support abort and timeout control. Timeout control implemented using setTimeout and Promise.reject does not prevent the request process from continuing to run in the background
  • Fetch has no way of natively monitoring the progress of requests

The basic configuration

The installation

# npm
$ npm install axios
# yarn
$ yarn add axios
# cdn
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Copy the code

Direct use of

Execute a request method. [method name] contains request, head, GET, PUT, delete, POST, and patch.

axios[method name](url[, data[, config]])
Copy the code

2. Call with a config object passed in

Axios ([config]).then(response => response).catch(error => error) // config Configuration options for optional content. Only urls are required. If method is not specified, the request uses the get method by default. {// 'url' is the server url for the request url:'/user'// 'method' is the method used to create the request:'get'// The default is get // baseURL will automatically precede the url unless the url is an absolute URL. // It can facilitate passing the relative URL baseURL to axios instance methods by setting a 'baseURL' :'https://some-domain.com/api/'// 'headers' is a custom request that will be sent.'X-Requested-With': 'XMLHttpRequest'}, // 'params' is the URL parameter to be sent with the request // Must be a plain object or URLSearchParams object params: {ID: 12345},... , // 'cancelToken' specifies the cancel token used to cancel the request. // (See the Cancellation section below for more information.)function (cancel) {
  })
Copy the code
  • For more configuration items, go toAxiosWebsite,Website configuration

3. Concurrent processing

axios.all(iterable)
axios.spread(callback)

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

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

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function(accT, perms) {// Both requests completed});Copy the code

Create instance using

  • throughaxios.createCreate a request instance that can receive oneconfigObject;
import axios from axios;
var instance = axios.create([config]);
Copy the code

The defaultconfigconfiguration

1. Set the request timeout period

# use the defaultsAxios.defaults. timeout = 30000 // The time is in millisecondsPass in config
var instance = axios.create({
    timeout: 30000 
});
Copy the code

2. Configure the request to carry cookies

# use the defaults
axios.defaults.withCredentials = true // trueFor automatic carryingPass in config
var instance = axios.create({
    withCredentials: true
});
Copy the code

3. Configure baseURL

  • baseURLWill automatically add inurlUp front, unlessurlIs an absolute URL.
# use the defaults
axios.defaults.baseURL = 'https://github.com/detanx'
Pass in config
var instance = axios.create({
    baseURL: 'https://github.com/detanx'
});
Copy the code

4. Configure headers

  • Such as settingtoken
# use the defaults
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
Pass in config
var instance = axios.create({
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded'.'Authorization': AUTH_TOKEN
});
Copy the code

5. Cancel the request cancelToken

  • (1) UseCancelToken.sourceFactory method creationcancelToken.
const CancelToken = axios.CancelToken;
const source= CancelToken.source(); axios.get(url, { cancelToken: source.token }).catch(thrown => thrown); // Cancel the request (message argument is optional) source.cancel('cancel.');
Copy the code
  • (2) By passing on oneexecutorFunction toCancelTokenConstructor of thecancelToken.
const CancelToken = axios.CancelToken;
let cancel;

axios.get(url, {
  cancelToken: new CancelToken(functionExecutor (c) {// The executor function accepts a cancel function as argument cancel = c; })}) // Cancel the request (message argument is optional) Cancel ('cancel.');
Copy the code

6 or more

Interceptor configuration and error handling

  • In a request or response bythenorcatchIntercept them before processing.

Request to intercept

  • You can add it directly toimportCome inaxiosYou are advised to create a new oneAxiosInstance to which the default values and interceptors are mounted.

1. Block repeated requests

const NotCancleUrl = ['/stockserver/user/login-user']; PendingRequestArray = []; const pendingRequestArray = []; Const {CancelToken} = axios; // Declare an array to store each request's cancellation function and request identifier const removePending = config => {for (const index in pendingRequestArray) {
    const key = `${config.url}&${config.method}`;
    if(pendingRequestArray[index].key === key && ! PendingRequestArray [index].cancel(); notCancleurl.includes (config.url)) {// Execute function body when current request exists in array pendingRequestArray[index].cancel(); / / cancel operation on pendingRequestArray. Splice (index, 1); // Remove this record from array}}}; / / add request interceptor axios. Interceptors. Request. Use (config = > {/ / such as adding to cancel the repeat request removePending (config); CancelToken = new cancelToken (c => {config. CancelToken = new cancelToken Pendingrequestarray. push({key: ') you can select some other method${config.url}&${config.method}`, cancel: c });
    });
    return config;
  }, function(error) {// Handle request errorreturn Promise.reject(error);
  });
Copy the code

2. Intercept the request address and replace the variables in the address

  • By convention with other developers, variables in the address are requested to pass{{varname}}Package, the variable corresponding to the value should be replaced in the request parameters, by replacing the variable, get the correct request address.
/** Variable replacement /* requestUrl Contains the variable string /* paramsObj variable object /*return[] **/ const varsReplace = (requestUrl, paramsObj) => { const SYMBOL_REGEXP = /\{{(.+?) \}}/g; const VARS_ARRAY = requestUrl.match(SYMBOL_REGEXP); const newParamsObj = Object.assign({}, paramsObj);if (VARS_ARRAY){
        for(const variable of VARS_ARRAY){ const varChartArray = variable.slice(2, -2); delete newParamsObj[varChartArray]; const value = paramsObj[varChartArray]; requestUrl = requestUrl.replace(variable, value); }} // Return the new request address and the request parameters after removing the variablesreturn[requestUrl, newParamsObj]; }; / / add a interceptor instance. Interceptors. Request. Use (config = > {let param = {};
        param = (config.method === 'get')? config.params : config.data; const [requestUrl, newParamsObj] = varsReplace(config.url, param);if (config.method === 'get') {
            config.params = newParamsObj;
        } else {
            config.data = newParamsObj;
        }
        config.url = requestUrl;
        return config;
    },
    error => Promise.reject(error)
);
Copy the code

3. Do not intercept address replacement for special requests

  • For example file upload, we passconfigIn theheadersUnder theContent-TypeTo determine the content format of the request, if yesmultipart/form-dataWe’ll just go straight backconfigOther types that do not need to be handled are similar.
// axios.js
instance.interceptors.request.use(
    config => {
+        const { headers, method, params, data, url } = config;
+        if (headers['Content-Type'= = ='multipart/form-data') {+returnconfig; +}letparam = {}; })Copy the code

The response to intercept

PendingRequestArray (pendingRequestArray, pendingRequestArray, pendingRequestArray, pendingRequestArray, pendingRequestArray, pendingRequestArray, pendingRequestArray, pendingRequestArray)

/ / add the response interceptor axios. Interceptors. Response. Use (/ / handle the response data response = > {removePending (response. Config); // After the request is successful, it is removed from the pendingRequestArrayreturnresponse; }, // Handle response error error => {returnPromise.reject(error); });Copy the code

2. Do the same for request timeout, 401, 403 status (although you can do other things depending on the actual application in your project).

Axios. Interceptors. Response. Use (response = > the response, the error = > {/ / service request timeoutif (error === undefined || error.code === 'ECONNABORTED') {
      message.warning('Service request timed out');
      returnPromise.reject(error); } const { response: { status } } = error; const { response } = error; const info = response.data; // 401 is not logged inif(status === 401) {// Not logged in to redirect login page... } // 403 Access deniedif (status === 403) {
      ...
    }
    returnPromise.reject(error); })Copy the code

Error handling

1. Handle in the catch method of the request

axios.get(url)
  .catch(function (error) {
    if(error.response) { const { data, status, headers } = error.response; Console. log(data, status, headers); }else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });
Copy the code

2. Use the validateStatus configuration option to define a custom HTTP status code error range.

axios.get(url), {
  validateStatus: function (status) {
    returnstatus < 500; Reject {reject}})Copy the code

Application in project

  • The default Settings and interceptors have been covered before, but the request method instance encapsulation will only be covered below.

Universal use package

// axios.js // request methodexport const AXIOS_METHOD_TYPE = {
  GET: 'GET',
  POST: 'POST',
  PUT: 'PUT',
  DELETE: 'DELETE',
  PATCH: 'PATCH'}; @param request * @param request * @param request * @param request Default get * @param Params request parameters default null * @param config Request configuration default null * @return function*/ const request = (API, method = AXIOS_METHOD_TYPE.GET, params = {}, config = {}) => { method = method.toLocaleUpperCase(); // Get requests are placed in params, other requests are placed in body const data = method ==='GET' ? 'params' : 'data'; // This part can also be set in defaultslet headers = {
        'X-Requested-With': 'XMLHttpRequest'.'Content-Type': 'application/json'
    };
    if(config.headers) { headers = { ... headers, ... config.headers }; }return axios({
        url: api,
        method,
        [data]: params,
        headers
    });
};
export default request;
Copy the code

use

// index.js
import request from 'request';
request('/user/login', post, {
    username: 'detanx',
    password: '123456'
}).then(response => console.log(response))
.catch(error => console.log(error))
Copy the code

hooksencapsulated

// useRequest.js
import { useState, useEffect } from 'react'; Import {instance, AXIOS_METHOD_TYPE} from for the axios instance exposed in myAxios with default methods and interceptors'./myAxios'; /** method description * @method useRequest * @return[responseData, // errorData is returned if the request is successful; // Loading is returned if the request failsset*/ const useRequest = (url, method = AXIOS_METHOD_TYPE.GET, params = {}, config = {}) => { method = method.toLocaleUpperCase(); const data = method ==='GET' ? 'params' : 'data';
    const [responseData, setResponseData] = useState({});
    const [errorData, setErrorData] = useState({});
    const [loading, setLoading] = useState(true);
    const [requestParams, setRequestParams] = useState(params);
    let headers = {
        'X-Requested-With': 'XMLHttpRequest'.'Content-Type': 'application/json'
    };
    if(config.headers) { headers = { ... headers, ... config.headers }; } useEffect(() => { instance({ url, method, [data]: requestParams, headers }) .then(({ data }) => {setLoading(false);
                setResponseData(data);
            })
            .catch(err => {
                setLoading(false);
                setErrorData(err);
            });
    }, [requestParams]);
    return [
        responseData,
        errorData,
        loading,
        setRequestParams
    ];
};
export default useRequest;
Copy the code

use

// index.js
import useRequest from 'useRequest';
expoert default () => {
    const [
        responseData,
        errorData,
        loading,
        setRequestParams
    ] = useRequest('/api/user'.'get')
    const clickHandle = () => {
        setRequestParams({name: 'detanx'})}return<> <button onClick={clickHandle}> </button> </>Copy the code

hooksPackaging perfect

  • One problem with the encapsulation above is that it is used every timeuseRequestSome pages actually do not need a request, such as pure login page, only need to submit login information to initiate a request, so the above encapsulation is optimized. conventionparamsforfalseDo not initiate a request.
// Change the default value of params tofalseConst useRequest = (url, method = axiOS_method_typet.get, params =false, config = {}) => { ... UseEffect (() => {// Specify 'params' as'false'Do not initiate request +if (requestParams === false) return; instance() }, [requestParams]); . };Copy the code

hooksPackage perfection II

  • After a successful request, the same request continues to trigger the same request. If the success or failure data is the same, the above code will not be updated. So in theuseRequestAdd the following code to.
const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = false, config = {}) => {
    ...
-    const [responseData, setResponseData] = useState({});
-    const [errorData, setErrorData] = useState({});
-    const [loading, setLoading] = useState(true); // Set loading to when the request is initiatedtrue
+    const [responseData, setResponseData] = useState(null);
+    const [errorData, setErrorData] = useState(null);
+    const [loading, setLoading] = useState(false);
+    const reloadRequest = param => {
+        setResponseData(null); // Reset the success data to NULL +setErrorData(null); // Reset failed data to NULL +setRequestParams(param); // Initiate a new request. useEffect(() => {if (requestParams === false) return; // Initiate a request. Loading is set totrue
+       setLoading(true);
        instance({})
        ...
    });
-   return[+return {
        responseData,
        errorData,
        loading,
-       setRequestParams
+       reloadRequest
-   ]
+   };
}
    
Copy the code
  • Return array to object, the advantage of array is to force corresponding to each data, the object can fetch their own data needs.

Afterword.

  • Most requirements are sufficient for daily development, if you have other requirements for your project, feel free to leave a comment.
  • For your useful words, leave your like 👍 oh, thank you for your support!