← 블로그 개발

URL 인코딩 완벽 가이드: 퍼센트 인코딩의 원리와 활용

2026년 3월 15일

웹 개발을 하다 보면 한번쯤은 URL에 한글이나 특수문자를 넣었다가 이상한 문자열로 바뀌는 걸 경험하게 됩니다. 처음에는 당황스럽지만, 이건 URL 인코딩이라는 아주 중요한 메커니즘이 작동한 결과입니다. 오늘은 이 URL 인코딩이 왜 필요한지, 어떤 원리로 작동하는지 하나씩 풀어보겠습니다.

URL 인코딩이란?

URL(Uniform Resource Locator)은 웹에서 자원의 위치를 나타내는 주소입니다. 그런데 URL에는 사용할 수 있는 문자가 제한되어 있습니다. ASCII 문자 중에서도 일부만 허용되고, 한글이나 중국어 같은 비ASCII 문자는 그대로 쓸 수 없습니다. URL 인코딩은 이런 문자들을 URL에서 안전하게 전송할 수 있는 형태로 바꿔주는 과정입니다.

공식적으로는 퍼센트 인코딩(Percent-encoding)이라고 부릅니다. 이름에서 알 수 있듯이 퍼센트 기호(%)를 사용해서 문자를 표현하기 때문입니다.

왜 URL 인코딩이 필요할까?

URL에는 구조적으로 특별한 의미를 가진 문자들이 있습니다. 예를 들어 /는 경로 구분자이고, ?는 쿼리 문자열의 시작을 알리며, &는 파라미터 사이의 구분자입니다. 만약 검색어에 &가 포함되어 있다면? 브라우저는 이걸 파라미터 구분자로 해석해버리겠죠. 이런 혼동을 방지하기 위해 인코딩이 필요합니다.

또 하나의 이유는 국제화입니다. URL 표준은 원래 영어 알파벳 기반으로 설계되었기 때문에, 한글이나 일본어 같은 문자를 직접 넣으면 서버가 제대로 인식하지 못할 수 있습니다. 인코딩을 통해 모든 문자를 안전한 ASCII 형태로 변환하면 이 문제가 해결됩니다.

퍼센트 인코딩의 원리

퍼센트 인코딩 방식은 단순합니다. 인코딩이 필요한 문자를 UTF-8로 변환한 뒤, 각 바이트를 %XX 형식으로 표현합니다. XX는 해당 바이트의 16진수 값입니다.

공백 → %20

"안녕" → %EC%95%88%EB%85%95

"hello world" → hello%20world

한글 "안"은 UTF-8에서 3바이트(EC, 95, 88)로 표현되므로, %EC%95%88이 됩니다. 영어 알파벳이나 숫자처럼 안전한 문자는 인코딩하지 않고 그대로 둡니다.

예약 문자와 비예약 문자

URL에서 사용되는 문자는 크게 두 종류로 나뉩니다.

  • 비예약 문자(Unreserved): 인코딩 없이 쓸 수 있는 문자들입니다. A-Z, a-z, 0-9, 그리고 - _ . ~ 네 가지 특수문자가 여기에 해당합니다.
  • 예약 문자(Reserved): URL 구조에서 특별한 의미를 가진 문자들입니다. : / ? # [ ] @ ! $ & ' ( ) * + , ; = 등이 있습니다. 이 문자들은 본래의 의미로 쓸 때는 그대로 두지만, 데이터의 일부로 쓸 때는 반드시 인코딩해야 합니다.

JavaScript에서의 URL 인코딩

JavaScript에는 URL 인코딩을 위한 함수가 두 개 있는데, 용도가 다릅니다. 이 차이를 모르면 버그가 생기기 쉽습니다.

encodeURI()는 전체 URL을 인코딩할 때 사용합니다. URL 구조를 유지해야 하므로 : / ? # & 같은 예약 문자는 인코딩하지 않습니다. 반면 encodeURIComponent()는 URL의 개별 파라미터 값을 인코딩할 때 사용하며, 예약 문자까지 전부 인코딩합니다.

encodeURI("https://example.com/검색?q=안녕")

→ https://example.com/%EA%B2%80%EC%83%89?q=%EC%95%88%EB%85%95

encodeURIComponent("key=value&name=test")

→ key%3Dvalue%26name%3Dtest

흔히 하는 실수들

1. 이중 인코딩

이미 인코딩된 문자열을 다시 인코딩하는 실수입니다. %20이 %2520으로 바뀌는 거죠. %의 16진수 코드가 25이기 때문입니다. API를 여러 번 거치는 구조에서 특히 자주 발생합니다. 디버깅할 때 URL을 직접 확인해보면 쉽게 찾을 수 있습니다.

2. encodeURI와 encodeURIComponent 혼동

