ぱんだツールズぱんだツールズ

技術背景

URLエンコードとは — 日本語URLの%記法とパーセントエンコーディングの仕組み

約5分

ブラウザのアドレスバーに日本語を入力すると、%E6%9D%B1%E4%BA%ACのような謎の文字列に変わることがあります。また、フォームで送信したデータがURLに含まれるとき、 スペースや記号が文字化けしたように見えた経験はないでしょうか。これらはすべてURLエンコード(パーセントエンコーディング)と呼ばれる仕組みによるものです。 この記事では、URLエンコードが必要な理由、仕組み、JavaScriptでの正しい使い方、 そしてよくあるトラブルを解説します。

URLエンコードとは

URLに使える文字はRFC 3986によって厳しく制限されています。 許可されているのは英数字(A〜Z、a〜z、0〜9)と、一部の記号(- _ . ~)のみです。 日本語・スペース・その他の特殊記号はそのままURLに含めることができません。

そこで登場するのがURLエンコードです。許可されていない文字を%16進数2桁の組み合わせに変換することで、あらゆる文字をURLの中で安全に扱えるようにします。 「パーセントエンコーディング」という名前はこの「%記法」に由来します。

URLで使える文字・使えない文字

分類文字の例エンコードの要否
非予約文字A-Z a-z 0-9 - _ . ~変換不要
予約文字: / ? # [ ] @ ! $ & ' ( ) * + , ; =文脈次第で変換が必要
それ以外日本語・スペース・特殊記号など必ず変換が必要

予約文字はURLの構造(パスの区切り/、 クエリの始まり?、 フラグメント#など)を表すために使われています。 これらをクエリパラメータの値の中に含めたいときは、URLエンコードで別の文字として扱わせる必要があります。 また、スペースの扱いには注意が必要で、クエリ文字列では+%20の2通りが存在します(詳細は後述)。

エンコードの仕組み

URLエンコードは次の2ステップで行われます。

  1. 文字をUTF-8のバイト列に変換する
  2. 各バイトを%XX形式(Xは16進数1桁)に変換する

たとえば「東京」をURLエンコードする場合は以下の流れになります。

「東」→ UTF-8: E6 9D B1%E6%9D%B1

「京」→ UTF-8: E4 BA AC%E4%BA%AC

なぜUTF-8なのかというと、RFC 3986とHTML5の仕様でUTF-8が推奨されているからです。 古いシステムではShift_JISを使うURLも存在しましたが、現代のWebではUTF-8が標準です。 UTF-8の「東」は3バイト、「京」も3バイトなので、「東京」の2文字で合計6バイト(12文字のパーセント表記)になります。

JavaScriptでの使い分け

JavaScriptにはURLエンコード関連の関数が2組あります。エンコードする対象が「URL全体」なのか 「URLの一部(クエリパラメータの値など)」なのかによって使い分けます。

関数エンコードしない文字用途
encodeURI()A-Z a-z 0-9 - _ . ~ : / ? # [ ] @ ! $ & ' ( ) * + , ; =URL全体をエンコードするとき
encodeURIComponent()A-Z a-z 0-9 - _ . ~クエリパラメータの値などURLの一部をエンコードするとき
decodeURI()encodeURI() でエンコードしたURLをデコードするとき
decodeURIComponent()encodeURIComponent() でエンコードした値をデコードするとき

実際の使用例です。検索キーワードをURLに含める場合はencodeURIComponentを使います。

// NG: & が URL の区切り文字として解釈されてしまう

const url = '/search?q=' + '東京&2026'

// OK: クエリの値部分だけを encodeURIComponent でエンコード

const url = '/search?q=' + encodeURIComponent('東京&2026')

// → /search?q=%E6%9D%B1%E4%BA%AC%262026

よくあるトラブル

スペースが「+」になるケース

HTMLフォームを送信するときのデータ形式(application/x-www-form-urlencoded)では、 スペースは+としてエンコードされます。 これはRFC 3986のパーセントエンコーディング(スペース→%20)とは別の仕様です。 受け取るサーバーや処理ライブラリがどちらの形式を想定しているかによって解釈が変わるため、 混在すると意図しない文字列が生まれることがあります。

二重エンコードの罠

すでにエンコード済みの文字列を再度エンコードしてしまう「二重エンコード」は典型的なバグです。 たとえば%20をもう一度エンコードすると%2520%%25になる)になり、 サーバーでデコードしても%20という文字列が残ります。 予防策は「エンコードするのは必ず生のデータに対して行う」「デコード済みの値を受け取った後に再度エンコードする」という一方向の流れを徹底することです。

「%2F」(スラッシュ)がパスに含まれると403になる

スラッシュ/をエンコードすると%2Fになりますが、 Apacheなどの一部のWebサーバーはパスの中に%2Fが含まれると セキュリティ上の理由から403エラーを返すことがあります(AllowEncodedSlashes設定による)。 URLのパス部分にスラッシュを含む値を埋め込む設計は避け、代わりにクエリパラメータで渡すかパスを再設計することを検討してください。

