LASSIC Media らしくメディア

2026.07.26 らしくコラム

URLエンコードの仕組み|パーセント記法と注意点

URLエンコードとは

プログラムコード

URLに使える文字は、実は限られています。半角の英数字や一部の記号だけが直接使える対象で、日本語のような非ASCII文字や、スペース・一部の記号はそのままでは使えません。これらの文字を「%」に続けて16進数2桁を並べた形式に変換して表す仕組みが、URLエンコード(パーセントエンコーディング)です。たとえば半角スペースは%20、疑問符「?」は%3Fという並びに置き換わります。

サーバールーム

本記事が扱うのは、あくまでURLの中で文字を問題なくやり取りするためのパーセントエンコーディングです。文字そのものをコンピュータ内部でどう符号化するか(文字コード・UTF-8やShift_JISといった一般論)は別テーマであり、本記事では変換の土台として触れる程度にとどめます。URLエンコードは、その文字コードの仕組みを利用しつつ、URLという限られた文字種のフィールドに情報を載せるための、もう一段上のルールだと捉えておくと整理しやすいでしょう。

普段ブラウザでURLを扱う際には意識しない場面が多いものですが、フォームの検索キーワードに日本語を入力した瞬間や、APIのクエリパラメータに記号を含む値を渡す場面では、この変換が裏側で常に働いています。開発担当者やプロジェクトマネージャーの立場でも、リンク切れやパラメータの文字化けといった不具合報告を受けた際に、この仕組みを理解しているかどうかで原因の切り分けやすさが変わってきます。

なぜURLエンコードが必要か

URLには、構造を表すために特別な意味を割り当てられた記号がいくつも含まれています。代表的なものは次のとおりです。

  • ?: パスとクエリ文字列(パラメータ部分)の区切りを表します。
  • &: 複数のクエリパラメータをつなぐ区切り記号です。
  • =: クエリパラメータのキーと値を結びつける記号です。
  • /: パスの階層を区切る記号です。
  • #: フラグメント(ページ内アンカー)の開始を示す記号です。
  • 空白: URLの区切りとして解釈される恐れがあり、そのままでは扱いにくい文字です。

これらの記号は、URLの中で使われる位置によって「区切り」としての意味を持ちます。もし検索キーワードの値の中に「&」がそのまま含まれていると、システムはそこをパラメータの区切りだと誤って解釈してしまい、意図した値が正しく渡らなくなるものです。こうした事態を防ぐため、値の中身として使いたい記号は%XX形式に変換し、構造を示す記号と区別できるようにしておく必要があります。

URLで使える文字は、大きく「予約文字(reserved characters)」と「非予約文字(unreserved characters)」に分けられます。予約文字は上記のような構造上の意味を持つ記号群で、非予約文字は英数字とハイフン・アンダースコア・ピリオド・チルダなど、URLの中でそのまま使ってよいとされる文字です。日本語をはじめとするASCII以外の文字は、この非予約文字にも予約文字にも当たらないため、いずれにしてもパーセントエンコーディングによる変換が求められます。この区別を細かく覚えておく必要はありませんが、「構造を表す記号」と「そのまま使える記号」が分かれているという発想は、後述する実装時の判断にも関わってくる考え方です。

どう変換されるか(パーセント記法の仕組み)

パーセントエンコーディングの変換手順は、次の2段階で成り立っています。

  1. 対象の文字を、まずUTF-8のバイト列に変換します。
  2. そのバイト列の各バイトを、「%」+16進数2桁という形式で表します。

英数字1文字はUTF-8で1バイトに収まるため、変換後も%XXが1つ付くだけで済みますが、日本語のように1文字が複数バイトになる文字は、その分だけ%XXが連続して並びます。実際の変換例を対比表で確認してみましょう。

元の文字 UTF-8のバイト列 エンコード結果
半角スペース 0x20 %20
? 0x3F %3F
& 0x26 %26
あ(日本語) 0xE3 0x81 0x82 %E3%81%82

「あ」という1文字が、UTF-8では3バイトの並びになり、結果として%E3%81%82という3組の%XXに展開される点がポイントです。日本語の文章をエンコードすると、元の文字数に比べて見た目の文字列が大きく長くなるのは、この1文字あたり複数バイトという性質によるものです。

