1. 程式人生 > >axios在後端返回401時,獲取不到error.response和返回的狀態碼問題

axios在後端返回401時,獲取不到error.response和返回的狀態碼問題

在axios中爬過的坑

專案是後端採用的grails + spring cloud + gorm + es等外掛做的, 前端採用的是element + axios + vue等,身份認證採用的是spring cloud oauth2.0 . 開發採用的是gradle搭建,語言使用的是groovy
在搭完框架後,正常流程postman都能跑的通,但是如果使用 axios就會遇到跨域問題
然後就解決吧 首先是preflight被禁的問題:
首先是webSecureAdapter這裡

class WebSecure extends WebSecurityConfigurerAdapter{
    @Override
protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().requestMatchers(new RequestMatcher() { @Override boolean matches(HttpServletRequest request) { return CorsUtils.isPreFlightRequest(request) } }).permitAll() //.and()其他的內容
} }

然後發現問題還是沒解決 由於認證中心和資源在同一個專案上,暫時未拆分所以 ResourceServerConfigurerAdapter 這裡也需要配置

class ResourceConf extends ResourceServerConfigurerAdapter {
@Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
        .requestMatchers(new RequestMatcher() {//preflght permitAll 
@Override boolean matches(HttpServletRequest request) { return CorsUtils.isPreFlightRequest(request) } }).permitAll() }

好了 ,到這裡資料訪問的跨域已經解決完成了
但是身份認證的時候也是要跨域的,而且我們的返回資料有部分內容是在header中的,這個在使用spring的框架時,會將其中的header替換掉,繼續修改
找了半天,終於找到一個將spring Boot的Filter的修改

private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 設定訪問源地址
        corsConfiguration.addAllowedHeader("*"); // 2 設定訪問源請求頭
        corsConfiguration.addAllowedMethod("GET"); // 3 設定訪問源請求方法
        corsConfiguration.addAllowedMethod("POST");
        corsConfiguration.addAllowedMethod("DELETE");
        corsConfiguration.addAllowedMethod("PUT");
        corsConfiguration.addAllowedMethod("PATCH");
        corsConfiguration.addExposedHeader("Content-Range")//這裡是需要額外配置的header內容
        return corsConfiguration;
    }
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 4 對介面配置跨域設定
        return new CorsFilter(source);
    }

好了,到這裡好像已經全部配置完成了,資料能正常的訪問,介面也都能正常的請求了,….
但是,在使用axios的時候,如果我們使用的token過期,或者token出錯的時候,在瀏覽器能獲取401 ,但是axios死活獲取不到正常的返回碼,找了一堆的原始碼,可以確定在axios中處理返回結果的位置
在axios 的lib/adapter/xhr.js中

request[loadEvent] = function handleLoad() {
      if (!request || (request.readyState !== 4 && !xDomain)) {
        return;
      }

      // The request errored out and we didn't get a response, this will be
      // handled by onerror instead
      // With one exception: request that using file: protocol, most browsers
      // will return status as 0 even though it's a successful request
      if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
        return;//注意這裡,這裡如果遇到上述的401/403等問題,直接返回,導致我們的axios不能取到返回碼
      }

      // Prepare the response
      var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
      var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
      var response = {
        data: responseData,
        // IE sends 1223 instead of 204 (https://github.com/mzabriskie/axios/issues/201)
        status: request.status === 1223 ? 204 : request.status,
        statusText: request.status === 1223 ? 'No Content' : request.statusText,
        headers: responseHeaders,
        config: config,
        request: request
      };

      settle(resolve, reject, response);

      // Clean up request
      request = null;
    };

同時前端會報錯 ,出現跨域問題, 再次整理後端程式碼,終於發現了WebSecurityConfigurerAdapter中

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    ...
        .csrf().disable();//這裡同上面是相同的位置
    }

這裡的csrf被禁用後,如果使用跨域,就導致axios不能獲取正常error.response
將這裡修改為

http.authorizeRequests()
...
.and().cors()

好了 這時候,如果token超時或者使用不正確的token的時候 就能正常的返回error.response了