问题:
错误日志
{
"id": 2,
"name": "user2"
}{
"timestamp": "2022-02-15T11:06:16.094+00:00",
"status": 200,
"error": "OK",
"path": "/user"
}
原因:
Filter 过滤器是在Servlet层面的,是在SpringMVC外层的。所以可能会出现Spring已经在Response写了响应,在Filter中又抛出了异常,请求被转到/error,再次把error响应写入到Response。出现上面的写了两个结果的情况。
ApplicationFilterChain.java
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
StandardWrapperValve.java
private void exception(Request request, Response response,
Throwable exception) {
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setError();
}
BasicErrorController.java error返回json
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = this.getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity(status);
} else {
Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity(body, status);
}
}
重现
创建filter, 并在doFilter后面抛出异常
@Component
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
throw new RuntimeException("error");
}
}
IndexController.java
@RestController
public class IndexController {
@GetMapping("/user")
public User user(@RequestParam int id) {
return new User(id, "user" + id);
}
}
使用postman构建请求,响应结果为:
{
"id": 2,
"name": "user2"
}{
"timestamp": "2022-02-15T11:06:16.094+00:00",
"status": 200,
"error": "OK",
"path": "/user"
}