LoginSignup
2
0

More than 5 years have passed since last update.

springのバージョンによってUriComponentsBuilderが"+"をエンコードしない

Posted at

現象

以下のようなコードでクエリパラメータをエンコードしたい、とする。

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("key", "a+b");
String u = UriComponentsBuilder.fromHttpUrl("http://www.google.com").queryParams(params).build().encode().toString();

System.out.println(u);

上記コードの結果は、以下表のように、spring-webのバージョンによって異なる。

spring-webのバージョン 結果
spring-boot1(spring-web-4.3.18.RELEASE) http://www.google.com?key=a%2Bb
spring-boot2(spring-web-5.0.4.RELEASE) http://www.google.com?key=a+b

新しい5.0では"+"がエンコードされなくなっている。

原因

https://stackoverflow.com/questions/50432395/whats-the-proper-way-to-escape-url-variables-with-springs-resttemplate-when-ca あたりに書いてあるが、クエリパラメータのエンコードの実装がRFC 3986ベースに変わったから、とかなんとか。

実装を確認する。HierarchicalUriComponentsというクラスが実際にエンコードを担当しており、その内部にエンコード対象かどうかを判定する箇所がある。

4.3ではこうなっている。

        QUERY_PARAM {
            @Override
            public boolean isAllowed(int c) {
                if ('=' == c || '+' == c || '&' == c) {
                    return false;
                }
                else {
                    return isPchar(c) || '/' == c || '?' == c;
                }
            }
        },

5.0ではこうなっており、"+"が外れているのが分かる。

        QUERY_PARAM {
            @Override
            public boolean isAllowed(int c) {
                if ('=' == c || '&' == c) {
                    return false;
                }
                else {
                    return isPchar(c) || '/' == c || '?' == c;
                }
            }
        },
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0