fetch捕获重定向302/301

11,714 阅读3分钟
  1. 读完本文大约需要5分钟
  2. 本文前置知识:HTTP状态码、fetch
  3. 阅读难度:初级
  4. 本文关键代码及输出结果都写了出来,可以不用编译器编译,直接浏览文章



事情发生在昨天,在调用接口的时候,接口写错了:

/xxx/interventionlist 写成了 /xxx/Interventionlist

果不其然红一片,点开network后,找到调用的接口 ⬇️

这里的302是对404处理后的结果,将所有出现404的结果跳转到一个指定的404页面。 不过这种跳转应该发生在访问页面时,而不是在调用接口传参交互时。

因此我决定对这种出现302的错误进行一个封装,在亲自踩过坑后,这篇文章诞生了!


重定向时无法直接捕获状态码

最开始我尝试直接做个 checkStatus() 来处理这种问题,当response.status === 302console.log出来

...

function checkStatus(response) {
    console.log(response)   // 注1
    // 尝试对302的捕获
    if (response.status === 302) {
        console.log(response) // 注2
    }

    if (response.status >= 200 && response.status < 300) {
        return response;
    }

    const error = new Error(response.statusText);
    error.response = response;
    throw error;
}

...

// url为调用的接口地址,options为fetch的配置
fetch(url, options)
.then(checkStatus)
.then(...)

结果啥都没输出,注1、注2的console.log都没有输出内容

我们梳理一下请求的流程

fetch 发送请求 -->

服务器返回 response 并且带有状态码(比如200) -->

浏览器接收到响应,结果递交给fetch -->

我们从fetch的回调函数获取相应数据 ✅

重定向 时的过程应该这样:

fetch 发送请求 -->

服务器返回 response(带有location) 并且带有状态码302 -->

浏览器接收到响应,通过location进行跳转 -->

服务器返回 response 并且带有状态码(比如200) -->

...

这就是为什么我们拿不到response的原因


那么结论一目了然:

重定向时无法直接捕获状态码


解决方案

方案A: fetch配置redirect

fetch的options配置里有一条叫做redirect

redirect:

  • follow 默认,跟随跳转
  • error 阻止并抛出异常
  • manual 阻止重定向 (并不是像它的名字描述的那样「手动」)

error

fetch('/xxx/Interventionlist', { redirect: 'error' })
.catch(reason => {
  console.error(reason);
});

在出现重定向时,我们会获得一个额外的信息 ⬇️


manual

fetch('/xxx/Interventionlist', { redirect: 'manual' })
.then(reason => {
  console.log(reason);
});

设置manual后不会抛出异常,但会获取到一个被过滤过后的response,里面几乎所有内容都被过滤掉了。

拿到这个响应只能知道这是一个重定向,无法得到其它任何有用的信息 ⬇️

通过这种方法只能知道发生了重定向,但是无法获取到具体的信息。

但是我们已经能判断发生了重定向,并且输出自己需要的东西方便排错

我并不知道这是出于什么安全因素考虑的会过滤掉 response 中的信息,如果有了解的希望能在评论里探讨一下

这种方式目前是我所知的唯一 纯前端 能判断发生重定向的方法


方案B: 后端改写状态码,前端手动处理

目前的302是对404的改写,那么如果我们将404改写成自定义状态码,然后前端捕获到这个状态码后,进行手动处理。

这种方法则需要前后端的同学都做处理。