URL의 «인코딩»과 «디코딩»은 무엇을 의미하나요?
URL 인코딩하기 («url encode», «urlencode»)은 주소에서 금지된 문자 — 공백, 악센트, 앰퍼샌드, 더하기 기호 — 를 퍼센트 기호와 그 바이트의 16진 두 자리로 이루어진 시퀀스로 바꿉니다. URL 디코딩하기 («url decode», «decoder url»)은 이 시퀀스를 거꾸로 읽습니다 : 바이트를 복원한 뒤 선언된 인코딩(대부분 UTF-8)에 따라 문자로 변환합니다. «encoder decoder url»이나 «percent encoding online»을 검색하는 사람이 바로 이 한 쌍을 찾는 것입니다.
percent-encoding은 압축도 암호도 아닙니다 : 악센트가 붙은 단어는 두 배로 길어지고 누구나 눈으로 읽을 수 있습니다. 유일한 역할은 URL에 아무 바이트나 태우는 것입니다. URL는 기본적으로 ASCII의 일부만 허용하거든요. 반대로 Base64는 완전한 텍스트 채널에서 바이트를 나르는 용도입니다 — 겉보기는 비슷하지만 서로 바꿔 쓸 수 없습니다.
URL을 percent-encoding으로 인코딩하는 방법
1단계 : 텍스트는 선택한 문자셋(기본값 UTF-8)에 따라 바이트로 변환됩니다. 2단계 : 각 바이트마다 해당 문자가 선택한 범위의 허용 문자 목록에 들어가는지 확인합니다. 3단계 : 들어 있으면 그대로 복사되고, 아니면 다음이 됩니다 %XX (XX는 바이트의 16진 두 자리). 4단계 : 공백을 + 로 바꾸는 옵션이 켜져 있으면 바이트 32는 더하기 기호로 대체되고, 원래 값은 %20.
구체적인 예 : « café & été »를 구성 요소 범위로 인코딩하면 caf%C3%A9%20%26%20%C3%A9t%C3%A9. 인코더에 이 텍스트를 입력하기만 하면 결과, 입력 크기, 출력 크기, 오버헤드가 키를 떼기 전에 표시됩니다.
인코딩 범위 네 가지
그중 구성 요소 범위 가 유지하는 것은 문자, 숫자 그리고 - _ . ! ~ * ' ( ) 뿐입니다. 이는 매개변수 값의 범위로, 다음과 encodeURIComponent와 일치합니다. 또한 쿼리 문자열 은 앰퍼샌드와 등호를 추가로 유지해 전체 query string을 다시 만듭니다. 경로 세그먼트 가 허용하는 기호는 / : @ & = + $ , ; 로, 세로선이 깨지지 않게 하기 위함입니다. 그리고 전체 URL 은 여기에 더합니다 : ?, #, [ 그리고 ] : 거의 아무것도 이스케이프되지 않습니다. %XX가 되는 것은 공백과 비 ASCII 문자뿐입니다 : %XX.
인코딩된 URL 디코딩하는 방법
디코딩은 문자열을 왼쪽에서 오른쪽으로 훑습니다 : 퍼센트 뒤에 16진 두 자리가 붙으면 바이트 하나가 되고, 그 밖의 문자는 선택한 인코딩으로 변환한 뒤 그대로 남습니다. 이후 바이트를 묶어 문자로 바꿉니다 — « é»는 두 바이트, « 日»는 세 바이트, 이모지는 네 바이트입니다. «디코딩» 탭에는 발견한 각 시퀀스와 문자열에서의 위치, 해당 바이트, 그리고 해당 텍스트가 표시됩니다.
퍼센트 뒤에 유효한 16진 두 자리가 붙지 않으면 오류가 분명하게 표시됩니다 : 시퀀스가 불완전하거나 16진 문자가 잘못된 경우입니다. «% 수정» 버튼은 고립된 퍼센트 기호를 %25로 바꿔서 정보 손실 없이 문자열을 디코딩할 수 있게 합니다 — 부분적으로만 이스케이프된 URL을 처리할 때 가장 안전한 방법입니다.
공백 : %20와 + — 폼의 규칙
%20 는 엄격한 percent-encoding의 공백으로, 경로, 쿼리, 프래그먼트, 헤더 모두에서 동작합니다. 반면 기호 +는 다음 형식에서만 공백으로 취급됩니다 : application/x-www-form-urlencoded 은 HTML 폼과 예전 query string이 쓰는 형식입니다. 다른 곳에서는 그대로 더하기 기호일 뿐이며, 혼동하기 쉬우므로 값을 인코딩할 때는 반드시 %2B 로 이스케이프해야 합니다.
실제로는 : 폼 필드에 값을 넣거나 <form>, « 공백을 + »에 체크하세요. 리디렉션 URL, canonical, 공유 링크에서는 항상 %20를 쓰세요. 디코더는 + 를 기본적으로 공백으로 취급하며, 이 설정은 클릭 한 번으로 끌 수 있습니다.
RFC 3986 : unreserved, sub-delims, gen-delims
RFC 3986은 ASCII 문자를 세 가지 범주로 나눕니다. 그중 비예약 문자 — 문자, 숫자, - _ . ~ —는 항상 그대로 유지됩니다. 다음 하위 구분 기호 ! $ & ' ( ) * + , ; = 와 일반 구분 기호 : / ? # [ ] @ 는 구조적 의미를 가집니다 : 권한, 경로, 쿼리, 프래그먼트를 나누는 역할입니다. 나머지 — 공백, 따옴표, 괄호, 중괄호, 퍼센트 기호 — 는 모두 인코딩해야 합니다.
이 범주들은 «RFC 3986 & 참고» 탭이 문자 하나하나 보여 주는 것과 정확히 같습니다 : 타일을 클릭하면 16진 코드, 범주, 이 문자를 유지하는 범위를 확인할 수 있습니다. «이 문자를 이스케이프해야 하나?»라는 질문에 답하기 위한 가장 빠른 참조입니다.
악센트 문자, 이모지, UTF-8
URL는 안전한 ASCII 바이트만 담으므로 U+007F를 넘는 모든 문자는 인코딩해야 합니다. UTF-8에서 « é»는 C3 A9 이고, 그 결과 %C3%A9입니다. « 日»는 세 바이트여서 시퀀스 세 개가 나오고, 이모지는 네 바이트를 써서 인코딩하면 여덟 문자가 됩니다. 결과가 길어 보여도 버그가 아닙니다 : 모든 프로토콜과 호환되기 위한 대가입니다. 마지막으로 원본 문자셋에 주의하세요 — Latin-1로 인코딩된 문자열을 UTF-8로 디코딩하면 이상한 문자가 나오므로 «디코딩» 탭에 네 가지 선택지가 있는 것입니다.
encodeURIComponent만으로는 왜 충분하지 않은가
encodeURIComponent 는 다음을 뺀 모든 것을 인코딩합니다 : A-Z a-z 0-9 - _ . ! ~ * ' ( ) 이 방식은 매개변수 값에는 맞지만 슬래시와 콜론, 앰퍼샌드까지 이스케이프하므로 전체 URL는 깨집니다. encodeURI 는 정반대입니다 : URL 구조는 유지하지만 공백과 악센트를 그대로 통과시키므로 날 텍스트에는 실패합니다. 이 두 동작은 여기서 모두 커버됩니다 — «쿼리 문자열» 범위와 «경로 세그먼트» 범위가 그 사이를 메워 주기 때문에 훨씬 더합니다.
percent-encoding과 Base64 : 서로 다른 두 도구
percent-encoding은 바이트마다 바꿔치기하여 원본 텍스트의 가독성을 지키는 대신 길이가 크게 늘어납니다. Base64는 바이트를 셋씩 묶어 64문자 알파벳으로 다시 씁니다 : 컴팩트하지만 전혀 읽을 수 없고, URL-safe 변형 없이는 URL에 그대로 쓸 수 없습니다. «교차 인코딩» 탭에서는 두 가지를 한 번에 볼 수 있고, 16진 바이트, HTML 엔티티, 이스케이프된 JSON 문자열까지 함께 나오니 무엇이든 복사하기 전에 알맞은 표현을 고를 수 있습니다.
자주 하는 실수 : 이중 인코딩과 고립된 %
가장 흔한 실수는 같은 문자열을 두 번 이스케이프하는 것입니다 : 공백이 %20가 되고, 다시 %2520이고, 서버는 문자 그대로 « %20»를 받습니다. 두 번째 실수는 퍼센트 기호 자체를 잊는 것으로, 이는 %25 여야 합니다 — 아니면 디코더가 시퀀스의 시작으로 오인해 멈추거나 잘립니다. 마지막으로, 폼 매개변수에서 + 이스케이프하지 않고 두면 요청하지도 않은 공백을 넣는 것과 같습니다. 디코더는 잘못된 시퀀스를 알려 주고, «% 수정» 버튼은 두 번째 경우를 손실 없이 고칩니다.
인코딩된 URL은 어디에 숨어 있을까
트래킹 query string의 UTM, 그리고 redirect_uri 그리고 상태 OAuth, 그리고 webhooks 로 대상 URL에 중첩된 매개변수를 담고 있는 것, 그리고 서명된 콜백 URL , 서버 로그, sitemap과 canonical, 그리고 <a href> 로 클라이언트에서 만들어진 것, 그리고 JWT 로 payload가 Base64URL인 것, 그리고 data: 그리고 Location 같은 헤더, 그리고 GET으로 전송되는 모든 HTML 폼에도 있습니다. 1초 만에 인코딩과 디코딩을 할 수 있으면 문자 하나 때문에 터미널을 열 일이 없습니다.
성능과 모범 사례
브라우저에서 인코딩과 디코딩은 선형이라 몇 메가바이트여도 눈에 띄는 비용이 없습니다 : 각 문자를 한 번씩만 처리하며 재귀도 문자별 할당도 없습니다. 주의할 점은 이중 인코딩 — 저장하기 전에 항상 왕복을 확인하세요 — 과 여러 킬로바이트짜리 URL로, 2 000자를 넘으면 프록시에 잘리는 일이 많습니다. 생성한 문자열 옆에 사용한 범위를 적어 두세요 : «구성 요소»와 «전체 URL»은 같은 텍스트에서도 결과가 다릅니다.
추천 대상
백엔드·프론트엔드 개발자(query string, 리디렉션, OAuth), 통합 담당자와 기술 작가(UTM 링크, canonical, 트래킹), 관리자와 DevOps(webhook, 서명 URL, 로그), 테스터와 침투 테스터(매개변수 퍼징, 필터 우회), 학생(UTF-8, ASCII, RFC 3986 학습), 그리고 다음이 필요한 모든 사람 : 온라인 URL 인코더 / 디코더 를 빠르고 완전하며 안심할 수 있는 것으로 — 보완으로는Base64 인코더 / 디코더 와 JSON 포매터.