一、為什么使用中間件
在我們很多時候,當一個請求過來之后,我們想對這個請求做各種各樣的操作和記錄,這個時候我們可以加入中間件
目的就是對這個請求和響應做處理,其實不難理解,這就是類似於工業機器,一個商品出來之前會有很多關卡,會執行N到工序,
最后加工出來的產品就是我們想要的,也是安全的。這些關卡就類似於中間件的作用了。
核心就是一系列的請求委托,Run、Use、Map
Run:是最后一道工序,管道末尾。
Use:連接請求委托,next 向下走。
Map:擴展用作約定創建管道分支。
自定義消息返回中間件
就是自定義消息返回值,在返回之前處理一下消息的格式和數據。(這個不建議使用,發布的時候會有fail,目前還沒有時間查找,有時間了會回來解決)
首先在Model層創建一個ErrorModel.cs 返回格式 實體類,代碼如下
using System; using System.Collections.Generic; using System.Text; namespace WebApi.Core.Model { /// <summary> /// 自定義返回消息實體類 /// </summary> public class ErrorModel { /// <summary> /// 狀態碼 /// </summary> public int code { get; set; } = 500; /// <summary> /// 錯誤信息 /// </summary> public string msg { get; set; } /// <summary> /// 錯誤詳情 /// </summary> public string detail { get; set; } /// <summary> /// 時間戳 /// </summary> public string timestamp { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } }
在api層增加一個文件夾Middleware 在新建一個中間件 CustomExceptionMiddleware
代碼如下,注意如果復制的話,命名空間注意一下,也可以右鍵-新建項-選擇中間件,只需要改一下就行。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using WebApi.Core.Api.Log; using WebApi.Core.Model; namespace WebApi.Core.Api.Middleware { // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project public class CustomExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILoggerHelper _logger; public CustomExceptionMiddleware(RequestDelegate next, ILoggerHelper logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception ex) { _logger.Error(ex.Message, ex); // 日志記錄 await HandleExceptionAsync(httpContext, ex.Message); } finally { var statusCode = httpContext.Response.StatusCode; var msg = ""; switch (statusCode) { case 401: msg = "未授權"; break; case 403: msg = "拒絕訪問"; break; case 404: msg = "未找到服務"; break; case 405: msg = "405 Method Not Allowed"; break; case 502: msg = "請求錯誤"; break; } if (!string.IsNullOrWhiteSpace(msg)) { await HandleExceptionAsync(httpContext, msg); } } } private async Task HandleExceptionAsync(HttpContext httpContext, string msg) { ErrorModel error = new ErrorModel { code = httpContext.Response.StatusCode, msg = msg }; var result = JsonConvert.SerializeObject(error); httpContext.Response.ContentType = "application/json;charset=utf-8"; await httpContext.Response.WriteAsync(result).ConfigureAwait(false); } } // Extension method used to add the middleware to the HTTP request pipeline. public static class CustomExceptionMiddlewareExtensions { public static IApplicationBuilder UseCustomExceptionMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<CustomExceptionMiddleware>(); } } }
注冊一下中間件
strartup.cs 中的Configure方法中 添加如下代碼 順序的話 放在權限處理(UseAuthentication)前面 就可以,不然請求從管道回來的時候會先走消息處理,然后在判斷權限,這樣的話就無法處理了。
app.UseCustomExceptionMiddleware();
接下來測試一下F5 可以看到 是沒問題了。
我們現在處理了響應消息,
接下來我們做一個獲取請求和響應的中間件
需要保存到日志中,查看都誰訪問的返回的是什么
在middleware文件夾下創建一個中間件LogReqResponseMiddleware 代碼如下
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using WebApi.Core.Api.Log; namespace WebApi.Core.Api.Middleware { // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project public class LogReqResponseMiddleware { private readonly RequestDelegate _next; private readonly ILoggerHelper _logger; public LogReqResponseMiddleware(RequestDelegate next, ILoggerHelper logger) { _next = next; _logger = logger; } public async Task Invoke(HttpContext httpContext) { var request = httpContext.Request; request.EnableBuffering(); //把請求body流轉換成字符串 string bodyAsText = await new StreamReader(request.Body).ReadToEndAsync();//記錄請求信息 var requestStr = $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}"; _logger.Info(typeof(LogReqResponseMiddleware), "Request:" + requestStr); request.Body.Seek(0, SeekOrigin.Begin); var originalBodyStream = httpContext.Response.Body; using (var responseBody = new MemoryStream()) { httpContext.Response.Body = responseBody; await _next(httpContext); var response = httpContext.Response; response.Body.Seek(0, SeekOrigin.Begin); //轉化為字符串 string text = await new StreamReader(response.Body).ReadToEndAsync(); //從新設置偏移量0 response.Body.Seek(0, SeekOrigin.Begin); //記錄返回值 var responsestr = $"{response.StatusCode}: {text}"; _logger.Info(typeof(LogReqResponseMiddleware),"Response:" + responsestr); await responseBody.CopyToAsync(originalBodyStream); } } } // Extension method used to add the middleware to the HTTP request pipeline. public static class LogReqResponseMiddlewareExtensions { public static IApplicationBuilder UseLogReqResponseMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<LogReqResponseMiddleware>(); } } }
然后在startup.cs 的configure注冊一下,這里位置可以隨意了,因為只是記錄一下並沒有對請求和響應做任何事情 代碼如下
//記錄請求和響應的json串 app.UseLogReqResponseMiddleware();
看一下效果 這里可以看到已經是記錄進去了,報錯是因為 我的redis沒有開啟。
今天寫記錄到這兒吧,后期遇到業務場景后,在慢慢添加吧