“奇怪”的 axios 拦截器

199 阅读2分钟

💣 事情经过

这是一个工作中发现的问题,简单描述一下场景:后端 api 接口返回格式大致如下:

{
  code: 200, // 200 表示接口返回正常,非 200 则为异常
    data: {}, // 返回的数据
      message: '', // 接口报错时的错误信息
      }
  • 当 code 字段为 200 时,则表示接口正常,这时候我们正常取数据就行;
  • 当 code 为非 200 时,表示接口异常,此时我们需要把对应的错误信息进行弹窗报错;

这属于一个通用的处理,因此我们可以利用 axios 返回拦截器进行处理:

import axios from 'axios';

  const handleRes = config => {
    if (config.data.code !== 200) {
        throw config;
          }
            return config;
            };
            
            const handleErr = error => {
              // 把错误信息进行弹窗
              };
              
              axios.interceptors.response.use(handleRes, handleErr);</code></pre><p>=.= 这就是我的直觉写法,handleRes 函数对响应体进行处理,对返回数据的 code 进行判断,如果不为 200 则抛出一个错误,并由 handleErr 函数捕获,然后再进行弹窗处理。</p><h2 id="item-0-2">💥 终究还是出问题了</h2><p>想法很美好,但其实 handleErr 是不生效的……</p><p>贴个官网的示例:</p><pre><code class="js">// Add a response interceptor
              axios.interceptors.response.use(function (response) {
                // Any status code that lie within the range of 2xx cause this function to trigger
                  // Do something with response data
                    return response;
                    }, function (error) {
                      // Any status codes that falls outside the range of 2xx cause this function to trigger
                        // Do something with response error
                          return Promise.reject(error);
                          });</code></pre><blockquote>只要状态码超过 2xx 便会触发这个函数</blockquote><p>也就是说,它只会在请求异常时触发,也就是接口 http code 不为 2xx 时。</p><h2 id="item-0-3">💊 发现原因</h2><p>解决问题,首先要研究源码 =.=</p><pre><code class="js">const responseInterceptorChain = [];
                          this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
                            responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
                            });
                            
                            // ...省略一大段代码
                            
                            try {
                              promise = dispatchRequest.call(this, newConfig);
                              } catch (error) {
                                return Promise.reject(error);
                                }
                                
                                i = 0;
                                len = responseInterceptorChain.length;
                                
                                while (i &lt; len) {
                                  promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
                                  }</code></pre><p>可以看出拦截器中的参数最终会作为 Promise.prototype.then 的参数,也就是说我们的代码可以等同于:</p><pre><code class="js">promise.then(handleRes, handleErr);</code></pre><p>而 handleErr 函数只捕获 promise 变量的错误,不捕获 handleRes 函数中的错误,如果需要捕获,应该在后面使用 catch 或是 then 函数:</p><pre><code class="js">promise.then(handleRes, handleErr).catch(err =&gt; {});
                                  promise.then(handleRes, handleErr).then(undefined, err =&gt; {});</code></pre><p>换成拦截器的语法,也就是再新增一个响应拦截器,定义一个错误捕获函数:</p><pre><code class="js">import axios from 'axios';
                                  
                                  const handleRes = config =&gt; {
                                    if (config.data.code !== 200) {
                                        throw config;
                                          }
                                            return config;
                                            };
                                            
                                            const handleErr = error =&gt; {
                                              // 把错误信息进行弹窗
                                              };
                                              
                                              axios.interceptors.response.use(handleRes);
                                              axios.interceptors.response.use(undefined, handleErr);</code></pre><h2 id="item-0-4">🍔 后续</h2><p>谢谢观看,希望可以帮到你!</p>