URL 인코딩이란? 퍼센트 인코딩과 한글·공백 처리
URL에 쓸 수 없는 공백·한글·특수문자를 %XX로 바꾸는 퍼센트 인코딩의 원리와 쿼리스트링 처리, 흔한 실수를 정리합니다.
주소창에 한글이 들어간 링크를 복사했더니 %ED%95%9C%EA%B8%80 같은 알 수 없는 문자열로 바뀐 경험이 한 번쯤 있을 것입니다. 검색어에 공백이 들어가면 %20이나 +로 바뀌고, 이메일 주소나 특수문자가 포함된 값을 링크로 전달하면 갑자기 페이지가 엉뚱하게 동작하기도 합니다. 이 모든 현상의 배경에는 URL 인코딩(퍼센트 인코딩) 이라는 규칙이 있습니다. URL은 정해진 글자만 안전하게 담을 수 있는 그릇이라서, 그 밖의 문자는 약속된 방식으로 변환해 주어야 의미가 깨지지 않습니다. 이 글에서는 퍼센트 인코딩이 무엇인지, 어떤 문자를 어떻게 바꾸는지, 쿼리스트링은 어떻게 처리하는지, 그리고 실무에서 자주 저지르는 실수까지 차근차근 정리합니다. 직접 변환해 보고 싶다면 URL 인코더 / 디코더를 함께 열어 두고 읽으면 이해가 훨씬 빠릅니다.
한눈에 보기
- URL 인코딩(퍼센트 인코딩)은 URL에 직접 쓸 수 없는 문자를
%+ 16진수 2자리로 바꾸는 규칙입니다. - 공백은
%20으로, 쿼리스트링에서는 관례적으로+로도 표현합니다. - 한글은 먼저 UTF-8 바이트로 바꾼 뒤 각 바이트를 퍼센트로 인코딩합니다. 예: "한" →
%ED%95%9C. - 예약문자(
? & = / #등)가 값 안에 들어가면 반드시 인코딩해야 URL 구조가 깨지지 않습니다. - 자바스크립트에서는 값 하나는
encodeURIComponent, 전체 URL은encodeURI로 구분해서 씁니다.
URL 인코딩이란
URL 인코딩은 인터넷 주소(URL)에 안전하게 담을 수 없는 문자를 약속된 형식으로 변환하는 방법입니다. 정식 명칭은 퍼센트 인코딩(percent encoding) 으로, 변환된 결과가 항상 퍼센트 기호(%)로 시작하기 때문에 붙은 이름입니다. 규칙은 단순합니다. 그대로 쓸 수 없는 문자를 그 문자에 해당하는 바이트 값으로 보고, 그 바이트를 % 다음에 16진수 두 자리 로 적습니다. 예를 들어 공백 문자는 바이트 값이 32(16진수로 20)이므로 %20이 됩니다.
URL이 이런 제약을 두는 이유는 역사적입니다. 초기 웹은 영문 알파벳, 숫자, 그리고 몇몇 기호만으로 주소를 표현하도록 설계되었습니다. 그래서 영어가 아닌 문자나 공백, 일부 기호는 주소 안에서 직접 표현할 수 없고, 반드시 퍼센트 인코딩을 거쳐야 합니다. 덕분에 어떤 브라우저나 서버를 거치더라도 주소의 의미가 동일하게 전달됩니다.
어떤 문자를 바꾸나
인코딩이 필요 없는 문자를 보통 비예약 문자(unreserved) 라고 부릅니다. 영문 대소문자(A-Z, a-z), 숫자(0-9), 그리고 - _ . ~ 네 가지 기호는 그대로 써도 안전합니다. 이 범위를 벗어나는 문자는 인코딩 대상이 됩니다. 대표적인 경우를 정리하면 다음과 같습니다.
| 입력 문자 | 인코딩 결과 | 설명 |
|---|---|---|
| 공백 | %20 (또는 +) | 쿼리스트링에서는 +로도 표현 |
한 | %ED%95%9C | UTF-8 3바이트를 각각 인코딩 |
& | %26 | 파라미터 구분자라 값에선 인코딩 필요 |
= | %3D | 키-값 구분자 |
? | %3F | 쿼리스트링 시작 기호 |
/ | %2F | 경로 구분자 |
# | %23 | 프래그먼트 시작 기호 |
여기서 한글 처리는 조금 더 설명이 필요합니다. 한글 같은 비ASCII 문자는 먼저 UTF-8 방식으로 바이트 열로 변환합니다. "한"이라는 글자는 UTF-8에서 세 개의 바이트(ED 95 9C)로 표현되므로, 이를 한 바이트씩 퍼센트 인코딩하면 %ED%95%9C가 됩니다. 즉 한 글자가 여러 개의 %XX 묶음으로 늘어나는 것이 정상입니다. 어떤 글자가 어떻게 바뀌는지 빠르게 확인하려면 URL 인코더 / 디코더에 직접 입력해 결과를 비교해 보세요.
쿼리스트링 처리
URL에서 ? 뒤에 오는 부분을 쿼리스트링 이라고 합니다. key=value 형태의 항목을 &로 이어 붙여 여러 값을 함께 전달하는 영역입니다. 예를 들어 search.html?q=고양이&page=2라면 q라는 키에 "고양이", page라는 키에 "2"를 담아 보내는 구조입니다.
여기서 핵심은 &와 =가 구분 기호 라는 점입니다. 이 기호들은 항목과 항목, 키와 값을 나누는 약속된 역할을 합니다. 따라서 값 자체에 &나 =가 들어 있다면 그대로 두면 안 됩니다. 예를 들어 검색어가 "커피 & 차"라면 &를 인코딩하지 않을 경우 서버는 "커피 "에서 값이 끝나고 그 뒤를 새로운 파라미터로 오해합니다. 이때 &를 %26으로 바꿔 주면 값의 일부로 올바르게 전달됩니다.
또 한 가지, 쿼리스트링에서는 공백을 %20 대신 +로 표현하는 오랜 관례가 있습니다. HTML 폼이 데이터를 전송할 때 쓰는 방식에서 비롯된 것으로, 많은 서버가 쿼리 영역의 +를 공백으로 되돌려 읽습니다. 다만 경로(path) 부분에서는 +가 공백으로 해석되지 않으므로, 위치에 따라 공백 표현이 달라질 수 있다는 점만 기억하면 됩니다.
자바스크립트로 직접 URL을 조립할 때는 두 함수를 구분해서 쓰는 것이 중요합니다. encodeURIComponent 는 쿼리 값 하나처럼 작은 조각을 인코딩할 때 사용하며, ? & = / # 같은 예약문자까지 모두 인코딩합니다. 반면 encodeURI 는 이미 완성된 전체 URL을 다룰 때 쓰며, 구조를 이루는 문자(: / ? & 등)는 보존합니다. 정리하면, 값 하나를 끼워 넣을 때는 encodeURIComponent, 주소 전체를 한 번 정리할 때는 encodeURI입니다.
const keyword = "커피 & 차";
const url = "https://example.com/search?q=" + encodeURIComponent(keyword);
// → https://example.com/search?q=%EC%BB%A4%ED%94%BC%20%26%20%EC%B0%A8
흔한 실수
가장 흔한 실수는 값에 들어 있는 &를 인코딩하지 않는 것 입니다. 앞에서 본 것처럼 &는 파라미터를 나누는 기호라서, 값 안의 &를 그대로 두면 그 지점에서 값이 잘리고 나머지가 별개의 파라미터로 인식됩니다. 결과적으로 데이터가 누락되거나 엉뚱하게 전달됩니다.
두 번째 실수는 이미 인코딩된 문자열을 한 번 더 인코딩하는 이중 인코딩 입니다. %20이 다시 인코딩되면 %2520이 되어 디코딩 단계에서 원래 값으로 돌아오지 못합니다. 값을 조립하기 전에 현재 상태가 인코딩 전인지 후인지 먼저 확인해야 합니다.
세 번째는 전체 URL에 encodeURIComponent를 적용하는 것 입니다. 이렇게 하면 ://나 ? 같은 구조 문자까지 모두 바뀌어 주소 자체가 망가집니다. 전체 URL에는 encodeURI를, 개별 값에는 encodeURIComponent를 쓴다는 원칙을 지키면 대부분의 문제를 피할 수 있습니다.
자주 묻는 질문
공백은 %20과 + 중 무엇이 맞나요?
둘 다 쓰이지만 위치가 다릅니다. 경로 부분에서는 %20이 표준이고, 쿼리스트링에서는 +도 공백으로 해석되는 관례가 있습니다. 헷갈린다면 %20을 쓰는 편이 대부분의 환경에서 안전합니다.
한글 한 글자가 왜 %XX 세 묶음으로 바뀌나요?
한글은 UTF-8에서 한 글자가 보통 3바이트로 표현되기 때문입니다. 퍼센트 인코딩은 바이트 단위로 동작하므로 3바이트짜리 글자는 %ED%95%9C처럼 세 개의 묶음으로 나타납니다.
encodeURI와 encodeURIComponent는 어떻게 구분하나요?
완성된 전체 URL을 정리할 때는 구조 문자를 보존하는 encodeURI를, 쿼리 값처럼 URL의 한 조각을 인코딩할 때는 예약문자까지 모두 바꾸는 encodeURIComponent를 사용합니다.
인코딩된 주소를 다시 원래대로 보려면 어떻게 하나요?
디코딩하면 됩니다. %ED%95%9C 같은 문자열을 입력하면 원래 글자로 되돌릴 수 있습니다. URL 인코더 / 디코더에서 인코딩과 디코딩을 모두 바로 확인할 수 있습니다.
왜 처음부터 한글을 그냥 주소에 쓰면 안 되나요? 브라우저 주소창은 보기 편하게 한글을 그대로 보여 주기도 하지만, 실제로 서버에 전송될 때는 인코딩된 형태로 바뀝니다. 링크를 복사하거나 프로그램에서 직접 다룰 때는 인코딩 규칙을 따라야 의미가 안전하게 전달됩니다.
URL 인코딩은 한 번 원리를 이해하면 그리 복잡하지 않습니다. "URL에 못 쓰는 문자는 % + 16진수로 바꾼다", "한글은 UTF-8 바이트로 인코딩한다", "값과 전체 URL은 다른 함수로 처리한다"는 세 가지만 기억하면 대부분의 상황에 대응할 수 있습니다. 직접 변환 결과를 눈으로 확인하면 가장 빠르게 익숙해지니, 지금 URL 인코더 / 디코더에 한글이나 특수문자를 넣어 보며 어떻게 바뀌는지 확인해 보세요.
🧰 관련 도구
관련 글
텍스트 음성 변환(TTS)이란? 원리와 똑똑한 활용법
글자를 음성으로 읽어주는 TTS의 원리와 브라우저 음성 합성(Web Speech API), 교정·접근성·외국어 발음 등 활용법을 정리합니다.
CSS box-shadow 완전 정복 — 그림자 값 5가지 이해
box-shadow의 가로·세로 오프셋·번짐(blur)·확산(spread)·색과 inset, 여러 그림자 겹치기를 예시 코드로 정리합니다.
CSS 그라데이션 만드는 법 — linear·radial·conic
CSS linear-gradient·radial-gradient·conic-gradient 문법과 방향·색 정지점(color stop) 지정법을 예시 코드로 정리합니다.