[英]Spring MVC REST Handing Bad Url (404) by returning JSON
我正在使用SpringMVC開發REST服務,其中在類和方法級別使用@RequestMapping。
當前已將該應用程序配置為返回在web.xml中配置的錯誤頁面jsp。
<error-page>
<error-code>404</error-code>
<location>/resourceNotFound</location>
</error-page>
但是,我想返回自定義JSON而不是此錯誤頁面。
通過在控制器中編寫此代碼,我能夠處理異常並為其他異常返回json,但不確定在URL根本不存在時如何以及在何處編寫返回JSON的邏輯。
@ExceptionHandler(TypeMismatchException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> handleTypeMismatchException(HttpServletRequest req, TypeMismatchException ex) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.request", null, locale);
errorMessage += ex.getValue();
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), headers, HttpStatus.BAD_REQUEST);
}
我嘗試了@ControllerAdvice,它適用於其他異常情況,但是當映射不可用時不起作用,
@ControllerAdvice
public class RestExceptionProcessor {
@Autowired
private MessageSource messageSource;
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestMethodNotSupported(HttpServletRequest req, HttpRequestMethodNotSupportedException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(NoSuchRequestHandlingMethodException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestHandlingMethodNotSupported(HttpServletRequest req, NoSuchRequestHandlingMethodException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
}
在SpringFramework中研究了DispatcherServlet和HttpServletBean.init()之后,我發現在Spring 4中它是可能的。
org.springframework.web.servlet.DispatcherServlet
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri +
"] in DispatcherServlet with name '" + getServletName() + "'");
}
if(throwExceptionIfNoHandlerFound) {
ServletServerHttpRequest req = new ServletServerHttpRequest(request);
throw new NoHandlerFoundException(req.getMethod().name(),
req.getServletRequest().getRequestURI(),req.getHeaders());
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
默認情況下throwExceptionIfNoHandlerFound為false,我們應該在web.xml中啟用它
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
然后,您可以使用此方法將其捕獲在帶有@ControllerAdvice注釋的類中。
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestHandlingNoHandlerFound(HttpServletRequest req, NoHandlerFoundException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.bad.url", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
這使我可以為不存在映射的錯誤URL返回JSON響應,而不是重定向到JSP頁面:)
{"message":"URL does not exist","url":"http://localhost:8080/service/patientssd"}
如果您使用的是Spring Boot,請同時設置以下兩個屬性:
spring.resources.add-mappings=false
spring.mvc.throw-exception-if-no-handler-found=true
現在,您的@ControllerAdvice帶注釋的類可以處理“ NoHandlerFoundException”,如下所示。
@ControllerAdvice
@RequestMapping(produces = "application/json")
@ResponseBody
public class RestControllerAdvice {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<Map<String, Object>> unhandledPath(final NoHandlerFoundException e) {
Map<String, Object> errorInfo = new LinkedHashMap<>();
errorInfo.put("timestamp", new Date());
errorInfo.put("httpCode", HttpStatus.NOT_FOUND.value());
errorInfo.put("httpStatus", HttpStatus.NOT_FOUND.getReasonPhrase());
errorInfo.put("errorMessage", e.getMessage());
return new ResponseEntity<Map<String, Object>>(errorInfo, HttpStatus.NOT_FOUND);
}
}
請注意,僅指定此屬性是不夠的:
spring.mvc.throw-exception-if-no-handler-found=true
,因為默認情況下,Spring會將未知的URL映射到/ **,所以實際上永遠不會“找不到處理程序”。
要禁用到/ **的未知URL映射,您需要
spring.resources.add-mappings=false ,
這就是兩個屬性共同產生所需行為的原因。
您可以在/ handle / 404下面的位置返回json。
<error-page>
<error-code>404</error-code>
<location>/handle/404</location>
</error-page>
在web.xml中配置此命令后,將出現404錯誤,該錯誤將重定向到/ handle / 404 ,您可以使用此映射創建一個控制器並返回json結果。 例如。
@RestController
@RequestMapping(value = "handle")
public class HttpErrorController {
@RequestMapping(value = "404")
public String handle404() {
return "404 error";
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.