cv.cm

지식 · 텍스트, 데이터, 보안

URL 인코딩이란 무엇인가요?

6분 분량

핵심 답변

URL 인코딩, 정식 명칭으로 퍼센트 인코딩은 URL에서 허용되지 않거나 특별한 의미를 갖는 문자를 바이트마다 %와 16진수 두 자리로 바꾸는 방식입니다. 공백은 %20, &는 %26이 되고, ASCII가 아닌 텍스트는 먼저 UTF-8로 변환되므로 "é"는 %C3%A9가 됩니다. 문자열 "a b&c"는 a%20b%26c로 인코딩됩니다.

URL 인코드 열기

URL에 인코딩이 필요한 이유

RFC 3986은 URL에 쓸 수 있는 문자를 소수의 ASCII 문자로 제한하며, 그중 일부는 맡은 역할이 있습니다. ?는 쿼리의 시작, &는 매개변수 구분, =는 이름과 값의 구분, #는 프래그먼트의 시작, /는 경로 구분입니다. 값에 이런 문자가 들어가면 URL의 의미가 모호해집니다.

"salt & pepper"를 검색한다고 해 봅시다. ?q=salt & pepper처럼 그대로 쓰면 서버는 값이 salt 인 매개변수 q와, pepper라는 이름의 빈 매개변수를 하나 더 받습니다. ?q=salt%20%26%20pepper로 인코딩하면 하나의 값으로 도착합니다.

어떤 문자를 인코딩할까

분류문자규칙
비예약 문자A–Z a–z 0–9 - . _ ~인코딩 불필요
예약 문자(gen-delims): / ? # [ ] @값 안에서 쓸 때 인코딩
예약 문자(sub-delims)! $ & ' ( ) * + , ; =값 안에서 쓸 때 인코딩
그 밖의 모든 문자공백, ", <, >, %, ASCII 외 문자항상 인코딩

인코딩은 문자가 아니라 바이트 단위로 이루어집니다. ASCII가 아닌 텍스트는 먼저 UTF-8로 변환되고, 각 바이트가 하나의 %XX 묶음이 됩니다.

입력UTF-8 바이트인코딩 결과
공백20%20
&26%26
%25%25
éC3 A9%C3%A9
日本E6 97 A5 E6 9C AC%E6%97%A5%E6%9C%AC

16진수는 대소문자를 구분하지 않으므로 %c3%a9와 %C3%A9는 같은 뜻이지만, RFC 3986은 일관성을 위해 대문자를 권장합니다.

%20과 +: 공백에 대한 두 가지 규칙

RFC 3986이 정의한 퍼센트 인코딩은 공백을 항상 %20으로 씁니다. HTML 양식 전송은 이와 비슷한 application/x-www-form-urlencoded 형식을 쓰는데, 여기서는 공백이 +가 되고 실제 더하기 기호는 %2B가 됩니다.

  • /files/my report.pdf 같은 경로에는 %20을 쓰세요. 경로의 +는 그냥 더하기 기호입니다.
  • 쿼리 문자열에서는 양식 인코딩을 해석하는 서버가 +를 공백으로 읽습니다. %20은 두 규칙 모두에서 이해되므로 확실하지 않을 때 더 안전합니다.
  • +84 같은 전화번호처럼 값에 실제 +가 들어갈 수 있다면 %2B로 보내야 합니다. 그렇지 않으면 공백으로 도착합니다.

JavaScript의 encodeURIComponent와 encodeURI

함수인코딩하지 않는 문자용도
encodeURIComponent()A–Z a–z 0–9 - _ . ! ~ * ' ( )단일 값: 쿼리 매개변수 하나 또는 경로 세그먼트 하나
encodeURI()위 문자 + ; , / ? : @ & = + $ #이미 구조가 갖춰진 URL 전체
URLSearchParams양식 인코딩 규칙(공백은 +)쿼리 문자열 만들기·읽기

encodeURIComponent("a b&c")는 a%20b%26c를 반환하지만, encodeURI("a b&c")는 &를 구분자로 간주해 a%20b&c를 반환합니다. 흔한 버그는 매개변수 값에 encodeURI를 호출해 &, =, #가 그대로 통과하면서 값이 쪼개지는 경우입니다.

new URLSearchParams({ q: "a b&c" }).toString()은 q=a+b%26c를 만듭니다. 표준 서버에서는 두 형식 모두 같은 값으로 디코딩됩니다.

흔한 실수

  1. 이중 인코딩: 이미 인코딩된 텍스트를 다시 인코딩하면 % 자체가 %25로 인코딩되어 %20이 %2520이 됩니다. 각 값은 URL에 넣는 시점에 정확히 한 번만 인코딩하세요.
  2. 컴포넌트용 함수로 URL 전체를 인코딩: https://가 https%3A%2F%2F가 되어 링크가 더 이상 동작하지 않습니다.
  3. 라우팅 전에 디코딩: 경로를 매칭하기 전에 %2F를 /로 디코딩하는 서버는 다른 경로를 읽도록 속을 수 있습니다.
  4. 구식 문자 집합 가정: 일부 오래된 시스템은 "é"를 %E9(Latin-1)로 인코딩했습니다. 최신 브라우저와 WHATWG URL Standard는 UTF-8을 씁니다.

자주 묻는 질문

URL에서 공백이 왜 %20인가요?

URL에는 공백을 쓸 수 없으므로 %와 그 바이트 값을 16진수로 쓴 것으로 바꿉니다. 공백의 ASCII 코드는 10진수로 32이고, 16진수로 20입니다.

URL의 %2F는 무슨 뜻인가요?

%2F는 인코딩된 슬래시입니다. 값 안에 /를 넣어도 경로 구분자로 읽히지 않게 합니다.

URL 인코딩과 Base64는 같은 건가요?

아니요. URL 인코딩은 안전하지 않은 문자만 바꾸고 나머지는 읽을 수 있게 남겨 둡니다. Base64는 모든 바이트를 64개 문자로 바꾸며, URL 안전 변형을 쓰지 않으면 표준 문자인 +와 / 자체도 URL 인코딩이 필요합니다.

악센트 문자나 한글도 인코딩해야 하나요?

네, 실제 요청에서는 그렇습니다. 브라우저 주소창에는 읽기 쉽게 표시되지만, 실제로는 日이 %E6%97%A5가 되는 식으로 UTF-8 퍼센트 인코딩 형식으로 전송됩니다.

전체 지식 문서