springboot異常處理之404

ps: 推薦一下本人的通用后臺(tái)管理項(xiàng)目spring-mybatis-admin

源碼分析

在springboot中默認(rèn)有一個(gè)異常處理器接口ErrorContorller,該接口提供了getErrorPath()方法,此接口的BasicErrorController實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)了getErrorPath()方法,如下:


/*
* AbstractErrorController是ErrorContoller的實(shí)現(xiàn)類(lèi)
*/
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

    private final ErrorProperties errorProperties;
    
    ...
    @Override
    public String getErrorPath() {
        return this.errorProperties.getPath();
    }
    
    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections
                .unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    }

    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity<>(status);
        }
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        return new ResponseEntity<>(body, status);
    }
    ....
}

errorProperties類(lèi)定義如下:

public class ErrorProperties {

    /**
     * Path of the error controller.
     */
    @Value("${error.path:/error}")
    private String path = "/error";
    ...
}

由此可見(jiàn),springboot中默認(rèn)有一個(gè)處理/error映射的控制器,有errorerrorHtml兩個(gè)方法的存在,它可以處理來(lái)自瀏覽器頁(yè)面和來(lái)自機(jī)器客戶(hù)端(app應(yīng)用)的請(qǐng)求。

當(dāng)用戶(hù)請(qǐng)求不存在的url時(shí),dispatcherServlet會(huì)交由ResourceHttpRequestHandler映射處理器來(lái)處理該請(qǐng)求,并在handlerRequest方法中,重定向至/error映射,代碼如下:

    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // For very general mappings (e.g. "/") we need to check 404 first
        Resource resource = getResource(request);
        if (resource == null) {
            logger.debug("Resource not found");
            response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404
            return;
        }
        ...
    }

getResource(request)會(huì)調(diào)用this.resolverChain.resolveResource(request, path, getLocations())方法,getLocations()方法返回結(jié)果如下:

image

接著程序會(huì)執(zhí)行到getResource(pathToUse, location)方法如下:

    @Nullable
    protected Resource getResource(String resourcePath, Resource location) throws IOException {
        // 新建一個(gè)resource對(duì)象,url為  location + resourcePath,判斷此對(duì)象(文件)是否存在
        Resource resource = location.createRelative(resourcePath);
        if (resource.isReadable()) {
            if (checkResource(resource, location)) {
                return resource;
            }
            else if (logger.isWarnEnabled()) {
                Resource[] allowedLocations = getAllowedLocations();
                logger.warn("Resource path \"" + resourcePath + "\" was successfully resolved " +
                        "but resource \"" + resource.getURL() + "\" is neither under the " +
                        "current location \"" + location.getURL() + "\" nor under any of the " +
                        "allowed locations " + (allowedLocations != null ? Arrays.asList(allowedLocations) : "[]"));
            }
        }
        return null;
    }

在resource.isReadable()中,程序會(huì)在locations目錄中尋找path目錄下文件,由于不存在,返回null。

最終也就導(dǎo)致程序重定向至/error映射,如果是來(lái)自瀏覽器的請(qǐng)求,也就會(huì)返回/template/error/404.html頁(yè)面,所以對(duì)于404請(qǐng)求,只需要在template目錄下新建error目錄,放入404頁(yè)面即可。

使用注意

  1. 在springboot4.x中我們可以自定義ControllerAdvice注解 + ExceptionHandler注解來(lái)處理不同錯(cuò)誤類(lèi)型的異常,但在springboot中404異常和攔截器異常由spring自己處理。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容