代码之家  ›  专栏  ›  技术社区  ›  Amir Saleem

如何在axios中处理401(身份验证错误)并做出反应?

  •  82
  • Amir Saleem  · 技术社区  · 8 年前

    我有一个文件请求。js,其中包含axios ajax请求的包装器。我从多个react组件调用请求函数,当其中一个请求失败时,我希望刷新令牌并再次重试所有失败的请求。我可以使用拦截器,但我不知道如何实现它。请帮忙。

    要求js公司

     var client = axios.create({
       baseURL: 'http://192.168.1.3:3000',
         headers: {
         appID: 8,
         version: "1.1.0",
         empID: localStorage.getItem('empID'),
         token: localStorage.getItem('accessToken')
        }
     });
    
     const request = function(options) {
         const onSuccess = function(response) {
             console.debug('Request Successful!', response);
             return response.data;
         } 
         const onError = function(error) {
             console.error('Request Failed:', error.config);
             if (error.response) {
                 console.error('Status:',  error.response.status);
                 console.error('Data:',    error.response.data);
                 console.error('Headers:', error.response.headers);
             } else {
                 console.error('Error Message:', error.message);
             }
    
             return Promise.reject(error.response || error.message);
         }
    
         return client(options)
             .then(onSuccess)
             .catch(onError);
             options
     }
    
     export default request;
    
    6 回复  |  直到 5 年前
        1
  •  119
  •   Pram    5 年前

    若你们想使用拦截器来处理401错误,这里有一段代码。

    axios.interceptors.response.use(response => {
       return response;
    }, error => {
      if (error.response.status === 401) {
       //place your reentry code
      }
      return error;
    });
    
        2
  •  17
  •   Amir Saleem    6 年前

    我用以下代码实现了它

    import axios from 'axios';
    import config from '../../configuration.json';
    import qs from 'qs';
    
    const baseURL = config['baseUrl_local'];
    let authTokenRequest;
    
    /**
      * @description axios instance for ajax requests
    */ 
    
    var client = axios.create({
    baseURL: baseURL,
    headers: {
        appID: 8,
        version: "1.1.0",
        empID: localStorage.getItem('empID'),
        token: localStorage.getItem('accessToken')
    }
    });
    
    /**
     * @description this method calls a requestNewToken method to issue a 
     new token to the client
    */ 
    
     function getAuthToken() {
       if (!authTokenRequest) {
       authTokenRequest = requestNewToken();
       authTokenRequest.then(resetAuthTokenRequest, resetAuthTokenRequest);
     }
     return authTokenRequest;
     }
    
    /**
      * @description this method requests the server to issue a new token, 
      the server response is updated in local storage accessToken
    */ 
    
    function requestNewToken() {
      var newToken = request({
      method: "post",
      url: '/sign-in',
      data:  qs.stringify({
             "userName":localStorage.getItem('userName'),
             "password":localStorage.getItem('password')
             })  
      }).then((res)=>{
      if(res.status == "success"){
        localStorage.setItem('accessToken',res.data.accessToken);
        //if featureArray is present in response object, update the 
        featureArray in local storage
        if(res.data.features){
          localStorage.setItem(
          'featureArray',
         JSON.stringify(res.data.features));
        }
        client = axios.create({
         baseURL: baseURL,
         headers: {
              appID: 8,
              version: "1.1.0",
              empID: localStorage.getItem('empID'),
              token: localStorage.getItem('accessToken')
          }
       });
     } else {
      window.location = "/logout";
     }
    });
     return newToken;
    }
    
    function resetAuthTokenRequest() {
      authTokenRequest = null;
     }
    
    /**
      * @description if any of the API gets 401 status code, this method 
       calls getAuthToken method to renew accessToken
      * updates the error configuration and retries all failed requests 
      again
    */ 
    
    client.interceptors.response.use(undefined, err => {
      const error = err.response;
      // if error is 401 
      if (error.status===401 && error.config && 
      !error.config.__isRetryRequest) {
      // request for a new token
      return getAuthToken().then(response => {
       // update the error config with new token
       error.config.__isRetryRequest = true;
       error.config.headers.token= localStorage.getItem("accessToken");
       return client(error.config);
      });
     } 
    });
    
    /**
     * @description wrapper for making ajax requests
     * @param {object} object with method,url,data etc.
    */ 
    
    const request = function(options) {
      const onSuccess = function(response) {
        return response.data;
      }
     const onError = function(error) {
      //console.error('Request Failed:', error.config);
       if (error.response) {
      //console.error('Status:',  error.response.status);
      //console.error('Data:',    error.response.data);
      //console.error('Headers:', error.response.headers);
      } else {
      console.error('Error Message:', error.message);
      }
     return Promise.reject(error.response || error.message);
     }
    
    return client(options)
            .then(onSuccess)
            .catch(onError);
            options
    }
    
    export default request;
    

    [编辑]2019年,这是同样的另一个实现。上述解决方案很好,但不能很好地处理多个失败的请求,反过来,它也会使用更新的令牌调用getToken。

     import axios from "axios";
    
     /* @internal */
     import config from "../config";
     import TokenService from "./token_service";
    
    class Request {
        constructor() {
            this.baseURL = config.baseUrl;
            this.isRefreshing = false;
            this.failedRequests = [];
            this.tokenService = new TokenService();
            this.client = axios.create({
                baseURL: config.apiServerBaseUrl,
                headers: {
                   clientSecret: this.clientSecret,
                },
            });
            this.beforeRequest = this.beforeRequest.bind(this);
            this.onRequestFailure = this.onRequestFailure.bind(this);
            this.processQueue = this.processQueue.bind(this);
            this.client.interceptors.request.use(this.beforeRequest);
            this.client.interceptors.response.use(this.onRequestSuccess, 
    this.onRequestFailure);
    }
    
    beforeRequest(request) {
        const token = TokenService.getAccessToken();
        request.headers.Authorization = `Token ${token}`;
        return request;
    }
    
    static onRequestSuccess(response) {
        return response.data;
    }
    
    async onRequestFailure(err) {
        const { response } = err;
        if (response.status === 401 && err && err.config && !err.config.__isRetryRequest) {
            if (this.isRefreshing) {
                try {
                    const token = await new Promise((resolve, reject) => {
                        this.failedRequests.push({ resolve, reject });
                    });
                    err.config.headers.Authorization = `Bearer ${token}`;
                    return this.client(err.config);
                }
                catch (e) {
                    return e;
                }
            }
            this.isRefreshing = true;
            err.config.__isRetryRequest = true;
            return new Promise((resolve, reject) => {
                this.tokenService.refreshAccessToken().then((token) => {
                    this.tokenService.setAccessToken(token);
                    err.config.headers.Authorization = `Bearer ${token}`;
                    this.isRefreshing = false;
                    this.processQueue(null, token);
                    resolve(this.client(err.config));
                }).catch((e) => {
                    this.processQueue(e, null);
                    reject(err.response);
                });
            });
        }
        throw response;
    }
    
    processQueue(error, token = null) {
        this.failedRequests.forEach((prom) => {
            if (error) {
                prom.reject(error);
            } else {
                prom.resolve(token);
            }
           });
            this.failedRequests = [];
        }
    
    }
    
    const request = new Request();
    
    export default request.client;
    
        3
  •  13
  •   estani    5 年前

    这项工作:

    // Add a 401 response interceptor
    window.axios.interceptors.response.use(function (response) {
        return response;
    }, function (error) {
        if (401 === error.response.status) {
            // handle error: inform user, go to login, etc
        } else {
            return Promise.reject(error);
        }
    });
    

    摘自: https://gist.github.com/yajra/5f5551649b20c8f668aec48549ef5c1f

    我有一个额外的问题:

    “网络错误”,无任何响应

    tl;dr-这是CORS及其设置的问题,因此axios从未从浏览器中获得信息。您必须从服务器端进行分类。

    描述

    如果您有类似的问题,可以在浏览器控制台中看到。浏览器将阻止您通过ajax访问其他url。

    在我的特殊情况下(node.js-express)是过滤器的顺序,CORS过滤器(开发环境)是在这个特定请求的处理程序之后添加的,因此服务器当时没有发送正确的CORS头,因此浏览器甚至不允许请求发生(没有任何对服务器的调用,因此没有返回错误对象)。

        4
  •  11
  •   Muhammad Shahzad    4 年前

    我们可以使用此方法捕获axios 401。

     axios.post('/add')
     .then(function (response) {...})
     .catch(function (error) {
         console.log(error.response.status) // 401
         console.log(error.response.data.error) //Please Authenticate or whatever returned from server
       if(error.response.status==401){
         //redirect to login
       }
     })
    
        5
  •  1
  •   James Westgate    3 年前

    在模块中使用Axios时,我还没有找到一个清晰简洁的答案。您需要将拦截器添加到 例子

    应用程序编程接口。js公司

    import axios from 'axios'
    import store from '../state'
    
    //Defaults will be combined with the instance
    axios.defaults.baseURL = '/some/page.aspx';
    
    //Create Axios Instance
    const axiosInstance = axios.create({
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json; charset=UTF-8'
        }
    });
    
    //Add interceptors to instance
    axiosInstance.interceptors.response.use(
        response => response,
        error => {
            if (!error.response) {
                store.commit('setServiceAvailable', false);
            }
            else if (error.response.status === 401) {
                store.commit('setUserAuthorised', false);
            }
            return error;
        });
    
    export default axiosInstance;
    

    然后正常使用

    组成部分js公司

    import api from '../api'
    ...
    async getServersJson() {
        try {
            var response = await api.post('GetReportAsServers', {name: 'get-servers', args: null});
            this.serversJson = this.prettifyJson(response.data.d);
        }
        catch (error) {
            console.error(`Exception getting servers. ${error}`);
        }
    },
    
        6
  •  1
  •   Thanh Nguyen    3 年前

    我咨询了其他一些问题,这是我的代码

    import axios from 'axios';
    
    const instance = axios.create({
        baseURL: window.location.hostname === 'localhost' ? 'http://localhost:5001/api/v1' : 'https://api.mysite.com/api/v1'
    });
    instance.defaults.headers.common['Content-Type'] = 'multipart/form-data';
    
    //validate response
    instance.interceptors.response.use((response) => {
        return response;
    }, (error) => {
            if (error.response.status === 401) {
    
                return window.location.href = '/login'
            }
        return Promise.reject(error);
    });
    
    // Set the AUTH token for any request
    instance.interceptors.request.use(
        (config) => {
            const token = localStorage.getItem('token');
            config.headers.Authorization =  token ? `Bearer ${token}` : '';
            return config;
        }
    )
    
    export default instance;