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

中间件读取请求体后,接口触发JSON反序列化400错误的问题

问题原因与解决方案

为什么会出现这个错误?

HttpContext.Request.Body是一个单向、不可重复读取的流。当你在中间件中调用ReadToEndAsync()读取完整个请求体后,流的指针会移动到流的末尾。后续ASP.NET Core的模型绑定器(负责解析[FromBody]参数的组件)尝试读取这个流时,只能读到空内容,自然就会抛出JSON解析失败的错误:

"The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true.
Path: $ | LineNumber: 0 | BytePositionInLine: 0."

你觉得只读取了一次,但实际上整个请求处理流程中,你的中间件是第一次读取,模型绑定器是第二次读取,所以必须让流支持重复读取。

解决方案:启用请求体缓冲

ASP.NET Core提供了内置的方法让请求体可以被重复读取,推荐使用EnableBuffering()(ASP.NET Core 3.0及以上版本),它会将请求体缓存到内存或磁盘中,让流支持多次读取和位置重置。

修改后的中间件代码示例:

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
    // 启用请求体缓冲,允许重复读取
    context.Request.EnableBuffering();

    // 读取请求体内容
    string requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
    
    // 重置流的位置到开头,确保后续组件能正常读取
    context.Request.Body.Position = 0;

    if(await CheckIfRequestIsAuthorize(requestBody))
    {
        await next.Invoke(context);
    }
}

private async Task<bool> CheckIfRequestIsAuthorize(string requestBody)
{
    Console.WriteLine("Inside method");
    dynamic tmp = JsonConvert.DeserializeObject(requestBody);
    string sessionId = (string)tmp.sessionId;

    return sessionId == "string";
}

额外优化建议

  • 直接将读取到的requestBody传入校验方法,避免重复操作流,代码更简洁。
  • 如果担心大请求体占用过多内存,可以通过配置限制缓冲大小,默认小请求用内存存储,大请求自动转磁盘存储。
  • 旧版本ASP.NET Core可以使用EnableRewind(),功能和EnableBuffering()类似,后者是前者的升级版。

关键注意点

  • 读取完流之后必须重置Position到0,否则后续组件依然读不到内容。
  • 不要直接修改原始流的状态而不做缓冲,非缓冲流不支持Seek操作,手动重置位置会抛出异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 21:54:25