日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

apache 设置404 页面_SpringBoot自定义错误页面

發(fā)布時間:2023/12/10 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 apache 设置404 页面_SpringBoot自定义错误页面 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

SpringBoot請求錯誤如404可能看到如下頁面:


有時可能需要自定義錯誤頁面針對不同的http.status,如404/400。

【1】解決方法

① 注冊錯誤頁面

如下所示:

@Componentpublic?class?ErrorPageConfig?implements?ErrorPageRegistrar?{????@Override????public?void?registerErrorPages(ErrorPageRegistry?registry)?{????????ErrorPage?error400Page?=?new?ErrorPage(HttpStatus.BAD_REQUEST,?"/error/404");????????ErrorPage?error404Page?=?new?ErrorPage(HttpStatus.NOT_FOUND,?"/error/404");????????ErrorPage?error500Page?=?new?ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,?"/error/500");????????registry.addErrorPages(error400Page,error404Page,error500Page);????}}

② controller進行攔截

然后你只需要寫個controller攔截不同請求然后跳到不同的自定義錯誤頁面即可,如下所示:

@RequestMapping("/error/{status}")public?String?errorPage(@PathVariable?Integer?status){????switch?(status){????????case?401:????????case?400:return?"/error/404";????????case?500:return?"/error/500";????????default:return?"/error/default";????}}

那么原理呢?

【2】原理講解

① 啟動SpringBoot,注冊錯誤頁面

如下圖所示,啟動項目時候再onRefresh方法中會創(chuàng)建一個WebServer,繼而獲取ServletWebServerFactory。

1.1AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization

在創(chuàng)建bean-tomcatServletWebServerFactory時會調(diào)用AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization,如下所示:

@Overridepublic?Object?applyBeanPostProcessorsBeforeInitialization(Object?existingBean,?String?beanName)?throws?BeansException?{Object?result?=?existingBean;for?(BeanPostProcessor?processor?:?getBeanPostProcessors())?{?Object?current?=?processor.postProcessBeforeInitialization(result,?beanName);?if?(current?==?null)?{??return?result;?}?result?=?current;}return?result;}

該方法會獲取bean后置處理器,然后循環(huán)遍歷調(diào)用每個bean后置處理器的postProcessBeforeInitialization方法。

1.2 ErrorPageRegistrarBeanPostProcessor.postProcessBeforeInitialization

當遍歷到ErrorPageRegistrarBeanPostProcessor時會調(diào)用其postProcessBeforeInitialization方法,方法源碼如下所示:

@Overridepublic?Object?postProcessBeforeInitialization(Object?bean,?String?beanName)?throws?BeansException?{?if?(bean?instanceof?ErrorPageRegistry)?{??postProcessBeforeInitialization((ErrorPageRegistry)?bean);?}?return?bean;}

方法會判斷當前bean是否ErrorPageRegistry類型,如果是,則調(diào)用postProcessBeforeInitialization方法,源碼如下所示:

private?void?postProcessBeforeInitialization(ErrorPageRegistry?registry)?{?for?(ErrorPageRegistrar?registrar?:?getRegistrars())?{??registrar.registerErrorPages(registry);?}}

該方法會獲取Registrars,然后循環(huán)遍歷調(diào)用每一個注冊器的registerErrorPages方法。獲取注冊其源碼如下所示:

private?Collection?getRegistrars()?{?if?(this.registrars?==?null)?{??//?Look?up?does?not?include?the?parent?context??this.registrars?=?new?ArrayList<>(????this.beanFactory.getBeansOfType(ErrorPageRegistrar.class,?false,?false).values());??this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);??this.registrars?=?Collections.unmodifiableList(this.registrars);?}?return?this.registrars;}

故而,當我們的ErrorPageConfig 實現(xiàn)了ErrorPageRegistrar時,會被檢測到并執(zhí)行registerErrorPages方法。

② 把錯誤頁面放到StandardContext.errorPageSupport中

StandardContext是什么?我們可以看下如下類繼承示意圖。

在①中我們提到會注冊錯誤頁面registrar.registerErrorPages(registry);,如下圖所示此時的registry為TomcatServletWebServerFactory:

我們再來看下TomcatServletWebServerFactory繼承示意圖(可以看到其父類AbstractConfigurableWebServerFactory實現(xiàn)了ErrorPageRegistry接口):

2.1 AbstractConfigurableWebServerFactory.addErrorPages

方法源碼如下:

@Overridepublic?void?addErrorPages(ErrorPage...?errorPages)?{?Assert.notNull(errorPages,?"ErrorPages?must?not?be?null");?this.errorPages.addAll(Arrays.asList(errorPages));}

也就說錯誤頁面現(xiàn)在被放到了屬性private Set errorPages = new LinkedHashSet<>();中。

2.2 TomcatServletWebServerFactory.configureContext

創(chuàng)建完TomcatServletWebServerFactory后會調(diào)用configureContext方法,如下圖所示:


在configureContext方法中會獲取錯誤頁面然后逐個調(diào)用StandardContext.addErrorPage方法添加到其ErrorPageSupport errorPageSupport中。

configureContext方法中遍歷錯誤頁面如下所示:

for?(ErrorPage?errorPage?:?getErrorPages())?{?org.apache.tomcat.util.descriptor.web.ErrorPage?tomcatErrorPage?=?new?org.apache.tomcat.util.descriptor.web.ErrorPage();?tomcatErrorPage.setLocation(errorPage.getPath());?tomcatErrorPage.setErrorCode(errorPage.getStatusCode());?tomcatErrorPage.setExceptionType(errorPage.getExceptionName());?context.addErrorPage(tomcatErrorPage);}

StandardContext.addErrorPage方法源碼如下所示:

@Override?public?void?addErrorPage(ErrorPage?errorPage)?{?????//?Validate?the?input?parameters?????if?(errorPage?==?null)?????????throw?new?IllegalArgumentException?????????????(sm.getString("standardContext.errorPage.required"));?????String?location?=?errorPage.getLocation();?????if?((location?!=?null)?&&?!location.startsWith("/"))?{?????????if?(isServlet22())?{?????????????if(log.isDebugEnabled())?????????????????log.debug(sm.getString("standardContext.errorPage.warning",??????????????????????????????location));?????????????errorPage.setLocation("/"?+?location);?????????}?else?{?????????????throw?new?IllegalArgumentException?????????????????(sm.getString("standardContext.errorPage.error",???????????????????????????????location));?????????}?????}//調(diào)用errorPageSupport.add?????errorPageSupport.add(errorPage);?????fireContainerEvent("addErrorPage",?errorPage);?}

ErrorPageSupport.add方法如下所示:

public?void?add(ErrorPage?errorPage)?{?????String?exceptionType?=?errorPage.getExceptionType();?????if?(exceptionType?==?null)?{?????????statusPages.put(Integer.valueOf(errorPage.getErrorCode()),?errorPage);?????}?else?{?????????exceptionPages.put(exceptionType,?errorPage);?????}?}

通過該方法可以看到,不止可以通過HTTP狀態(tài)碼定義錯誤頁面,還可以通過異常類型進行定義。

那么ErrorPageSupport、statusPages、exceptionPages分別是什么呢?我們看下圖示意:

③ 錯誤頁面如何被用到

在ResourceHttpRequestHandler.handleRequest方法處理請求時,找不到資源會調(diào)用response.sendError方法:


這里只需要關(guān)注這一點,無需關(guān)注細節(jié),我們繼續(xù)往下走。。。。一直走到StandardHostValve.status方法。

StandardHostValve.status中會對響應(yīng)狀態(tài)碼進行處理。

private?void?status(Request?request,?Response?response)?{?????int?statusCode?=?response.getStatus();?????//?Handle?a?custom?error?page?for?this?status?code?????Context?context?=?request.getContext();?????if?(context?==?null)?{?????????return;?????}?????/*?Only?look?for?error?pages?when?isError()?is?set.??????*?isError()?is?set?when?response.sendError()?is?invoked.?This??????*?allows?custom?error?pages?without?relying?on?default?from??????*?web.xml.??????*/?????if?(!response.isError())?{?????????return;?????}//這里會從errorPageSupport.find(errorCode)獲取到錯誤頁//根據(jù)錯誤碼,比如404從statusPages獲取對應(yīng)的ErrorPage對象?????ErrorPage?errorPage?=?context.findErrorPage(statusCode);?????if?(errorPage?==?null)?{?????????//?Look?for?a?default?error?page?????????errorPage?=?context.findErrorPage(0);?????}?????if?(errorPage?!=?null?&&?response.isErrorReportRequired())?{?????????response.setAppCommitted(false);?????????request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,???????????????????????????Integer.valueOf(statusCode));?????????String?message?=?response.getMessage();?????????if?(message?==?null)?{?????????????message?=?"";?????????}?????????request.setAttribute(RequestDispatcher.ERROR_MESSAGE,?message);?????????request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,?????????????????errorPage.getLocation());?????????request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,?????????????????DispatcherType.ERROR);?????????Wrapper?wrapper?=?request.getWrapper();?????????if?(wrapper?!=?null)?{?????????????request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,???????????????????????????????wrapper.getName());?????????}?????????request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,??????????????????????????????request.getRequestURI());??????????????????????????????//這里很重要,將會嘗試跳轉(zhuǎn)到我們自定義錯誤請求頁面?????????if?(custom(request,?response,?errorPage))?{?????????????response.setErrorReported();?????????????try?{?????????????????response.finishResponse();?????????????}?catch?(ClientAbortException?e)?{?????????????????//?Ignore?????????????}?catch?(IOException?e)?{?????????????????container.getLogger().warn("Exception?Processing?"?+?errorPage,?e);?????????????}?????????}?????}?}

如下圖所示,在StandardHostValve.custom方法中將會調(diào)用ApplicationDispatcher.forwar進行請求轉(zhuǎn)發(fā)。

版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。

本文鏈接:

https://blog.csdn.net/j080624/article/details/109197726

總結(jié)

以上是生活随笔為你收集整理的apache 设置404 页面_SpringBoot自定义错误页面的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。