URL에 한글 넣으면 %EC%95%88, 왜 이상한 문자로 바뀔까?
URL 주소에 한글을 입력했더니 %EC%95%88 같은 코드로 변하는 것은 깨진 게 아닙니다. 이것은 '퍼센트 인코딩'이라는 정상적인 과정입니다. 왜 이런 변환이 필요하고, UTF-8에서 한글 한 글자가 3바이트로 바뀌는 원리를 설명합니다.
URL에 한글을 넣으니 %EC%95%88… 깨진 걸까?
분명 'https://예시.com/검색?q=한글' 같은 주소였는데, 복사해서 붙여넣으니 `https://예시.com/%EA%B2%80%EC%83%89?q=%ED%95%9C%EA%B8%80` 처럼 알아볼 수 없는 코드로 바뀐 경험이 있을 겁니다. 이메일이나 메신저로 보냈더니 상대방이 주소가 깨졌다며 열리지 않는다고 말하기도 합니다.
결론부터 말하면, 이건 깨진 것이 아니라 지극히 정상적인 변환입니다. '퍼센트 인코딩(Percent-encoding)' 또는 'URL 인코딩'이라 부르는 표준 방식입니다. 웹 브라우저, 서버, 그리고 웹에서 동작하는 모든 프로그램이 한글이나 특수문자를 안전하게 주고받기 위해 사용하는 약속입니다.
원인: 주소창에는 알파벳과 일부 특수문자만 쓸 수 있다
위 표처럼 '안'이라는 한글 한 글자는 국제 표준인 유니코드(Unicode)에서 `C548`이라는 고유한 번호를 가집니다. 이 글자를 UTF-8 방식으로 표현하면 `EC`, `95`, `88`이라는 3개의 바이트가 됩니다. 그래서 최종적으로 `%EC%95%88`이라는 세 덩어리의 코드가 되는 것입니다. 한글 한 글자가 `%XX` 세 개로 바뀌는 이유가 바로 이것입니다.
과거에는 EUC-KR이라는 2바이트 인코딩 방식도 많이 쓰였습니다. EUC-KR에서 '안'은 `BE C8` 두 바이트이므로 `%BE%C8`로 인코딩됩니다. 만약 이런 형태의 코드를 본다면 아주 오래된 시스템에서 생성된 URL일 가능성이 높습니다. 현재는 거의 모든 웹 환경이 UTF-8을 표준으로 사용합니다.
| 문자 | 유니코드 | UTF-8 (16진수) | 퍼센트 인코딩 |
|---|---|---|---|
| 안 | U+C548 | EC 95 88 | %EC%95%88 |
| 녕 | U+B155 | EB 85 95 | %EB%85%95 |
가장 흔한 실수: 이중 인코딩
대부분의 경우 우리는 URL 인코딩을 신경 쓸 필요가 없습니다. 웹 브라우저가 알아서 다 해주기 때문입니다. 주소창에 `https://ko.wikipedia.org/wiki/대한민국` 이라고 치면, 브라우저는 서버에 요청을 보낼 때 한글 '대한민국'을 `%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD`으로 자동 변환해서 보냅니다. 사용자는 그 과정을 볼 수 없을 뿐입니다.
문제는 이미 인코딩된 URL을 또 인코딩할 때 발생합니다. 이를 '이중 인코딩'이라고 부릅니다. 퍼센트 인코딩에서 `%`는 특별한 의미를 지닌 제어 문자입니다. 따라서 문자 그대로의 '%'를 표현하려면 `%` 자체도 `%25`로 인코딩해야 합니다.
만약 `%EC%95%88`('안')을 실수로 다시 인코딩하면 어떻게 될까요? 브라우저는 `%`를 `%25`로 바꾸어 `%25EC%2595%2588`이라는 끔찍한 결과를 만들어냅니다. 서버는 이 코드를 '안'으로 해석하지 못하고, `%EC%95%88`이라는 문자열 자체로 인식하게 되어 완전히 다른 주소로 판단하거나 오류를 냅니다.
해법 1: URL 인코더로 직접 변환하고 원리 확인하기
URL 인코딩이 자동으로 처리된다지만, 개발자나 마케터는 링크 템플릿을 만들거나 API 요청을 보낼 때 수동으로 값을 인코딩해야 할 때가 많습니다. 이럴 때 원리를 이해하고 정확한 값을 얻기 위해 URL 인코더/디코더 도구를 사용할 수 있습니다.
툴즈의 URL 인코더·디코더는 단순히 변환만 해주는 것이 아니라, 인코딩의 두 가지 주요 방식을 선택하고 그 원리를 눈으로 확인할 수 있게 해줍니다.
- **툴즈의 [URL 인코더·디코더](/url-encode)**로 이동합니다.
- **입력** 창에 `https://example.com/검색?q=무선 드릴` 같은 한글이나 공백이 포함된 문자열을 붙여넣습니다.
- 결과 창에 인코딩된 `https://example.com/%EA%B2%80%EC%83%89?q=%EB%AC%B4%EC%84%A0%20%EB%93%9C%EB%A6%B4` 이 즉시 나타납니다.
- 결과 아래 **'한글·특수문자 인코딩 확인'** 표를 주목하세요. '검'이라는 글자가 유니코드 `U+AC80`, UTF-8 바이트 `EA B2 80`을 거쳐 `%EA%B2%80`으로 변환되는 과정을 직접 확인할 수 있습니다.
해법 2: URL 파서로 복잡한 주소 분해하고 수정하기
위와 같은 URL을 **툴즈의 [URL 파서](/url-parser)**에 붙여넣으면, 도구는 이 주소를 다음과 같이 각 구성 요소로 분해해서 보여줍니다.
- **경로(pathname):** `/카테고리/전동공구` (자동으로 디코딩되어 한글로 보입니다)
- **쿼리(search):** `?q=무선%20드릴&page=2&utm_source=naver`
- **프래그먼트(hash):** `#리뷰`
더 중요한 기능은 쿼리 파라미터를 표로 보여준다는 점입니다. `q`의 값 `무선%20드릴`은 '무선 드릴'로, `utm_source`는 'naver'로 디코딩되어 표시됩니다. 이 표에서 직접 값을 수정할 수 있습니다. 예를 들어 '무선 드릴'을 '유선 드릴'로 바꾸고 싶다면, 그냥 표 안의 입력 상자에서 글자를 고치기만 하면 됩니다.
수정이 끝나면 도구가 알아서 변경된 값을 다시 정확하게 퍼센트 인코딩하여 완전한 URL로 재조립해 줍니다. 복잡한 URL의 특정 값만 안전하게 바꾸고 싶을 때, 이중 인코딩 같은 실수를 원천적으로 방지할 수 있는 가장 확실한 방법입니다.
https://shop.example.co.kr:8443/카테고리/전동공구?q=무선%20드릴&page=2&utm_source=naver#리뷰
자주 묻는 질문
URL에서 공백(스페이스)은 왜 %20, +, %2B 등 여러 가지로 보이나요?
모두 공백과 관련 있지만 역할이 다릅니다. `%20`이 공백 문자에 대한 표준 퍼센트 인코딩입니다. `+`는 아주 오래된 웹 초창기 규격(HTML 폼의 `application/x-www-form-urlencoded`)에서 공백을 대신하던 표기입니다. 지금도 일부 시스템에서 호환성을 위해 사용합니다. `%2B`는 `+` 문자 자체를 인코딩한 것입니다. 툴즈의 URL 인코더에서 '공백 ↔ +' 옵션을 켜면 `%20` 대신 `+`로 변환할 수 있습니다.
그럼 주소를 공유할 땐 어떤 걸 보내야 하나요? 한글이 보이는 것? %코드가 보이는 것?
어떤 프로그램에 붙여넣느냐에 따라 다릅니다. 카카오톡, 슬랙, 디스코드 같은 최신 메신저나 이메일 클라이언트는 한글이 그대로 보이는 URL을 붙여넣어도 대부분 알아서 인코딩 처리해 링크를 만들어줍니다. 하지만 일반 텍스트 편집기, 오래된 시스템, 또는 HTML 코드 안에 직접 링크를 넣을 때는 `%` 코드가 포함된, 완전히 인코딩된 버전을 사용하는 것이 안전합니다. 헷갈릴 때는 브라우저 주소창의 주소를 전체 선택하여 복사(Ctrl+C)하면 보통 인코딩된 버전이 복사되므로, 그 값을 사용하는 것이 좋습니다.
EUC-KR(CP949)로 인코딩된 URL은 어떻게 하나요?
한글 한 글자가 `%BE%C8`처럼 `%XX` 두 개로 구성된 URL은 EUC-KR 방식으로 인코딩된 것입니다. 현대 웹 표준은 UTF-8이므로, 대부분의 브라우저와 도구는 이 값을 제대로 디코딩하지 못하고 깨진 문자를 보여줄 수 있습니다. `decodeURIComponent` 같은 표준 함수는 UTF-8을 가정하고 동작하기 때문입니다. 이런 URL을 올바르게 해석하려면 EUC-KR(또는 CP949) 디코딩을 명시적으로 지원하는 별도의 프로그램이나 라이브러리가 필요합니다.
encodeURI와 encodeURIComponent는 정확히 뭐가 다른가요?
`encodeURI`는 URL 전체를 인코딩하기 위한 함수입니다. URL의 구조를 형성하는 예약 문자들(`,`, `/`, `?`, `:`, `@`, `&`, `=`, `+`, `$`, `#`)은 의미를 유지하기 위해 인코딩하지 않습니다. 반면 `encodeURIComponent`는 URL의 일부, 즉 파라미터의 키나 값 하나를 인코딩하기 위한 함수입니다. 이 함수는 알파벳과 숫자 외의 거의 모든 문자를 인코딩하므로, 예약 문자들도 모두 `%XX` 형태로 바꿔버립니다. URL 파라미터 값에 `&`나 `=`가 포함될 경우, 이 문자들이 URL 구조를 깨뜨리지 않도록 `encodeURIComponent`를 써야 안전합니다.