SpringBoot Filter Error导致响应json额外追加了一段json

问题:

错误日志

{
    "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"
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容