如何处理Fetch API网络故障,修复读取undefined的status错误?
解决Fetch API网络错误(如
net::ERR_CONNECTION_REFUSED)的异常处理问题 我编写了以下工具函数处理网络请求,正常场景下运行正常,但遇到net::ERR_CONNECTION_REFUSED这类网络错误时,会抛出cannot read properties of undefined (reading 'status')错误,而非预期的“Failed to fetch”。尝试在checkStatus函数中添加if (!response.ok)的处理不仅无效,还会引发CORS错误。请问如何修正这个问题?
import configureStore from '../configureStore'; import { logout } from '../containers/App/actions'; const store = configureStore({}); /** * Parses the JSON returned by a network request * * @param {object} response A response from a network request * * @return {object} The parsed JSON from the request */ function parseJSON(response) { if ( response.status === 204 || response.status === 205 || parseInt(response.headers.get('content-length')) === 0 ) { return null; } return response.json(); } /** * Checks if a network request came back fine, and throws an error if not * * @param {object} response A response from a network request * * @return {object|undefined} Returns either the response, or throws an error */ function checkStatus(response) { if (response.status >= 200 && response.status < 300) { return response; } const error = new Error(response.statusText); error.response = response; throw error; } /** * Requests a URL, returning a promise * * @param {string} url The URL we want to request * @param {object} [options] The options we want to pass to "fetch" * * @return {object} The response data */ export default function request(url, options) { const headers = { Accept: 'application/json', 'Content-Type': 'application/json', 'Access-Control-Request-Headers': 'Content-Type, Authorization' }; const token = localStorage.getItem('token'); if (token) { headers['Authorization'] = `Bearer ${token}`; } const newOptions = { ...options, mode: 'cors', headers }; // FIXME // properly handle `net::ERR_CONNECTION_REFUSED` // currently, we return `cannot read properties of undefined (reading 'status')` return fetch(url, newOptions) .then(checkStatus) .then(parseJSON) .catch(err => { // check for 401 here and throw an action to clean the store and the logout. if (err.response.status === 401) { store.dispatch(logout); } throw err; }); }
问题根源
Fetch API的错误逻辑特殊:当发生net::ERR_CONNECTION_REFUSED这类网络层面错误时,fetch会直接将Promise置为reject状态,此时进入catch块的err对象并没有response属性——原代码直接访问err.response.status,自然会抛出“读取undefined的status属性”的错误。
另外,response.ok的判断无效是因为:网络错误根本不会走到checkStatus函数,只有服务器返回HTTP响应时,才会进入then链的checkStatus环节。
修正方案
修改catch块逻辑,先判断错误是否携带response属性:
- 无
response则判定为网络错误,抛出明确的“Failed to fetch”错误 - 有
response则处理HTTP状态码错误(如401登出)
同时推荐使用可选链操作符(?.)避免意外报错,修正后的request函数如下:
export default function request(url, options) { const headers = { Accept: 'application/json', 'Content-Type': 'application/json', 'Access-Control-Request-Headers': 'Content-Type, Authorization' }; const token = localStorage.getItem('token'); if (token) { headers['Authorization'] = `Bearer ${token}`; } const newOptions = { ...options, mode: 'cors', headers }; return fetch(url, newOptions) .then(checkStatus) .then(parseJSON) .catch(err => { // 处理网络错误:无response属性时抛出明确提示 if (!err.response) { throw new Error('Failed to fetch'); // 也可保留原始错误信息:throw err; } // 处理HTTP 401错误,用可选链避免报错 if (err.response?.status === 401) { store.dispatch(logout); } throw err; }); }
额外说明
- 网络错误(连接拒绝、DNS失败等)不会触发
checkStatus,因为fetch不会返回任何HTTP响应 - 可选链操作符
err.response?.status可以替代显式的存在性判断,让代码更简洁
内容的提问来源于stack exchange,提问作者Igor Shmukler
相关产品推荐
相关产品推荐

