URLエンコーディングとBase64エンコーディング:その違いとは?
URLエンコーディング(パーセントエンコーディング)は、RFC 3986に従ってURL内の特殊文字を%XX形式に変換します。Base64エンコーディングは、RFC 4648に従ってバイナリデータを64個のASCII文字を使ったテキスト文字列に変換します。両者は異なる目的を持ち、互換性はありません。
URLエンコーディングとは?
URLエンコーディング(パーセントエンコーディングとも呼ばれます)は、URI内で使用が許可されていない文字や特別な意味を持つ文字を表現するための仕組みとして、RFC 3986で定義されています。エンコード対象の各文字は(UTF-8を使って)1つ以上のバイトに変換され、各バイトはパーセント記号(%)に続く2桁の大文字の16進数として表現されます。
たとえば、スペース文字は%20に、アンパサンドは%26になり、ユーロ記号のような非ASCII文字は%E2%82%AC(3つのUTF-8バイトがそれぞれパーセントエンコードされたもの)になります。
// JavaScriptにおけるURLエンコーディングの例
encodeURIComponent('hello world'); // "hello%20world"
encodeURIComponent('price=10&qty=2'); // "price%3D10%26qty%3D2"
encodeURIComponent('cafe'); // "caf%C3%A9"
URLエンコーディングは、URLを安全かつ正当なものにするために特化して設計されています。URIで許可されていない文字や予約された意味を持つ文字だけをエンコードし、英数字といくつかの安全な記号はそのまま残します。
Base64エンコーディングとは?
Base64エンコーディングは、RFC 4648で定義されているバイナリからテキストへのエンコード方式で、64個のASCII文字(A-Z、a-z、0-9、+、/)を使ってバイナリデータを表現し、パディングには=を使用します。入力3バイトごとに、4文字の出力が生成されます。
Base64は、電子メール(MIME)やXML/JSONへのデータ埋め込みのように、テキストしか確実に扱えないチャネルを通じてバイナリデータを送信するために設計されました。URLに特化したものではなく、特殊文字だけでなく入力のすべてのバイトをエンコードします。
// JavaScriptにおけるBase64エンコーディングの例
btoa('hello world'); // "aGVsbG8gd29ybGQ="
btoa('price=10&qty=2'); // "cHJpY2U9MTAmcXR5PTI="
// Unicode文字列の場合は、まずUTF-8にエンコードする
function toBase64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
toBase64('cafe'); // "Y2Fmw6k="
Base64にはURLセーフな変種(Base64url)も存在し、+を-に、/を_に置き換え、多くの場合=のパディングを省略します。この変種は、JWT、URL内のデータURI、その他標準のBase64文字がURL構文と衝突してしまうような場面で使われます。
主な違い
| 特徴 | URLエンコーディング | Base64エンコーディング |
|---|---|---|
| 標準規格 | RFC 3986 | RFC 4648 |
| 目的 | URLを安全にする | バイナリをテキストとして表現する |
| エンコード対象 | 特殊文字・予約文字のみ | 入力のすべてのバイト |
| 出力形式 | %XXの16進シーケンス |
A-Z, a-z, 0-9, +, /, = |
| サイズの増加 | 可変(エンコードされた文字のみ増加) | 常に約33%大きくなる |
| 可逆性 | あり | あり |
| 人間が読めるか | 部分的(非予約文字はそのまま残る) | いいえ |
| デフォルトでURLセーフか | はい(設計上) | いいえ(+, /, =を含む) |
どちらをいつ使うべきか
URLエンコーディングを使うのは、クエリパラメータの値、パスセグメント、フラグメント識別子など、URLに特殊文字を含める必要があるときです。データをURL構造の中に埋め込む必要があるあらゆる状況では、URLエンコーディングが正しい選択となります。
Base64エンコーディングを使うのは、バイナリデータ(画像、ファイル、暗号化されたペイロード)をテキストとして表現する必要があるとき、バイナリコンテンツをJSONやXMLに埋め込むとき、あるいはテキストのみのチャネルを通じてデータを送信するときです。Base64は、HTTP Basic認証ヘッダーやJSON Web Token(JWT)でも使われています。
// URLエンコーディング:検索語をURLに埋め込む
const searchUrl = 'https://example.com/search?q=' +
encodeURIComponent('C++ & Java');
// "https://example.com/search?q=C%2B%2B%20%26%20Java"
// Base64:画像をCSSやHTMLに埋め込む
const imageData = 'data:image/png;base64,iVBORw0KGgoAAAANS...';
// Base64:HTTP Basic認証ヘッダー
const credentials = btoa('username:password');
const header = 'Authorization: Basic ' + credentials;
両者を組み合わせられるか?
はい、組み合わせられますし、場合によっては組み合わせる必要があります。Base64エンコードしたデータをURLパラメータとして渡す必要がある場合、標準のBase64出力には+、/、=といった、URL内で特別な意味を持つ文字が含まれる可能性があります。この場合、選択肢は2つあります。
選択肢1: Base64文字列をURLに配置する前にURLエンコードします。+は%2Bに、/は%2Fに、=は%3Dになります。
選択肢2: Base64urlの変種(RFC 4648 Section 5)を使います。これは+を-に、/を_に置き換え、パディングを取り除きます。JWTや多くの最新のAPIで採用されているアプローチです。
// 選択肢1:標準のBase64をURLエンコードする
const base64 = btoa('binary data here'); // "YmluYXJ5IGRhdGEgaGVyZQ=="
const urlSafe = encodeURIComponent(base64);
// "YmluYXJ5IGRhdGEgaGVyZQ%3D%3D"
// 選択肢2:Base64urlエンコーディング
function toBase64url(str) {
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
toBase64url('binary data here');
// "YmluYXJ5IGRhdGEgaGVyZQ"