首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

SpringMVC 返回 400 錯誤時攜帶自定義 JSON 錯誤信息

     編輯:程式設計綜合問答

問題現象

  • 正常請求:返回自定義 JSON,Content-Type: application/json。
  • 參數校驗失敗(如 @Valid 失敗):SpringMVC 預設拋出 MethodArgumentNotValidException,容器直接返回 **HTML 400 頁面**,忽略了 DefaultHandlerExceptionResolver 中寫的 JSON 邏輯。

根本原因

在 DefaultHandlerExceptionResolver 子類中調用 response.sendError(400) 會**觸發容器預設錯誤頁面機制**,導致響應體被容器覆蓋為 HTML,且 Content-Type 被重置。

正確做法:用 response.setStatus(400)

@ControllerAdvice
public class GlobalExceptionHandler extends DefaultHandlerExceptionResolver {

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request,
                                              HttpServletResponse response,
                                              Object handler,
                                              Exception ex) {
        if (ex instanceof MethodArgumentNotValidException) {
            // 關鍵:setStatus 不觸發容器錯誤頁
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 400
            response.setContentType("application/json;charset=UTF-8");
            try {
                String json = "{\"code\":400,\"msg\":\"參數校驗失敗\",\"errors\":[...]}";
                response.getWriter().write(json);
            } catch (IOException e) {
                logger.error("write error response failed", e);
            }
            return new ModelAndView(); // 返回空 MV,終止後續處理
        }
        return super.doResolveException(request, response, handler, ex);
    }
}

關鍵差異對比

方法行為適用場景
response.sendError(400)容器攔截,返回預設錯誤頁(HTML),**丟棄自定義響應體**真的想讓容器處理錯誤頁
response.setStatus(400)**僅設置狀態碼**,不觸發容器錯誤頁,**保留自定義響應體**REST API 返回 JSON 錯誤

補充:Spring Boot 2.x+ 更簡單的寫法

@RestControllerAdvice
public class ApiExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidException(MethodArgumentNotValidException ex) {
        List errors = ex.getBindingResult()
            .getFieldErrors().stream()
            .map(e -> e.getField() + ": " + e.getDefaultMessage())
            .collect(Collectors.toList());
        return new ErrorResponse(400, "參數校驗失敗", errors);
    }
}
  • @RestControllerAdvice = @ControllerAdvice + @ResponseBody。
  • @ResponseStatus 直接設置狀態碼,**不走 sendError**。

總結

REST API 返回錯誤碼 + JSON 體,永遠用 response.setStatus() 或 @ResponseStatus,禁用 sendError()。這是 SpringMVC/SpringBoot 開發的鐵律。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved