Description
WebClient using built in JdkClientHttpConnector sends a empty Cookie header even if there are no cookies added to the request.
The empty Cookie header seems to create trouble with some infrastructure components like LoadBalancers and Firewalls, e.g. the request can end up being rejected.
Example request that is generated.
GET https://some-api.host.tld
Accept: application/json
Content-Length: 0
Host: some-api.host.tld
User-Agent: Java-http-client/17.0.7
Cookie:
The issue (Cookie header) is not present when using the Netty or Jetty reactive client implementations.
The header seems to be applied in JdkClientHttpRequest#applyCookies() method, and by the implementation it looks like it ends up adding the Cookie header even if there are no cookies. There is no way to override or remove this header when setting up a request using the WebClient, as it's added after all interception points that client code can use to remove it.
JdkClientHttpRequest:
@Override
protected void applyCookies() {
this.builder.header(HttpHeaders.COOKIE, getCookies().values().stream()
.flatMap(List::stream).map(HttpCookie::toString).collect(Collectors.joining(";")));
}
This ends up calling the builder with a empty string as value if there are no cookies, which passes the header validation and we end up "automagically" getting a unwanted Cookie header on all our requests. As mentioned some Loadbalancers, Firewalls, API Gateways etc. do not allow this type of header (not sure what the RFC says), and the only workaround using the JDK client seems to be to set some dummy cookie so that the header is set to something like Cookie: dummy=dummy; Getting rid of the header do not seem possible from client code.
ReactorClientHttpRequest (Netty):
@Override
protected void applyCookies() {
getCookies().values().forEach(values -> values.forEach(value -> {
DefaultCookie cookie = new DefaultCookie(value.getName(), value.getValue());
this.request.addCookie(cookie);
}));
}
In this implementation a Cookie header is only added if there are any cookies to add.
Spring Boot 3.2, Spring Framework version 6.1.1