본문 바로가기

내배캠/TIL

gateway http header too large 오류 해결

MSA로 전환하며 Gateway와 Eureka를 도입하여 Gateway, Auction, Point 서버를 Eureka에 등록하는 것까지 성공했지만 Gateway를 통해 요청을 보낼 때 계속 gateway http header too large (error code: 431) 오류가 발생했다.

 

헤더 설정 길이를 늘려주면 해결될 줄 알고 계속 늘려갔는데

아무리 늘려도 계속해서 부족하다는 오류가 발생했다.

 

https://docs.spring.io/spring-cloud-gateway/reference/appendix.html

 

Common application properties :: Spring Cloud Gateway

Various properties can be specified inside your application.properties file, inside your application.yml file, or as command line switches. This appendix provides a list of common Spring Cloud Gateway properties and references to the underlying classes tha

docs.spring.io

 

20만까지 설정했다가 요청을 하는데 3분이 걸리길래 다른 문제가 있다고 판단해서 알아봤다.

 

혹시 필터에서 사이즈를 늘려주면 되지 않을까 했지만 마찬가지로 소용 없었다.

 

https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/gatewayfilter-factories/requestheadersize-factory.html

 

RequestHeaderSize GatewayFilter Factory :: Spring Cloud Gateway

The RequestHeaderSize GatewayFilter factory takes maxSize and errorHeaderName parameters. The maxSize parameter is the maximum data size allowed by the request header (including key and value). The errorHeaderName parameter sets the name of the response he

docs.spring.io

 

 

혹시 netty 서버 설정에서 바꿔주면 될까 해서 했지만 적용이 안됐다.

@Component
public class CustomizeNetty implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
    @Override
    public void customize(NettyReactiveWebServerFactory factory) {
        factory.addServerCustomizers(httpServer -> httpServer.http2Settings(builder -> builder.maxHeaderListSize(65536)));
    }
}

 

https://stackoverflow.com/questions/77399781/how-to-increase-request-header-size-in-spring-webflux-with-netty

 

How to increase request header size in Spring WebFlux with Netty?

Is there a way to configure maximum http request header size for a request in Spring WebFlux with embedded Netty server? I am getting following exception. io.netty.handler.codec.http2.Http2Exception$

stackoverflow.com

 

 

근본적으로 왜 HTTP Header의 사이즈가 너무 커졌을까 보니 log에 처음보는 Forwarded가 잔뜩 찍혀있었다.

 

Forwarded: <filtered>
Forwarded: <filtered>
Forwarded: <filtered>
Forwarded: <filtered>
Forwarded: <filtered>
Forwarded: <filtered>
Forwarded: <filtered>
...

 

 

Forwarded 헤더는 클라이언트가 실제로 어떤 IP 주소, 프로토콜, 포트 등을 통해 서버에 접속했는지 정보를 전달하기 위해 HTTP/1.1 표준으로 정의된 헤더로, 주로 프록시나 로드 밸런서가 클라이언트 요청을 서버로 전달할 때 추가한다. 

클라이언트와 서버 사이에 여러 프록시나 로드 밸런서가 연결되며 각 프록시가 Forwarded 헤더를 추가하면서 원래 정보가 계속 누적된 것으로 보였다. 프록시나 로드 밸런서는 클라이언트의 IP 주소 및 접속 경로를 남기기 위해 매번 Forwarded 헤더를 추가하는데, 이렇게 되면 요청 경로의 중간 단계에 해당하는 IP 정보가 헤더에 계속 쌓여 다중 값으로 나타날 수 있기 때문이다. 

 

따라서 이 Forwarded 헤더를 하나만 남기고 중복되는 것을 제거하는 코드를 추가했더니 해결이 되었다.

 

@Component
public class ForwardedHeaderFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        // Forwarded 헤더 중복 제거
        List<String> forwardedHeaders = exchange.getRequest().getHeaders().get("Forwarded");
        if (forwardedHeaders != null && forwardedHeaders.size() > 1) {
            List<String> uniqueForwardedHeaders = forwardedHeaders.stream()
                    .distinct()
                    .collect(Collectors.toList());
            exchange.mutate().request(exchange.getRequest().mutate().headers(
                    headers -> headers.put("Forwarded", uniqueForwardedHeaders)
            ).build()).build();
        }

        return chain.filter(exchange);
    }

}

 

 

사실 이 부분도 처음에

exchange.getRequest().mutate().headers(headers -> headers.put("Forwarded", uniqueForwardedHeaders));

 

이렇게 적었다가 UnsupportedOperationException 오류가 나서 또 한참 헤맸다. ReadOnlyHttpHeaders는 불변 헤더인데 여기에 HttpHeaders의 put 메서드를 호출해 값을 설정하려고 하니 발생한 오류같았다. 

위처럼 적지 않도록 주의하자.