URLエンコードは「URLの中で暴れる文字をおとなしくさせる」技
業務システムで外部APIを叩くとき、ブラウザからのリダイレクトURLを組み立てるとき、クエリパラメータを自前で作るとき。
そのたびに出てくるのが「URLエンコード」です。
URLエンコードの本質は、「URLの中で特別な意味を持つ文字(スペース、日本語、記号など)を、そのままでは壊れない“安全な形”に変換する」ことです。
これを雑にやると、「日本語が文字化けする」「& や = を含む値でクエリが壊れる」「API が 400 を返す」といった、地味に痛いバグが出ます。
URLエンコードのざっくりしたイメージ
「そのまま置けない文字を %XX 形式に逃がす」
URLの中では、? や &、=、# などは特別な意味を持ちます。
また、日本語やスペースなどの非ASCII文字も、そのままでは安全に運べません。
URLエンコードは、そういった文字を「%」+16進数2桁のコードに変換します。
例えば、スペースは %20、あ は %E3%81%82 のようになります。
重要なのは、「URLエンコードは“値”に対して行うものであって、“URL全体を丸ごとエンコードするものではない”」という感覚です。
特にクエリパラメータでは、? や &、= は構造を表す記号なので、そこはエンコードせず、値の部分だけをエンコードします。
Javaでの基本:URLEncoder をそのまま使わない、ユーティリティで包む
URLEncoder の「罠」を理解する
Java には java.net.URLEncoder というクラスがあります。
これを使えば簡単に URLエンコードできますが、そのまま使うと微妙な罠があります。
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class RawUrlEncodeExample {
public static void main(String[] args) throws UnsupportedEncodingException {
String encoded = URLEncoder.encode("こんにちは 世界", "UTF-8");
System.out.println(encoded);
}
}
Java出力はこうなります。
%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF+%E4%B8%96%E7%95%8C
ここでのポイントは、「スペースが %20 ではなく + に変換されている」ことです。
これは「HTMLフォームの application/x-www-form-urlencoded 形式」に合わせた仕様で、
クエリパラメータでは一般的に許容されますが、「URL全体のパス部分」などでは %20 を期待されることもあります。
また、URLEncoder.encode は第二引数に文字コード名(”UTF-8″ など)を文字列で渡す必要があり、
タイプミスしてもコンパイルエラーにならない、という地味にイヤな仕様です。
そのため、業務コードでは URLEncoder をそのまま散らばらせるのではなく、
「UTF-8 固定」「用途を明示した」ユーティリティで包んでしまうのがおすすめです。
URLエンコード用の小さなユーティリティを作る
クエリパラメータ用の encode を一箇所に集約する
まずは、「クエリパラメータの値をエンコードする」ことに特化したユーティリティを作ります。
import java.io.UncheckedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public final class UrlEncoders {
private UrlEncoders() {}
public static String encodeQueryParam(String value) {
if (value == null) {
return "";
}
try {
return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new UncheckedIOException(e);
}
}
}
Javaここで深掘りしたい重要ポイントは三つです。
一つ目は、「UTF-8 を固定している」ことです。
業務システムでは、URLエンコードの文字コードはほぼ確実に UTF-8 です。
毎回 “UTF-8” と書くのではなく、StandardCharsets.UTF_8.name() を使うことで、タイプミスのリスクを減らしています。
二つ目は、「null を空文字として扱う」という方針を決めていることです。
ここはプロジェクトの方針次第ですが、「クエリパラメータに null を渡したら空文字にする」と決めておくと、呼び出し側が楽になります。
三つ目は、「チェック例外 UnsupportedEncodingException を、UncheckedIOException にラップして投げ直している」ことです。
UTF-8 は Java 標準で必ずサポートされているので、本来この例外は起きません。
そのため、「起きたらプログラミングミス」とみなして、ランタイム例外にしてしまう設計がよく使われます。
例題:クエリ文字列を安全に組み立てるユーティリティ
「&」や「=」を自分で意識しないで済むようにする
URLエンコードが必要になる典型的な場面が、「クエリ文字列の組み立て」です。
これを毎回手書きでやると、& の付け忘れやエンコード漏れが起きやすくなります。
そこで、「キーと値を渡すと、クエリ文字列を組み立ててくれる」ユーティリティを作ります。
public final class QueryStringBuilder {
private final StringBuilder sb = new StringBuilder();
private boolean first = true;
public QueryStringBuilder add(String name, String value) {
if (!first) {
sb.append('&');
} else {
first = false;
}
sb.append(UrlEncoders.encodeQueryParam(name));
sb.append('=');
sb.append(UrlEncoders.encodeQueryParam(value));
return this;
}
public String build() {
return sb.toString();
}
}
Java使い方はこうです。
QueryStringBuilder qs = new QueryStringBuilder()
.add("q", "Java URL エンコード")
.add("page", "1")
.add("sort", "created_at desc");
String url = "https://example.com/search?" + qs.build();
System.out.println(url);
Java出力イメージは次のようになります。
https://example.com/search?q=Java+URL+%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89&page=1&sort=created_at+desc
ここでの重要ポイントは、「呼び出し側は“& や = を一切意識せず、キーと値だけを渡している」ことです。
URLエンコードも、パラメータの連結も、すべて QueryStringBuilder の中に閉じ込められています。
こうしておくと、「パラメータが増えた」「値にスペースや日本語が入るようになった」といった変更にも、呼び出し側はほぼ無傷で対応できます。
例題:リダイレクトURLに「戻り先URL」を埋め込む
URLの中にさらにURLを入れるときこそ、エンコードが必須
業務でよくあるのが、「ログイン画面にリダイレクトするとき、ログイン後の戻り先URLをクエリパラメータに載せる」というパターンです。
例えば、こんな URL を作りたいとします。
https://example.com/login?redirect=https://example.com/app/home?tab=profile
このままだと、redirect の値の中に ? や & が含まれているため、クエリの構造が壊れてしまいます。
そこで、「redirect の値としての URL」を丸ごと URLエンコードする必要があります。
String redirectTo = "https://example.com/app/home?tab=profile";
String encodedRedirect = UrlEncoders.encodeQueryParam(redirectTo);
String url = "https://example.com/login?redirect=" + encodedRedirect;
System.out.println(url);
Java出力イメージはこうです。
https://example.com/login?redirect=https%3A%2F%2Fexample.com%2Fapp%2Fhome%3Ftab%3Dprofile
ここで深掘りしたいのは、「“URL全体”をエンコードするのではなく、“クエリパラメータの値としての URL”をエンコードしている」という点です。
外側の ? や & は構造を表す記号なのでそのまま、
内側の URL は「値」として扱うので、: や /、?、= を含めてエンコードします。
この「どこまでが構造で、どこからが値か」を意識できるようになると、URLエンコードの使いどころが一気にクリアになります。
URLエンコードで気をつけたいポイント
「パス部分」と「クエリ部分」で扱いを分ける
URLエンコードは、主にクエリパラメータの値に対して使うことが多いですが、
パス部分(/users/山田太郎 のようなところ)に日本語やスペースを含めたい場合にも必要になります。
ただし、パス部分のエンコードは URLEncoder よりも java.net.URI や java.net.URLEncoder 以外の手段を使うことも多く、
「パス用」「クエリ用」を分けて考えるのが現実的です。
初心者のうちは、まず「クエリパラメータの値は必ず encodeQueryParam を通す」というルールから始めるとよいです。
パス部分のエンコードは、必要になったときに少し深掘りする、くらいで十分です。
「二重エンコード」をしない
よくある失敗が、「すでにエンコード済みの文字列を、もう一度エンコードしてしまう」パターンです。
例えば、%E3%81%82 という文字列をさらに URLエンコードすると、%25E3%2581%2582 のように % 自体がエンコードされてしまいます。
これをサーバ側で一回だけデコードしても、元の あ には戻りません。
「どの時点でエンコードしたか」「どの時点でデコードするか」を設計として決めておき、
「同じ値を複数回エンコードしない」という意識を持つことが大事です。
まとめ:URLエンコードユーティリティで身につけたい感覚
URLエンコードは、「URLの中で暴れそうな文字を、おとなしく安全な形に変える」ための技です。
押さえておきたい感覚は、まず「URLエンコードは“値”に対して行うものであり、URL全体を丸ごとエンコードするものではない」こと。
次に、「URLEncoder をそのまま散らばらせず、UTF-8 固定・用途別(クエリ用など)のユーティリティに閉じ込める」こと。
そして、「クエリ文字列の組み立てをユーティリティに任せることで、& や =、エンコード漏れといった細かいミスを根こそぎ減らす」ことです。
