블로그 글 링크를 카카오톡에 공유했더니 주소가 %EC%95%88%EB%85%95 같은 문자열로 바뀌어 있다. 링크가 깨진 게 아니라, 한글이 URL 인코딩된 것이다. 클릭하면 정상적으로 열리지만, 주소가 길고 지저분해 보인다.
URL 인코딩이 필요한 이유
URL에는 쓸 수 있는 문자가 정해져 있다. 영문 알파벳, 숫자, 일부 특수문자(-_.~)만 허용되고, 나머지는 퍼센트 기호(%)와 16진수 코드로 변환해야 한다.
| 원래 문자 | 인코딩 결과 | 이유 |
|---|---|---|
| 공백 | %20 | URL에서 공백은 구분자로 해석될 수 있음 |
| & | %26 | 쿼리 파라미터 구분자와 충돌 |
| = | %3D | 키=값 구분자와 충돌 |
| 한 | %ED%95%9C | ASCII 범위 밖의 문자 |
한글 한 글자는 UTF-8 인코딩에서 3바이트를 차지하기 때문에, 퍼센트 코드 3개(%XX%XX%XX)로 변환된다. "안녕"이라는 두 글자가 %EC%95%88%EB%85%95으로 늘어나는 이유다.
URL이 깨져 보이는 경우
실제로 URL이 깨진 게 아니라 인코딩된 상태로 보이는 것이다. 하지만 문제가 되는 경우도 있다.
- 이중 인코딩
- 이미 인코딩된 URL을 한 번 더 인코딩하면 %25EC%2595%2588처럼 %까지 인코딩되어 버린다. 이러면 서버가 원래 주소를 복원하지 못해서 404 오류가 난다.
- 잘못된 인코딩 방식
- EUC-KR로 인코딩된 한글 URL을 UTF-8로 디코딩하면 깨진 문자가 나온다. 한국 웹에서는 대부분 UTF-8을 쓰지만, 오래된 사이트는 EUC-KR일 수 있다.
- 쿼리 파라미터 누락
- &나 = 같은 특수문자를 인코딩하지 않으면 서버가 파라미터를 잘못 파싱한다. 검색어에 &가 포함된 경우 흔히 발생한다.
인코딩과 디코딩 방법
JavaScript에서
// 인코딩
encodeURIComponent('안녕하세요')
// 결과: "%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94"
// 디코딩
decodeURIComponent('%EC%95%88%EB%85%95')
// 결과: "안녕"
encodeURI와 encodeURIComponent는 다르다. 전자는 URL 전체를 인코딩하되 :, /, ? 같은 구조 문자는 건드리지 않고, 후자는 파라미터 값처럼 모든 특수문자를 인코딩한다.
온라인에서 바로 변환
코드를 작성할 환경이 아니라면 URL 인코딩 변환 도구에서 텍스트를 붙여넣고 인코딩 또는 디코딩 버튼을 누르면 된다. 인코딩된 URL을 넣으면 원래 한글 주소가 복원되고, 한글 텍스트를 넣으면 퍼센트 코드로 변환된다.
실무에서 주의할 점
- API 호출: 쿼리 파라미터에 한글이나 특수문자가 들어가면 반드시 encodeURIComponent를 적용한다.
- 리다이렉트 URL: redirect_uri 파라미터 안에 또 다른 URL이 들어갈 때는 내부 URL을 먼저 인코딩해야 한다.
- 로그 분석: 서버 로그에 인코딩된 URL이 찍히면 디코딩해서 원래 경로를 확인해야 정확한 분석이 된다.
- SNS 공유: 한글 URL을 공유할 때 플랫폼이 자동 인코딩하는 경우가 있어, 미리 인코딩해두면 이중 인코딩이 될 수 있다.
%EC%95%88이 "안"이라는 걸 알 필요는 없다. 중요한 건 언제 인코딩해야 하고, 언제 디코딩해야 하는지 구분하는 것이다. 404 오류의 원인이 인코딩 문제인 경우가 생각보다 잦다.