国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

2020-07-01 14:54Lamond Lu ASP.NET教程

這篇文章主要給大家介紹了關于在ASP.NET Core自定義中間件中如何讀取Request.Body與Response.Body的內容,文中通過示例代碼介紹的非常詳細,對大家學習或者使用ASP.NET Core具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

背景#

最近在徒手造輪子,編寫一個ASP.NET Core的日志監控器,其中用到了自定義中間件讀取Request.BodyResponse.Body的內容,但是編寫過程,并不像想象中的一帆風順,ASP.NET Core針對Request.Body和Response.Body的幾個特殊設計,導致了完成以上功能需要繞一些彎路。

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

原始代碼#

為了讀取Request.Body和Response.Body的內容,我的實現思路如下:

創建一個LoggerMiddleware的中間件,將它放置在項目中間件管道的頭部。因為根據ASP.NET Core的中間件管道設計,只有第一個中間件才能獲取到原始的請求信息和最終的響應信息。

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

Request.Body和Response.Body屬性都是Steram類型, 在LoggerMiddleware中間件的InvokeAsync方法中,我們可以分別使用StreamReader讀取Request.Body和Response.Body的內容。

根據以上思路,我編寫了以下代碼。

LoggerMiddleware.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   public class LoggerMiddleware
{
private readonly RequestDelegate _next;
 
public LoggerMiddleware(RequestDelegate next)
{
 _next = next;
}
 
public async Task InvokeAsync(HttpContext context)
{
 var requestReader = new StreamReader(context.Request.Body);
 
       var requestContent = requestReader.ReadToEnd();
       Console.WriteLine($"Request Body: {requestContent}");
 
       await _next(context);
 
       var responseReader = new StreamReader(context.Response.Body);
       var responseContent = responseReader.ReadToEnd();
       Console.WriteLine($"Response Body: {responseContent}");
}
}

Startup.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
 app.UseMiddleware<LoggerMiddleware>();
 app.UseDeveloperExceptionPage();
}
else
{
 app.UseHsts();
}
 
app.UseHttpsRedirection();
app.UseMvc();
}

問題1:Response.Body的Stream不可讀#

這里為了測試我創建了一個默認的ASP.NET Core WebApi項目。當運行程序,使用GET方式調用/api/values之后,控制臺會返回第一個需要處理的錯誤。

?
1
System.ArgumentException: Stream was not readable.

即ASP.NET Core默認創建的Response.Body屬性是不可讀的。

這一點我們可以通過打斷點看到Response.Body屬性的CanRead值是false。

這就很糟糕了,ASP.NET Core默認并不想讓我們在中間件中直接讀取Response.Body中的信息。

這里看似的無解,但是我們可以轉換一下思路,既然ASP.NET Core默認將Response.Body是不可讀的,那么我們就使用一個可讀可寫的Stream對象將其替換掉。這樣當所有中間件都依次執行完之后,我們就可以讀取Response.Body的內容了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public async Task InvokeAsync(HttpContext context)
{
     var requestReader = new StreamReader(context.Request.Body);
 
 var requestContent = requestReader.ReadToEnd();
 Console.WriteLine($"Request Body: {requestContent}");
 
 using (var ms = new MemoryStream())
 {
  context.Response.Body = ms;
  await _next(context);
 
  context.Response.Body.Position = 0;
 
  var responseReader = new StreamReader(context.Response.Body);
 
  var responseContent = responseReader.ReadToEnd();
  Console.WriteLine($"Response Body: {responseContent}");
 
  context.Response.Body.Position = 0;
 }
}

注意:

  • 讀取Response.Body的時候,需要設置Position = 0, 這樣是為了重置指針,如果不這樣做的話,會導致讀取的流不正確。
  • 這里千萬不要用using包裹StreamReader, 因為StreamReader會在讀取完Stream內容之后,將Stream關閉,導致后續由于Stream關閉,而不能再次讀取Stream中的內容。如果必須使用,請使用StreamReader的以下重載,將leaveOpen參數設置為true, 確保StreamReader對象被銷毀的時候不會自動關閉讀取的Stream.
?
1
public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen);

重新啟動程序,請求/api/values, 我們就得到的正確的結果。

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

進一步完善代碼#

以上代碼實現,看似已經能夠讀取Response.Body的內容了,但是其實還是有問題的。

回想一下,我們做出以上方案的前提是,當前LoggerMiddleware中間件必須位于中間件管道的頭部。

如果不能保證這個約定, 就會出現問題,因為我們在LoggerMiddleware中間件中將Response.Body屬性指向了一個新的可讀可寫的Stream對象。如果LoggerMiddleware中間件之前的某個中間件中設置過Response.Body, 就會導致這部分設置丟失。

因此正確的設置方式應該是這樣的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public async Task InvokeAsync(HttpContext context)
{
var originalResponseStream = context.Response.Body;
 
var requestReader = new StreamReader(context.Request.Body);
 
var requestContent = requestReader.ReadToEnd();
Console.WriteLine($"Request Body: {requestContent}");
 
 
using (var ms = new MemoryStream())
{
 context.Response.Body = ms;
 await _next(context);
 
 
 ms.Position = 0;
 var responseReader = new StreamReader(ms);
 
 var responseContent = responseReader.ReadToEnd();
 Console.WriteLine($"Response Body: {responseContent}");
 
 ms.Position = 0;
 
 await ms.CopyToAsync(originalResponseStream);
 context.Response.Body = originalResponseStream;
}
}

