日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

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

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

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方法中會創建一個WebServer,繼而獲取ServletWebServerFactory。

1.1AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization

在創建bean-tomcatServletWebServerFactory時會調用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后置處理器,然后循環遍歷調用每個bean后置處理器的postProcessBeforeInitialization方法。

1.2 ErrorPageRegistrarBeanPostProcessor.postProcessBeforeInitialization

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

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

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

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

該方法會獲取Registrars,然后循環遍歷調用每一個注冊器的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 實現了ErrorPageRegistrar時,會被檢測到并執行registerErrorPages方法。

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

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

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

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

2.1 AbstractConfigurableWebServerFactory.addErrorPages

方法源碼如下:

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

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

2.2 TomcatServletWebServerFactory.configureContext

創建完TomcatServletWebServerFactory后會調用configureContext方法,如下圖所示:


在configureContext方法中會獲取錯誤頁面然后逐個調用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));?????????}?????}//調用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狀態碼定義錯誤頁面,還可以通過異常類型進行定義。

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

③ 錯誤頁面如何被用到

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


這里只需要關注這一點,無需關注細節,我們繼續往下走。。。。一直走到StandardHostValve.status方法。

StandardHostValve.status中會對響應狀態碼進行處理。

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)獲取到錯誤頁//根據錯誤碼,比如404從statusPages獲取對應的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());??????????????????????????????//這里很重要,將會嘗試跳轉到我們自定義錯誤請求頁面?????????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方法中將會調用ApplicationDispatcher.forwar進行請求轉發。

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。