URL 인코딩이란? 퍼센트 인코딩과 한글 깨짐 원리

검색창에 한글로 검색어를 입력했더니 주소창이 온통 %EC%9D%B4%EB%9F%B0 같은 글자로 바뀌는 걸 본 적이 있을 겁니다. 반대로 직접 만든 링크에 한글이나 공백을 그대로 이어붙였다가 페이지가 안 열리거나, 서버가 요청을 엉뚱하게 잘라 받는 경우도 있습니다.

URL은 애초에 쓸 수 있는 문자가 정해진 문법입니다. 그 문법 밖의 문자(공백, 한글, 이모지, 일부 특수기호)는 %XX 형태의 퍼센트 인코딩으로 바꿔야만 브라우저와 서버가 같은 문자열로 정확히 주고받을 수 있습니다.

요약 ① URL 문법이 허용하는 문자는 정해져 있고, 그 밖의 문자(공백·한글·특수문자)는 %XX 형태의 퍼센트 인코딩으로 바꿔야 브라우저와 서버가 같은 문자열로 해석합니다. ② encodeURI는 URL 전체 구조를 지키려고 /, ?, :, &, = 같은 예약문자를 그대로 남기지만, encodeURIComponent는 값 하나만 다룬다고 가정해 이 예약문자까지 전부 %XX로 바꿉니다. ③ 쿼리스트링에 들어갈 값(검색어 등)에 &나 =가 섞여 있다면 encodeURI가 아니라 encodeURIComponent로 인코딩해야, 그 문자가 파라미터 구분자로 오인되지 않습니다.

URL 문법이 허용하는 문자는 정해져 있다

URL(정확히는 URI) 문법은 쓸 수 있는 문자를 두 그룹으로 나눕니다. 알파벳·숫자·일부 기호(- _ . ~)로 이루어진 "비예약 문자"는 있는 그대로 써도 되고, :, /, ?, #, [, ], @, !, $, &, ', (, ), *, +, ,, ;, = 같은 "예약 문자"는 주소의 구조(스킴, 호스트, 경로, 쿼리, 프래그먼트)를 나누는 구분자로 쓰입니다.

이 두 그룹 밖의 문자, 즉 공백이나 한글 같은 비ASCII 문자는 애초에 URL 문법에 정의되어 있지 않습니다. 브라우저나 서버 입장에서는 이런 문자가 그대로 들어오면 어디까지가 값이고 어디서 주소가 끝나는지 판단할 근거가 없습니다. 그래서 이런 문자는 UTF-8 바이트로 변환한 뒤, 바이트 하나하나를 %XX 형식으로 바꿔서 표현합니다.

한글이 유독 길게 %XX로 늘어나는 이유

한글 한 글자는 UTF-8로 인코딩하면 보통 3바이트를 차지합니다. 퍼센트 인코딩은 바이트 단위로 이루어지므로, 한글 한 글자가 %EC%95%88처럼 %XX가 세 번 이어진 형태로 바뀝니다. "안녕" 두 글자라면 %XX가 여섯 번 반복되는 식입니다.

영어 알파벳은 UTF-8에서 1바이트라 %XX 한 번으로 끝나거나 아예 인코딩이 필요 없지만, 한글은 구조적으로 인코딩 결과가 길어질 수밖에 없습니다. 이건 도구나 브라우저의 결함이 아니라 문자 인코딩 방식 자체의 특성입니다.

encodeURI와 encodeURIComponent가 결과를 다르게 만드는 이유

자바스크립트는 인코딩 함수를 두 가지로 나눠 제공합니다. encodeURI는 "이미 완성된 URL 전체"를 대상으로 한다고 가정하고, :, /, ?, &, = 같은 구분자를 그대로 남겨둡니다. 이 문자들까지 인코딩해버리면 주소 구조 자체가 깨지기 때문입니다.

반면 encodeURIComponent는 "URL 안에 끼워 넣을 값 하나"를 대상으로 한다고 가정합니다. 그 값 안에 &나 =가 우연히 들어 있어도 구분자로 오해받으면 안 되므로, 이 함수는 구분자가 될 수 있는 문자까지 전부 %XX로 바꿉니다.

사용자가 입력한 검색어에 &가 들어 있는 경우를 예로 들면, encodeURI로 인코딩할 때 그 &는 그대로 남아 실제 쿼리 파라미터 구분자와 구별되지 않습니다. 반면 encodeURIComponent로 인코딩하면 그 &는 %26으로 바뀌어 값의 일부라는 사실이 그대로 보존됩니다.

이 차이를 직접 확인하려면 브라우저 개발자 도구 콘솔을 열고 encodeURI와 encodeURIComponent에 같은 문자열을 각각 넣어 결과를 비교해야 합니다. 매번 콘솔을 열어 함수를 다시 타이핑하고 결과를 눈으로 대조하는 일은, 값 하나를 확인할 때마다 반복하기엔 번거롭습니다.

URL 퍼센트 인코드 및 디코드 분석기

