Asp.net-Core

讀取請求正文兩次

  • July 13, 2015

我正在嘗試讀取中間件中的主體以進行身份驗證,但是當請求到達 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-urlencodedor multipart/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 中添加緩衝中間件。

引用自:https://stackoverflow.com/questions/31389781