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

ASP.NET Core Web API过期JWT令牌处理引发客户端异常排查

解决JWT过期响应导致WPF客户端“响应过早结束”异常

在ASP.NET Core Web API中配置JWT认证时,处理过期令牌的代码返回ProblemDetails,但WPF客户端调用GetAsync时抛出“Error while copying content to a stream”,内部异常为“IOException: The response ended prematurely”。

问题根源

  1. 未终止请求管道:在OnAuthenticationFailed事件中写入响应后,没有标记请求已处理,后续中间件可能继续操作响应流,导致响应内容被截断。
  2. 缺少Content-Length头:手动序列化并写入ProblemDetails时,未设置Content-Length响应头,HttpClient无法确定响应内容的准确长度,引发读取异常。

修复方案

方案1:改进现有响应处理逻辑

在写入响应后,调用context.HandleResponse()终止请求管道,并手动设置Content-Length头:

OnAuthenticationFailed = context =>
{
    if (context.Exception is SecurityTokenExpiredException)
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.ContentType = "application/problem+json";
        context.Response.SetErrorCodeHeader(Constants.TOKEN_EXPIRED_CODE);

        var problemDetails = new ProblemDetails
        {
            Status = StatusCodes.Status401Unauthorized,
            Title = "Unauthorized",
            Detail = "Token expired",
            Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
        };

        problemDetails.Extensions["errorCode"] = Constants.TOKEN_EXPIRED_CODE;

        var json = JsonSerializer.Serialize(problemDetails);
        var bytes = System.Text.Encoding.UTF8.GetBytes(json);
        
        // 设置Content-Length头
        context.Response.ContentLength = bytes.Length;
        // 写入响应并终止管道
        return context.Response.Body.WriteAsync(bytes, 0, bytes.Length).ContinueWith(task =>
        {
            context.HandleResponse();
        });
    }

    return Task.CompletedTask;
}

方案2:使用框架内置方法(推荐)

ASP.NET Core提供了标准化的响应生成方法,自动处理序列化、响应头设置和管道终止,代码更简洁规范:

OnAuthenticationFailed = context =>
{
    if (context.Exception is SecurityTokenExpiredException)
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.SetErrorCodeHeader(Constants.TOKEN_EXPIRED_CODE);
        
        // 生成标准ProblemDetails响应,自动处理所有细节
        return context.Response.Problem(
            detail: "Token expired",
            statusCode: StatusCodes.Status401Unauthorized,
            extensions: new Dictionary<string, object> { { "errorCode", Constants.TOKEN_EXPIRED_CODE } }
        );
    }

    return Task.CompletedTask;
}

客户端注意事项

确保客户端HandleResponse方法正确处理401状态码,避免在读取响应前提前关闭流。修复API端响应逻辑后,HttpClient可正常读取完整的ProblemDetails内容。

内容的提问来源于stack exchange,提问作者CoderForHire

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 06:37:22