복붙노트

[SPRING] Spring - 처리 후 모든 요청에 ​​대한 헤더 수정 (postHandle에서)

SPRING

Spring - 처리 후 모든 요청에 ​​대한 헤더 수정 (postHandle에서)

내가 원하는 것은 요청이 처리 된 후 응답에 새로운 헤더를 추가하는 것입니다. 처리 된 HttpStatus 코드 (내 경우에는 권한이없는 401)를 확인하고 새 헤더를 추가해야합니다. 나는 스프링이 인터셉터를 가지고 있지만, 응답은 문서에 언급 된대로 수정할 수 없다는 것을 알고있다.

글쎄, 나는 ResponseBodyAdvice를 구현했다. 예, 본문 수정이 가능하지만 헤더를 수정할 수 없어서 이벤트가 컨트롤러에서 반환 된 상태 코드를 찾을 수 없습니다.

서블릿 필터를 사용하는 다른 옵션도 성공하지 못합니다. filterChain.doFilter (servletRequest, servletResponse) 다음에 헤더를 추가해야합니다. 요구. 그러나 다시 헤더 값을 수정하지는 않습니다. 이 쉬운 작업을 수행 할 수있는 방법이 있습니까?

해결법

  1. ==============================

    1.서블릿 필터로 올바르게 작동하는 것처럼 들리 겠지만 아마도 서블릿 응답 객체를 401 상태 코드가 설정되었을 때 감지하고 그 시점에 사용자 정의 헤더를 추가하는 것으로 Servlet 응답 객체를 래핑하면됩니다.

    서블릿 필터로 올바르게 작동하는 것처럼 들리 겠지만 아마도 서블릿 응답 객체를 401 상태 코드가 설정되었을 때 감지하고 그 시점에 사용자 정의 헤더를 추가하는 것으로 Servlet 응답 객체를 래핑하면됩니다.

    HttpServletResponse wrappedResponse = new HttpServletResponseWrapper(response) {
    
      public void setStatus(int code) {
        super.setStatus(code);
        if(code == 401) handle401();
      }
    
      // three similar methods for the other setStatus and the two
      // versions of sendError
    
      private void handle401() {
        this.addHeader(...);
      }
    };
    
    filterChain.doFilter(request, wrappedResponse);
    
  2. ==============================

    2.자, 자바는 당신이 다른 필드를 독립적으로 변경할 수있는 Object로서의 HTTP 응답을 보여줍니다.

    자, 자바는 당신이 다른 필드를 독립적으로 변경할 수있는 Object로서의 HTTP 응답을 보여줍니다.

    그러나 실제로 서버와 클라이언트간에 교환되는 것은 바이트 스트림이며 헤더이며 본문 앞에 전송됩니다. 그것이 HttpResponse가 isCommitted () 메소드를 갖는 이유입니다. 헤더가 전송되면 응답이 커밋됩니다. 물론 커밋 된 후에는 더 이상 헤더를 수정할 수 없습니다. 서블릿 컨테이너는 충분한 문자가 몸에 쓰여지면 응답을 커밋하고 플러시 할 수 있습니다.

    헤더를 변경하려고하면 요청이 처리 된 후 안전하지 않습니다. 요청이 커밋되지 않은 경우에만 작동 할 수 있습니다. 컨트롤러가 응답 자체를 작성하지 않고보기로 전달하는 경우에만 안전합니다. 그런 다음 postHandle 인터셉터 메서드에서 응답이 커밋되지 않았으므로 헤더를 변경할 수 있습니다. 그렇지 않으면 isCommitted ()를 테스트해야하고 true를 반환하면 ... 헤더를 변경하기에는 너무 늦습니다!

    물론이 경우 인터셉터 나 필터는 아무 것도 할 수 없습니다 ...

  3. ==============================

    3.체크 상태 코드가 필요 없다면 preHandle 메소드에 헤더를 추가하면됩니다 (Spring이 postHandle이 발생하기 전에 응답을하기 때문에 postHandle에 추가하는 것은 @ResponseBody로 표시된 응답에서 응답하지 않습니다).

    체크 상태 코드가 필요 없다면 preHandle 메소드에 헤더를 추가하면됩니다 (Spring이 postHandle이 발생하기 전에 응답을하기 때문에 postHandle에 추가하는 것은 @ResponseBody로 표시된 응답에서 응답하지 않습니다).

    public class ControllerHandleInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
           if (handler instanceof HandlerMethod) {
              response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 
              response.setHeader("Pragma", "no-cache"); 
              response.setHeader("Expires", "0"); 
           }
    
           return true;
        }
    
        // other code...
    }
    
  4. ==============================

    4.ServletFilter를 구현하고 원래 응답 객체를 감쌀 수 있습니다.

    ServletFilter를 구현하고 원래 응답 객체를 감쌀 수 있습니다.

    이렇게하면 응답의 실제 작성을 지연하고 사용자 정의 헤더를 추가 할 수 있습니다.

    다른 한편으로는 : 이것은 Spring Security Processing 체인과 비슷합니다.

  5. ==============================

    5.ServerHttpResponse를 ServletServerHttpResponse로 전송하면 실제로 가능합니다.

    ServerHttpResponse를 ServletServerHttpResponse로 전송하면 실제로 가능합니다.

    ResponseBodyAdvice가 호출되는 방식에 따라 ServletServerHttpResponse 여야하며, ResponseBodyAdvice에 전달 된 ServerHttpResponse는 실제로이 메소드에서 ServletServerHttpResponse입니다.

    따라서 단순히 ResponseBodyAdvice를 구현하고 HttpServletResponse를 더 이상 감쌀 필요는 없습니다.

    @ControllerAdvice
    public class FooBodyAdvice implements ResponseBodyAdvice {
    
        @Override
        public boolean supports(MethodParameter returnType, Class converterType) {
            return true;
        }
    
        @Override
        public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    
            if(response instanceof  ServletServerHttpResponse) {
    
                ServletServerHttpResponse res= (ServletServerHttpResponse)(response);
                res.getServletResponse().getStatus(); //get the status code
    
                res.getHeaders().set("fooHeader", "fooValue"); //modify headers
                res.getHeaders().setETag("33a64df551425fcc55e4d42a148795d9f25f89d4") //use "type safe" methods to modify header 
            }
    
            return body;
        }
    }
    
  6. from https://stackoverflow.com/questions/30702970/spring-modifying-headers-for-every-request-after-processing-in-posthandle by cc-by-sa and MIT license