1. 程式人生 > >跟我一起學.NetCore之MVC過濾器,這篇看完走路可以仰著頭走

跟我一起學.NetCore之MVC過濾器,這篇看完走路可以仰著頭走

**前言** MVC過濾器在之前Asp.Net的時候就已經廣泛使用啦,不管是面試還是工作,總有一個考點或是需求涉及到,可以毫不疑問的說,這個技術點是非常重要的; 在之前參與的面試中,得知很多小夥伴只知道有一兩個過濾器,而對其執行順序瞭解的還是很模糊,少部分小夥伴甚至還沒有使用過。這裡就詳細來說說這塊的內容。 ![img](https://i.loli.net/2020/10/22/yXqi1TapWYcD3QA.jpg) **正文** 來,直接上菜,然後再慢慢品;在Asp.NetCore 中,MVC有以下五種過濾器,根據執行順序的不同,用於不同場景: ![img](https://i.loli.net/2020/10/22/PqUWyVtQmo9Jlu7.png) 上圖中大概的流程如下: 1. 使用者發起一個請求; 2. 請求經過Asp.NetCore應用程式的中介軟體管道; 3. 管道走完之後進入MVC的第一個過濾器:授權過濾器; 4. 授權通過之後進入資源過濾器的前置方法; 5. 將異常過濾器加入使用,後續有異常可以進行捕獲,之前如果發生異常不能捕獲; 6. 進行資料模型繫結,比如引數通過資料模型繫結傳參; 7. 進入Action過濾器前置方法; 8. 執行Action方法具體邏輯; 9. 進入Action過濾器後置方法; 10. 進入Result過濾器前置方法; 11. 渲染Result結果; 12. 進入Result過濾器後置方法; 13. 進入資源過濾器的後置方法; 14. 進入中介軟體管道返回; 15. 最後將響應結果展現給使用者; 接下來就好好說說每種過濾器的使用,老規矩,還是WebApi專案↓↓↓ 1. 授權過濾器(Authorization Filter) 授權,用於驗證請求是否有許可權訪問對應的Action,一般包含登入驗證、選單許可權(即介面許可權)驗證等。授權過濾器只對請求進行驗證,是單向的,響應返回時不走該過濾器; 程式碼擼起來: ![img](https://i.loli.net/2020/10/22/SjyYga5HiZftITr.png) 這裡先進行全域性註冊過濾器進行測試,即只要註冊之後,所有請求都需要經過授權過濾器校驗,後續單獨說說註冊方式範圍: ![img](https://i.loli.net/2020/10/22/QXjI2SFrZgVhtYi.png) 在預設生成的介面中列印字串,方便看執行結果: ![img](https://i.loli.net/2020/10/22/hmDe9XwNQqJjira.png) 執行看結果: ![img](https://i.loli.net/2020/10/22/6sAIUTt7n1DerFS.png) 通過上圖可以看到,已經進入授權過濾器中進行相關邏輯判斷;如果將授權邏輯中的區域性變數validate設定為true,執行結果如下: ![img](https://i.loli.net/2020/10/22/gApOqrtyVCl4JQ7.png) 看過上一篇([跟我一起學.NetCore之熟悉的介面許可權驗證不能少(Jwt)](http://mp.weixin.qq.com/s?__biz=MzU1MzYwMjQ5MQ==&mid=2247484129&idx=1&sn=3c38de1ae440b8c1fa45301116220b25&chksm=fbf11e35cc869723f1a4cd6f6f6a9089b9e5b59e92021a3e132191c495a0f008667069ca807a&scene=21#wechat_redirect))的小夥伴肯定有疑問:這和授權中介軟體中使用Authorize特性授權有什麼區別?沒看過的小夥伴也沒關係,應該也會有同樣的疑問;來,聽我慢慢道來,老套路,扒扒授權中介軟體的程式碼,看看怎麼回事? ![img](https://i.loli.net/2020/10/22/S7OlrWZXsePCKnt.jpg) 先來看看Authorize特性裡面都有什麼,關鍵是實現了IAuthorizeData介面,如下圖: ![img](https://i.loli.net/2020/10/22/ujAEXlUTfVRBC5o.png) 找到授權的入口點,即中介軟體註冊授權那裡著手,如下圖: ![img](https://i.loli.net/2020/10/22/lsKxXNCMP5L4ezi.png) 從而找AuthorizationMiddleware的具體實現,關鍵程式碼如下圖: ![img](https://i.loli.net/2020/10/22/sLKVQrRMXN1tcgp.png) 總的來說,使用授權中間的時,標註Authorize特性的Action,會通過預設的AuthorizeFilter進行驗證處理,這就是為什麼在上一節許可權驗證的時候我們沒有單獨編寫授權過濾器,而是偏重於校驗的邏輯,只關注驗證的角色或策略;這裡就不打算再看AuthorizeFilter的原始碼,有興趣的小夥伴好好研究研究。 2. 資源過濾器(Resource Filter) 資源過濾器分為前置方法和後置方法,一般都會在前置方法做相關處理,比如說需要改改模型繫結的邏輯,但更多常用的是用於資料快取處理,因為是在授權過濾器之後的第一個,如果取得快取資料,直接返回結果,就減少後面程式碼邏輯執行;後置方法在之後所有程式碼邏輯執行完成,返回時經過。 程式碼擼起來: ![img](https://i.loli.net/2020/10/22/1HEzLnoikcX4BlQ.png) 這裡還是以全域性的方式進行註冊資源過濾器: ![img](https://i.loli.net/2020/10/22/DkpdIU5RnvAoQ3c.png) 執行效果如下: ![img](https://i.loli.net/2020/10/22/q7GCSbt2fjTMvLF.png) 將授權過濾器中的validate改為false,這裡模擬代表有許可權繼續執行: ![img](https://i.loli.net/2020/10/22/1eagjDBfvVmSYdo.png) 3. 異常過濾器(Exception Filter) 用於伺服器向客戶端寫入響應內容之前進行系統異常捕獲,一般用於業務場景統一異常的處理,如果沒有特殊需求,不必每種業務都進行異常處理,通過異常過濾器統一捕獲處理即可,記錄相關日誌,便於異常問題分析; 先模擬處理業務時,拋異常了,如下: ![img](https://i.loli.net/2020/10/22/ALJmW9gTQyz7lvC.png) 異常資訊直接返回給使用者,體驗是相當不好的,所以一般會將異常進行捕獲處理,由於異常資訊容易讓開發者進行問題排查,所以一般會將其以日誌的形式記錄;系統中肯定會考慮很多異常的地方,不可能處處都進行手動捕獲一下再處理,顯得程式碼臃腫的同時還不好維護,所以用異常過濾器統一進行捕獲處理就顯得很有必要了,當然,一些很關鍵的業務可以進行單獨捕獲處理;異常過濾使用如下: ![img](https://i.loli.net/2020/10/22/WrxNoTJip1ZCqPY.png) 將其全域性註冊,看執行效果: ![img](https://i.loli.net/2020/10/22/ImM95w4k2OUxhND.png) 小夥伴看到這,有沒好奇為什麼不在授權過濾器和資源過濾器中丟擲異常測試,而是選擇在Action方法中丟擲異常,還記得第一張圖過濾器順序嗎(小夥伴再去重溫一下~),那是因為授權過濾器和資源過濾器那還沒有異常過濾器,所以發生異常時捕獲不到,這也是小夥伴要特別注意的,需要自己處理好異常;只要在異常過濾器之後請求處理的異常都能捕獲到啦; ![img](https://i.loli.net/2020/10/22/GbVF7nz86MiOh4E.jpg) 4. Action過濾器(Action Filter) Action過濾器有前置和後置兩種方法,一般偏向於業務使用,比如在前置方法中進行驗證模型繫結引數的合法性,也可以對引數進行加工等;後置方法可以對返回結果的處理; 平時用的比較多,如下: ![img](https://i.loli.net/2020/10/22/xhjuL1n4357HVyz.png) 全域性註冊,執行如下: ![img](https://i.loli.net/2020/10/22/MQl4NKLARxTVFSo.png) 有沒有想試一下,在Action過濾器方法中丟擲異常時,看看異常過濾器能不能捕獲到,答案肯定是:能,但在這不截圖給小夥伴們看,小夥伴們動手試試嘛。 5. Result過濾器(Result Filter) Result過濾器也有前置和後置兩種方法,前置方法可以在結果沒返回前,可以對Action返回的結果進行干預處理,後置方法一般是結果已經渲染之後執行; API專案用的不多,在MVC Web專案比較適用,使用方式如下: ![img](https://i.loli.net/2020/10/22/lTeav3uUzchJs75.png) 將其進行全域性註冊,執行如下: ![img](https://i.loli.net/2020/10/22/schUtOSrbYD7P4X.png) 同樣在此過濾器中丟擲異常,異常過濾器捕獲不到啦。 ![img](https://i.loli.net/2020/10/22/I5KzlQFxPBJOtZj.png) 意不意外,驚不驚喜,其實只要開始進行響應結果處理時,異常過濾器就不捕獲對應異常,需要自己單獨處理; **過濾器的註冊範圍** 除了上面的全域性註冊,過濾器還可以以特性的方式標註在控制器或對應Action方法上: **全域性註冊**:針對系統中所有過濾器都有效; **標註在控制器上(Controller)**:對標註控制器中所有Action方法都有效; **標註在Action上**:只針對對應的Action有效; ![img](https://i.loli.net/2020/10/22/GIXOWnDgqRTS319.png) **思路**:如果有極個別Action不想使用統一的過濾器,可以通過標註特性的方式在對應過濾器邏輯中將其進行過濾掉。 **過濾器註冊方式** - 全域性方式註冊 在Startup中ConfigureServices註冊服務時全域性註冊過濾器,如下圖: ![img](https://i.loli.net/2020/10/22/3VQespwTu9ICNvE.png) - 特性方式標註 A、繼承Attribute類時,可以直接標註在控制器(Controller)和Action上,如下圖: ![img](https://i.loli.net/2020/10/22/ev1JKgcQrYCi5Ay.png) B、沒有繼承Attribute類的情況,借用TypeFilter、ServiceFilter或自定義IFilterFactory進行特性標註。 **TypeFilter的方式**,如下圖: ![img](https://i.loli.net/2020/10/22/Umsjea9CzxbuQIZ.png) **ServiceFilter的方式**需要單獨註冊一下過濾器服務,控制生命週期,如果沒有註冊過濾器服務會報異常,如下圖: ![img](https://i.loli.net/2020/10/22/UudVo1mtFBXW4pI.png) 註冊過濾器服務就正常了,如下圖: ![img](https://i.loli.net/2020/10/22/UlaecjJIBsC3LDT.png) **自定義IFilterFactory**,先實現一個特性類,如下: ![img](https://i.loli.net/2020/10/22/oLlFPdqnMaSNIsD.png) 使用如下: ![img](https://i.loli.net/2020/10/22/FpM2vHKQxCA6hWn.png) **同種過濾器的執行順序** 對於不同型別過濾器的執行順序,開篇的圖就說明了,接下來說多個同種過濾器的執行順序; - 不同範圍的同種過濾器順序 上面說到過濾的註冊範圍,有全域性註冊、控制器標註、Action標註,同種過濾器在不同範圍註冊是什麼個順序?這裡以常用的Action過濾器為例,其他過濾器的練習就交給小夥伴了,這裡複製出MyActionFilter兩份,分別改名為MyActionFilter1和MyActionFilter2,其中MyActionFilter用於全域性註冊,MyActionFilter1用於控制器特性標註,MyActionFilter2用於Action方法標註,執行結果如下: ![img](https://i.loli.net/2020/10/22/fluXG7CzSvjWHbM.png) **結論:全域性註冊->控制器->Action。** - 相同範圍的同種過濾器順序 將MyActionFilter、MyActionFilter1和MyActionFilter2三個過濾器都標註在Action上,全域性和控制器上都註釋掉,看效果: ![img](https://i.loli.net/2020/10/22/ufaNC1XOwQEK39Y.png) **結論:預設情況註冊或特性標註順序與執行順序一致。** 到這可能小夥伴會想:終於結束啦!!!,哈哈哈,nonono,對於過濾器的執行順序,除了以上預設順序之外,是可以任意調整的,通過實現IOrderedFilter介面,設定對應過濾器的順序屬性即可改變對應的順序,Order值越小,優先順序就越高,如下使用: ![img](https://i.loli.net/2020/10/22/84tBKz21IvNq6GS.png) 沒有效果圖,差評? 別別別,這裡是督促小夥伴自己試一把,不然小夥伴看一下就完事了(不自己操作一把,過兩天就會忘),有沒有用心良苦~ 重點:Order排序優先於範圍排序,即先會以Order進行排序,如果一致,再以註冊的範圍排序。 ![img](https://i.loli.net/2020/10/22/k4MHeyWFNYb1pJ3.jpg) **總結** 好啦,完啦!主要分享了MVC各種過濾器的使用,大概的應用場景,執行順序,註冊範圍及註冊方式。有沒有感覺脖子有點小酸,來,起來走走,仰著頭的那種,標題是不是沒騙小夥伴,絕對真實。 下一篇說說MediatR元件和中介者設計模式。 整理了一些面試資料,關注公眾號“Code綜藝圈”,傳送"**面試**"獲取下載地址,至於教程,手裡的也有一些Web前端、.Net後端、Java的教程,但現在網上資源比較多,大部分小夥伴喜歡線上看;如果有需要,小夥伴可以私聊我,目前先把面試相關的資料放上去,收集內容會持續更新,包含一些大廠面試題,助力小夥伴找到心儀的工作: 一個被程式搞醜的帥小夥,關注"Code綜藝圈",識別關注跟我一起學~~~ ![img](https://i.loli.net/2020/10/22/6c7XP58q2mdgjJt.png) 擼文不易,莫要白瞟,三連