URL 문자열을 붙여넣으면 encodeURI·encodeURIComponent·RFC 3986 방식으로 즉시 인코딩·디코딩해 주는 URL 퍼센트 인코딩 도구

도구가 encodeURI·encodeURIComponent 차이를 화면으로 보여주는 방식

URL 퍼센트 인코딩 도구는 "URL 인코딩(Encode)"과 "URL 디코딩(Decode)" 두 탭으로 나뉘어 있고, 인코딩 탭에는 "인코딩 방식(범위)" 선택 메뉴가 있습니다. 이 메뉴에서 "쿼리 파라미터 값(encodeURIComponent)", "전체 URL 구조 유지(encodeURI)", "RFC 3986 엄격 모드" 세 가지 중 하나를 고를 수 있습니다.

같은 입력값을 그대로 둔 채 이 메뉴만 바꿔보면, 앞서 설명한 차이가 바로 눈앞의 결과로 나타납니다. "전체 URL 구조 유지"를 고르면 한글과 공백만 바뀌고 &, =, :, /는 그대로 남고, "쿼리 파라미터 값"을 고르면 그 구분자들까지 전부 %XX로 바뀌는 것을 같은 화면에서 비교할 수 있습니다.

어떤 문자가 바뀌었는지도 한눈에 확인할 수 있다

결과 아래에는 "치환된 문자 상세 매핑"이라는 표가 따로 나타나, 원본 문자열에서 어떤 글자가 어떤 %XX 코드로 바뀌었는지를 항목별로 나열해 줍니다. 어떤 문자가 왜 인코딩됐는지를 결과 문자열만 보고 역추적할 필요가 없습니다.

반대로 서버 로그나 URL에 남은 %XX 문자열을 원래 문자로 되돌리고 싶을 때는 "URL 디코딩" 탭으로 바꾸면 됩니다. 잘못된 형식의 퍼센트 인코딩이 섞여 있으면 무리하게 해석하지 않고 오류로 알려주기 때문에, 깨진 값을 원래 문자로 착각하는 일을 막아줍니다.

정리

  • URL 문법이 허용하는 문자(알파벳·숫자·일부 기호)는 정해져 있고, 그 밖의 공백·한글·특수문자는 %XX 형태의 퍼센트 인코딩으로 바꿔야 합니다.
  • 한글은 UTF-8에서 한 글자당 3바이트를 차지해, 인코딩하면 %XX가 세 번 이어지는 형태로 길어집니다.
  • encodeURI는 이미 완성된 URL 구조를 지키려고 :, /, ?, &, = 같은 예약문자를 그대로 남겨둡니다.
  • encodeURIComponent는 값 하나만 다룬다고 가정해 그 예약문자까지 전부 인코딩하므로, 쿼리 파라미터 값에는 이 함수를 써야 값 안의 &나 =가 구분자로 오인되지 않습니다.
  • 어떤 방식을 골라야 할지 헷갈릴 때는 도구에서 인코딩 방식을 바꿔가며 같은 입력값의 결과를 바로 비교해 보는 편이 빠릅니다.
URL 퍼센트 인코드 및 디코드 분석기

URL 문자열을 붙여넣으면 encodeURI·encodeURIComponent·RFC 3986 방식으로 즉시 인코딩·디코딩해 주는 URL 퍼센트 인코딩 도구

자주 묻는 질문

encodeURI와 encodeURIComponent 중 어떤 걸 써야 하나요?

이미 스킴과 경로, 쿼리 구분자까지 갖춘 완성된 URL 전체를 다룬다면 encodeURI를 씁니다. 반대로 그 URL의 쿼리 파라미터 자리에 끼워 넣을 값 하나(검색어, 사용자 입력 등)만 다룬다면 encodeURIComponent를 써야 그 값 안의 &나 =가 실수로 구분자와 겹치지 않습니다.

URL에 공백을 그대로 쓰면 왜 문제가 되나요?

공백은 URL 문법에 정의되지 않은 문자입니다. 브라우저나 서버가 공백을 어디까지가 하나의 값이고 어디서 주소가 끝나는지 판단하는 기준으로 쓸 수 없기 때문에, 공백은 반드시 %20 같은 퍼센트 인코딩으로 바꿔야 합니다.

한글 URL이 %EC%95%88%EB%85%95처럼 길게 나오는 이유는 무엇인가요?

한글은 UTF-8로 인코딩할 때 한 글자가 보통 3바이트를 차지합니다. 퍼센트 인코딩은 바이트 하나마다 %XX 하나를 대응시키기 때문에, 한글 한 글자를 인코딩하면 %XX가 세 번 이어진 형태로 나타납니다.

디코딩할 때 오류가 나는 이유는 무엇인가요?

%XX 형식을 따르지 않는 문자열이거나, %XX 바이트들을 이어 붙였을 때 유효한 UTF-8 문자로 완성되지 않는 경우 디코딩 함수가 오류를 냅니다. 이럴 때는 원본 문자열이 이미 손상되었거나, 인코딩이 두 번 겹쳐 적용됐을 가능성을 의심해봐야 합니다.

가격 보기카톡 무료 상담