目錄
* 前言 <https://www.cnblogs.com/AprilBlank/p/11282409.html#前言>
* 攔截器 <https://www.cnblogs.com/AprilBlank/p/11282409.html#攔截器>
* 異常攔截器 <https://www.cnblogs.com/AprilBlank/p/11282409.html#異常攔截器>
* 測(cè)試結(jié)果 <https://www.cnblogs.com/AprilBlank/p/11282409.html#測(cè)試結(jié)果>
* 身份驗(yàn)證攔截器 <https://www.cnblogs.com/AprilBlank/p/11282409.html#身份驗(yàn)證攔截器>
* 測(cè)試 <https://www.cnblogs.com/AprilBlank/p/11282409.html#測(cè)試>
* 小結(jié) <https://www.cnblogs.com/AprilBlank/p/11282409.html#小結(jié)>
* 補(bǔ)充 2019-07-31
<https://www.cnblogs.com/AprilBlank/p/11282409.html#補(bǔ)充-2019-07-31>
前言
一天天不知道怎么過(guò)的,但確實(shí)挺忙,事趕事不帶停那種,讓我感覺(jué)跟在流水線(xiàn)干活一樣,忙活的事差不多了就喘口氣繼續(xù)補(bǔ)充這一系列的內(nèi)容,前面幾篇基本上把一個(gè)常規(guī)的后端服務(wù)搭建差不多了,后面的會(huì)時(shí)不時(shí)根據(jù)自己需要或者常規(guī)的測(cè)試內(nèi)容來(lái)一點(diǎn)點(diǎn)完善更新。
攔截器
這里先不提AOP的內(nèi)容,其實(shí)在我個(gè)人之前的理解,AOP開(kāi)發(fā)的思想就是,我們做的某些操作例如身份驗(yàn)證,日志記錄,異常抓捕等等這些操作,可以單獨(dú)拎出來(lái)放那,誰(shuí)用了加個(gè)頭部標(biāo)識(shí)就可以了,剩余的交給代碼來(lái)處理,這樣我們開(kāi)發(fā)就只需要關(guān)心業(yè)務(wù)功能,而其他的全都可以不用考慮,這就是框架的好處,別人封裝集成好,就可以省去很大的開(kāi)發(fā)工作量。
好,開(kāi)始說(shuō)攔截器,其實(shí)也是中間層,個(gè)人感覺(jué)跟AOP的概念類(lèi)似,就放到這里寫(xiě)上了。
異常攔截器
在我們Api的工程目錄下新建文件夾Filters用于存放攔截器,之后我們新建ExceptionFilter
這個(gè)異常的攔截器,用于記錄工程拋異常并做對(duì)應(yīng)回調(diào)處理。
代碼如下,具體不過(guò)多解釋?zhuān)驗(yàn)閷?shí)在覺(jué)得這個(gè)沒(méi)啥說(shuō)的,只是注意異步調(diào)用的問(wèn)題即可。
public class ExceptionFilter { private readonly RequestDelegate _next; ///
<summary> /// /// </summary> /// <param name="next"></param> public
ExceptionFilter(RequestDelegate next) { _next = next; } /// <summary> /// ///
</summary> /// <param name="context"></param> /// <returns></returns> public
async Task Invoke(HttpContext context) { try { await _next(context); } catch
(Exception ex) //發(fā)生異常 { context.Response.StatusCode = 500;
LogUtil.Error($"response exception:{ex.Message}");// {ex.StackTrace} await
ResponseUtil.HandleExceptionAsync(500, "服務(wù)器錯(cuò)誤"); } } }
這個(gè)地方的ResponseUtil是單獨(dú)在Util層創(chuàng)建的(公共類(lèi)盡量扔到同一個(gè)工程類(lèi)庫(kù)下,以后一鍵打包,各種復(fù)用)。
public class ResponseUtil { /// <summary> /// 回調(diào) /// </summary> /// <param
name="statusCode">html狀態(tài)碼</param> /// <param name="msg">消息</param> ///
<returns></returns> public static Task HandleExceptionAsync(int statusCode,
string msg) { var data = new { code = statusCode, msg = msg }; string text =
JsonConvert.SerializeObject(data); var response =
AprilConfig.HttpCurrent.Response; if
(string.IsNullOrEmpty(response.ContentType)) { //跨域的時(shí)候注意,不帶header沒(méi)法接收回調(diào)
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Credentials", "true"); //因?yàn)檫@個(gè)是json
response.ContentType = "application/json;charset=utf-8"; response.StatusCode =
200; response.ContentLength = text.Length; return response.WriteAsync(text); }
else { return response.WriteAsync(text); } } }
之后我們依然要在Startup中注冊(cè)我們這個(gè)中間層。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
app.UseMiddleware<ExceptionFilter>(); … }
這樣我們?cè)谌秩绻霈F(xiàn)異常的時(shí)候,可以統(tǒng)一捕獲到問(wèn)題,然后做記錄,當(dāng)然在測(cè)試環(huán)境下注意,如果這個(gè)錯(cuò)誤幫助頁(yè)打開(kāi)的時(shí)候,那上面的攔截器將毫無(wú)亂用。
測(cè)試結(jié)果
這樣如果真是哪個(gè)地方?jīng)]有做異常捕獲,全局最終都會(huì)一個(gè)不漏的抓住然后告訴你,好處是如果懶那就所有地方都不寫(xiě)了,問(wèn)題是有些異常即使捕獲但是不需要告知用戶(hù)也不需要做記錄(比如文件上傳下載的線(xiàn)程中斷異常之類(lèi)的),所以這個(gè)只是為了保險(xiǎn)起見(jiàn)而不是為了省事。
身份驗(yàn)證攔截器
接下來(lái)我們繼續(xù)創(chuàng)建一個(gè)AuthFilter,目的是做身份驗(yàn)證的判斷,如果沒(méi)通過(guò)就沒(méi)必要再進(jìn)入具體的控制器了。
public class AuthFilter { private readonly RequestDelegate _next; public
AuthFilter(RequestDelegate next) { _next = next; } public Task
Invoke(HttpContext context) { if (context.Request.Method == "OPTIONS") { return
_next(context); } var headers = context.Request.Headers; //檢查頭文件是否有jwt token if
(!headers.ContainsKey("Authorization")) { string path =
context.Request.Path.Value; if (!AprilConfig.AllowUrl.Contains(path) &&
path.IndexOf("swagger") < 0) { //這里做下相關(guān)的身份校驗(yàn) return
ResponseUtil.HandleExceptionAsync(401, "請(qǐng)登錄");
//判斷是否有權(quán)限查看(在身份驗(yàn)證后判斷對(duì)應(yīng)的權(quán)限,這個(gè)方法后續(xù)再寫(xiě)) return
ResponseUtil.HandleExceptionAsync(-2, "無(wú)權(quán)訪問(wèn)"); } } return _next(context); } }
同樣我們需要在Startup注冊(cè)使用中間層。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
app.UseMiddleware<ExceptionFilter>(); app.UseMiddleware<AuthFilter>(); … }
測(cè)試
然后訪問(wèn)我們的Swagger,效果就很明顯了。
小結(jié)
這一篇主要就是引入中間層的使用,個(gè)人認(rèn)為什么AOP開(kāi)發(fā)OOP開(kāi)發(fā)完全因人而異,沒(méi)必要為了追求新技術(shù)而去整體大功能改造,新技術(shù)確實(shí)使用起來(lái)方便,也有很好的前景,但是對(duì)于企業(yè)來(lái)講,穩(wěn)定是最重要的,不會(huì)為了1%的性能速度而去冒30%甚至更高的風(fēng)險(xiǎn),但是我還是要說(shuō)一句,
net core到目前為止已經(jīng)歷過(guò)一個(gè)大版本的更新,雖然3.0沒(méi)有正式發(fā)布,但是一個(gè)個(gè)版本的更新之后,穩(wěn)定性已經(jīng)很ok了,所以該吃螃蟹都可以動(dòng)手了。
下一篇,繼續(xù)引入AOP的開(kāi)發(fā),主要用的第三方的組件AspectCore,將針對(duì)接口調(diào)用的時(shí)候做一些常規(guī)操作。
補(bǔ)充 2019-07-31
今天在做調(diào)試的時(shí)候發(fā)現(xiàn)一個(gè)問(wèn)題,現(xiàn)狀如下
發(fā)現(xiàn)這個(gè)問(wèn)題我的第一反應(yīng)是,字符編碼
,但是看到我回調(diào)的時(shí)候明顯已經(jīng)設(shè)置了ContentType,所以這個(gè)應(yīng)該不是錯(cuò)誤的原因,但是多次刷新的測(cè)試結(jié)果是偶爾正常,怪異的情況總是伴隨著bug,于是比對(duì)了正確的回調(diào)信息和錯(cuò)誤的回調(diào)信息(這里是通過(guò)chrome瀏覽器調(diào)試然后獲取的回調(diào)信息,具體調(diào)試方法后續(xù)前端介紹,當(dāng)然基本上都知道)。
這樣一看發(fā)現(xiàn)了問(wèn)題所在,所以這個(gè)地方?jīng)Q定不再自主去設(shè)置Length了。
熱門(mén)工具 換一換
