TegaruTools
開発者ガイド

URLエンコード完全ガイド|なぜ %E3%81%82 になるのか

URLに日本語を入れたときに現れる謎の文字列「%E3%81%82」の正体と、URLエンコードの仕組みを基礎から解説。予約文字・UTF-8・フォーム送信の +20 表現・encodeURI と encodeURIComponent の違いまで網羅します。

公開: 2026年6月17日読了 約8TegaruTools

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」に置き換える

ルールはシンプルです。

  1. 使えない文字を、UTF-8 のバイト列に変換する。
  2. 各バイトを % + 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を発行する設計を検討します。

各言語での扱い方

  • JavaScriptencodeURI() / encodeURIComponent()、または URLSearchParams
  • Pythonurllib.parse.quote() / quote_plus()。後者はスペースを + にする。
  • PHPrawurlencode() / urlencode()。後者はフォーム形式(スペース→ +)。
  • RubyURI.encode_www_form_component()

本サイトの URLエンコード/デコードツール なら、コーディング不要で双方向の変換をブラウザ完結で試せます。日本語・記号・予約文字を含む文字列の挙動を、目で見て確認するのに便利です。

関連する変換方式

  • Base64:バイナリをテキスト化する用途。URLエンコードと役割が異なる。詳しくは Base64エンコード徹底解説 へ。
  • HTMLエンティティ&amp;&lt;。HTMLの中に予約文字を表示するとき用。
  • JavaScript文字列エスケープ\n\"。JS の文字列リテラル内で使う。

どれも「文字列を安全な形に変換する」点は同じですが、適用される場面と目的が違います。区別を意識して使い分けましょう。

まとめ — 3つの覚えるべき要点

  1. URLには使える文字が決まっており、それ以外は %XX の形にエンコードする。
  2. JavaScript なら encodeURIComponent がほぼ常に正解。URL全体には encodeURI
  3. 現代の文字コードは UTF-8 で統一。Shift_JIS が混じると文字化けの元。

試しに変換してみたいときは本サイトの URLエンコードツール へどうぞ。コピペで即確認、データはブラウザの外に出ません。

この記事で紹介したツール

関連するガイド記事