代碼解釋:

  • 這里當進入LoggerMiddleware中間件時,我們將之前中間件操作完成之后的Response.Body對象對應的原始Stream, 保存在一個臨時變量中
  • 當LoggerMiddelware中間件的任務完成之后,我們需要將后續產生的Response.Body流追加到原始Stream中,然后將Response.Body對象重置為這個新的Stream。

至此Repsonse.Body的問題都解決,下面我們再來看一下Request.Body的問題。

問題2:Request.Body的內容可以正確的顯示,但是后續的ModelBinding都失敗了#

下面我們來請求POST /api/values, Request.Body里面的內容是字符串"123123"

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

服務器端返回了400錯誤, 錯誤信息

?
1
A non-empty request body is required.

這里就很奇怪,為啥請求體是空呢?我們回到中間件部分代碼,這里我們在讀取完Request.Body中的Stream之后,沒有將Stream的指針重置,當前指針已經是Stream的尾部,所以后續ModelBinding的時候,讀取不到Stream的內容了。

?
1
2
3
4
5
6
7
8
9
public async Task InvokeAsync(HttpContext context)
{
...
var requestReader = new StreamReader(context.Request.Body);
 
var requestContent = requestReader.ReadToEnd();
Console.WriteLine($"Request Body: {requestContent}");
...
}

于是,這里我們需要采取和Response.Body相同的處理方式,在讀取完Request.Body之后,我們需要將Request.Body的Stream指針重置

?
1
2
3
4
5
6
7
8
9
10
public async Task InvokeAsync(HttpContext context)
{
...
var requestReader = new StreamReader(context.Request.Body);
 
var requestContent = requestReader.ReadToEnd();
Console.WriteLine($"Request Body: {requestContent}");
context.Request.Body.Position = 0;
...
}

你一定覺著至此問題就解決了,不過ASP.NET Core和你又開了一個玩笑。

當你重新請求POST /api/values之后,你會得到以下結果。

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

?
1
System.NotSupportedException: Specified method is not supported.

翻譯過來就是指定方法不支持。到底不支持啥呢?在代碼上打上斷點,你會發現Request.Body的CanSeek屬性是false, 即Request.Body的Stream, 你是不能隨便移動指針的,只能按順序讀取一次,默認不支持反復讀取。

ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內容詳解

那么如何解決這個問題呢?

你可以在使用Request對象中的EnableRewind或者EnableBuffering。 這2個方法的作用都是在內存中創建緩沖區存放Request.Body的內容,從而允許反復讀取Request.Body的Stream。

說明: 其實EnableBuffering方法內部就只直接調用的EnableRewind方法。

下面我們修改代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task InvokeAsync(HttpContext context)
{
context.Request.EnableBuffering();
var requestReader = new StreamReader(context.Request.Body);
 
var requestContent = requestReader.ReadToEnd();
Console.WriteLine($"Request Body: {requestContent}");
context.Request.Body.Position = 0;
 
 
using (var ms = new MemoryStream())
{
 context.Response.Body = ms;
 await _next(context);
 
 
 ms.Position = 0;
 var responseReader = new StreamReader(ms);
 
 var responseContent = responseReader.ReadToEnd();
 Console.WriteLine($"Response Body: {responseContent}");
 
 ms.Position = 0;
}
}

再次請求POST /api/values, api請求被正確的處理了。

源代碼: https://github.com/lamondlu/webapi-logger

總結

到此這篇關于ASP.NET Core自定義中間件中如何讀取Request.Body與Response.Body的內容的文章就介紹到這了,更多相關ASP.NET Core自定義中間件讀取Request.Body與Response.Body內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/lwqlun/p/10954936.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 午夜欧美一区二区三区在线播放 | 精品久久久久久久 | 黄久久久| 婷婷色av | 天天影视网色香欲综合网无拦截 | 亚洲黄色特级片 | 亚洲高清免费视频 | 福利国产片 | 综合久久综合久久 | 一级毛片免费完整视频 | 欧美欧美欧美 | 黄色免费在线网站 | 国产精品永久 | 伊人草 | 国产亚洲精品久久久久动 | 日本中文字幕在线观看 | 免费观看av网站 | 日韩在线精品视频 | 精品视频二区 | 免费 成 人 黄 色 | 久久久久久亚洲av毛片大全 | 激情一区| 综合在线视频 | 国产第一区二区三区 | 超碰c| 不卡一区 | 国产超碰在线观看 | 在线二区 | 亚洲精品一| 男人天堂网av | 亚洲免费成人 | 日韩精品在线观看中文字幕 | 国产亚洲精品美女久久久久久久久久 | 免费的黄网站 | 国产久| 成人爽a毛片一区二区免费 日韩av高清在线 | 精品乱码一区二区三四区 | 久久99精品久久久久久久青青日本 | 国产精品一级毛片在线 | 久久国内精品 | 久久一区二 |