You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 00:11:04