/10分で読めます

URL Encodingとは?Percent-Encoding完全ガイド

検索する、special charactersを含むlinkをclickする、web formを送信する。そのたびにURL encodingは裏側で動いています。unsafe charactersをinternet上で安全に送れるformatへ変換します。

URLとは?

URL、つまりUniform Resource Locatorは、internet上のresourceのaddressです。pages、images、API endpoints、files、downloadsにはすべてURLがあります。

URLはbrowserに、resourceがどこにあるか、どのprotocolを使うか、query parametersやfragmentsなどのextra dataをどう適用するかを伝えます。

たとえばhttps://www.example.com/search?q=hello+worldにはscheme、host、path、query stringが含まれます。

URLの構造

完全なURLには複数のcomponentsを含められます。

https://user:pass@www.example.com:443/path/page?key=value&q=test#section
scheme  userinfo      host            port path       query            fragment
Component説明
Schemehttpsresourceへaccessするためのprotocol
User infouser:pass任意のcredentials。現在はあまり使われません
Hostwww.example.comserverのdomain nameまたはIP address
Port443server port。HTTP/HTTPSでは通常implicitです
Path/path/pageserver上のspecific resource location
Querykey=value&q=testquestion mark以降のkey-value data
Fragment#sectionserverへ送信されないpage bookmark

URL Encodingとは?

URL encodingpercent-encodingとも呼ばれ、URL内でunsafeまたは許可されないcharactersを安全な表現へ変換します。

formatはpercent signの後に2桁のhexadecimal digitsを続けます。spaceはASCII byteがdecimal 32、hex 20なので%20になります。

Percent-encodingはRFC 3986などのURI standardsで定義され、URLがtextを安全に運ぶための中核です。

Before encoding:
  https://example.com/search?q=hello world&lang=en

After encoding:
  https://example.com/search?q=hello%20world&lang=en

Space becomes %20

URL Encodingが必要な理由

URL encodingはいくつかの理由で必要です。

  • Reserved charactersには意味がある - ?&=#などはURL partsを区切ります。
  • Spacesは直接使えない - URLではspaceを%20、またはform dataでは+としてencodeする必要があります。
  • Non-ASCII textにはbytesが必要 - Thai、Japanese、accented letters、emojiはまずUTF-8 bytesへ変換されます。
  • Data integrityが重要 - encodingによりbrowser、proxy、serverがuser dataをURL structureとして誤読するのを防ぎます。
  • Securityはcontextに依存する - 正しいencodingはparameter injectionやbroken redirectsの防止に役立ちます。

URL Encodingの仕組み

processは単純です。

  1. encodingが必要なcharacterを取ります。
  2. UTF-8 bytesへ変換します。
  3. 各byteを%と2桁のuppercase hexadecimal digitsで書きます。

ASCII charactersでは、各characterは1 byteです。

Character: space   ASCII: 32   Hex: 20   Encoded: %20
Character: !       ASCII: 33   Hex: 21   Encoded: %21
Character: #       ASCII: 35   Hex: 23   Encoded: %23
Character: @       ASCII: 64   Hex: 40   Encoded: %40

Non-ASCII charactersでは、UTF-8が複数bytesを生成することがあります。

Character: é       UTF-8 bytes: C3 A9          Encoded: %C3%A9
Character: ñ       UTF-8 bytes: C3 B1          Encoded: %C3%B1
Character: 日      UTF-8 bytes: E6 97 A5       Encoded: %E6%97%A5
Character: 😀      UTF-8 bytes: F0 9F 98 80    Encoded: %F0%9F%98%80

Reserved CharactersとUnreserved Characters

RFC 3986はURL charactersをreservedとunreservedのcategoriesに分けています。

Unreserved characters

Letters、digits、hyphen、underscore、period、tildeは安全で、通常encodingは不要です: A-Z a-z 0-9 - _ . ~

Reserved characters

: / ? # [ ] @ ! $ & ' ( ) * + , ; = などはstructural meaningを持つことがあります。syntaxではなくdataとして使う場合はencodeします。

Unsafe or special characters

Spaces、percent signs、quotes、angle brackets、non-ASCII characters、control charactersはencodeするべきです。

よく使われるURL-Encoded Characters

CharacterEncodedCharacterEncoded
space%20!%21
"%22#%23
$%24%%25
&%26'%27
(%28)%29
+%2B,%2C
/%2F:%3A
?%3F=%3D

UnicodeとInternational CharactersのEncoding

現代のURLにはinternational textがよく含まれます。characterはまずUTF-8としてencodeされ、その各byteがpercent-encodedされます。

Example: Encoding "café" in a URL

c -> c                    (ASCII, no encoding needed)
a -> a                    (ASCII, no encoding needed)
f -> f                    (ASCII, no encoding needed)
é -> UTF-8 C3 A9 -> %C3%A9

Result: caf%C3%A9
Full URL: https://example.com/search?q=caf%C3%A9

Browsersはaddress barに読みやすいcharactersを表示しつつ、実際のrequestではencoded formを送ることがあります。

Programming LanguagesでのURL Encoding

多くのlanguagesにはURL encodingとdecodingのhelpersがあります。

JavaScript

// Encode a single query parameter value
encodeURIComponent("hello world & goodbye")
// "hello%20world%20%26%20goodbye"

