Asp.net-Web-Api
在 ASP.NET Core Web API 中實現 HTTP 記憶體 (ETag)
我正在開發 ASP.NET Core (ASP.NET 5) Web API 應用程序,並且必須在實體標籤的幫助下實現 HTTP 記憶體。之前我也使用過 CacheCow,但目前它似乎不支持 ASP.NET Core。我也沒有找到任何其他相關的庫或框架支持細節。
我可以為此編寫自定義程式碼,但在此之前我想看看是否有任何可用的東西。如果某些東西已經可用,請分享,以及實現它的更好方法是什麼。
經過一段時間嘗試使其與中間件一起工作後,我發現MVC 動作過濾器實際上更適合此功能。
public class ETagFilter : Attribute, IActionFilter { private readonly int[] _statusCodes; public ETagFilter(params int[] statusCodes) { _statusCodes = statusCodes; if (statusCodes.Length == 0) _statusCodes = new[] { 200 }; } public void OnActionExecuting(ActionExecutingContext context) { } public void OnActionExecuted(ActionExecutedContext context) { if (context.HttpContext.Request.Method == "GET") { if (_statusCodes.Contains(context.HttpContext.Response.StatusCode)) { //I just serialize the result to JSON, could do something less costly var content = JsonConvert.SerializeObject(context.Result); var etag = ETagGenerator.GetETag(context.HttpContext.Request.Path.ToString(), Encoding.UTF8.GetBytes(content)); if (context.HttpContext.Request.Headers.Keys.Contains("If-None-Match") && context.HttpContext.Request.Headers["If-None-Match"].ToString() == etag) { context.Result = new StatusCodeResult(304); } context.HttpContext.Response.Headers.Add("ETag", new[] { etag }); } } } } // Helper class that generates the etag from a key (route) and content (response) public static class ETagGenerator { public static string GetETag(string key, byte[] contentBytes) { var keyBytes = Encoding.UTF8.GetBytes(key); var combinedBytes = Combine(keyBytes, contentBytes); return GenerateETag(combinedBytes); } private static string GenerateETag(byte[] data) { using (var md5 = MD5.Create()) { var hash = md5.ComputeHash(data); string hex = BitConverter.ToString(hash); return hex.Replace("-", ""); } } private static byte[] Combine(byte[] a, byte[] b) { byte[] c = new byte[a.Length + b.Length]; Buffer.BlockCopy(a, 0, c, 0, a.Length); Buffer.BlockCopy(b, 0, c, a.Length, b.Length); return c; } }然後在您想要作為屬性的操作或控制器上使用它:
[HttpGet("data")] [ETagFilter(200)] public async Task<IActionResult> GetDataFromApi() { }中間件和過濾器之間的重要區別在於,您的中間件可以在 MVC 中間件之前和之後執行,並且只能與 HttpContext 一起使用。同樣,一旦 MVC 開始將響應發送回客戶端,就為時已晚,無法對其進行任何更改。
另一方面,過濾器是 MVC 中間件的一部分。他們可以訪問 MVC 上下文,在這種情況下,實現此功能會更簡單。更多關於過濾器及其在 MVC 中的管道。