ブラウザツールで手軽に確認する

URLエンコード・デコードを手軽に試したい場合は、URLエンコード/デコードツールが便利です。テキストを入力するだけでリアルタイムにエンコード・デコードでき、 日本語や特殊記号がどのように変換されるかをすぐに確認できます。 また、エンコードとBase64の違いを確認したい場合はBase64エンコード/デコードツールと並べて試してみると理解が深まります。 どちらのツールもブラウザ内で処理が完結するため、機密情報を含む文字列でも安心して使えます。

まとめ

  • URLに使える文字はRFC 3986で英数字と一部記号のみに制限されており、日本語などはそのまま含められない
  • URLエンコード(パーセントエンコーディング)は、許可されていない文字をUTF-8バイト列に変換してから%XX形式で表す仕組み
  • JavaScriptでは「URL全体」にはencodeURI、「URLの一部(クエリパラメータの値など)」にはencodeURIComponentを使う
  • スペースの表現は%20(RFC 3986)と+(フォームデータ形式)の2種類があり、使用する文脈によって異なる
  • 二重エンコードは「すでにエンコード済みの値を再エンコード」することで起きる典型的なバグ。常に生データに対してエンコードを適用する
  • URLエンコードはURLでの文字伝送に、Base64エンコードはバイナリデータのテキスト化に使う。目的が異なる

よくある質問

URLエンコードとは何ですか?

URLに直接含められない文字(日本語・スペース・特殊記号など)を「%」と16進数2桁の組み合わせに変換する仕組みです。「パーセントエンコーディング」とも呼ばれ、RFC 3986で定義されています。たとえば「東京」という文字列はUTF-8バイト列を通じて「%E6%9D%B1%E4%BA%AC」へ変換されます。

パーセントエンコーディングとURLエンコードは同じものですか?

はい、同じ仕組みを指しています。「URLエンコード」は一般的な呼び方で、「パーセントエンコーディング」はRFC 3986における正式な名称です。Webフォームの送信データ形式を指す「application/x-www-form-urlencoded」もほぼ同じ仕組みですが、スペースの扱いが「%20」ではなく「+」になるなど細部に差異があります。

日本語はなぜURLに使えないのですか?

URLで使える文字はRFC 3986によって英数字と一部の記号(-._~など)のみに制限されています。この制約はインターネットの黎明期にASCII文字を前提としたプロトコルとして設計されたためです。日本語のような非ASCII文字を含む場合、まずUTF-8のバイト列に変換してから各バイトを「%XX」形式にエンコードすることでURLに埋め込めるようにします。

スペースが「%20」と「+」の2種類があるのはなぜですか?

「%20」はRFC 3986によるパーセントエンコードの正規表現です。一方「+」はHTMLフォームのsubmit時に使われる「application/x-www-form-urlencoded」形式でのスペース表現です。APIのクエリパラメータやHTMLフォームのデータ送信では「+」を使うことが多いですが、パスの一部や一般的なURLエンコードでは「%20」を使います。受信側の実装によって解釈が変わるため、使用する場所に合わせた選択が重要です。

「encodeURI」と「encodeURIComponent」はどう使い分けるのですか?

「encodeURI」はURLの構造を保つ文字(:/?#[]@!$&'()*+,;=など)はエンコードせず、URLとして不正な文字だけをエンコードします。URL全体をエンコードするときに使います。「encodeURIComponent」はほぼすべての特殊文字(URLの構造文字も含む)をエンコードするため、クエリパラメータの値など「URLの一部」としてエンコードするときに使います。たとえば検索キーワードを「q=東京&2026」のようにURLへ埋め込む場合は「encodeURIComponent」が適切です。

URLエンコードとBase64エンコードの違いは何ですか?

目的が異なります。URLエンコードはURLに含められない文字を「%XX」形式に変換してURLで安全に使えるようにするための仕組みです。Base64エンコードはバイナリデータ(画像・PDFなど)をASCII文字列に変換して、テキストのみを扱えるプロトコルで送受信できるようにするための仕組みです。URLエンコードした文字列はURLに埋め込む目的で使い、Base64エンコードはHTMLのdata URIやAPIのレスポンスでバイナリを扱う目的で使います。

二重エンコードとは何ですか?どう防ぎますか?

二重エンコードとは、すでにエンコード済みの文字列を再度エンコードしてしまう問題です。たとえば「%20」を再度エンコードすると「%2520」(%を「%25」にエンコードした結果)になり、サーバー側でデコードしても「%20」という文字列が残って意図しない挙動になります。防ぐには「エンコード前の生のデータにのみエンコードを適用する」「すでにエンコード済みかどうかを先に確認する」という方針を徹底します。デコード後の値に再度エンコードを適用するのが正しい順序です。

ファイルはサーバーに送信されますか?

このツールはブラウザ内(JavaScript)で処理が完結するため、ファイルやテキストはサーバーに送信されません。URLエンコード・デコードの処理はすべてお使いの端末上で行われます。機密情報を含む文字列でも安心してお使いいただけます。

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