Axios:如何拦截和响应Axios请求

6

有没有一种方法可以在axios请求启动之前不仅拦截它,还可以响应它?也就是说,从浏览器发出请求,然后从浏览器响应该请求+防止发送该请求。

我知道我可以使用axios拦截器在请求和响应被发送和返回到组件之前拦截它们,我也知道在请求拦截器中我可以抛出一个错误并触发带有失败请求的响应拦截器。那么如何处理成功的请求呢?给定某些条件,我希望axios响应好像已传递给服务器一样,实际上它甚至没有经过拦截器。这可能吗?

这是我目前的伪代码:

      axios.interceptors.request.use(
      request => {
        if (localResponse) {
              throw { isLocal: true, data: { hello: 'world' } }; // <- this will stop request and trigger 
                                                                 // response error. I want to trigger 
                                                                 // the actual response callback
        } else {
            return request;   // <- will perform full request
        }
      },
      error => {
        return Promise.reject(error);
      }
    );

    axios.interceptors.response.use(
      response => {
        return response; // <- I want to trigger this callback
      },
      error => { // <- so far i can only trigger a response error
        if (error?.isLocal) { 
          return Promise.resolve(error.data); 
        }
        
        return Promise.reject(error);
      }
    );

我尝试只解决请求拦截器,但这种方法会继续满足请求。是否有任何创意来解决这个问题?也许有比使用拦截器更好的解决方案?


1
你可以在生产代码中使用jest-mock-axios或moxios等_mock_ Axios库之一。只是一个想法 ¯\(ツ) - Phil
我认为那基本上是最后的选择。我正在使用 Electron 和 axios 进行 HTTP 和 IPC 通信的实验,唯一剩下的问题是停止 axios 请求,改用 IPC 发送数据,并像 axios 完成 HTTP 请求一样响应。 - Frederik Petersen
我有同样的“需求”,即直接从拦截器响应请求,但似乎没有简单的内置解决方案。 - dragonfly02
3个回答

7

我成功地自己解决了这个问题。这样一来,所有我的axios调用都不需要改变,我只需要改变拦截器的行为。

注意:如果有人想到更好的解决方案,我会很高兴地将他们的答案标记为正确并点赞。目前,这是我能想到的最好的解决方案。

解决方案

以下是我如何解决这个问题的方法:

      axios.interceptors.request.use(
      request => {
        if (localResponse) {
              throw { isLocal: true, data: { hello: 'world' } }; // <- this will stop request and trigger 
                                                                 // response error. I want to trigger 
                                                                 // the actual response callback
        } else {
            return request;   // <- will perform full request
        }
      },
      error => {
        return error?.isLocal 
                    ? Promise.resolve(error); // <- triggers response intercept
                    : Promise.reject(error);
      }
    );

    axios.interceptors.response.use(
      response => {
        return response; 
      },
      error => {
          error?.isLocal 
                ? Promise.resolve(error); // <- sends as successful response
                : Promise.reject(error);
      }
    );

本质上我所做的是抛出一个错误来阻止请求继续执行,但是我会将该错误解决而不是拒绝它。这有点hacky,但可以完成工作。


5
多么美丽的丑陋黑客 :D - rudolfbyker
1
我最终通过在请求拦截器中设置适配器来实现结果,正如这个axios github问题中所提到的那样。感觉这是正确的做法。 - Pepijn Olivier
1
谢谢您链接到另一个解决方案,@PepijnOlivier。如果您将其重写为解决方案并在此处发布,供寻找答案的人轻松查看(并可能点赞),那将是一个额外的服务。 - Frederik Petersen

1
你能在本地场景中完全跳过请求吗?
function getData() {
  if (localResponse) {
    return Promise.resolve({ isLocal: true, data: { hello: 'world' }});
  }
  else {
    return axios.whatever;
  }
}
...
getData().then(...)

我一直无法让 Promise.resolve 在不发送请求的情况下正常工作,而我希望它跳过该请求。 - Frederik Petersen
在我上面的例子中,请求是在else块中发送的,因此不可能发送和调用Promise.resolve - Brandon Gano
1
你说得对,我看错了。问题在于那个解决方案需要我修改一个已经存在的结构并且“包装”axios而不是利用已经存在的功能。通过使用拦截器,我可以添加这个功能而无需修改所有的axios代码。对于我的特定问题,我不能进行这种修改。不过,你的回答确实帮助我找到了自己的答案,对我的头脑风暴很有帮助,所以谢谢你;) - Frederik Petersen

0
您可以提供自定义的适配器
import axios, { getAdapter } from 'axios';

const xhrAdapter = getAdapter('xhr');

axios.defaults.adapter = (config) => {
  if (useLocal) {
    return Promise.resolve({
      data: yourData,
      status: 200,
      statusText: 'ok',
      headers: {},
      config: config,
      request: {}
    });
  }
  return xhrAdapter(config)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接