先前有寫過一篇個人常用的 ASP.NET MVC 自訂 HTTP 回應碼畫面的套路,一切看起來都很好,但是當使用者輸入一些資料,驗證不通過的時候,想要送 400(Bad Request)順便在 Body 中塞入一些訊息回傳給使用者,不做點調整是做不到的。
冤枉路一:existingResponse="Auto"、TrySkipIisCustomErrors
因為原先自訂回應碼畫面都是強制由 IIS 自訂錯誤網頁提供,所以當回傳 400 時就不能走這條路,因此嘗試將 existingResponse
設成 Auto
,並且將 Response 的 TrySkipIisCustomErrors
屬性值設成 true
。
看起來運作正常,回傳 400 時能在 Body 塞入訊息,其他自訂回應碼的畫面也好好的。
直到我輸入了一個不存在的網址,看到的不是我自訂的畫面。
原來 ASP.NET MVC UrlRoutingModule 在 Match 不到網址回傳 404 的時候,是會跳過 IIS 自訂錯誤網頁的,這條路被封死了。
冤枉路二:<customErrors ... redirectMode="ResponseRewrite">
既然這樣,那我改走 customErrors 這條路,也將自訂回應碼畫面弄一組到 customErrors 上,然後將 redirectMode 設成 ResponseRewrite。
但是這條路也被封死了,因為 redirectMode="ResponseRewrite" 的情況下,自訂回應碼畫面的 redirect 值必須是檔案的型態。
路是人走出來的
無意中發現,IIS 自訂錯誤網頁觸發時,會將原來的 Request 內容原封不動地轉發給自訂錯誤網頁,那這樣是不是就能將訊息塞入 Request 裡面,讓它隨著轉發機制一路送到自訂錯誤網頁手上,再由自訂錯誤網頁把訊息塞入 Body 裡面回傳給使用者? 我們來試試看。
先在 IIS 錯誤網頁再自訂一條給 400 用的設定
然後約定好當 400 被觸發的時候,訊息可以從 Headers["400"]
裡面存取得到。
最後只要在需要的時候,指定回應碼為 400,將訊息塞進 Headers["400"] 裡面,就大功告成了。
當然不只有純文字訊息,JSON 也可以,也可以傳遞一個檔案路徑,回傳 FileResult,但看我們的需求去變化。