파라미터 값에 URL이 들어가는 경우가 대표적입니다. redirect URL을 쿼리 파라미터로 전달할 때, encodeURI를 쓰면 내부 URL의 구조가 그대로 남아서 파싱 오류가 발생합니다. 이럴 때는 반드시 encodeURIComponent를 써야 합니다.

3. 서버와 클라이언트의 인코딩 불일치

클라이언트에서 UTF-8로 인코딩했는데 서버가 EUC-KR로 디코딩하면 한글이 깨집니다. 요즘은 대부분 UTF-8을 사용하지만, 레거시 시스템을 다룰 때는 여전히 주의가 필요합니다.

실전 활용 사례

URL 인코딩은 생각보다 많은 곳에서 쓰입니다. API 호출 시 쿼리 파라미터에 사용자 입력을 넣을 때, HTML 폼 데이터를 전송할 때(application/x-www-form-urlencoded), OAuth 인증에서 콜백 URL을 전달할 때, 그리고 파일명에 특수문자가 포함된 다운로드 링크를 만들 때 등 다양합니다.

특히 검색 기능을 구현할 때 주의해야 합니다. 사용자가 검색창에 입력한 한글이나 특수문자가 URL 파라미터로 전달되는 과정에서 제대로 인코딩되지 않으면, 검색 결과가 엉뚱하게 나오거나 아예 서버 오류가 발생할 수 있습니다.

URL 구조 상세 분석

URL 인코딩을 제대로 이해하려면 먼저 URL의 구조를 알아야 합니다. RFC 3986에 정의된 URL의 구성 요소를 하나씩 살펴보겠습니다.

https://user:pass@example.com:8080/path/to/page?key=value&q=test#section

scheme: https

authority: user:pass@example.com:8080

path: /path/to/page

query: key=value&q=test

fragment: section

