JavaURLエンコード/デコードのガイド
1. 概要
簡単に言うと、 URLエンコーディングは、特殊文字をURLから、仕様に準拠し、正しく理解および解釈できる表現に変換します。
このチュートリアルでは、 URLまたはフォームデータをエンコード/デコードして、仕様に準拠し、ネットワークを介して正しく送信する方法に焦点を当てます。
2. URLを分析します
まず、基本的なURI構文を見てみましょう。
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
URIをエンコードするための最初のステップは、URIの部分を調べてから、関連する部分のみをエンコードすることです。
次に、URIの例を見てみましょう。
String testUrl =
"http://www.baeldung.com?key1=value+1&key2=value%40%21%242&key3=value%253";
URIを分析する1つの方法は、文字列表現をjava.net.URIクラスにロードすることです。
@Test
public void givenURL_whenAnalyze_thenCorrect() throws Exception {
URI uri = new URI(testUrl);
assertThat(uri.getScheme(), is("http"));
assertThat(uri.getHost(), is("www.baeldung.com"));
assertThat(uri.getRawQuery(),
.is("key1=value+1&key2=value%40%21%242&key3=value%253"));
}
URI クラスは、文字列表現URLを解析し、getXXXなどの単純なAPIを介してその部分を公開します。
3. URLをエンコードする
URIをエンコードする場合、よくある落とし穴の1つは、完全なURIをエンコードすることです。 通常、URIのクエリ部分のみをエンコードする必要があります。
URLEncoderクラスのencode(data、encodingScheme)メソッドを使用してデータをエンコードしてみましょう。
private String encodeValue(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
}
@Test
public void givenRequestParam_whenUTF8Scheme_thenEncode() throws Exception {
Map<String, String> requestParams = new HashMap<>();
requestParams.put("key1", "value 1");
requestParams.put("key2", "value@!$2");
requestParams.put("key3", "value%3");
String encodedURL = requestParams.keySet().stream()
.map(key -> key + "=" + encodeValue(requestParams.get(key)))
.collect(joining("&", "http://www.baeldung.com?", ""));
assertThat(testUrl, is(encodedURL));
encode メソッドは、次の2つのパラメーターを受け入れます。
- data –変換される文字列
- encodingScheme –文字エンコードの名前
このencodeメソッドは、文字列を application /x-www-form-urlencoded形式に変換します。
エンコード方式は、特殊文字を「 %xy」の形式で表される8ビットの2桁の16進表現に変換します。 パスパラメーターを処理するとき、または動的なパラメーターを追加するときは、データをエンコードしてからサーバーに送信します。
注: World Wide Webコンソーシアムの推奨事項では、UTF-8を使用する必要があると規定されています。 そうしないと、非互換性が生じる可能性があります。 (参照: https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html )
4. URLをデコードします
URLDecoder のデコード方法を使用して、前のURLをデコードしてみましょう。
private String decode(String value) {
return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
}
@Test
public void givenRequestParam_whenUTF8Scheme_thenDecodeRequestParams() {
URI uri = new URI(testUrl);
String scheme = uri.getScheme();
String host = uri.getHost();
String query = uri.getRawQuery();
String decodedQuery = Arrays.stream(query.split("&"))
.map(param -> param.split("=")[0] + "=" + decode(param.split("=")[1]))
.collect(Collectors.joining("&"));
assertEquals(
"http://www.baeldung.com?key1=value 1&key2=value@!$2&key3=value%3",
scheme + "://" + host + "?" + decodedQuery);
}
ここで覚えておくべき2つの重要なポイントがあります。
- デコードする前にURLを分析する
- エンコードとデコードに同じエンコードスキームを使用する
デコードしてから分析すると、URL部分が正しく解析されない可能性があります。 別のエンコード方式を使用してデータをデコードすると、ガベージデータが発生します。
5. パスセグメントをエンコードする
URLのパスセグメントのエンコードにURLEncoderを使用することはできません。 パスコンポーネントは、ディレクトリパスを表す階層構造を指します。または、「/」で区切られたリソースを見つけるのに役立ちます。
パスセグメントの予約文字は、クエリパラメータ値とは異なります。 たとえば、「+」記号はパスセグメントで有効な文字であるため、エンコードしないでください。
パスセグメントをエンコードするには、代わりにSpringFrameworkのUriUtilsクラスを使用します。
UriUtils クラスは、パスとパスセグメントをそれぞれエンコードするためのencodePathメソッドとencodePathSegmentメソッドを提供します。
private String encodePath(String path) {
try {
path = UriUtils.encodePath(path, "UTF-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("Error encoding parameter {}", e.getMessage(), e);
}
return path;
}
@Test
public void givenPathSegment_thenEncodeDecode()
throws UnsupportedEncodingException {
String pathSegment = "/Path 1/Path+2";
String encodedPathSegment = encodePath(pathSegment);
String decodedPathSegment = UriUtils.decode(encodedPathSegment, "UTF-8");
assertEquals("/Path%201/Path+2", encodedPathSegment);
assertEquals("/Path 1/Path+2", decodedPathSegment);
}
上記のコードスニペットでは、 encodePathSegment メソッドを使用すると、エンコードされた値が返され、+はパスコンポーネントの値文字であるためエンコードされていないことがわかります。
テストURLにパス変数を追加しましょう。
String testUrl
= "/path+1?key1=value+1&key2=value%40%21%242&key3=value%253";
そして、適切にエンコードされたURLをアセンブルしてアサートするために、テストをセクション2から変更します。
String path = "path+1";
String encodedURL = requestParams.keySet().stream()
.map(k -> k + "=" + encodeValue(requestParams.get(k)))
.collect(joining("&", "/" + encodePath(path) + "?", ""));
assertThat(testUrl, CoreMatchers.is(encodedURL));
6. 結論
この記事では、データを正しく転送および解釈できるように、データをエンコードおよびデコードする方法について説明しました。
この記事はURIクエリパラメータ値のエンコード/デコードに焦点を当てていましたが、このアプローチはHTMLフォームパラメータにも適用されます。
いつものように、ソースコードはGitHubでから入手できます。