读取请求正文两次

问题描述 投票:11回答:2

我试图在中间件中读取正文以进行身份​​验证,但是当请求到达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 );
asp.net-core asp.net-core-mvc asp.net-core-webapi
2个回答
30
投票

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

如果您使用的是其他内容类型,则必须手动缓冲请求,并通过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。


7
投票

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();
    ...
    }
© www.soinside.com 2019 - 2024. All rights reserved.