读取请求正文两次

Read request body twice

我正在尝试读取中间件中的正文以进行身份​​验证,但是当请求到达 api 控制器时,对象为空,因为正文已被读取。有没有办法解决。我正在我的中间件中这样读取正文。

var buffer = new byte[ Convert.ToInt32( context.Request.ContentLength ) ];
await context.Request.Body.ReadAsync( buffer, 0, buffer.Length );
var body = Encoding.UTF8.GetString( buffer );

如果您正在使用 application/x-www-form-urlencodedmultipart/form-data,您可以安全地多次调用 context.Request.ReadFormAsync(),因为它 returns 是后续调用的缓存实例。

如果您使用不同的内容类型,则必须手动缓冲请求并用 MemoryStream 等可倒带流替换请求正文。以下是使用内联中间件的方法(您需要尽快在您的管道中注册它):

app.Use(next => async context =>
{
    // Keep the original stream in a separate
    // variable to restore it later if necessary.
    var stream = context.Request.Body;

    // Optimization: don't buffer the request if
    // there was no stream or if it is rewindable.
    if (stream == Stream.Null || stream.CanSeek)
    {
        await next(context);

        return;
    }

    try
    {
        using (var buffer = new MemoryStream())
        {
            // Copy the request stream to the memory stream.
            await stream.CopyToAsync(buffer);

            // Rewind the memory stream.
            buffer.Position = 0L;

            // Replace the request stream by the memory stream.
            context.Request.Body = buffer;

            // Invoke the rest of the pipeline.
            await next(context);
        }
    }

    finally
    {
        // Restore the original stream.
        context.Request.Body = stream;
    }
});

您还可以使用 BufferingHelper.EnableRewind() 扩展,它是 Microsoft.AspNet.Http 包的一部分:它基于类似的方法,但依赖于开始在内存中缓冲数据并假脱机处理所有内容的特殊流达到阈值时到磁盘上的临时文件:

app.Use(next => context =>
{
    context.Request.EnableRewind();

    return next(context);
});

仅供参考:将来可能会在 vNext 中添加一个缓冲中间件。

PinPoint 提及 EnableRewind 的用法

Startup.cs
using Microsoft.AspNetCore.Http.Internal;

Startup.Configure(...){
...
//Its important the rewind us added before UseMvc
app.Use(next => context => { context.Request.EnableRewind(); return next(context); });
app.UseMvc()
...
}

然后在您的中间件中,您只需倒回并重新阅读

private async Task GenerateToken(HttpContext context)
    {
     context.Request.EnableRewind();
     string jsonData = new StreamReader(context.Request.Body).ReadToEnd();
    ...
    }

这适用于 .Net Core 2.1 及更高版本。

今天我 运行 遇到了类似的问题。长话短说,以前用什么

Body.Seek(0, SeekOrigin.Begin);

导致今天异常,至少在我的情况下。这发生在代码迁移到最新版本的 .NET Core 之后。

我的解决方法是添加:

app.Use(next => context => { context.Request.EnableBuffering(); return next(context);

在设置控制器或 MVC 之前添加它。这似乎是作为 .NET Core 2.1 版本的一部分添加的。

希望这对某人有所帮助!

干杯,编码愉快。