URL을 디코딩하는 방법
- 인코딩된 텍스트를 인코딩된 URL 또는 텍스트에 붙여넣으세요.
- 쿼리 문자열과 폼 데이터에는 +를 공백으로 처리를 켜 두고, 경로나 Base64 값에는 끄세요.
- 결과에 아직
%XX시퀀스가 남아 있으면 상태 메시지가 알려 줍니다. 반복 디코딩을 켜세요. - 로그 파일이나 값이 한 열로 나열된 목록이라면 줄마다 따로를 켜서 줄마다 따로 디코딩하세요.
- 원본이 UTF-8이 아니면 문자 인코딩을 고른 뒤 출력 복사를 누르세요.
입력이 전체 URL이면 창 아래 표에 스킴, 호스트, 디코딩된 경로, 쿼리 파라미터(한 행에 하나씩), 프래그먼트가 표시됩니다. 길고 복잡한 추적 URL이나 리디렉션 URL을 읽는 가장 빠른 방법입니다.
예시
| 인코딩됨 | 디코딩 결과 | 참고 |
|---|---|---|
q=base64%20%26%20%22url-safe%22 | q=base64 & "url-safe" | %26은 &, %22는 " |
lang=%E6%97%A5%E6%9C%AC%E8%AA%9E | lang=日本語 | UTF-8에서 문자당 3바이트 |
%F0%9F%98%80 | 😀 | 이모지는 4바이트 |
q=a+b%2Bc | q=a b+c | +를 공백으로 처리 사용 시 |
next=%252Fhome%253Ftab%253D1 | next=/home?tab=1 | 이중 인코딩, 2회 디코딩 |
caf%E9 | café | UTF-8이 아니라 Windows-1252 또는 ISO-8859-1 |
이중 인코딩
이미 인코딩된 문자열을 다시 인코딩할 때마다 모든 %가 %25가 됩니다. 그래서 /는 %2F, 그다음 %252F, 그다음 %25252F가 됩니다. 리디렉션 URL이 여러 서비스를 거치거나, 코드에서 이미 인코딩한 값을 프레임워크가 또 인코딩할 때 생깁니다.
이런 문자열을 읽으려면 이스케이프가 남지 않을 때까지 디코딩하세요. 반복 디코딩이 그 일을 하고 횟수를 알려 줍니다. 원인을 고치려면 두 번째로 인코딩하는 계층을 찾으세요. 다른 URL을 담은 next=나 url= 파라미터처럼 정당하게 중첩된 URL은 정확히 한 겹만 더 인코딩되어야 합니다.
이메일 보안 게이트웨이는 이런 중첩이 흔히 생기는 곳입니다. Microsoft Defender Safe Links URL은 https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fexample.com%2Freset%3Fid%3D42&data=…처럼 생겼습니다. 붙여넣으면 아무것도 클릭하지 않고도 파라미터 표에서 실제 목적지 https://example.com/reset?id=42를 확인할 수 있습니다.
잘못된 이스케이프와 레거시 문자 인코딩
% 뒤에는 정확히 hex 두 자리가 와야 합니다. 100%, %zz, 이스케이프 중간에서 잘린 URL은 오류이며, 디코더는 N 위치의 이스케이프가 잘못되었습니다라고 알려 줍니다. JavaScript의 decodeURIComponent는 같은 경우에 URIError: URI malformed를 던지고, Python의 unquote는 시퀀스를 그대로 둡니다.
또 다른 오류 원인은 문자 인코딩입니다. 퍼센트 이스케이프는 바이트이고, %E9 하나만으로는 올바른 UTF-8이 아닙니다. Python은 이를 대체 문자로 디코딩하고 JavaScript는 오류를 던집니다. 문자 인코딩을 Windows-1252나 ISO-8859-1로 설정하면 é로 디코딩됩니다. Shift_JIS, GBK, EUC-KR, KOI8-R 등 다른 레거시 문자 인코딩도 같은 목록에 있습니다. 오래된 한국어 사이트의 URL에서 한글이 깨진다면 EUC-KR을 선택해 보세요.
코드에서 URL 디코딩
decodeURIComponent("a%20b%26c") // "a b&c"
new URLSearchParams("q=a+b%2Bc").get("q") // "a b+c"
from urllib.parse import unquote, unquote_plus, parse_qs
unquote("caf%C3%A9") # 'café'
unquote("caf%E9", encoding="latin-1") # 'café'
unquote_plus("q=a+b%2Bc") # 'q=a b+c'
parse_qs("q=a+b%2Bc&tag=x&tag=y") # {'q': ['a b+c'], 'tag': ['x', 'y']}
decodeURIComponent는 +를 공백으로 바꾸지 않지만, URLSearchParams와 unquote_plus는 바꿉니다. 문자열을 만든 방식에 맞는 것을 고르세요. 인코딩은 URL 인코더를, URL을 거쳐 온 Base64는 Base64URL 디코더를 참고하세요.
자주 묻는 질문
URL 인코딩된 문자열은 어떻게 디코딩하나요?
위에 붙여넣으면 입력하는 대로 디코딩된 텍스트가 나타납니다. JavaScript에서는 decodeURIComponent(s), Python에서는 urllib.parse.unquote(s)를 쓰고, +가 공백을 뜻한다면 unquote_plus(s)를 쓰세요.
디코딩한 URL에 아직 %20이나 %3A가 남아 있는 이유는 무엇인가요?
두 번 인코딩되었기 때문입니다. 한 번 디코딩하면 %2520이 %20이 되고, 두 번째에 공백이 됩니다. 반복 디코딩을 켜면 이스케이프가 남지 않을 때까지 최대 다섯 번 디코딩하고 몇 번 걸렸는지 알려 줍니다.
decodeURIComponent가 URI malformed 오류를 내는 이유는 무엇인가요?
100%처럼 % 뒤에 hex 두 자리가 없거나, Windows-1252 시스템에서 온 %E9처럼 바이트가 올바른 UTF-8이 아닌 경우입니다. 이 디코더는 정확한 위치를 알려 주며, 문자 인코딩 옵션으로 레거시 인코딩도 디코딩합니다.
+를 공백으로 디코딩해야 하나요?
쿼리 문자열과 폼 본문에서는 그렇습니다. 그래서 +를 공백으로 처리가 기본으로 켜져 있습니다. URL 경로나 Base64가 들어 있을 수 있는 값에서는 끄세요. 그런 곳의 +는 문자 그대로의 더하기 기호입니다.