目次
概要
Webアプリケーションにおいて、URLパラメータ経由で受け取ったデータ(日本語の検索キーワードなど)を利用するには、エンコードされた文字列を元の形式に戻す「デコード処理」が不可欠です。
本記事では、JavaScriptに用意されている2つのデコード関数 decodeURI と decodeURIComponent の決定的な違いと、実際の開発現場での正しい使い分けについて解説します。
仕様(入出力)
メソッドの比較
どちらもパーセントエンコーディング(%xx)された文字列を元の文字に戻しますが、デコード対象とする範囲が異なります。
| メソッド | 意味・用途 | 挙動の特徴 |
decodeURI(str) | URL全体をデコードする | URLの意味を持つ予約文字(; / ? : @ & = + $ , #)のエンコード値(例: %2F)はデコードしません。 |
decodeURIComponent(str) | URLの構成要素をデコードする | すべてのエンコード値を文字に戻します。パラメータ値の読み取りにはこちらを使用します。 |
- 入力: エンコードされた文字列(String)
- 出力: デコードされた文字列(String)
- 例外: 無効なエンコード形式(例:
%の後に不適切な文字が続くなど)の場合、URIErrorがスローされます。
基本の使い方
1. URL全体を戻す (decodeURI)
encodeURI でエンコードされたURL全体を元に戻す場合に使用します。URLの構造(スラッシュやクエスチョンマーク)を維持したい場合に適しています。
// URL全体としての構造は保たれる
const url = 'https://example.com/%E6%A4%9C%E7%B4%A2';
console.log(decodeURI(url));
// "https://example.com/検索"
2. パラメータ値を読み取る (decodeURIComponent)
クエリパラメータの値など、完全に元のテキストデータに戻したい場合に使用します。
// スラッシュ(%2F)なども含め、すべて文字に戻る
const param = '%E6%9D%B1%E4%BA%AC%2F%E6%B8%8B%E8%B0%B7';
console.log(decodeURIComponent(param));
// "東京/渋谷"
コード全文(HTML / JavaScript)
URLのクエリパラメータ(?q=...)から検索キーワードを取得し、画面に表示するシミュレーションです。
パラメータ値には、URLの区切り文字として誤認されやすい記号が含まれる可能性があるため、強力な decodeURIComponent を採用します。
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Decoding Demo</title>
<style>
.result-panel {
border: 1px solid #ddd;
padding: 20px;
border-radius: 8px;
font-family: sans-serif;
max-width: 400px;
background-color: #f9f9f9;
}
.keyword {
color: #d32f2f;
font-weight: bold;
font-size: 1.2em;
}
.label {
font-size: 0.9em;
color: #666;
}
</style>
</head>
<body>
<div class="result-panel">
<p class="label">現在の検索キーワード:</p>
<p>「<span id="output-keyword" class="keyword"></span>」</p>
</div>
<script src="decoder.js"></script>
</body>
</html>
JavaScript
/**
* クエリ文字列から指定したキーの値を取得し、デコードして返す関数
* @param {string} queryString - 解析対象のクエリ文字列 (例: "?q=%E3%83...")
* @param {string} key - 取得したいパラメータ名
* @returns {string|null} デコード済みの値、またはnull
*/
const getDecodedParam = (queryString, key) => {
// 先頭の?を除去して分割
const params = queryString.substring(1).split('&');
for (const param of params) {
const [currentKey, currentValue] = param.split('=');
if (currentKey === key && currentValue) {
try {
// 安全にデコードを実行
return decodeURIComponent(currentValue);
} catch (e) {
console.error('URIのデコードに失敗しました:', e);
return currentValue; // デコード失敗時は生の値を返すなどの対策
}
}
}
return null;
};
// メイン処理
const init = () => {
const outputElement = document.getElementById('output-keyword');
// シミュレーション用URLパラメータ(実際は window.location.search を使用)
// q = "JavaScript & HTML" (%26 はアンパサンド)
const mockQueryString = '?category=tech&q=JavaScript%20%26%20HTML';
const keyword = getDecodedParam(mockQueryString, 'q');
if (keyword) {
outputElement.textContent = keyword;
} else {
outputElement.textContent = 'なし';
}
};
// DOM読み込み完了後に実行
document.addEventListener('DOMContentLoaded', init);
カスタムポイント
window.location.searchの利用:本コードはデモ用に固定文字列を使っていますが、実稼働させる場合はmockQueryStringの部分をwindow.location.searchに置き換えてください。- スペースの扱い:古いシステムではスペースが
%20ではなく+でエンコードされている場合があります。その場合はdecodeURIComponentの前に.replace(/\+/g, ' ')を実行する処理を追加すると互換性が高まります。
注意点
- URIErrorのハンドリング不正なパーセントエンコーディング(例:
%E3%81のようにバイト数が足りない状態で切れているなど)をデコードしようとすると、JavaScriptはURIErrorをスローして停止します。外部からの入力を扱う際は、必ずtry...catchブロックで囲むことを推奨します。 - XSS(クロスサイトスクリプティング)リスクデコードされた文字列には
<script>などのタグが含まれている可能性があります。これをそのままinnerHTMLで表示するのは危険です。上記のコード例のようにtextContentを使用して、テキストとして扱うことがセキュリティ上の鉄則です。 decodeURIの落とし穴decodeURIは%2F(スラッシュ)や%3F(クエスチョンマーク)をデコードしません。パスパラメータの中にスラッシュが含まれるデータを扱いたい場合にdecodeURIを使うと、期待通りに復元されないため注意が必要です。
応用
URLSearchParams を使ったモダンな実装
現代のブラウザでは、パラメータ解析専用の API である URLSearchParams が利用可能です。これは内部で自動的に decodeURIComponent 相当の処理を行います。
const queryString = '?q=JavaScript%20%26%20HTML';
const params = new URLSearchParams(queryString);
// getメソッドが自動的にデコードして値を返す
const keyword = params.get('q');
console.log(keyword); // "JavaScript & HTML"
まとめ
- 基本戦略: パラメータの値を取得する場合は、より強力な変換能力を持つ
decodeURIComponentを使用するのが正解です。 - 例外: URL全体の構造を保ったまま可読性を上げたい場合のみ
decodeURIを使用します。 - 安全性: デコード処理はエラーが発生しやすいため、例外処理とXSS対策を忘れずに行いましょう。
