🕳️
Java WebClientで'+'(プラス記号)がスペースに置き換わってしまったときの対処法
概要
Java Spring BootのWebClientに'+'記号を含むクエリストリングを渡すと、スペースとして解釈されてしまった
- 例)元のURL
http://localhost:8080/sample/?date=2022-08-01T11:22:33+09:00
- WebClientによって変換されたURL
http://localhost:8080/sample/?date=2022-08-01T11:22:33 09:00
これでは、URLをデコードしてもスペースは+
に変換されず元のURLに戻すことが出来ない
- 期待していたURL
http://localhost:8080/sample/?date=2022-08-01T11:22:33%2B09:00
プラス記号をURLエンコードすると本来は%2B
となる。
そこで、WebClientのエンコード前後にプラス記号を%2B
にエンコードするインターセプターを挟むことで対処できたので、本記事その方法を紹介する。
対象
- Spring Bootフレームワークが提供する
WebClient
の利用を想定している -
RestTemplate
利用時の対処法は下記サイトを参照
対処法
RestTemplate
では、interceptors
メソッドが提供されており、引数にプラス記号をエンコードする処理するインターセプターを渡せば対応できる。
インターセプターはリクエストに対する共通の処理(エンコードやロギング、監視、認証など)を実行したい場合に適している。
一方で、WebClient
はこのメソッドが用意されていないため、似たような動作を行うfilter
メソッドを変わりに利用する。
実装例
以下では、WebClientを返すメソッドに、プラス記号を%2B
にエンコードするカスタムフィルターfilterPlusSignEncoding
をアタッチした実装例を紹介する
import org.apache.commons.lang3.StringUtils;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
/**
* WebClientの設定
*
* @return 設定が適用されたWebClientを返却
*/
public WebClient webClient() {
ConnectionProvider connectionProvider = ConnectionProvider.builder("tcp-client-pool")
.maxConnections(poolMaxTotal)
.build();
HttpClient httpClient = HttpClient.create(connectionProvider)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
.doOnConnected(conn -> conn
.responseTimeout(Duration.ofMillis(1000));
return WebClient.builder()
+ .filter(filterPlusSignEncoding())
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
/**
* プラス記号をエンコードするインターセプター
*
* @return エンコードを施したurlを含むClientRequestを返却する
*/
private ExchangeFilterFunction filterPlusSignEncoding() {
return (clientRequest, nextFilter) -> {
// プラス記号を%2Bにエンコードする
String encodedUrl = StringUtils.replace(clientRequest.url().toString(), "+", "%2B");
ClientRequest filteredRequest = ClientRequest.from(clientRequest)
.url(URI.create(encodedUrl))
.build();
return nextFilter.exchange(filteredRequest);
};
}
filterPlusSignEncoding
はインターフェースExchangeFilterFunction
を返すメソッドにしなければいけない。
また、作成したカスタムフィルターはWebClient.builder()
を使用することで追加できる。
結果
実装したwebClient
を使用することで、期待するURLでリクエストが可能になった。
http://localhost:8080/sample/?date=2022-08-01T11:22:33%2B09:00
まとめ
- WebClientをそのまま利用するとプラス記号がスペースに変換されてしまった
- RestTemplateでは、
interceptors
を使えば対処できるがWebClientでは用意されていない - WebClientでは
filter
メソッドを利用する - プラス記号を
%2B
へ変換するカスタムフィルターをアタッチすることで対処した
参考サイト
Discussion