// Decode it back
decodeURIComponent("hello%20world%20%26%20goodbye")
// "hello world & goodbye"

// Encode an entire URI while keeping URL structure intact
encodeURI("https://example.com/path?q=hello world")
// "https://example.com/path?q=hello%20world"

// URLSearchParams handles query encoding automatically
const params = new URLSearchParams({ q: "hello world", lang: "en" });
params.toString();
// "q=hello+world&lang=en"

Python

from urllib.parse import quote, unquote, urlencode

quote("hello world & goodbye")
# 'hello%20world%20%26%20goodbye'

unquote("hello%20world%20%26%20goodbye")
# 'hello world & goodbye'

urlencode({"q": "hello world", "lang": "en"})
# 'q=hello+world&lang=en'

quote("/path/to/resource", safe="/")
# '/path/to/resource'

PHP

// Spaces become %20
rawurlencode("hello world & goodbye");
// "hello%20world%20%26%20goodbye"

// Spaces become + for form-style data
urlencode("hello world & goodbye");
// "hello+world+%26+goodbye"

rawurldecode("hello%20world");  // "hello world"
urldecode("hello+world");       // "hello world"

Java

import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

URLEncoder.encode("hello world", StandardCharsets.UTF_8);
// "hello+world"

URLDecoder.decode("hello%20world", StandardCharsets.UTF_8);
// "hello world"

encodeURIとencodeURIComponent

JavaScriptには似た名前のfunctionsが2つありますが、用途は異なります。

FunctionUse CaseEncodeしないもの
encodeURI()URL structureを保ったままcomplete URLをencodeする: / ? # [ ] @ ! $ & ' ( ) * + , ; =
encodeURIComponent()単一のparameter valueまたはpath segmentをencodeする- _ . ~ ! ' ( ) *
const value = "price=10&currency=USD";

// Wrong for parameter values: & and = are not encoded
encodeURI("https://api.com/search?filter=" + value);
// "https://api.com/search?filter=price=10&currency=USD"
// Server sees two parameters: filter=price=10 and currency=USD

// Correct: encode the value as one component
"https://api.com/search?filter=" + encodeURIComponent(value);
// "https://api.com/search?filter=price%3D10%26currency%3DUSD"
// Server sees one parameter: filter=price=10&currency=USD

目安

query parametersやpath segmentsなどの個別valueにはencodeURIComponent()を使います。encodeURI()は、すでに組み立て済みのfull URLにだけ使います。

URL Encodingでよくある失敗

1. Double encoding

すでにencodedされたtextをさらにencodingすると、percent sign自体が%25になるため%20が%2520になります。dataがURLへ入る境界で一度だけencodeします。

2. Using encodeURI for query values

encodeURIは&や=をencodeしないため、user inputが意図せずextra query parametersになることがあります。valuesにはencodeURIComponentを使います。

3. Confusing + and %20

+はapplication/x-www-form-urlencoded dataではspaceを意味しますが、decodeURIComponentは+を自動でspaceに変換しません。

4. Not encoding file names or path segments

File namesにはspacesやspecial charactersを含められます。URLへ入れる前に各path segmentをencodeします。

const encoded = encodeURIComponent("hello world");
// "hello%20world"

encodeURIComponent(encoded);
// "hello%2520world"  <-- wrong, % became %25

const value = "hello world";
const url = "/search?q=" + encodeURIComponent(value);
// Encode once at the boundary
// Broken or ambiguous URL
const url = "/files/" + "my report (final).pdf";
// "/files/my report (final).pdf"

// Properly encoded path segment
const url = "/files/" + encodeURIComponent("my report (final).pdf");
// "/files/my%20report%20(final).pdf"

Real-World Examples

URL encodingは通常のweb workで常に登場します。

Google Search

https://www.google.com/search?q=what+is+URL+encoding%3F

Spaces become +
Question mark becomes %3F

API Requests

GET /api/users?name=O%27Brien&city=San%20Francisco

Decoded:
  name = O'Brien
  city = San Francisco

Email Mailto Links

mailto:user@example.com?subject=Hello%20World&body=Hi%2C%20how%20are%20you%3F

Decoded:
  subject = Hello World
  body = Hi, how are you?

Redirect URLs

https://auth.example.com/login?redirect=https%3A%2F%2Fapp.example.com%2Fdashboard%3Ftab%3Dsettings

Decoded redirect value:
  https://app.example.com/dashboard?tab=settings

URLをすぐにEncode & Decode

無料のURL Encoder & Decoder toolで、任意のURL、query parameter、textをbrowser内ですぐにencodeまたはdecodeできます。

URL Encoder & Decoderを試す

参考資料

  1. Berners-Lee, T., Fielding, R., & Masinter, L. (2005). RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax. https://datatracker.ietf.org/doc/html/rfc3986
  2. Berners-Lee, T., Masinter, L., & McCahill, M. (1994). RFC 1738 - Uniform Resource Locators (URL). https://datatracker.ietf.org/doc/html/rfc1738
  3. Mozilla Developer Network. encodeURIComponent() - JavaScript. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
  4. WHATWG. URL Standard. https://url.spec.whatwg.org/
  5. Python Software Foundation. urllib.parse - Parse URLs into components. https://docs.python.org/3/library/urllib.parse.html