ホーム技術ガイドURL / URI Component Encoder & Decoder
ENESJADEPT
技術設計・詳細実践ガイド

URL / URI コンポーネント エンコーダー&デコーダー:技術アーキテクチャと詳細実践ガイド

Uniform Resource Identifier(URI)および Uniform Resource Locator(URL)は、ワールドワイドウェブ(WWW)におけるリソース指定の基盤プロトコルです。[RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) および [WHATWG URL Living Standard](https:

47 分で読める
9275 文字
完全ローカル実行・通信ゼロ
インタラクティブツール提供中

ブラウザ上で100%ローカル実行・サーバー通信ゼロで即座に利用可能。

オンラインツールを開く

# URL / URI コンポーネント エンコーダー&デコーダー:技術アーキテクチャと詳細実践ガイド

Uniform Resource Identifier(URI)および Uniform Resource Locator(URL)は、ワールドワイドウェブ(WWW)におけるリソース指定の基盤プロトコルです。blank" rel="noopener noreferrer" class="text-emerald-400 hover:text-emerald-300 underline underline-offset-4 decoration-emerald-500/40 hover:decoration-emerald-400 font-medium transition inline-flex items-center gap-0.5">RFC 3986 および WHATWG URL Living Standard によって統括される Web アドレス体系は、プロキシ、ロードバランサー、API ゲートウェイ、分散マイクロサービス間における決定論的なルーティングを保証するため、極めて厳格な構文上の制約を課しています。

クエリ文字列(Query Strings)、パスセグメント(Path Segments)、あるいはフォーム送信ペイロード(Form Payloads)を介してデータを伝送する際、記号、半角スペース、非 ASCII Unicode 文字(日本語の漢字・ひらがな等)、バイナリデータなどの任意文字は、パーセントエンコーディング(Percent-Encoding / URL エンコード) と呼ばれる US-ASCII 準拠フォーマットへ変換されなければなりません。不適切なエスケープ処理は、パラメータの欠落やルーティング障害を招くだけでなく、オープンリダイレクト(Open Redirect)や SSRF(Server-Side Request Forgery)などの重大な脆弱性、さらには実行時における未捕捉の URIError: URI malformed クラッシュを引き起こす主因となります。

ToolsAA URL / URI コンポーネント エンコーダー&デコーダー(URL Encoder & Decoder Online) は、高速かつ高精度な URL エンコード オンライン変換、双方向の URL デコード、そして厳密な encodeURIComponent オンライン検証 を提供するエンジニア向け開発スイートです。完全なゼロ知識・クライアントサイド実行アーキテクチャ("use client")を採用しており、すべてのデータ処理はお使いのブラウザ内部のローカルメモリ上で 100% 完結します。機密性の高い OAuth 認可トークン、API シークレット、内部エンドポイント URL を含むネットワークパケットは、外部サーバーへ 1 バイトたりとも送信されません。


# 包括的概要と実践的なユースケース

URL エンコード(パーセントエンコーディング)の本質は、任意のバイトストリームを %XY という形式の US-ASCII 3 文字のトリプレット(XY は 2 桁の 16 進数バイト値)へと射影することです。これにより、URL の構文構造を決定づける予約区切り文字を保護しつつ、データペイロードとしてのリテラル文字を安全にカプセル化します。

text 14 lines
+---------------------------------------------------------------------------------------------------+
|                                      現代の URI 解剖図(構造分解)                                 |
|  https://api.domain.com:443 /v2/search/resource ;matrix=val ?q=developer+tools&lang=ja #results   |
|  |___|   |____________| |__| |________________| |__________| |_______________________| |_______|  |
| スキーム    ホスト名    ポート       パス         マトリクス         クエリ文字列       フラグメント |
+---------------------------------------------------------------------------------------------------+
                                                   |
                        +--------------------------+--------------------------+
                        |                                                     |
                        v                                                     v
          [ コンポーネント単位のエンコード ]                         [ 完全な URI 全体のエンコード ]
          - 保護対象: ALPHA, DIGIT, - _ . ~                          - 保護対象: スキーム, ホスト,
          - 変換対象: : / ? # [ ] @ ! $ & ' ( ) * + , ; =              パスのスラッシュ, クエリ区切り文字
          - 適用領域: 個別クエリパラメータの Key & Value             - 適用領域: Web アドレス全体の正規化

# 開発・運用現場における主要エンタープライズユースケース

  • OAuth 2.0 / OIDC 認可ワークフロー: 認可エンドポイントへのリダイレクト時に、コールバック先の redirecturi、CSRF 防護用の state、PKCE の codechallenge トークンが正しく分離・保護されるよう、厳密なコンポーネントエンコードが要求されます。
  • REST & GraphQL クエリのシリアライズ: GET リクエストを介してフィルタオブジェクトやページネーションカーソルを伝送する際、ネストされた JSON 文字列(例: filter={"status":"active"} → filter=%7B%22status%22%3A%22active%22%7D)をエスケープして伝送路上でのデータ破損を防ぎます。
  • 暗号署名付きリクエスト(AWS SigV4 / クラウド API 認証): AWS Signature Version 4 などのクラウド認可基盤では、クエリパラメータを辞書順(辞書式ソート)に整列させた後、厳格な RFC 3986 規則に基づくパーセントエンコーディングを適用してキャノニカルクエリ文字列(Canonical Query String)を算出することが義務付けられています。
  • 多言語ルーティングと国際化(i18n): 日本語の漢字・ひらがな(例: 「東京」→ %E6%9D%B1%E4%BA%AC)や絵文字(例: 「🚀」→ %F0%9F%9A%80)などの非 ASCII 文字列は、生文字のまま HTTP ヘッダーや URL パスに含めることが禁じられており、UTF-8 バイト列に基づく 16 進数変換が必須となります。
  • Webhook ペイロードとフォーム送信: application/x-www-form-urlencoded 形式の通信において、空白文字を + に置換し、メッセージブローカーや Webhook 受信サーバーへの伝送過程で文字崩れが発生するのを防ぎます。

# クライアントサイド処理(ローカル実行)がプライバシー保護に不可欠な理由

一般的なオンライン URL エンコーダーやデコーダーの多くは、ユーザーが貼り付けた文字列を HTTP POST リクエスト経由でリモートサーバーへ送信し、バックエンドで処理した結果を返送するアーキテクチャを採用しています。しかし、開発業務で扱われる URL には、極めて秘匿性の高いデータが日常的に含まれています。

認可コード(OAuth Auth Code)、セッション ID、署名済み JWT、API シークレット、S3 プリサインド URL のクレデンシャル、あるいは内部ネットワークのドメイン構造などがその代表です。これらが外部サーバーを経由すると、第三者のアクセスログ、プロキシキャッシュ、WAF のバッファに永続化され、SOC 2、HIPAA、GDPR、および日本の個人情報保護法(APPI)における重大なセキュリティ侵害インシデントに直結します。

ToolsAA は、厳格な ゼロサーバー処理モデル(Zero-Server Processing Model) を徹底しています。すべての構文解析、正規表現変換、バイナリバイト変換はお使いのブラウザ内部の分離された JavaScript サンドボックス内で完結します。データを含むパケットは端末から 1 バイトも送信されないため、最高機密のトークンであっても完全なプライバシーを保ったまま安全に作業を行えます。


# 技術アーキテクチャと内部動作原理

URL エンコードを正しく理解し実装するためには、複数の歴史的規格と最新標準の境界線を把握し、バイトレベルでのシリアライズ挙動を掌握することが不可欠です。

text 16 lines
+-----------------------------------------------------------------------------------------+
|                  UTF-8 パーセントエンコーディングの内部バイト変換パイプライン           |
+-----------------------------------------------------------------------------------------+
  入力文字(例: "あ")
    |
    v
  [ Unicode コードポイントの特定 ] : U+3042
    |
    v
  [ UTF-8 マルチバイトエンコード ] : 0xE3 0x81 0x82 (3バイト)
    |
    v
  [ 16進数トリプレット射影 ]       : %E3 %81 %82
    |
    v
  出力文字列: "%E3%81%82"

# 1. 標準規格の変遷と境界線: RFC 3986 vs RFC 2396 vs WHATWG

  • RFC 2396(1998年策定): 古い URI 構文仕様。記号類のうち !、'、(、)、* を非予約文字(Unreserved Marks)として定義していました。JavaScript ネイティブの encodeURIComponent() は、後方互換性維持のため現在もこの古い挙動を踏襲しており、これらの記号をエスケープせずに素通しします。
  • RFC 3986(2005年策定): 現在のインターネット標準規格。上記 5 文字を予約サブデリミタ(Sub-delimiters)として再分類しました。したがって、AWS SigV4 や厳格な OAuth 1.0a 認証などの現代的な API では、これらの文字も明示的に %21、%27、%28、%29、%2A へとエスケープしなければ署名不一致エラーとなります。非予約文字(Unreserved Characters)として永久にエスケープされないのは、アルファベット英大小文字(A-Z, a-z)、数字(0-9)、および -、_、.、~ の 4 記号のみです。
  • WHATWG URL Living Standard: 現代のブラウザ実装および Node.js / Deno などのランタイムが準拠する最新仕様。URL パースアルゴリズムを厳密化し、application/x-www-form-urlencoded 仕様を形式化しました。

# 2. UTF-8 パーセントエンコーディングのバイト長力学

パーセントエンコーディングは文字単位ではなく、文字を UTF-8 シリアライズした際の個々のバイト値に対して適用されます。

  • 1 バイト文字(U+0000 〜 U+007F): 標準 US-ASCII 領域。半角スペース(U+0020)は 1 バイト 0x20 で表現され、%20 へ変換されます。
  • 2 バイト文字(U+0080 〜 U+07FF): ラテン文字拡張、キリル文字、アラビア文字等。例えばアクセント付き文字 é(U+00E9)は UTF-8 で 0xC3 0xA9 となり、%C3%A9 に変換されます。
  • 3 バイト文字(U+0800 〜 U+FFFF): CJK 統合漢字、日本語のひらがな・カタカナ等。例えば漢字「東」(U+6771)は 0xE6 0x9D 0xB1 となり、%E6%9D%B1 に変換されます。「あ」(U+3042)は 0xE3 0x81 0x82 となり、%E3%81%82 となります。
  • 4 バイト文字(U+10000 〜 U+10FFFF): 絵文字および追加文字。ロケット絵文字「🚀」(U+1F680)は 0xF0 0x9F 0x9A 0x80 となり、%F0%9F%9A%80 へと変換されます。
Warning
JavaScript の文字列内部表現は UTF-16 です。U+10000 以上の文字はサロゲートペア(2 個の 16 ビットコードユニット)として保持されるため、文字列スライス等でサロゲートペアが泣き別れになると、ネイティブの encodeURIComponent() は URIError: URI malformed をスローしてクラッシュします。

# 3. ブラウザ標準 Web API の 3 本柱

JavaScript には URL 処理用のネイティブ API が 3 種類備わっており、目的とスコープが明確に分かれています。

  1. encodeURIComponent(): 個別のクエリパラメータ(Key や Value)およびパス要素を対象とします。URL 構造文字(:, /, ?, #, &, =)を含め、主要な記号をすべてパーセントエンコードします。
  2. encodeURI(): 完全な URL アドレス全体の正規化を対象とします。プロトコルやホスト、パス構造を維持する必要があるため、構造区切り文字(:, /, ?, #, [, ], @, !, $, &, ', (, ), *, +, ,, ;, =)はエンコードせず保持します。
  3. URLSearchParams: HTML フォーム仕様(application/x-www-form-urlencoded)に準拠したクエリ文字列操作 API です。半角スペースを + としてフォーマットし、パース時には + と %20 の双方を半角スペースとしてデコードします。

# 4. ブラウザ Web API、Web Crypto、WASM による高効率アーキテクチャ

ToolsAA は、最新の Web プラットフォーム標準技術を駆使して、デスクトップネイティブツールに匹敵する軽快な操作性と応答性を実現しています。

  • 非ブロッキング UI スケジューリング(React 18 useDeferredValue): 高速タイピング時に入力イベントとパース処理を分離。数万文字におよぶ長大な API ペイロードを入力しても、UI スレッドの 60 FPS 応答性を維持します。
  • Web Workers & Typed Arrays: 500 KB を超える巨大な JSON や URL リストのバッチ処理では、TextEncoder および TextDecoder を用いたバイナリ変換をバックグラウンドスレッドへ自動オフロードし、メインスレッドのフリーズを防止します。
  • Web Crypto API による署名整合性検証: ブラウザ標準の window.crypto.subtle.digest("SHA-256") を活用し、PKCE コードチャレンジ値やクエリハッシュをローカル環境のみで高速検証します。
  • HTML5 Canvas による視覚化: 入力データに含まれる文字種別(ASCII、CJK、絵文字、記号)のバイト分布チャートをオフスクリーン <canvas> 上で直接描画し、DOM リフローの発生を極小化しています。

# ステップ・バイ・ステップ実践チュートリアル

ToolsAA のインターフェースは、開発者が遭遇するあらゆる複雑なユースケースに柔軟に対応できるよう設計されています。

# ステップ 1: データの入力とプリセットの読み込み

エディタの入力エリアに、変換対象のクエリ文字列、完全な URL、またはエンコード済みトークンを直接ペーストします。 右上の「プリセット」ドロップダウンから OAuth 2.0 PKCE 認可パラメータ や ネストされた JSON API クエリ を選択して、本番さながらのサンプル構造をワンクリックで読み込むことも可能です。また、ローカルのログファイルやテキストファイルをドラッグ&ドロップして即座に読み込めます。

# ステップ 2: エンコードアルゴリズムの選択

伝送先のシステム要件に応じて、適切な変換モードを選択します。

  • encodeURIComponent(標準コンポーネント): REST API の GET クエリ値やパスセグメントのエンコードに最適です。
  • Strict RFC 3986(厳格 RFC 3986 準拠): AWS SigV4、OAuth 1.0a、クラウドストレージの認証署名生成に必須です。!、'、(、)、* も漏れなくエスケープします。
  • encodeURI(完全 URI): アドレス全体の構文構造(スラッシュやコロン)を保ちつつ、マルチバイト文字や空白のみをサニタイズしたい場合に使用します。
  • application/x-www-form-urlencoded: 従来の HTML フォーム送信や一部のレガシー Webhook 向けに、空白を + で表現します。

# ステップ 3: インタラクティブなクエリパラメータ解析と編集

入力された URL にクエリ文字列が含まれている場合、ToolsAA は自動的に構文解析を行い、直感的な Key-Value 編集テーブルを展開します。

  • パラメータごとの有効化/無効化(チェックボックス操作)
  • キー名や値のインライン編集
  • トラッキングパラメータ(UTM タグ等)のワンクリック追加・削除

# ステップ 4: 安全かつ再帰的なデコード処理

難解な多重エンコード文字列や破損したデータも、以下の機能で安全に復元できます。

  • 二重エンコード検知(Double-Encoding Detection): 文字列中に %2520 や %253A などの %25 パターンが存在する場合、多重エンコードの警告バナーを即座に表示します。
  • 再帰的アンパック(Auto-Unpack): 「自動アンパック」ボタンを押すことで、何層にもネストされたパーセントエンコーディングを、文字列が変化しなくなるまで安全に再帰展開します。
  • 耐障害性デコード(Fault-Tolerant Decoding): 不正な 16 進数シーケンスが含まれていても、全体をクラッシュさせることなく、問題箇所を特定インジケーターでハイライト表示しながら正常なトークンのみを復元します。

# ステップ 5: メトリクス検証とワンクリック出力エクスポート

変換完了後、文字数、UTF-8 総バイト数、エンコードによるデータ膨張率(Inflation Ratio)がリアルタイムに表示されます。結果はワンクリックでクリップボードにコピーできるほか、テキストファイルとしてのダウンロードも可能です。


# プロダクションコード実装(TypeScript & Python)

実際のバックエンドおよびフロントエンド開発現場でそのまま使用できる、堅牢かつ依存関係ゼロのエンコード/デコード実装例を提示します。

# 1. モダン TypeScript / JavaScript 実装

厳密な RFC 3986 準拠、安全なエラーリカバリ機能、およびクエリ文字列パーサーを備えたプロダクション仕様のコーデッククラスです。

typescript 92 lines
/**
 * URL エンコード方式の定義
 */
export type EncodingMode = "rfc3986" | "component" | "fullUri" | "formUrlEncoded";

/**
 * 堅牢な URL コーデックユーティリティクラス
 */
export class UrlCodec {
  /**
   * RFC 3986 に厳密に準拠したエンコード
   * encodeURIComponent が素通しする ! ' ( ) * を 16 進数エスケープする
   */
  public static encodeStrictRFC3986(input: string): string {
    if (!input) return "";
    return encodeURIComponent(input).replace(
      /[!'()*]/g,
      (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
    );
  }

  /**
   * 指定されたモードに応じたエンコード処理
   */
  public static encode(input: string, mode: EncodingMode = "component"): string {
    if (!input) return "";
    switch (mode) {
      case "rfc3986":
        return this.encodeStrictRFC3986(input);
      case "component":
        return encodeURIComponent(input);
      case "fullUri":
        return encodeURI(input);
      case "formUrlEncoded":
        // application/x-www-form-urlencoded 仕様: 空白を '+' に変換
        return encodeURIComponent(input)
          .replace(/%20/g, "+")
          .replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
      default:
        throw new Error(`未対応のエンコードモードです: ${mode}`);
    }
  }

  /**
   * 不正なバイト列でもクラッシュしない耐障害性デコード処理
   */
  public static safeDecode(input: string, isForm = false): { text: string; hasError: boolean } {
    if (!input) return { text: "", hasError: false };
    // フォーム形式の場合は '+' を半角スペースに正規化
    const normalized = isForm ? input.replace(/\+/g, " ") : input;

    try {
      // 標準のデコードを試行
      return { text: decodeURIComponent(normalized), hasError: false };
    } catch {
      // URIError 発生時: トークンごとに分割して復元可能な部分を救済
      let output = "";
      let hasError = false;
      const tokens = normalized.split(/(%[0-9a-fA-F]{2})/g);

      for (const token of tokens) {
        if (token.startsWith("%") && token.length === 3) {
          try {
            output += decodeURIComponent(token);
          } catch {
            output += token; // デコード失敗時は生トークンを保持
            hasError = true;
          }
        } else {
          output += token;
        }
      }
      return { text: output, hasError };
    }
  }

  /**
   * URL またはクエリ文字列を高精度にパースして Key-Value 配列を生成
   */
  public static parseQuery(urlOrQuery: string): Record<string, string[]> {
    if (!urlOrQuery) return {};
    const raw = urlOrQuery.includes("?")
      ? urlOrQuery.split("?")[1].split("#")[0]
      : urlOrQuery.split("#")[0];

    const params: Record<string, string[]> = {};
    new URLSearchParams(raw).forEach((value, key) => {
      params[key] = params[key] ? [...params[key], value] : [value];
    });
    return params;
  }
}

# 2. モダン Python 3.11+ 実装

型ヒントを完備し、AWS SigV4 や HMAC 署名検証に必要なキャノニカルクエリ文字列の構築に対応した Python 実装です。

python 58 lines
"""
URL エンコード&キャノニカルクエリ構築ユーティリティ
Python 3.11+ 標準ライブラリのみを使用
"""
from typing import Dict, List, Tuple, Union
import urllib.parse


class UrlCodec:
    @staticmethod
    def encode_rfc3986(value: str) -> str:
        """
        RFC 3986 厳格モードによるパーセントエンコード
        非予約文字: [A-Za-z0-9-_.~] のみを安全とみなす
        """
        if not value:
            return ""
        return urllib.parse.quote(str(value), safe="-_.~")

    @staticmethod
    def encode_form(value: str) -> str:
        """
        application/x-www-form-urlencoded 形式によるエンコード
        半角スペースを '+' へ変換
        """
        if not value:
            return ""
        return urllib.parse.quote_plus(str(value))

    @staticmethod
    def safe_decode(encoded_str: str, is_form: bool = False) -> str:
        """
        不正なエスケープ文字列が含まれていても安全に置換デコードする
        """
        if not encoded_str:
            return ""
        decoder = urllib.parse.unquote_plus if is_form else urllib.parse.unquote
        # 不正な UTF-8 シーケンスを U+FFFD (置換文字) でフォールバック
        return decoder(encoded_str, errors="replace")

    @classmethod
    def build_canonical_query(cls, params: Dict[str, Union[str, List[str]]]) -> str:
        """
        AWS SigV4 等の認証で使用されるキャノニカルクエリ文字列を生成
        1. キーと値を厳格 RFC 3986 でエンコード
        2. キー昇順(キー同一時は値昇順)で辞書式ソート
        3. '&' で連結
        """
        pairs: List[Tuple[str, str]] = []
        for key, val in params.items():
            encoded_key = cls.encode_rfc3986(str(key))
            values = val if isinstance(val, list) else [val]
            for item in values:
                pairs.append((encoded_key, cls.encode_rfc3986(str(item))))

        # 辞書式(バイトコード順)ソート
        pairs.sort(key=lambda x: (x[0], x[1]))
        return "&".join(f"{k}={v}" for k, v in pairs)

# 開発現場における落とし穴とエッジケースのトラブルシューティング

パーセントエンコーディングにまつわる不具合は、静的型チェックをすり抜け、本番環境のログ監視に異常値として現れるケースが多々あります。代表的な 6 大トラブルとその解決策を解説します。

# 1. 二重エンコード問題(The Double-Encoding Problem: %2520)

既にエンコードされている文字列に対して、後続のプロキシや別レイヤーのライブラリが重複してエンコードをかけてしまう現象です。文字 % 自身が %25 へとエスケープされるため、半角スペース %20 は %2520 へ、%3A は %253A へと変質します。

  • 解決策: 入力値がすでにパーセントエンコード済みであるかを事前判定します。decodeURIComponent(str) !== str であれば、文字列内にエンコード済みシーケンスが存在します。送信処理の入口で一度正規デコードを行ってから再エンコードするか、API 境界で冪等性を担保するバリデーションを導入してください。

# 2. 空白表現の二重性(The + vs %20 Space Duality)

半角スペースの表現方法において、RFC 3986 標準規格は %20 を指定しているのに対し、HTML フォーム仕様(application/x-www-form-urlencoded)は伝統的に + を使用します。 REST API のクエリパラメータで filter=c++ を送信した際、サーバー側がフォーム仕様でデコードすると filter=c (スペース 2 個)として誤認識されてしまいます。

  • 解決策:
  • 本来のプラス記号文字 + を送信する場合は、必ず明示的に %2B へエンコードする。
  • モダンな JSON REST API や GraphQL では、クエリパラメータの空白に + ではなく %20 を使用するルールを統一する。

# 3. 孤立サロゲート(Lone Surrogates)と未捕捉の JavaScript URIError

JavaScript の文字列は内部的に UTF-16 コードユニットの配列です。絵文字などの 4 バイト文字(例: 😀 \uD83D\uDE00)の途中で文字列を切り詰めてしまうと、上位サロゲート(\uD83D)のみが残る「孤立サロゲート(Lone Surrogate)」が発生します。この状態で encodeURIComponent() を実行すると、ブラウザは回復不能な URIError: URI malformed をスローします。

  • 解決策: ECMAScript 2024 で導入された標準メソッド String.prototype.toWellFormed() を使用して、孤立サロゲートを事前に Unicode 置換文字(\uFFFD)へ無害化してからエンコードします。

```javascript const safeInput = rawString.toWellFormed(); const encoded = encodeURIComponent(safeInput); ```

# 4. クエリ文字列のナイーブな文字列分割(Naive String Splitting)

url.split("?")[1].split("&") のような安易な文字列分割ロジックは、クエリパラメータの値の中にエンコードされていない & や =、あるいはハッシュ記号 # が含まれていた場合に致命的なパース崩壊を起こします。

  • 解決策: 独自文字列分割を廃止し、WHATWG 標準の new URL(url) および new URLSearchParams(url.search) を使用してください。標準パーサーはエスケープ境界を正しく解釈します。

# 5. リバースプロキシを経由するスラッシュのエンコード(%2F)と脆弱性

REST API のパスセグメントにエンコードされたスラッシュ(%2F)を含める設計(例: /api/v1/files/folder%2Fdocument.pdf)は、リバースプロキシで深刻な不具合を誘発します。 Apache HTTP Server はセキュリティ保護のためデフォルトで %2F を含むリクエストを HTTP 404 で遮断します(AllowEncodedSlashes On が必要)。一方、Nginx はアップストリームへ転送する前に %2F を生の / へ勝手にデコード・正規化してルーティングするため、パストラバーサルやルーティング不整合を引き起こします。

  • 解決策: パス階層の一部としてスラッシュを渡す設計を避け、クエリパラメータ(例: /api/v1/files?path=folder%2Fdocument.pdf)として伝送してください。

# 6. 国際化ドメイン名(IDN: Punycode)とパス・クエリエンコードの混同

日本語ドメイン(例: https://総務省.jp/data)全体に対して encodeURI() を適用すると、https://%E7%B7%8F%E5%8B%99%E7%9C%81.jp/data と変換されてしまい、DNS リゾルバが名前解決に失敗します。

  • 解決策: ホスト名部分はパーセントエンコーディングではなく、RFC 5891 準拠の Punycode(ピュニコード)(例: xn--l8jeg3b.jp)へ変換する必要があります。パーセントエンコーディングの適用領域は、パス、クエリ、およびフラグメントのみに限定してください。

# 詳細 FAQ セクション(よくある質問と回答)

# Q1: encodeURI() と encodeURIComponent() の決定的な違いは何ですか?

回答: 目的とする変換スコープが異なります。encodeURI() は「完全な URL 全体」を正規化するための関数であり、プロトコル(http:)やパス階層(/)、クエリ境界(?、&、=)などの構文区切り文字を破壊しないようエスケープから除外します。これに対して encodeURIComponent() は「個別のクエリパラメータ(キーや値)」を対象としており、区切り文字も含めてすべて %XX へ変換します。パラメータ値の中に / や & が含まれる場合は、必ず encodeURIComponent() を使用しなければなりません。

# Q2: なぜ JavaScript の encodeURIComponent() は !, ', (, ), * をエンコードしないのですか?

回答: JavaScript の仕様策定時、当時の標準規格であった旧 RFC 2396 に準拠したためです。旧規格ではこれら 5 文字が非予約文字と定義されていました。現行の RFC 3986 ではこれらは予約文字に昇格していますが、ECMAScript では既存の Web アプリケーションの後方互換性を破壊しないよう、当時の挙動が維持されています。AWS SigV4 などの厳格な仕様を満たすには、正規表現 .replace(/[!'()*]/g, ...) を用いた追加エスケープが必要です。

# Q3: 半角スペースを + でエンコードすべきケースと %20 でエンコードすべきケースの使い分けは?

回答: 半角スペースを + に変換するのは、HTML フォーム送信規格である application/x-www-form-urlencoded 仕様のみです。それ以外のあらゆる標準的 URI 構文、REST API クエリ、URL パス、RFC 3986 仕様においては、半角スペースは %20 と表現しなければなりません。特に URL パスセグメント内において + は文字通りのプラス記号と解釈されるため、パス内で空白を表現する際に + を使用してはなりません。

# Q4: 外部から受信した不正なパーセント文字列をデコードする際、URIError: URI malformed を回避するには?

回答: ブラウザ標準の decodeURIComponent() は、% の直後に不正な文字が続いたり、不完全な UTF-8 バイト列が渡されると即座に例外をスローします。これを防ぐには、デコード処理を try...catch で囲み、例外発生時には本ガイドに掲載した TypeScript 実装のように、正規表現 /(%[0-9a-fA-F]{2})/g でトークン分解して安全な部分のみを部分復元するフォールバック設計を導入してください。また、入力文字列に対して事前に toWellFormed() を実行することも有効です。

# Q5: 日本語(漢字・ひらがな・カタカナ)や絵文字(4バイト文字)に対する UTF-8 パーセントエンコーディングの内部構造は?

回答: まず対象文字が Unicode コードポイントから UTF-8 バイナリバイト列へと変換されます。日本語の多くの漢字や仮名文字は UTF-8 で 3 バイトを消費するため、3 つの %XX トリプレットになります(例: 「東」は 0xE6 0x9D 0xB1 → %E6%9D%B1)。絵文字などのサロゲートペア領域文字は 4 バイトを消費するため、4 つのトリプレットになります(例: 「🚀」は 0xF0 0x9F 0x9A 0x80 → %F0%9F%9A%80)。

# Q6: 文字列が「すでに URL エンコードされているか」をプログラムで正確に検出する方法は?

回答: 2 段階の検証を行います。第 1 に、正規表現 /%[0-9A-Fa-f]{2}/.test(str) を用いてパーセント記号に続く 16 進数パターンの存在を確認します。第 2 に、デコードの冪等性をテストします。decodeURIComponent(str) !== str が成立すれば、その文字列にはデコード可能なエンコード済み文字が含まれています。ただし、元データとして % 記号そのものを意図して含む文字列との区別は本質的に文脈依存となるため、二重エンコード防止には送信側と受信側の仕様統一が最も確実です。

# Q7: ToolsAA のツール利用時に、機密性の高い API キーや OAuth トークンが外部サーバーへ送信されることはありますか?

回答: いいえ、一切送信されません。ToolsAA は "use client" ディレクティブによる完全なクライアントサイド実行モデルを採用しています。エンコード、デコード、クエリ解析、文字数・バイト数計算の全アルゴリズムは、お客様のブラウザの JavaScript エンジン内部でのみ動作します。外部サーバーへの通信リクエストは一切発生せず、ログが記録されることもありません。

# Q8: URL パス内のエンコードされたスラッシュ(%2F)が、Nginx や Apache などのリバースプロキシで 404 や 400 エラーを引き起こす理由は?

回答: Web サーバーやリバースプロキシ(Apache、Nginx、AWS ALB 等)は、パストラバーサル攻撃(../ による不正なファイルアクセス)を防ぐためのセキュリティポリシーを持っています。Apache はデフォルトでパス内の %2F を検知すると 404 Not Found を返します。また Nginx はアップストリームへのプロキシ時に %2F を / に勝手にデコードして渡すため、パス階層の解釈が崩壊します。パスセグメント内にスラッシュを含める設計は避け、クエリパラメータに格納して伝送してください。


# 技術比較マトリクス(URL エンコード仕様の徹底比較)

比較項目 / パラメータRFC 3986(標準 URI 規格)JavaScript encodeURIComponentJavaScript encodeURIWHATWG URLSearchParams
主対象スコープURI 汎用構文の完全定義クエリパラメータのキーおよび値完全な URL 文字列の正規化フォームデータ / クエリ文字列
半角スペースの変換結果%20%20%20+
/ および ? のエンコードはい(コンポーネント内)はい(%2F, %3F)いいえ(保持)はい(%2F, %3F)
& および = のエンコードはい(コンポーネント内)はい(%26, %3D)いいえ(保持)はい(%26, %3D)
! および ' のエンコードはい(予約サブデリミタ)いいえ(旧 RFC 2396 互換で保持)いいえ(保持)はい
( および ) のエンコードはい(予約サブデリミタ)いいえ(旧 RFC 2396 互換で保持)いいえ(保持)はい
* のエンコードはい(予約サブデリミタ)いいえ(旧 RFC 2396 互換で保持)いいえ(保持)はい
チルダ ~ の保持はい(非予約文字)はい(非予約文字)はい(非予約文字)はい(非予約文字)
エラーハンドリング数学的構文仕様不正 UTF-16 時に URIError不正 UTF-16 時に URIError置換文字 \uFFFD で自動回復

# 結論・まとめ

適切な URL エンコード処理は、堅牢かつ安全な Web アーキテクチャを構築するための絶対的な基礎です。OAuth 2.0 認可コールバックの保護、AWS SigV4 クラウド API 署名のキャノニカルクエリ生成、多言語エンドポイントの正確なルーティングに至るまで、文字とバイトの厳密な取り扱いがシステムの脆弱性やデータ欠落を防ぎます。

RFC 3986、JavaScript ネイティブの encodeURIComponent()、そして HTML フォーム仕様の違いを正確に理解することで、開発現場を悩ませる二重エンコード障害やエッジケースの例外クラッシュを未然に排除できます。ToolsAA URL / URI コンポーネント エンコーダー&デコーダー は、あらゆるエンコード・デコード作業、クエリパラメータの可視化と編集を、完全なクライアントサイド・ゼロ知識アーキテクチャにより安全かつ決定論的に支援します。

今すぐこのツールを実行しますか?

インストール不要。ブラウザ完結型のゼロ知識アーキテクチャで高速・安全に処理。