0

我已经编写了 ExceptionHandlerExceptionResolver 的一些扩展,它拦截了它应该拦截的所有异常,但是它不是只返回错误消息和 HTTP 状态代码,而是通过它自己的基于用户请求的 URL 构建的 URL 进行非常奇怪的重定向。例如:

user's url -> .../myModule/api/myEntity/123 (it's an id)
resolver's redirect url -> .../myModule/api/myEntity/myEntity/123 

服务器没有这样的资源,显然它会以 404 响应。

问题是:为什么要进行重定向以及如何将其配置为仅返回消息和状态码?

我的解析器:

public class BusinessLayerExceptionHandler extends ExceptionHandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView wrappedResponse = new ModelAndView();
        wrappedResponse.addObject("errorMessage", ex.getMessage());
        wrappedResponse.setStatus(HttpStatus.BAD_REQUEST);
        return wrappedResponse;
    }
}

ModelAndView我猜假设重定向的用法。至少这是我在 DispatcherServlet 中找到的方法描述。

...
     * @return a corresponding ModelAndView to forward to
     * @throws Exception if no error ModelAndView found
     */
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) throws Exception {
...

如果是这样,如何让它只返回错误消息和 HTTP 状态码?

4

1 回答 1

1

您可以通过创建自定义的View.

public class YourCustomView implements View {

    private final String errorMessage;

    public YourCustomView(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        response.setContentType("text/plain;charset=UTF-8");
        try (PrintWriter pw = response.getWriter()) {
            pw.write(errorMessage);
        }
    }

}

您需要将自定义View对象ModelAndView放入HandlerExceptionResolver#resolveException.

public class BusinessLayerExceptionHandler implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        ModelAndView wrappedResponse = new ModelAndView();
        wrappedResponse.setStatus(HttpStatus.BAD_REQUEST);
        wrappedResponse.setView(new YourCustomView(ex.getMessage()));
        return wrappedResponse;
    }
}


为什么它会重定向

似乎 Spring 将视图名称识别为 adefaultViewName并转发给它(通过调用RequestDispatcher#forward)。
DispatcherServlet#processHandlerException中,adefaultViewName设置为没有对象时ModelAndView返回的 a 的视图名称。A是从中获得的,它将 HTTP 请求转换为视图名称。resolveExceptionViewdefaultViewNameDispatcherServlet#getDefaultViewName


另一种解决方案

我认为您可以使用@ControllerAdviceand@ExceptionHandler代替。它还可以处理从控制器抛出的异常。

@ControllerAdvice
public class YourControllerAdvice {

    @ExceptionHandler
    public ResponseEntity<Map<String, String>> handleBusinessLayerException(
            Exception exception) {
        Map<String, String> body = Map.of("errorMessage", exception.getMessage());
        return ResponseEntity.badRequest().body(body);
    }

}

也可以看看

关于 HandlerExceptionResolver 的
Spring Web MVC 文档 关于 ControllerAdvice的 Spring Web MVC 文档

于 2020-02-22T08:34:08.443 回答