Googleで「ラーメン」と検索した後のURLを見たことはありますか?https://google.com/search?q=%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3 といった、見慣れない % だらけの文字列が並んでいます。これが URLエンコード(パーセントエンコーディング) です。
URLには「使ってよい文字」が厳密に決まっていて、日本語・スペース・記号などは直接書けません。そこで使われるのがURLエンコード。仕組みを理解しておくと、文字化けやリンク切れの謎が一気に解けます。
URLには「使える文字」が決まっている
URLの規格(RFC 3986)では、URLに使える文字は次の ASCIIの一部だけ と定められています。
- 英字(
A-Z a-z) - 数字(
0-9) - 記号のうち
- . _ ~(非予約文字) - 区切りに使う予約文字
: / ? # [ ] @ ! $ & ' ( ) * + , ; =
ここから漏れる文字、つまり日本語・スペース・<>・改行・絵文字などはすべて、URLにはそのままでは含められません。
この制限は1990年代初頭のインターネット黎明期に作られた古い仕様の名残ですが、世界中のサーバ・プロキシ・キャッシュ・ブラウザがこれを前提に動いているため、いまも生きています。
URLエンコードの仕組み — 1バイトを「%XX」に置き換える
ルールはシンプルです。
- 使えない文字を、UTF-8 のバイト列に変換する。
- 各バイトを
%+ 16進数2桁の形に置き換える。
例として「あ」を見てみましょう。
- 「あ」の UTF-8 バイト表現:
E3 81 82(3バイト) - URLエンコード後:
%E3%81%82
日本語1文字=UTF-8で3バイト=URLエンコードで9文字、という換算になります。「ラーメン」が %E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3 という長い文字列に化けるのはこのためです。
「+」と「%20」 — スペースが2通りある理由
URLでスペースを表す方法は 2つあります。
%20— RFC 3986 の標準的なパーセントエンコーディング。スペース(ASCII 0x20)をそのままエンコード。+— フォーム送信(application/x-www-form-urlencoded)専用の歴史的な略記。
どちらを使うかは 場所による のがポイント。
- パス部分(
/path/to/file):%20を使う。 - クエリ文字列(
?key=value):両方使えるが、ブラウザのフォーム送信は+を出す。
実害として、クエリ文字列で + をリテラルなプラス記号として送りたい場合(電話番号 +81-3-... など)は %2B とエンコードする必要があります。送信時に + のままだとサーバ側でスペースに復号されてしまうからです。
「予約文字」と「非予約文字」の使い分け
URLエンコードを すべき文字 と してはいけない文字 があります。
非予約文字(エンコード不要)
A-Z a-z 0-9 - . _ ~ はそのまま使ってOK。エンコードしても意味は同じですが、慣例として素のまま書きます。
予約文字(用途次第でエンコード)
: / ? # [ ] @ ! $ & ' ( ) * + , ; = はURLの構造上の意味を持つため、URLの「構造」として使う場合はそのまま、「データ」として使う場合はエンコードします。
例:クエリパラメータの値に & や = を含めたいとき。
- NG:
?q=R&B→ サーバは「q=R」と「B」という2つのパラメータと解釈してしまう - OK:
?q=R%26B→ 「q」というパラメータの値が「R&B」と正しく解釈される
encodeURI と encodeURIComponent — JavaScript の2つの関数
JavaScriptには2種類のURLエンコード関数があります。用途を間違えると変な動作になるので、違いをしっかり押さえましょう。
encodeURI() — 「URL全体」をエンコード
URL全体(プロトコル・ホスト・パス・クエリ・フラグメント)を渡す前提。区切り記号 :/?#[]@!$'()*+,;= はエンコードしないので、URL構造を壊さずに使えます。
例:encodeURI('https://example.com/?q=ラーメン') → https://example.com/?q=%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3。URLの構造はそのまま、日本語だけがエンコードされます。
encodeURIComponent() — 「値1つ」をエンコード
クエリパラメータの値やパスの一部など、URLの「部品」をエンコードする想定。区切り記号も含めて全部エンコードするので、データの中身が構造に影響しません。
例:encodeURIComponent('R&B') → R%26B。
使い分けの鉄則
- ユーザー入力をクエリパラメータに乗せるとき → encodeURIComponent
- 外部から渡されたURL文字列を整形するとき → encodeURI
- 自分でURLを組み立てるとき → 区切り記号は手で書き、値だけ encodeURIComponent
迷ったら encodeURIComponent の方が安全です。
URLSearchParams — 現代的なAPI
ブラウザにもNode.jsにも標準で入っている URLSearchParams を使うと、URLエンコードを意識せず安全にクエリを組み立てられます。
const params = new URLSearchParams({ q: 'R&B', page: '1' });params.toString() // → "q=R%26B&page=1"
手書きの ?q='...' + '&page=' + ... を組み立てる時代は終わりです。エンコード漏れや結合バグを防げるため、新規コードでは URLSearchParams を使うのが定番。
URLエンコードの「文字コード問題」
URLエンコードは 「バイト列を %XX で表す」 規則なので、元のバイト列の文字コードによって結果が変わります。
- 「あ」を UTF-8 で:
%E3%81%82 - 「あ」を Shift_JIS で:
%82%A0 - 「あ」を EUC-JP で:
%A4%A2
現代のWebでは UTF-8 が事実上の標準 ですが、古いシステムでは Shift_JIS や EUC-JP でエンコードされたURLがいまだに残っています。文字化けの原因がここにあることが多いです。
詳しい文字コードの背景は 文字コードと文字化けの基礎 でまとめています。
ハマりやすいポイント
二重エンコード
既にエンコード済みのURLをもう一度エンコードすると、% が %25 になり、%E3%81%82 が %25E3%2581%2582 になってしまいます。受け側は元の文字列を復元できず、文字化けや404の原因に。
URLを操作するときは「既にエンコード済みかどうか」を意識しましょう。リダイレクト処理や、ログ→ブラウザに貼り直しの操作で起きやすい事故です。
パス内の「/」をエンコードしてはいけないケース
encodeURIComponent はスラッシュ / も %2F にエンコードします。これをURLパスにそのまま使うと「/ 1文字」ではなく「%2F という値の一部」と解釈され、ルーティングが壊れることがあります。
対策:パスの構造を作る区切り / は手で書き、各セグメントだけ encodeURIComponent。
URLの最大長
仕様上の上限はありませんが、ブラウザは2,000〜8,000文字程度、サーバも8,000文字前後で切ることが多いです。日本語の長いクエリは、UTF-8 + URLエンコードで3倍に膨らむため、思ったよりすぐ上限に当たります。
長くなる場合はクエリでなく POSTボディに乗せる、もしくはサーバ側で短縮IDを発行する設計を検討します。
各言語での扱い方
- JavaScript:
encodeURI() / encodeURIComponent()、またはURLSearchParams。 - Python:
urllib.parse.quote() / quote_plus()。後者はスペースを+にする。 - PHP:
rawurlencode() / urlencode()。後者はフォーム形式(スペース→+)。 - Ruby:
URI.encode_www_form_component()。
本サイトの URLエンコード/デコードツール なら、コーディング不要で双方向の変換をブラウザ完結で試せます。日本語・記号・予約文字を含む文字列の挙動を、目で見て確認するのに便利です。
関連する変換方式
- Base64:バイナリをテキスト化する用途。URLエンコードと役割が異なる。詳しくは Base64エンコード徹底解説 へ。
- HTMLエンティティ:
&、<。HTMLの中に予約文字を表示するとき用。 - JavaScript文字列エスケープ:
\n、\"。JS の文字列リテラル内で使う。
どれも「文字列を安全な形に変換する」点は同じですが、適用される場面と目的が違います。区別を意識して使い分けましょう。
まとめ — 3つの覚えるべき要点
- URLには使える文字が決まっており、それ以外は
%XXの形にエンコードする。 - JavaScript なら
encodeURIComponentがほぼ常に正解。URL全体にはencodeURI。 - 現代の文字コードは UTF-8 で統一。Shift_JIS が混じると文字化けの元。
試しに変換してみたいときは本サイトの URLエンコードツール へどうぞ。コピペで即確認、データはブラウザの外に出ません。