Spring の UriComponentsBuilder のちょっと罠っぽいところ
UriComponentsBuilder は以下のように、URIの構築を簡単にできるやつです。 Spring とか使っている人だと使ったことあると思います。
String result = UriComponentsBuilder
.fromUriString("https://example.com/")
.queryParam("hoge", "あ")
.toUriString();
assertThat(result).isEqualTo("https://example.com/?hoge=%E3%81%82");
最近使っていて気づいたのですが、UriComponentsBuilder.fromUriString(str) or UriComponentsBuilder.fromHttpUrl(str) に渡す URI string に query がついている場合、その部分も encode されるという挙動をします。
つまり、予め encodeしていると2重に encode されてしまうわけです。
こんな感じです。
String result = UriComponentsBuilder
.fromHttpUrl("https://example.com/?nextPath=%2Fpath%2Fto%2Fsome%2Fpage") // "/path/to/some/page"
.queryParam("hoge", "あ")
.toUriString();
assertThat(result).isNotEqualTo(
"https://example.com/?nextPath=%2Fpath%2Fto%2Fsome%2Fpage&hoge=%E3%81%82");
assertThat(result).isEqualTo(
"https://example.com/?nextPath=%252Fpath%252Fto%252Fsome%252Fpage&hoge=%E3%81%82");
んー。個人的には、queryParam で指定した部分だけのほうが直感的だと思いますが...。
参考までに、Apache HttpClient にある URIBuilder だと query 部分が2重にencodeされるということはありません。
String result = new URIBuilder("https://example.com/?nextPath=%2Fpath%2Fto%2Fsome%2Fpage") .addParameter("hoge", "あ") .build().toString(); assertThat(result).isEqualTo( "https://example.com/?nextPath=%2Fpath%2Fto%2Fsome%2Fpage&hoge=%E3%81%82");