javascript
html页面源码_整合SpringMVC之错误处理底层原理及源码分析
一. SpringBoot的默認(rèn)錯誤處理策略
1. 對404的默認(rèn)處理策略
我們在發(fā)送請求的時候,如果發(fā)生了404異常,SpringBoot是怎么處理的呢?
我們可以隨便發(fā)送一個不存在的請求來驗(yàn)證一下,就會看到如下圖所示:
2. 對500的默認(rèn)處理策略
當(dāng)服務(wù)器內(nèi)部發(fā)生代碼等錯誤的時候,會發(fā)生什么呢?
比如我們?nèi)藶榈闹圃煲粋€異常出來,如下面的代碼所示:
@GetMapping("/user/{id:d+}")public User get(@PathVariable String id) { throw new RuntimeException();}結(jié)果產(chǎn)生了如下所示效果圖:
3.在error頁面中可以獲取的錯誤信息
timestamp: 時間戳.status: 狀態(tài)碼.error: 錯誤提示.exception: 異常對象.message: 異常消息.errors: 數(shù)據(jù)效驗(yàn)相關(guān)的信息.二. Spring Boot錯誤處理機(jī)制探究
通過上面的兩個案例,我們發(fā)現(xiàn)無論發(fā)生了什么錯誤,Spring Boot都會返回一個對應(yīng)的狀態(tài)碼以及一個錯誤頁面,那么這個錯誤頁面是怎么來的呢?
要弄明白這個問題,我們需要從Spring Boot中錯誤處理的底層源碼來進(jìn)行分析。
1. SpringBoot的錯誤配置信息
SpringBoot的錯誤配置信息是通過ErrorMvcAutoConfiguration這個類來進(jìn)行配置的,這個類中幫我們注冊了以下組件:
DefaultErrorAttributes: 幫我們在頁面上共享錯誤信息;ErrorPageCustomizer: 項(xiàng)目中發(fā)生錯誤后,該對象就會生效,用來定義請求規(guī)則;BasicErrorController: 處理默認(rèn)的 ’/error‘ 請求,分為兩種處理請求方式:一種是html方式,一種是json方式;DefaultErrorViewResolver: 默認(rèn)的錯誤視圖解析器,將錯誤信息解析到相應(yīng)的錯誤視圖.2. Spring Boot處理error的流程
- 一旦系統(tǒng)中出現(xiàn) 4xx 或者 5xx 之類的錯誤, ErrorPageCustomizer就會生效(定義錯誤的相應(yīng)規(guī)則);
- 然后內(nèi)部的過濾器就會映射到 ’/error‘ 請求,接著該/error請求就會被BasicErrorController處理;
- 然后BasicErrorController會根據(jù)請求中的Accept來區(qū)分該請求是瀏覽器發(fā)來的,還是由其它客戶端工具發(fā)來的.此時一般分為兩種處理方式:errorHtml()和error().
- 在errorHtml()方法中,獲取錯誤狀態(tài)信息,由resolveErrorView解析器解析到默認(rèn)的錯誤視圖頁面,默認(rèn)的錯誤頁面是/error/404.html頁面;
- 而如果templates目錄中的error目錄里面有這個頁面,404錯誤就會精確匹配404.html;
- 如果沒有這個404.html頁面它就會模糊匹配4xx.html頁面;
- 如果templates中沒有找到錯誤頁面,它就會去static文件中找.
注:
static文件夾存放的是靜態(tài)頁面,它沒有辦法使用模板引擎表達(dá)式.
簡單概括就是:
1??. 當(dāng)出現(xiàn)4xx或5xx的錯誤:ErrorPageCustomizer開始生效;
2??. 然后ErrorPageCustomizer發(fā)起 /error 請求;
3??. /error 請求被BasicErrorController處理;
4??. BasicErrorController根據(jù)請求頭中的Accept決定如何響應(yīng)處理.
其實(shí)在以上的所有類中,最重要的一個類就是BasicErrorController,所以接下來我們來分析BasicErrorController源碼,看看Spring Boot底層到底是怎么實(shí)現(xiàn)error處理的。
三. BasicErrorController源碼詳解
在Spring Boot中,當(dāng)發(fā)生了錯誤后,默認(rèn)情況下,Spring Boot提供了一個處理程序出錯的結(jié)果映射路徑 /error。當(dāng)發(fā)生錯誤后,Spring Boot就會將請求轉(zhuǎn)發(fā)到BasicErrorController控制器來處理這個錯誤請求。
1. BasicErrorController源碼
所以我們重點(diǎn)分析BasicErrorController源碼,首先呈上源碼內(nèi)容:
@Controller@RequestMapping("${server.error.path:${error.path:/error}}")public class BasicErrorController extends AbstractErrorController { private final ErrorProperties errorProperties; /** * Create a new {@link BasicErrorController} instance. * @param errorAttributes the error attributes * @param errorProperties configuration properties */ public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) { this(errorAttributes, errorProperties, Collections.emptyList()); } /** * Create a new {@link BasicErrorController} instance. * @param errorAttributes the error attributes * @param errorProperties configuration properties * @param errorViewResolvers error view resolvers */ public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List errorViewResolvers) { super(errorAttributes, errorViewResolvers); Assert.notNull(errorProperties, "ErrorProperties must not be null"); this.errorProperties = errorProperties; } @Override public String getErrorPath() { return this.errorProperties.getPath(); } @RequestMapping(produces = "text/html") public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map model = Collections.unmodifiableMap(getErrorAttributes( request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView == null ? new ModelAndView("error", model) : modelAndView); } @RequestMapping @ResponseBody public ResponseEntity> error(HttpServletRequest request) { Map body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity>(body, status);}2. error.path分析
這個源碼的注釋信息中說明了,這是一個Spring Boot自帶的全局錯誤Controller.
這個Controller中有一個RequestMapping注解,內(nèi)部有一個相當(dāng)于三元運(yùn)算符的操作。如果你在配置文件配置了server.error.path的話,就會使用你配置的異常處理地址,如果沒有就會使用你配置的error.path路徑地址,如果還是沒有,則默認(rèn)使用/error來作為發(fā)生異常時的處理地址。
所以我們可以按照如下圖中的配置,來設(shè)置自定義的錯誤處理頁面。
3. errorHtml()與error()方法解析
從上面的源碼我們可以看到,BasicErrorController中有兩個RequestMapping方法,分別是errorHtml()與error()方法來處理錯誤請求。
那么為什么會是兩個呢?請看下面的截圖:
BasicErrorController內(nèi)部是通過讀取request請求頭中的Accept屬性值,判斷其內(nèi)容是否為text/html;然后以此來區(qū)分請求到底是來自于瀏覽器(瀏覽器通常默認(rèn)自動發(fā)送請求頭內(nèi)容Accept:text/html),還是客戶端,從而決定是返回一個頁面視圖,還是返回一個 JSON 消息內(nèi)容。
可以看到其中errorHtml()方法是用來處理瀏覽器發(fā)送來的請求,它會產(chǎn)生一個白色標(biāo)簽樣式(whitelabel)的錯誤視圖頁面,該視圖將以HTML格式渲染出錯誤數(shù)據(jù)。
該方法返回了一個error頁面,如果你的項(xiàng)目靜態(tài)頁面下剛好存在一個error所對應(yīng)的頁面,那么Spring Boot會得到你本地的頁面,如下圖:
而error()方法用來處理來自非瀏覽器,也就是其他軟件app客戶端(比如postman等)發(fā)送來的錯誤請求,它會產(chǎn)生一個包含詳細(xì)錯誤,HTTP狀態(tài)及其他異常信息的JSON格式的響應(yīng)內(nèi)容。
注:
BasicErrorController可以作為自定義ErrorController的基類,我們只需要繼承BasicErrorController,添加一個public方法,并添加@RequestMapping注解,讓該注解帶有produces屬性,然后創(chuàng)建出該新類型的bean即可。
4. /error映射默認(rèn)處理策略總結(jié)
經(jīng)過上面的源碼分析得知,在默認(rèn)情況下,Spring Boot為這兩種情況提供了不同的響應(yīng)方式.
4.1 響應(yīng)'Whitelabel Error Page'頁面
一種是瀏覽器客戶端請求一個不存在的頁面或服務(wù)端處理發(fā)生異常時,這時候一般Spring Boot默認(rèn)會響應(yīng)一個html文檔內(nèi)容,稱作“Whitelabel Error Page”:
4.2 響應(yīng)JSON字符串
另一種是當(dāng)我們使用Postman等調(diào)試工具發(fā)送請求一個不存在的url或服務(wù)端處理發(fā)生異常時,Spring Boot會返回類似如下的一個 JSON 字符串信息:
{ "timestamp": "2019-05-20T06:12:45.209+0000", "status": 404, "error": "Not Found", "message": "No message available", "path": "/login.html"}總結(jié)
以上是生活随笔為你收集整理的html页面源码_整合SpringMVC之错误处理底层原理及源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nodejs源码_格物致知记一次node
- 下一篇: cors跨域_Nginx通过CORS配置