문자열을 URL 인코딩하는 방법
- 텍스트 또는 URL에 텍스트를 입력하거나 붙여넣으세요. 입력하는 대로 출력이 바뀝니다.
- 인코딩에서 모드를 고르세요.
- 구성 요소 (encodeURIComponent): 쿼리 값 하나, 폼 필드, 경로 세그먼트용.
- 전체 URL (encodeURI): 공백이나 ASCII 밖의 문자가 들어 있는 완전한 URL용.
- 폼 데이터 (공백을 +로):
application/x-www-form-urlencoded본문과, HTML 폼과 같은 방식으로 만드는 쿼리 문자열용. - 모든 문자: 디코더 테스트용으로 영문자를 포함한 모든 바이트를 퍼센트 인코딩합니다.
- 받는 시스템이 레거시 인코딩을 기대하지 않는 한 문자 인코딩은 UTF-8로 두세요.
- 값 목록을 한 번에 인코딩하려면 줄마다 따로를 켠 다음 출력 복사를 누르세요. 바꾸기는 결과를 디코더로 보내 왕복 변환을 확인합니다.
입력한 전체 URL은 스킴, 호스트, 경로, 각 쿼리 파라미터, 프래그먼트로도 나뉘어 창 아래 표에 표시됩니다.
encodeURIComponent, encodeURI, 폼 인코딩 비교
같은 입력 a b&c=d/é?#+를 흔히 쓰는 세 가지 방식으로 인코딩하면 다음과 같습니다.
| 모드 | 출력 | 용도 |
|---|---|---|
구성 요소 (encodeURIComponent) | a%20b%26c%3Dd%2F%C3%A9%3F%23%2B | URL 안의 값 하나 |
전체 URL (encodeURI) | a%20b&c=d/%C3%A9?#+ | 구조가 이미 올바른 URL 전체 |
폼 데이터 (URLSearchParams) | a+b%26c%3Dd%2F%C3%A9%3F%23%2B | HTML 폼 전송, 많은 쿼리 문자열 라이브러리 |
구성 요소는 A–Z a–z 0–9 - _ . ! ~ * ' ( )만 이스케이프하지 않습니다. 전체 URL은 URL의 구조를 이루는 ; / ? : @ & = + $ , #도 유지하므로, 이런 문자가 들어 있는 값은 보호하지 못합니다. 폼 데이터는 영문자, 숫자, - _ . *만 유지하고 공백을 +로 씁니다.
대표적인 버그는 전체 URL 인코딩으로 URL을 만드는 것입니다. ?q=C++ & Go는 +와 &가 그대로 남아 서버가 q=C 와 엉뚱한 파라미터 하나를 받습니다. 값은 구성 요소로 인코딩하세요: ?q=C%2B%2B%20%26%20Go.
공백, 더하기 기호, 그 밖의 말썽꾼
| 문자 | 인코딩 | 중요한 이유 |
|---|---|---|
| 공백 | %20 또는 + | +는 쿼리 문자열과 폼 본문에서만 공백을 뜻함 |
+ | %2B | 인코딩하지 않으면 많은 서버가 공백으로 바꿈: +49 30 1234567이 49 30 1234567이 됨 |
& | %26 | 새 쿼리 파라미터를 시작함 |
= | %3D | 이름과 값을 구분함. 표준 Base64는 이것으로 끝남 |
/ | %2F | 경로 세그먼트를 나눔. 일부 서버는 경로의 %2F를 거부함 |
# | %23 | 프래그먼트를 시작하며, 프래그먼트는 서버로 전송되지 않음 |
% | %25 | 자기 자신도 인코딩해야 함. 아니면 디코더가 잘못된 이스케이프로 읽음 |
€ | %E2%82%AC | UTF-8 3바이트, 이스케이프 3개 |
URL 속 Base64는 +, /, = 문제가 생기는 흔한 경우입니다. 구성 요소로 퍼센트 인코딩하거나, 이런 문자를 쓰지 않는 Base64URL로 바꾸세요.
UTF-8이 아닌 문자 인코딩
퍼센트 인코딩은 바이트 단위로 동작하므로 결과는 문자 인코딩에 따라 정해집니다. é는 UTF-8에서 %C3%A9, Windows-1252나 ISO-8859-1에서 %E9입니다. 최신 브라우저와 API는 UTF-8을 쓰지만, 오래된 PHP 애플리케이션, 일부 결제 게이트웨이, 레거시 인트라넷 시스템은 아직 Latin-1이나 Windows-1252를 기대하고, 일본 사이트는 Shift_JIS를, 오래된 한국어 사이트는 EUC-KR을 기대하기도 합니다. 문자 인코딩에서 그에 맞게 고르세요. 선택한 문자 인코딩에 없는 문자는 표현할 수 없으니 출력에서 그런 문자가 있는지 확인하세요.
코드에서 URL 인코딩
encodeURIComponent("a b&c") // "a%20b%26c"
new URLSearchParams({ q: "C++ & Go" }).toString() // "q=C%2B%2B+%26+Go"
from urllib.parse import quote, quote_plus, urlencode
quote("/files/a b.txt") # '/files/a%20b.txt' (keeps / by default)
quote("/files/a b.txt", safe="") # '%2Ffiles%2Fa%20b.txt'
quote_plus("a b&c") # 'a+b%26c'
urlencode({"q": "C++ & Go"}) # 'q=C%2B%2B+%26+Go'
Python의 quote는 safe=""를 넘기지 않으면 /를 유지합니다. 값을 인코딩할 때 자주 놀라는 부분입니다. 다른 언어로는 PHP의 rawurlencode가 %20, urlencode가 +를 내고, Java의 URLEncoder.encode는 +를 쓰는 폼 인코딩이며, Go에는 url.PathEscape(%20)와 url.QueryEscape(+)가 있습니다. encodeURIComponent는 ! ' ( ) *를 그대로 두므로, 엄격한 RFC 3986 출력이 필요하면 나중에 바꾸세요.
const strict = s => encodeURIComponent(s).replace(/[!'()*]/g,
c => "%" + c.charCodeAt(0).toString(16).toUpperCase());
JavaScript 쪽은 JavaScript Base64 페이지에서 더 다룹니다. 이 모든 것을 되돌리려면 URL 디코더를 쓰세요.
자주 묻는 질문
URL 인코딩이란 무엇인가요?
URL 인코딩, 즉 퍼센트 인코딩은 URL에서 허용되지 않거나 특별한 의미가 있는 문자를 %와 각 바이트의 hex 두 자리로 바꾸는 것입니다. 공백은 %20, &는 %26, UTF-8의 é는 %C3%A9가 됩니다.
URL에서 공백은 %20과 + 중 무엇으로 인코딩하나요?
%20은 어디서나 통합니다. +는 폼 인코딩 규칙을 따르는 쿼리 문자열과 폼 본문에서만 공백을 뜻하고, 경로에서는 문자 그대로의 더하기 기호입니다. 확실하지 않으면 %20을 쓰세요.
URL 전체를 URL 인코딩해야 하나요?
아니요, 값을 넣기 전에 값마다 인코딩하세요. URL 전체를 구성 요소로 인코딩하면 :, /, ?, &까지 이스케이프되어 URL이 깨집니다. 전체 URL 모드는 이런 구조 문자를 유지하고 공백과 ASCII 밖의 텍스트만 고칩니다.
인코딩한 문자열에 %25가 들어 있는 이유는 무엇인가요?
%25는 인코딩된 퍼센트 기호입니다. 즉 입력이 이미 인코딩되어 있었는데 한 번 더 인코딩된 것입니다. a%20b는 a%2520b가 됩니다. 원본 텍스트는 정확히 한 번만 인코딩하세요.
퍼센트 인코딩의 hex는 대문자인가요, 소문자인가요?
RFC 3986은 %2F와 %2f를 같은 것으로 보고 대문자를 권장합니다. 서명을 비교할 때처럼 소문자를 만드는 시스템과 맞춰야 할 때만 소문자 hex를 켜세요.