javaspringspring-webflux

How to encode properly the plus sign (+) when making a request with webflux webclient?


I am trying to send an international formatted phone number using spring Webflux Webclient and to read this phone number via another application also using webflux.

My code looks like this :

webClient = WebClient.builder()
            .baseUrl(baseUrl)
            .build();

return webClient
            .get()
            .uri(uriBuilder -> uriBuilder
                    .path("/endpoint")
                    .queryParam("phone-number", "+33612345678")
                    .build()
            )
            .retrieve()
            .bodyToMono(String.class);

Unfortunately, somewhere between this call and the receiver, the plus sign is replaced by a space. The endpoint receives : " 33612345678" as a String.

The netty debug log of the request shows this :

+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 63 75 73 74 6f 6d 65 72 73 3f 70 |GET  /endpoint?p|
|00000010| 68 6f 6e 65 2d 6e 75 6d 62 65 72 3d 2b 33 33 36 |hone-number=+336|
|00000020| 31 32 33 34 35 36 37 38 26 6f 6e 6c 79 2d 72 65 |12345678

I tried to encode the phone-number by myself like this :

.queryParam("phone-number", UriUtils.encode("+34612345678", StandardCharsets.UTF_8))

And netty's log shows :

+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 63 75 73 74 6f 6d 65 72 73 3f 70 |GET  /endpoint?p|
|00000010| 68 6f 6e 65 2d 6e 75 6d 62 65 72 3d 25 32 35 32 |hone-number=%252|
|00000020| 42 33 34 36 31 32 33 34 35 36 37 38 20 48 54 54 |B34612345678 HTT|

It seems that the phone number has been encoded twice.

+ -> %2B -> %252B

the plus sign has been encoded by UriUtils.encode then uriBuilder has encoded the %.

The only way I found to make it work is by disabling the encoding of the UriBuilder :

 DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
    factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
    this.webClient = WebClient.builder()
            .baseUrl(baseUrl)
            .uriBuilderFactory(factory)
            .build();

and having my custom encoding UriUtils.encode("+34612345678", StandardCharsets.UTF_8)

in which case the netty's logs looks like expected :

+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 63 75 73 74 6f 6d 65 72 73 3f 70 |GET  /endpoint?p|
|00000010| 68 6f 6e 65 2d 6e 75 6d 62 65 72 3d 25 32 42 33 |hone-number=%2B3|
|00000020| 34 36 31 32 33 34 35 36 37 38 20 48 54 54 50 2f |4612345678 HTTP/|

And of course, the endpoint receiving the phone number get : "+33612345678"

To sum it up, it looks like the UriBuilder is encoding certain sign like "%" but does not encode the "+" sign. Spring reference : https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#web-uri-encoding


Solution

  • I struggled with same issue but found a workaround from the Spring reference you linked.

    This should work for you:

    return webClient
                .get()
                .uri(uriBuilder -> UriComponentsBuilder.fromUri(uriBuilder.build())
                        .path("/endpoint")
                        .queryParam("phone-number", "{phone-number}")
                        .encode()
                        .buildAndExpand("+33612345678")
                        .toUri()
                )
                .retrieve()
                .bodyToMono(String.class);