2024. 2. 7. 17:18ㆍDevelopment
레거시 시스템에 Spring cloud gateway를 도입하면서 하나의 장벽에 부딪히게 되었습니다.
오랫동안 유지되어온 시스템에서 client들에게 완벽한 하위호환을 보장해주어야하는 상황에서 일부 client들이 url에 포함해서는 안되는 특수문자들을 인코딩을 하지 않고, 날 것으로 그대로 보내오고 있었습니다.
http://localhost:8080/test/case/key/var1|var2
[2dd57409, L:/127.0.0.1:8080 - R:/127.0.0.1:59831] Decoding failed: REQUEST(decodeResult: failure(java.net.URISyntaxException: Illegal character in path at index 40: http://localhost:8080/test/case/key/var1|var2), version: HTTP/1.1)
사용되어지는 특수문자들도 심지어 여러가지..
|, ^, {, } 등등.. 모두 url 인코딩이 필요한 character들인데, 인코딩 없이 request가 들어오고 있는 상황에서 문제는 기본적으로 Spring cloud gateway 내부에서 requet url을 이용하여 JAVA URI object를 생성하면서 URISyntaxException 을 발생 시킨다는 것 입니다.
실제 저희가 작성 중인 besinsess 로직으로 오기도 전에 framework 에서 자체적으로 400 을 리턴해버리고 있기 때문에 해당 framework 코드 동작 전에 무언가 조치가 필요한 상황이었습니다.
다행히도 netty 레벨에서 동작에 network state에 전환되는 중간에 custom 한 code를 개입할 수 있고, 이때 request 에 손을 대는 것이 가능했고 아래와 같이 이슈를 해결하였습니다.
@Slf4j
@Component
public class NettyWebServerCustomizer
implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Override
public void customize(NettyReactiveWebServerFactory factory) {
factory.addServerCustomizers(serverCustomizers -> serverCustomizers
.childObserve(new CustomEncoderObserver())
);
}
}
public class CustomEncoderObserver implements ConnectionObserver {
@Override
public void onStateChange(@NonNull Connection connection, @NonNull State newState) {
if (newState == ConnectionObserver.State.CONNECTED) {
connection.channel().pipeline()
.addAfter(
NettyPipeline.HttpCodec, "", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(
@NonNull ChannelHandlerContext channelHandlerContext,
@NonNull Object message) {
if (message instanceof HttpRequest) {
HttpRequest request = (HttpRequest) message;
if (/* request.uri()를 받아와서 확인하고 싶은 포인트를 검증 */) {
request.setUri(/* uri를 변경한 것을 다시 SET */);
}
}
channelHandlerContext.fireChannelRead(message);
}
@Override
public boolean isSharable() {
return true;
}
});
}
}
}
Connection을 모니터링 한 후, connected 는 모든 연결에 최초 1회만 일어나기 때문에 이때 개입하여 특정 인코딩이 되지 않은 특수문자들에 대해서 수동으로 인코딩된 값으로 replace 하는 형태로 문제를 해결할 수 있었습니다.
'Development' 카테고리의 다른 글
개인용 Maven library github으로 셋업하기 (0) | 2023.01.24 |
---|---|
bytebuddy로 Java class 일부 method 교체하기 (해킹) (0) | 2023.01.24 |
Spring cloud gateway response body cache (0) | 2023.01.24 |
Spring cloud gateway request body cache (0) | 2023.01.24 |
Server test용 General Mock server 만들기 (0) | 2023.01.24 |