从catch块返回fetch Promise时遇TypeError问题求助
问题排查与解决方案
错误根源
- fetch的特性:fetch仅在网络请求失败(如断网、跨域错误)或Promise被主动
reject时才会触发catch,HTTP 4xx/5xx状态码的响应会被视为成功的Promise(resolve),不会进入catch。 - 当前代码问题:报错
response.json is not a function,是因为catch捕获到的不是401的响应对象,而是其他错误(比如第一个response.json()解析失败时抛出的Error实例),Error对象没有json()方法,调用时自然报错。
修复步骤
- 手动处理HTTP错误状态:在第一个
then中检查响应的ok属性(response.ok为true等价于状态码200-299),非成功状态则手动reject响应对象,让catch能正确捕获401场景。 - 区分错误类型:在
catch中判断是否为401响应,仅针对该场景执行刷新token逻辑,避免处理无关错误。 - 抽离重复逻辑:把列表请求封装成函数,减少代码冗余,同时确保刷新token后重新请求时能拿到最新的token。
修复后的完整代码
// 封装列表请求函数,复用逻辑 function fetchList() { return fetch(host + '/api/v1/list', { headers: { "Accept": "application/json", "Content-Type": "application/json", "Authorization": "Bearer " + getBearerToken() } }) .then(response => { // 非2xx状态码手动reject,让catch能捕获 if (!response.ok) { return Promise.reject(response); } return response.json(); }) .then(data => data.items); } // 执行请求并处理token刷新逻辑 fetchList() .catch(response => { // 仅处理401的token过期场景 if (response.status === 401) { return fetch(host + '/refresh', { method: 'POST', headers: { "Accept": "application/json", "Content-Type": "application/json", "Authorization": "Bearer " + getBearerToken() } }) .then(refreshRes => { // 检查刷新token接口的状态 if (!refreshRes.ok) { throw new Error('刷新token失败'); } return refreshRes.json(); }) .then(data => { const token = data['Access_token']; document.cookie = 'SSO_token=' + token + '; expires=0; path=/'; // 刷新token后重新发起列表请求 return fetchList(); }); } // 其他错误直接抛出,不进入后续逻辑 throw response; });
额外注意
- 刷新token的接口同样需要检查状态码,避免刷新失败后继续执行无效逻辑。
- 若刷新token接口也返回401(如refresh token已过期),需补充处理逻辑(如跳转登录页),防止进入无限循环。
内容的提问来源于stack exchange,提问作者PDStat
相关产品推荐
相关产品推荐

