Read request body twice

后端 未结 3 1749
傲寒
傲寒 2020-12-03 13:30

I am trying to read the body in a middleware for authentication purposes, but when the request gets to the api controller the object is empty as the body has already been re

3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-03 13:59

    If you're using application/x-www-form-urlencoded or multipart/form-data, you can safely call context.Request.ReadFormAsync() multiple times as it returns a cached instance on subsequent calls.

    If you're using a different content type, you'll have to manually buffer the request and replace the request body by a rewindable stream like MemoryStream. Here's how you could do using an inline middleware (you need to register it soon in your pipeline):

    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;
        }
    });
    

    You can also use the BufferingHelper.EnableRewind() extension, which is part of the Microsoft.AspNet.Http package: it's based on a similar approach but relies on a special stream that starts buffering data in memory and spools everything to a temp file on disk when the threshold is reached:

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

    FYI: a buffering middleware will probably be added to vNext in the future.

提交回复
热议问题