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"
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容