ReactJS+ASP.NET Core 6 API:Axios Post请求无法处理过期Token响应
解决Axios捕获401响应时error.response为undefined的问题
问题场景
在React应用中使用Axios向ASP.NET Core 6 API发送Post请求,请求头携带JWT Bearer Token。当Token过期时,服务器返回401状态码,但Axios进入catch语句后error.response为undefined,无法正常处理响应结果。
核心原因
服务端在OnAuthenticationFailed事件中仅设置了响应状态码、ContentType和自定义头,但未写入响应体内容,也未正确终止认证流程,导致ASP.NET Core没有发送完整的响应给客户端。此外,跨域场景下若CORS配置未暴露自定义头,浏览器会拦截响应,也会导致Axios无法获取error.response。
解决方案
1. 修复服务端代码
修改JWT认证的事件处理逻辑,确保Token过期时返回完整的JSON响应,并正确终止认证流程:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, ValidateIssuerSigningKey = true, ClockSkew = TimeSpan.Zero, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("test")) }; options.Events = new JwtBearerEvents { OnAuthenticationFailed = async context => { if (context.Exception is SecurityTokenExpiredException) { context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; context.Response.ContentType = "application/json"; context.Response.Headers.Add("Token-Expired", "true"); // 写入完整的JSON响应体 var responseBody = JsonSerializer.Serialize(new { message = "Token已过期", statusCode = 401 }); await context.Response.WriteAsync(responseBody); } // 调用Fail终止认证流程,确保响应被正确发送 context.Fail(context.Exception); } }; }); builder.Services.AddAuthorization();
如果是跨域请求,需要配置CORS允许暴露自定义头:
// 添加CORS配置 builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .WithExposedHeaders("Token-Expired"); // 暴露自定义头给前端 }); }); // 在管道中启用CORS(需放在UseRouting之后,UseAuthorization之前) app.UseCors("AllowAll");
2. 优化客户端Axios处理
通过Axios全局拦截器统一处理错误,简化业务代码:
// 配置Axios全局响应拦截器 axios.interceptors.response.use( response => response, error => { // 处理无响应的情况(如网络错误) if (!error.response) { console.error('请求失败:', error.message); return Promise.reject(new Error('网络异常,请稍后重试')); } // 处理401状态码 if (error.response.status === 401) { const isTokenExpired = error.response.headers['token-expired'] === 'true'; if (isTokenExpired) { console.log('Token已过期,跳转登录页'); // 清除本地过期Token并跳转登录 localStorage.removeItem('jwtToken'); window.location.href = '/login'; } else { console.error('未授权访问'); } } return Promise.reject(error.response); } ); // 简化后的postData函数 async function postData(endPoint, payload, isSecured = false) { const token = isSecured ? localStorage.getItem('jwtToken') : ''; const headers = { 'Content-Type': 'application/json', Accept: 'application/json', }; if (token && isSecured) { headers.Authorization = `Bearer ${token}`; } const response = await axios.post(endPoint, payload, { headers }); return response.data; }
验证说明
修改完成后,当Token过期时,服务端会返回完整的401响应(包含状态码、响应体和自定义头),Axios的catch块中可以正常获取error.response,进而执行Token过期后的处理逻辑(如跳转登录页)。
内容的提问来源于stack exchange,提问作者Reza Shirazi
相关产品推荐
相关产品推荐

