React+Redux+Thunk中Axios带XSFR-token的POST请求Promise异常处理问题
解决Axios POST请求失败但Promise仍resolve的问题
看起来你遇到的核心问题是Thunk里的错误没有正确传递到组件的Promise链中——当获取XSRF token成功后,哪怕后续POST请求失败,Thunk返回的Promise还是被resolve了,导致组件里不管怎样都走then分支返回'yes'。
我来帮你梳理下问题根源和解决办法:
1. 先看问题出在哪(错误代码示例)
你的Thunk可能是类似这样的写法:
export const submitData = (formData) => async (dispatch) => { try { // 获取XSRF token const tokenRes = await axios.get('/api/xsrf-token'); const xsrfToken = tokenRes.data.token; // 提交数据 const postRes = await axios.post('/api/submit', formData, { headers: { 'X-XSRF-TOKEN': xsrfToken } }); dispatch({ type: 'SUBMIT_SUCCESS', payload: postRes.data }); return postRes.data; } catch (err) { dispatch({ type: 'SUBMIT_FAILURE', payload: err.message }); // 这里没抛出错误!Thunk的Promise会默认resolve } };
问题就出在catch块里:当捕获到错误后,你只dispatch了失败action,但没有把错误继续传递出去。Thunk返回的Promise会因为catch处理了错误而变成resolved状态,组件里的then自然会执行。
2. 修复Thunk:正确传递错误
只需要在catch块末尾重新抛出错误,或者返回一个rejected Promise,这样Thunk返回的Promise就会进入rejected状态,组件就能捕获到失败:
export const submitData = (formData) => async (dispatch) => { try { const tokenRes = await axios.get('/api/xsrf-token'); const xsrfToken = tokenRes.data.token; const postRes = await axios.post('/api/submit', formData, { headers: { 'X-XSRF-TOKEN': xsrfToken } }); dispatch({ type: 'SUBMIT_SUCCESS', payload: postRes.data }); return postRes.data; } catch (err) { const errMsg = err.response?.data?.message || '提交失败'; dispatch({ type: 'SUBMIT_FAILURE', payload: errMsg }); // 关键:重新抛出错误,让Promise进入reject状态 throw err; // 或者用 return Promise.reject(err); 效果一样 } };
3. 组件中正确处理Promise的失败分支
然后在你的React组件里,要加上catch分支来处理失败情况,这样就不会不管成功失败都返回'yes'了:
const handleSubmit = () => { dispatch(submitData(yourFormData)) .then(() => { console.log('yes'); // 只有POST成功才会执行这里 }) .catch((err) => { console.log('no', err); // 获取token失败或POST失败都会走这里 }); };
4. 优化:用Axios拦截器自动处理XSRF token
另外,你可以用Axios的请求拦截器来自动获取和携带XSRF token,不用每次提交都手动写获取token的逻辑,代码更简洁:
// 在你的Axios配置文件(比如axiosInstance.js)里 import axios from 'axios'; const axiosInstance = axios.create({ baseURL: '/api' }); // 请求拦截器:POST请求自动获取并携带XSRF token axiosInstance.interceptors.request.use( async (config) => { if (config.method === 'post') { const tokenRes = await axiosInstance.get('/xsrf-token'); config.headers['X-XSRF-TOKEN'] = tokenRes.data.token; } return config; }, (err) => Promise.reject(err) ); export default axiosInstance;
之后你的Thunk就可以简化成:
import axiosInstance from './axiosInstance'; export const submitData = (formData) => async (dispatch) => { try { const postRes = await axiosInstance.post('/submit', formData); dispatch({ type: 'SUBMIT_SUCCESS', payload: postRes.data }); return postRes.data; } catch (err) { const errMsg = err.response?.data?.message || '提交失败'; dispatch({ type: 'SUBMIT_FAILURE', payload: errMsg }); throw err; } };
这样就能彻底解决你的问题啦——只有当获取token和POST请求都成功时,组件才会返回'yes',任何一步失败都会走到catch分支。
内容的提问来源于stack exchange,提问作者Håkan KA
相关产品推荐
相关产品推荐