ここで押さえておきたいのが、スペースの扱いに2通りの流儀がある点です。URLの本体部分やパスをエンコードする一般的なパーセントエンコーディングでは、スペースは%20になります。一方、HTMLフォームの送信で使われるapplication/x-www-form-urlencodedという形式では、スペースは慣習的に「+」で表されます。これはWeb初期のフォーム送信のために定められた、パーセントエンコーディングの一種の別バージョンです。両者は混同されやすく、「+」を単純に%20へ置き換えるだけの処理を書いてしまうと、逆に元々「+」という文字自体を値に含めたいケースで意図しない変換が起きることもあるため、どちらの文脈で扱っているコードなのかを意識しておくことが大切です。

もう一つ実務で押さえておきたいのが、URL全体をエンコードする用途とパラメータ1つの値をエンコードする用途とで、使う関数が異なるという点です。JavaScriptを例にすると、encodeURIはURLの構造を表す「/」「:」「?」「&」などをエンコード対象から外し、URLとしての形をおおむね保ったまま非予約文字以外を変換します。一方encodeURIComponentは、クエリパラメータの値のように「そこだけを切り出して渡したい」文字列を対象にした関数で、「/」や「&」を含めほとんどの記号を変換します。どちらもパーセントエンコーディングという同じ仕組みの上に成り立っていますが、対象がURL全体なのかパラメータの値1つなのかで使い分ける、という考え方は覚えておくとよいでしょう。

実務で問題になる場面

URLエンコードの仕組みそのものはシンプルですが、実装や運用の現場では、次のような形でつまずきが起きやすいポイントがあります。

  • 二重エンコード: すでに%XX形式にエンコード済みの値を、気づかずもう一度エンコードしてしまう不具合です。たとえば%3Fという文字列をそのまま再度エンコードすると、「%」自体が0x25というバイトに変換され、%253Fという二重の並びになってしまいます。受け取り側で一度しかデコードしない実装だと、値が本来の形に戻らず、そのまま画面や検索条件に表示されてしまう恐れがあるものです。
  • エンコード漏れ: 逆に、本来エンコードすべき記号をそのままURLに埋め込んでしまうケースです。パラメータの値に「&」や「#」がそのまま入っていると、区切り記号と誤認されてリンク切れやパラメータの一部欠落を招きます。
  • フォーム送信・APIのクエリパラメータ: ユーザー入力をそのままURLの一部として組み立てる処理では、入力値に含まれる記号や日本語の扱い次第で、送信先での値の受け取り方が変わってきます。
  • 日本語ドメイン・日本語ファイル名: 日本語を含むドメイン(国際化ドメイン名)やファイル名をURLに含める場合も、内部的にはパーセントエンコーディングや専用の変換方式を経由しており、単純な文字列比較では一致しないことがある点に注意が必要です。
  • ブラウザのアドレスバー表示との食い違い: 多くのブラウザは、アドレスバーに表示する際、日本語部分の%XXを元の文字に戻して見せています。表示上は日本語のままでも、コピーしたテキストやログに残るURLはエンコード済みの%XXの並びになっていることがあり、見た目と実際の文字列が異なる点を知らないまま比較・検索して不具合の原因を見誤るケースもあるものです。

下図は、スペースや日本語の文字がUTF-8のバイト列を経て%XXの並びに変換される流れと、二重エンコードが起きる様子を示したものです。

図

いずれのケースも、値がどの時点でエンコード済みなのか、これからエンコードすべき生の文字列なのかという状態管理があいまいになることが根本の原因になっています。ライブラリやフレームワークの内部でエンコードが自動的に行われている箇所に対して、開発者が手動で追加のエンコードをかけてしまう、という組み合わせで二重エンコードが起きるケースは特に見かけやすいものです。

実装時のポイント

URLエンコードを扱う実装では、次のような点を意識しておくと、不具合を避けやすくなります。

  • 言語・フレームワークの標準関数を使う: JavaScriptのencodeURIComponent、PythonのurllibやPHPのrawurlencodeなど、各言語には仕様に沿ったエンコード関数が用意されています。文字の変換規則を自前で実装しようとすると、対象文字の範囲や記号の扱いに抜け漏れが生まれやすく、標準関数に任せるほうが結果として手堅い選択になります。
  • エンコードすべき箇所を正しく選ぶ: URL全体を一括でencodeURIComponentのような関数にかけてしまうと、「/」や「?」といった構造を表す記号までエンコードされ、URLとして機能しなくなります。パスの各セグメントやクエリの値(パラメータの中身)だけを部分的にエンコードし、URLの構造そのものを表す記号は変換しない、という区別が求められます。
  • 文字コードはUTF-8で統一する: エンコード側とデコード側で前提とする文字コードがずれていると、同じ%XXの並びから異なる文字が復元されてしまいます。フロントエンド・API・データベースの各層でUTF-8に統一しておくことが、文字化けを避ける土台になります。
  • デコード回数を送信側のエンコード回数とそろえる: プロキシやCDN、フレームワークのルーティング層など、複数の箇所でエンコード・デコードが行われるシステムでは、どこで何回変換が行われるのかを整理しておくと、二重エンコードや逆に未デコードの値が残る問題を見つけやすくなります。

