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”。
问题根源
- 未终止请求管道:在
OnAuthenticationFailed事件中写入响应后,没有标记请求已处理,后续中间件可能继续操作响应流,导致响应内容被截断。 - 缺少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
相关产品推荐
相关产品推荐

