内容简介:在開發 Web API 的時候你可能會遇到這種情境,想要收集所有對我們網站所發起的 HTTP 要求,從呼叫 API 的網址、HTTP 方法、甚至 HTTP 要求的內容(Request Body)等,要把這些資訊儲存下來,供之後分析使用,以前你可能會透過 IIS Log 來做,現在在 ASP.NET Core 的程式架構中,我們可以在專案架構的中介程序中,攔截 HTTP 資訊,來做任何我們想要做的事。上圖是 ASP.NET Core 中介程序架構的簡單表示圖,而我們這次的目標像是在 ASP.NET Core
在開發 Web API 的時候你可能會遇到這種情境,想要收集所有對我們網站所發起的 HTTP 要求,從呼叫 API 的網址、HTTP 方法、甚至 HTTP 要求的內容(Request Body)等,要把這些資訊儲存下來,供之後分析使用,以前你可能會透過 IIS Log 來做,現在在 ASP.NET Core 的程式架構中,我們可以在專案架構的中介程序中,攔截 HTTP 資訊,來做任何我們想要做的事。
上圖是 ASP.NET Core 中介程序架構的簡單表示圖,而我們這次的目標像是在 ASP.NET Core 的中介程序中,加入一個我們客製的 Logging Middleware,讓所有進入此應用程式的 HTTP Request 都會被我們攔截,然後記錄下來。
啟動 Logging 記錄器
首先,我們可以在應用程式啟動時,加入 ASP.NET Core 內建支援的 Logging 記錄器 ,只要在 Program.cs 檔案中設定 Logging 的機制,寫法如下:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
// 加入 Logging 的機制
.ConfigureLogging((logging) =>
{
logging.AddDebug();
logging.AddConsole();
})
.UseStartup<Startup>();
預設這個功能會使用 appsettings.json (或開發時期使用的 appsettings.Development.json ) 裡面的設定值,為了讓這個記錄器能夠將 Trace (追蹤)等級的資訊記錄下來,要修改這個檔案 Logging 的 LogLevel 預設紀錄層級為 Trace ,如下:
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
}
}
客製 Logging Middleware 中介程序
重點在這裡,接著我們增加一個 LoggingMiddleware.cs 中介程序,這裡面將會是實作整個處理 HTTP Request 並將其記錄下來的關鍵。
關於 ASP.NET Core 中介程序的用途說明及基本寫法,請參考 這篇官方文件 。
我們預期的動作會像下圖這樣,request 進入到此中介程序時,會將該 request 複製一份給 Logger 記錄器做處理,同時也把一樣的 request 往下傳遞。
為什麼要複製一份呢?是因為在 ASP.NET Core 的 HttpContext 中,該 HTTP 的 Request.Body 屬性是 Stream 類型,且此屬性僅能被讀取一次,若不將其存留起來,後續的中介程序會拿不到完整的 HTTP Request,造成應用程式異常。
因此在這裡的處理有些地方需要特別注意,先看一下下面的程式碼:
public async Task Invoke(HttpContext context)
{
// 確保 HTTP Request 可以多次讀取
context.Request.EnableBuffering();
// 讀取 HTTP Request Body 內容
// 注意!要設定 leaveOpen 屬性為 true 使 StreamReader 關閉時,HTTP Request 的 Stream 不會跟著關閉
using (var bodyReader = new StreamReader(stream: context.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 1024,
leaveOpen: true))
{
var body = await bodyReader.ReadToEndAsync();
var log = $"{context.Request.Path}, {context.Request.Method}, {body}";
_logger.LogTrace(log);
}
// 將 HTTP Request 的 Stream 起始位置歸零
context.Request.Body.Position = 0;
await _next.Invoke(context);
}
第一步,要確表 HTTP Request 可以被多次讀取,必須要執行 context.Request.EnableBuffering(); 開啟緩存的機制。
第二步,在建立 StreamReader 來存取 HTTP Request 的時候,必須在 StreamReader 建構式中設定 leaveOpen: true ,使 StreamReader 的來源( Request.Body )不會因為 StreamReader 關閉 Stream 而跟著關閉,這點很重要!如果沒有這樣做,你的應用程式會出現類似下面這樣的錯誤訊息:
{
"errors": {
"": [
"A non-empty request body is required."
]
},
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "8000001e-0001-ff00-b63f-84710c7967bb"
}
A non-empty request body is required 就是告訴你,後續要處理 HTTP Request 的中介程序,無法接受空的 Request.Body ,因此出現錯誤。
第三步,使用 StreamReader.ReadToEndAsync() 來讀取資料,讀取到資料後,你可以做任何你想要做的事,例如上述情境所提到的,將所有 HTTP Request 儲存記錄下來。
第四步,透過 context.Request.Body.Position = 0; 將原本的 Request.Body 的 Stream 起始位置歸零。
啟用客製的 Logging Middleware 中介程序
為了優雅的啟用我們客製的 Logging Middleware 中介程序,在範例程式碼中做了一個 LoggingMiddlewareExtensions 擴充方法:
public static class LoggingMiddlewareExtensions
{
public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoggingMiddleware>();
}
}
這個擴充方法是讓我們在 Startup.cs 檔案的 Configure() 要啟用 Logging Middleware 中介程序時,只需要使用 app.UseLoggingMiddleware(); 這樣直覺的寫法,就能輕鬆啟動。
本篇完整範例程式碼請參考 poychang/Demo-Logging-Http-Request 。
後記
這個範例的核心精神還可以延伸處理很多事情,例如我可以透過這樣的處理方式,建立一個特定的 API Endpoint,只要 HTTP Request 進去這個中介程序,當網址路徑符合預期的位置,就執行特定功能,在往下接續處理;或是將限制來源 IP 的功能(參考 這裡 )封裝成一個中介程序,讓 ASP.NET Core 應用程式,能輕鬆地加上新功能。
參考資料:
以上所述就是小编给大家介绍的《收集 ASP.NET Core 網站所有的 HTTP Request 資訊》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构 Python语言描述
[美] Kenneth A. Lambert 兰伯特 / 李军 / 人民邮电出版社 / 2017-12-1 / CNY 69.00
在计算机科学中,数据结构是一门进阶性课程,概念抽象,难度较大。Python语言的语法简单,交互性强。用Python来讲解数据结构等主题,比C语言等实现起来更为容易,更为清晰。 《数据结构 Python语言描述》第1章简单介绍了Python语言的基础知识和特性。第2章到第4章对抽象数据类型、数据结构、复杂度分析、数组和线性链表结构进行了详细介绍,第5章和第6章重点介绍了面向对象设计的相关知识、......一起来看看 《数据结构 Python语言描述》 这本书的介绍吧!