Scheme(스킴): 프로토콜을 나타냅니다. http, https, ftp, mailto 등이 있습니다. 콜론과 이중 슬래시(//)로 나머지 부분과 구분됩니다.

Authority(권한): 사용자 정보(선택), 호스트명, 포트 번호로 구성됩니다. 요즘은 URL에 사용자 정보를 넣는 것이 보안상 권장되지 않습니다.

Path(경로): 서버 내 자원의 위치입니다. /로 계층을 구분합니다. 경로 안의 각 세그먼트에 특수문자가 포함되면 인코딩이 필요합니다.

Query(쿼리): ? 뒤에 오는 key=value 쌍들입니다. &로 구분됩니다. 여기서 인코딩이 가장 많이 필요한 부분입니다.

Fragment(프래그먼트): # 뒤에 오며, 페이지 내 특정 위치를 가리킵니다. 브라우저에서만 처리되고 서버로 전송되지 않습니다.

각 구성 요소마다 인코딩 규칙이 미묘하게 다릅니다. 예를 들어 /는 경로에서는 구분자이므로 인코딩하지 않지만, 쿼리 값에 포함되면 %2F로 인코딩해야 합니다. 이 맥락 의존성이 URL 인코딩을 까다롭게 만드는 핵심 원인입니다.

한글과 유니코드 URL 인코딩

한글 URL은 특히 한국 개발자들이 자주 마주치는 문제입니다. 한글은 ASCII가 아니므로 반드시 인코딩되어야 하는데, 이 과정에서 몇 가지 주의점이 있습니다.

한글은 UTF-8에서 한 글자당 3바이트를 사용합니다. 따라서 "한글"이라는 두 글자는 6바이트, 즉 6개의 퍼센트 인코딩 토큰으로 변환됩니다.

"한" → UTF-8 바이트: ED 95 9C → %ED%95%9C

"글" → UTF-8 바이트: EA B8 80 → %EA%B8%80

"한글" → %ED%95%9C%EA%B8%80

최신 브라우저들은 주소창에 한글을 그대로 표시해주지만, 실제 HTTP 요청에서는 인코딩된 형태로 전송됩니다. 브라우저가 사용자 편의를 위해 디코딩해서 보여주는 것일 뿐입니다.

국제화 도메인 이름(IDN): 도메인에 한글을 쓰는 경우(예: 한글.kr)는 퍼센트 인코딩이 아닌 퓨니코드(Punycode) 방식을 사용합니다. "한글.kr"은 "xn--bj0bj06e.kr"로 변환됩니다. 경로와 쿼리 부분은 일반적인 퍼센트 인코딩을 그대로 사용합니다.

다른 프로그래밍 언어에서의 URL 인코딩

JavaScript 외에 다른 언어들도 URL 인코딩 함수를 제공합니다. 언어마다 함수명과 동작이 조금씩 다르므로 주의가 필요합니다.

// Python

from urllib.parse import quote, quote_plus

quote("안녕 세상") → %EC%95%88%EB%85%95%20%EC%84%B8%EC%83%81

quote_plus("안녕 세상") → %EC%95%88%EB%85%95+%EC%84%B8%EC%83%81

// Java

URLEncoder.encode("안녕", "UTF-8")

// PHP

urlencode("안녕") // 공백을 +로

rawurlencode("안녕") // 공백을 %20으로

주의할 점은 Python의 quote()quote_plus(), PHP의 urlencode()rawurlencode()가 공백 처리 방식이 다르다는 것입니다. +로 바꾸느냐 %20으로 바꾸느냐의 차이인데, API 연동 시 이 차이가 버그를 일으킬 수 있습니다.

공백 인코딩: %20 vs +

공백 처리는 URL 인코딩에서 가장 혼란스러운 부분 중 하나입니다. 두 가지 방식이 공존하기 때문입니다.

%20은 RFC 3986에 정의된 표준 퍼센트 인코딩입니다. URL의 모든 부분(경로, 쿼리, 프래그먼트)에서 사용할 수 있습니다.

+는 HTML 폼의 application/x-www-form-urlencoded 형식에서만 사용되는 규칙입니다. HTML 폼을 제출하면 브라우저가 공백을 +로 바꿔서 전송합니다.

실무 규칙은 간단합니다. URL 경로에서는 항상 %20을 사용하고, 쿼리 문자열에서는 둘 다 작동하지만 %20이 더 안전합니다. 폼 데이터를 직접 처리할 때만 +를 고려하면 됩니다.

실전 디버깅 가이드

URL 인코딩 관련 버그를 만났을 때, 체계적으로 접근하면 빠르게 원인을 찾을 수 있습니다.

1단계: 원본 URL 확인

브라우저 개발자 도구의 Network 탭에서 실제로 전송되는 URL을 확인합니다. 주소창에 보이는 것과 실제 요청 URL이 다를 수 있습니다.

2단계: 인코딩 횟수 확인

URL에 %25가 보이면 이중 인코딩 가능성이 높습니다. %2520은 공백이 두 번 인코딩된 결과입니다.

3단계: 인코딩/디코딩 지점 추적

코드에서 인코딩과 디코딩이 일어나는 모든 지점을 확인합니다. 프레임워크나 라이브러리가 자동으로 인코딩/디코딩하는 경우가 많아서, 개발자가 추가로 인코딩하면 이중 인코딩이 발생합니다.

4단계: 문자셋 확인

서버와 클라이언트가 동일한 문자 인코딩(보통 UTF-8)을 사용하는지 확인합니다. 한글이 깨진다면 EUC-KR과 UTF-8 간의 불일치를 의심해보세요.

보안과 URL 인코딩

URL 인코딩은 보안과도 밀접한 관계가 있습니다. 제대로 처리하지 않으면 심각한 취약점이 발생할 수 있습니다.

경로 순회 공격(Path Traversal): 공격자가 %2e%2e%2f(../의 인코딩)를 사용해 서버의 상위 디렉토리에 접근하려 할 수 있습니다. 서버는 디코딩 후 경로를 검증해야 합니다.

XSS(Cross-Site Scripting): URL 파라미터에 스크립트 코드를 인코딩해서 삽입하는 공격입니다. 서버에서 URL 파라미터를 HTML에 출력할 때 반드시 별도의 HTML 이스케이프 처리가 필요합니다. URL 인코딩과 HTML 이스케이프는 목적이 다르므로, URL 디코딩만 하고 HTML 이스케이프를 빠뜨리면 취약점이 생깁니다.

오픈 리다이렉트: redirect_url 파라미터에 외부 URL을 인코딩해 넣으면 사용자가 피싱 사이트로 이동할 수 있습니다. 리다이렉트 URL은 화이트리스트 기반으로 검증해야 합니다.

정리

URL 인코딩은 웹의 기본 중에서도 기본입니다. 한번 제대로 이해해두면 API 연동, 폼 처리, 리다이렉트 등 수많은 상황에서 버그를 예방할 수 있습니다. 핵심만 기억하면 됩니다: 비예약 문자는 그대로, 나머지는 퍼센트 인코딩. 파라미터 값에는 encodeURIComponent, 전체 URL에는 encodeURI.

자주 묻는 질문

URL 인코딩은 왜 필요한가요?

이 주제에 대한 자세한 내용은 위 본문을 참고하시거나, 관련 도구를 직접 사용해 보세요.

encodeURI와 encodeURIComponent의 차이는?

이 주제에 대한 자세한 내용은 위 본문을 참고하시거나, 관련 도구를 직접 사용해 보세요.

한글 URL은 어떻게 처리되나요?

이 주제에 대한 자세한 내용은 위 본문을 참고하시거나, 관련 도구를 직접 사용해 보세요.

URL 인코딩은 보안에 도움이 되나요?

이 주제에 대한 자세한 내용은 위 본문을 참고하시거나, 관련 도구를 직접 사용해 보세요.