発注担当者やプロジェクトマネージャーの立場では、こうした実装の細部まで直接確認する場面は多くないでしょう。ただ、日本語を含む検索キーワードのリンクが正しく開けない、フォームから送った値が一部欠けているといった不具合報告を受けた際に、URLエンコードという仕組みの存在を知っておくと、開発チームへの状況確認や原因の切り分けがしやすくなります。

受け入れテストの観点でも、URLエンコードは見落とされやすい領域です。半角英数字だけの入力値では問題なく動作していても、日本語や記号を含む値を試していないためにリリース後の本番環境で初めて不具合が判明する、というケースは珍しくありません。テスト計画の中に「日本語を含む検索キーワード」「&や#を含む値」「スペースを含む値」といった観点を明示的に組み込んでおくことが、URLエンコード起因の不具合を事前に洗い出す手がかりになるでしょう。

まとめ

URLエンコードは、URLで直接使えない日本語や記号・スペースを、UTF-8のバイト列を経て%XX形式に置き換える仕組みです。「?」や「&」のようにURLの構造を表す記号を、値の中身と区別するために欠かせないルールになります。実務では、すでにエンコード済みの値をもう一度変換してしまう二重エンコードや、逆にエンコードすべき記号を漏らしてしまうことによるリンク切れ・パラメータ破損が起きやすいポイントです。標準のエンコード関数を使い、エンコードすべき範囲を正しく見極め、文字コードをUTF-8に統一しておくことが、トラブルの少ない実装につながります。

相談するメリット

URL設計やAPI連携、多言語対応を含むシステムでは、パーセントエンコーディングの扱いが甘いまま公開されているケースが少なくありません。日本語を含むパラメータでリンクが開けない、二重エンコードで検索条件が崩れる、日本語ファイル名を含むダウンロードURLが環境によって文字化けするといった不具合は、開発の後半や本番運用に入ってから表面化しがちです。LASSICでは、ニアショア開発体制を生かした受託開発の中で、URL設計やAPI連携部分の点検、多言語対応システムにおける文字化け・リンク切れの洗い出しに対応しています。既存システムの点検や新規開発でお困りの際は、お気軽にご相談ください。

よくある質問

なぜ日本語のURLは長い%記号の羅列になるのですか。

日本語の1文字はUTF-8で表すと3バイト前後になることが多く、パーセントエンコーディングではその各バイトごとに%XXが1組付くためです。「あ」という1文字だけでも%E3%81%82という3組の並びになるため、日本語の文章をエンコードすると、見た目の文字数に比べて元の文字数からは想像しにくいほど長い文字列になります。

「+」と「%20」の違いは何ですか。

どちらもスペースを表しますが、使われる文脈が異なります。%20は一般的なパーセントエンコーディングでのスペースの表し方で、URLのパス部分などで使われるものです。一方「+」は、HTMLフォームの送信形式であるapplication/x-www-form-urlencodedという文脈での慣習的な表現であり、両者を混同すると、値の中に本来含めたい「+」という文字まで誤って変換してしまうことがあります。

二重エンコードはどうやって見つければよいですか。

URLの中に%25という並びが出てきていないかを確認するのが手がかりの一つです。%25は「%」自体をエンコードした結果であり、すでにエンコード済みの値を再度エンコードした際に現れやすい記号です。エンコード・デコードの処理がどの層で何回行われているかを、リクエストのログなどで一度整理してみることをおすすめします。

URL全体をencodeURIComponentのような関数に一括でかけても問題ありませんか。

おすすめできません。encodeURIComponentはURLの構造を表す「/」「?」「&」なども変換対象にしてしまうため、URL全体にかけるとリンクとして機能しなくなることがあります。パスの各セグメントやクエリパラメータの値部分だけを個別にエンコードし、URLの構造を示す記号はそのまま残す、という使い分けが必要です。

著者:テレリモ総研編集部 鈴木 亮佑

URLエンコードの扱いを含むAPI連携やURL設計、多言語対応の点検でお困りの際は、ニアショア開発によるコスト最適化と品質確保を両立するLASSICにご相談ください。要件のヒアリングから設計、実装まで伴走いたします。

出典


View