DevUtils
기술 가이드
웹 & 프로토콜5분 읽기

URL 퍼센트 인코딩(RFC 3986) 표준과 encodeURI vs encodeURIComponent 완벽 비교

RFC 3986 URI 표준 사양, 쿼리 스트링에서의 "+" 기호와 "%20" 공백 혼선 방지, UTF-8 멀티바이트 인코딩 원리, JavaScript 전역 인코딩 함수의 올바른 활용법을 정리합니다.

실시간 온라인 도구 바로가기

URL 인코더 / 디코더

서버 전송 없이 100% 브라우저 로컬에서 안전하게 직접 테스트하고 검증해보세요.

도구 실행하기

RFC 3986 표준에서 URL 퍼센트 인코딩이 필수적인 이유

인터넷 표준 RFC 3986으로 규정된 URI(Uniform Resource Identifier)는 엄격히 제한된 US-ASCII 문자 집합만을 사용하여 경로와 리소스를 식별하도록 설계되었습니다. 네트워크 전송 계층의 게이트웨이, 프록시, 메일 라우터 등 레거시 장비들이 제어 문자나 비ASCII 문자를 임의로 변조하지 못하도록 하기 위함입니다.

이로 인해 공백 문자, 한글이나 일본어 같은 비영어권 유니코드 문자, 그리고 URL 문법 구조에서 경로 구분자로 예약된 특수문자(:, /, ?, #, [, ], @)를 안전하게 전송하려면 퍼센트 인코딩(Percent-Encoding, URL 인코딩)을 거쳐야 합니다. 비허용 문자를 UTF-8 바이트 시퀀스로 변환한 뒤, 각 바이트를 % 기호 뒤에 2자리 16진수로 표기합니다.

가장 흔한 버그: "+" 기호와 "%20" 공백의 차이점

웹 개발자가 가장 자주 겪는 인코딩 혼선 중 하나는 공백을 나타낼 때 쓰는 +와 %20의 차이입니다:

  • RFC 3986 표준 URI 경로 (%20): /api/documents/my%20file.pdf와 같은 일반적인 URL 경로에서는 공백이 오직 %20으로만 표현되어야 합니다. URI 경로에서 +는 예약된 문자이며 문자 그대로의 덧셈 기호로 해석됩니다.
  • HTML 폼 인코딩 규격 (+): 과거 HTML <form> 전송 시 사용되던 application/x-www-form-urlencoded 명세에서는 쿼리 스트링 내부의 공백을 전통적으로 + 기호로 치환했습니다 (?search=hello+world).

현대 웹 서버와 프레임워크마다 쿼리 스트링의 +를 공백으로 디코딩할지, 실제 더하기 기호로 인식할지 처리가 달라 파싱 에러나 서명 불일치 버그가 빈번하게 발생합니다. API마다 한 가지 규칙을 정해 양쪽에서 똑같이 쓰는 것이 안전합니다. URLSearchParams는 폼 인코딩 규칙을 따라 공백을 +로 만들고(아래 예제 참고), encodeURIComponent는 항상 %20을 만듭니다. 한쪽 방식으로 인코딩하고 다른 방식으로 디코딩할 때 이런 버그가 생깁니다.

JavaScript 인코딩 함수 완벽 비교: encodeURI vs encodeURIComponent

자바스크립트 표준 런타임은 용도가 전혀 다른 두 가지 전역 인코딩 함수를 제공합니다:

  • encodeURI(uri): 완전한 전체 URI 주소를 인코딩할 때 사용합니다. 프로토콜, 호스트, 경로를 나누는 구조적 예약어(; / ? : @ & = + $ , #)를 고의로 보존합니다. 만약 쿼리 파라미터 값에 들어있는 &나 ?를 encodeURI로 인코딩하면 예약어가 유지되어 쿼리 구조가 깨져버립니다.
  • encodeURIComponent(str): 개별 쿼리 파라미터의 키(Key)나 값(Value) 단위를 인코딩할 때 사용합니다. 영숫자와 일부 안전 문자(A-Z a-z 0-9 - _ . ! ~ * ' ( ))를 제외한 모든 특수문자를 공격적으로 인코딩합니다. 쿼리 스트링 값을 조립할 때는 무조건 encodeURIComponent를 써야 합니다.
JAVASCRIPTDevUtils Code Reference
const userInput = "data&id=100"; // 사용자가 입력한 검색어

// ❌ 치명적 오류: encodeURI는 '&'를 인코딩하지 않음
const badUrl = "https://api.devutils.run/search?query=" + encodeURI(userInput);
// 결과: https://api.devutils.run/search?query=data&id=100 ('query'와 'id' 두 개의 파라미터로 쪼개짐!)

// ✅ 올바른 처리: encodeURIComponent는 '&'를 '%26'으로 안전하게 이스케이프함
const safeUrl = "https://api.devutils.run/search?query=" + encodeURIComponent(userInput);
// 결과: https://api.devutils.run/search?query=data%26id%3D100 (단일 파라미터로 온전히 보존)

유니코드 UTF-8 멀티바이트 문자의 인코딩 메커니즘

영어 알파벳은 1바이트(ASCII)로 끝나지만, 다국어 문자는 UTF-8 규칙에 따라 2~4바이트로 확장된 후 각 바이트별로 인코딩됩니다:

  • 영어 알파벳 'A': ASCII 65(0x41) -> 인코딩 불필요 그대로 'A'
  • 한글 '가': 유니코드 U+AC00 -> UTF-8 3바이트(0xEA 0xB0 0x80) -> %EA%B0%80
  • 일본어 히라가나 'あ': 유니코드 U+3042 -> UTF-8 3바이트(0xE3 0x81 0x82) -> %E3%81%82
  • 이모지 '🚀': 유니코드 U+1F680 -> UTF-8 4바이트(0xF0 0x9F 0x9A 0x80) -> %F0%9F%9A%80

과거 EUC-KR이나 Latin-1 기반으로 인코딩하던 시스템과의 통신에서는 글자가 깨지는 모지바케(Mojibake)가 발생할 수 있으므로, 웹 환경에서는 항상 UTF-8 기반 인코딩 표준을 고수해야 합니다.

실무 권장 표준: WHATWG URL API 활용

문자열을 직접 + 연산자로 이어 붙여 URL을 조합하는 방식은 실수를 유발하기 쉽습니다. 현대 브라우저와 Node.js에 기본 탑재된 표준 WHATWG URL 및 URLSearchParams 클래스를 사용하면 인코딩과 구분자 처리를 안전하게 자동화할 수 있습니다.

JAVASCRIPTDevUtils Code Reference
// 최신 표준 WHATWG URL API를 사용한 안전한 파라미터 조립
const url = new URL("https://api.devutils.run/v1/search");
url.searchParams.set("query", "인공지능 & 데이터");
url.searchParams.set("tags", "nextjs/react");
url.searchParams.set("author", "Justin Kwak");

console.log(url.toString());
// 출력: https://api.devutils.run/v1/search?query=%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5+%26+%EB%8D%B0%EC%9D%B4%ED%84%B0&tags=nextjs%2Freact&author=Justin+Kwak
태그:URL 인코딩웹 표준RFC 3986HTTP자바스크립트
실시간 온라인 도구 바로가기

URL 인코더 / 디코더

온라인 무료 URL 인코더 및 디코더. encodeURIComponent 및 encodeURI 지원.

도구 실행하기