簡體   English   中英

當控制器返回ResponseEntity時,如何在Filter中設置響應狀態代碼?

[英]How to set response status code in Filter when controller returns ResponseEntity?

我正在開發一個帶有servlet過濾器的簡單Spring Boot應用程序,該應用程序旨在設置響應狀態代碼:

@Component
public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) resp;
        response.setStatus(201);
        chain.doFilter(req, resp);
    }

如果控制器返回字符串,則一切按預期進行(狀態為201)。 但是,如果控制器返回一個ResponseEntity,則在調用doFilter()之后,狀態碼為200而不是201:

@RestController
public class TestController {

    @GetMapping("/string")
    public String testString() {
        return "OK"; // status code is 201 as set by Filter
    }
}

@RestController
public class TestController {

    @GetMapping("/entity")
    public ResponseEntity<String> testResponseEntity() {
        return ResponseEntity.ok("OK"); // status code is 200
    }
}

為什么使用ResponseEntity時過濾器不會更改狀態代碼?

-

Github上的項目: https//github.com/timofeev-denis/set-status-code

如文檔所述, ResponseEntity#ok返回HTTP OK( https://httpstatuses.com/200 )狀態代碼。 篩選器較早運行,因此以后將覆蓋狀態。

您應該使用https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html中描述的其他方法創建ResponseEntity

使用/string端點,您無需修改​​狀態代碼。 使用/entity端點,您將明確地處於(通過返回ok將其設置為200)。

您的過濾器實現更改響應狀態代碼, 然后繼續運行其余的過濾器鏈- 然后運行servlet 並且我們剛剛建立了servlet(您的控制器)將響應狀態代碼設置為其他內容。

因此,您需要在servlet /控制器完成其工作更改響應代碼。

您首先想到的是重新實現過濾器,如下所示:

@Component
public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(req, resp);
        } finally {
            HttpServletResponse response = (HttpServletResponse) resp;

            response.setStatus(205);
        }
    }
}

但是不幸的是,那也不行! 根據文檔

請注意,對於@ResponseBody和ResponseEntity方法,postHandle的用處不大,在HandlerAdapter內以及postHandle之前,將其寫入並提交響應。 這意味着對響應進行任何更改為時已晚,例如添加額外的標頭。 對於這種情況,您可以實現ResponseBodyAdvice並將其聲明為Controller Advice Bean或直接在RequestMappingHandlerAdapter上對其進行配置。

這可能會達到您想要的效果(請注意,我將其設置為“ CHECKPOINT”只是為了說明要點!):

@ControllerAdvice
public class TestResponseBodyAdvice<T> implements ResponseBodyAdvice<T> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //
        // insert status code of choice here
        response.setStatusCode(HttpStatus.CHECKPOINT);

        return body;
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM