본문 바로가기

URL 인코딩

텍스트를 퍼센트 인코딩해 URL에 안전하게 넣으세요. 서로 다른 세 가지 작업에 맞는 세 가지 인코딩이 있고, 잘못 고르면 값이 조용히 깨집니다. 그래서 이 페이지가 어떤 것이 필요한지 알려 드립니다.

  • 저장되지 않음
  • 대기열 없음, 기다림 없음
  • 회원가입 없음, 워터마크 없음
인코딩 결과

여기에 인코딩 결과 내용이 표시돼요.

사용 방법

1

텍스트 붙여넣기

어떤 언어의 어떤 텍스트든 됩니다. 모든 최신 서버가 기대하는 UTF-8로 인코딩합니다.

2

용도 선택

쿼리 문자열에 들어갈 값 하나, 이미 완성된 URL 전체, 또는 폼 전송. 차이가 중요하므로 각각 설명해 드립니다.

3

결과 복사

한꺼번에 처리할 목록이 있다면 줄마다 따로 인코딩하세요.

올바른 답이 세 가지이고, 버튼 하나가 틀린 이유

퍼센트 인코딩은 문자를 %와 그 바이트 값의 16진수로 바꿉니다. 명세는 문자를 세 그룹으로 나누며, 헷갈리는 모든 것이 여기서 비롯됩니다. 비예약 문자, 즉 영문자, 숫자, 하이픈, 마침표, 밑줄, 물결표는 인코딩할 필요가 전혀 없습니다. 예약 문자, 즉 URL의 구조를 만드는 슬래시, 물음표, 앰퍼샌드, 등호, 콜론은 *데이터일 때는* 인코딩해야 하고 *구조일 때는* 인코딩하면 안 됩니다. 그 밖의 모든 문자는 항상 인코딩합니다.

그래서 정답이 하나가 아닙니다. URL 전체를 인코딩할 때는 슬래시와 물음표를 그대로 두어야 합니다. 그렇지 않으면 주소가 더 이상 주소가 아니게 됩니다. 쿼리 매개변수에 넣을 값을 인코딩할 때는 앰퍼샌드와 등호를 이스케이프해야 합니다. 그렇지 않으면 이 문자가 든 값이 매개변수 두 개로 쪼개집니다. 경로 세그먼트를 인코딩할 때는 슬래시를 이스케이프해야 합니다. 그렇지 않으면 슬래시가 든 파일 이름이 디렉터리 두 개가 됩니다. 인코딩 버튼 하나는 이 중 하나를 골라 나머지 3분의 2 상황에서 틀립니다. 대개 조용히, 그리고 대개 특이한 입력에서만 드러나는 방식으로요.

공백은 가장 많은 사연이 얽힌 문자입니다. URL에서는 %20입니다. 전송된 HTML 폼에서는 +인데, 이는 1994년부터 폼이 그렇게 동작해 왔기 때문에 살아남은 별개의, 더 오래된 인코딩입니다. 둘 다 각자의 맥락에서는 맞고 다른 맥락에서는 틀립니다. 그래서 쿼리 문자열의 더하기 기호는 인코딩하는 쪽에서 아무리 조심해도 해결할 수 없는 방식으로 모호합니다.

ASCII가 아닌 텍스트는 먼저 UTF-8로 바꾼 뒤 바이트 단위로 인코딩하므로, 한글 한 글자는 퍼센트 시퀀스 세 개가 되고 이모지는 네 개가 됩니다. 이중 인코딩은 전형적인 버그입니다. 이미 인코딩된 것을 다시 인코딩하면 모든 %가 %25가 되어 %20이 %2520이 되고, 받는 쪽에는 퍼센트 기호가 문자 그대로 전달됩니다. URL에 %25가 가득하다면 인코더를 한 번 더 거친 것입니다.

다른 작업이 필요할 때

코드에서는 언어 자체의 함수를 쓰되, 이 페이지가 고르게 하듯 신중하게 고르세요. JavaScript에는 주소 전체용 encodeURI와 값용 encodeURIComponent가 있습니다. Python에는 safe 인수가 있는 urllib.parse.quote가 있으며, 이 인수는 기본적으로 슬래시를 그대로 둡니다. PHP는 rawurlencode와 urlencode를 구분하는데, 둘은 바로 위에서 말한 공백 대 더하기 문제에서 다릅니다. 더 좋은 방법은 문자열을 이어 붙이지 말고 URL 타입으로 URL을 만드는 것이며, 그러면 이 문제 자체가 사라집니다.

명령줄에서는 jq -rR @uri가 안전하게 인코딩하며 목록도 처리합니다. curl --data-urlencode는 세 가지 경우 중 어디에 해당하는지 고민할 필요 없이 올바르게 인코딩된 매개변수를 만들어 주며, 이 작업이 정말로 쉬운 유일한 곳입니다.

자주 묻는 질문

세 가지 중 무엇을 써야 하나요?

거의 항상 ‘값 하나’(컴포넌트 인코딩)입니다. 검색어, 이메일 주소, 리디렉션 대상처럼 쿼리 문자열이나 경로 세그먼트에 들어갈 값 ‘하나’를 인코딩할 때 쓰세요. 세 가지 중 &, =, ?, /를 이스케이프하는 것은 이것뿐이며, 바로 이것이 값이 매개변수 밖으로 빠져나가 매개변수 두 개가 되는 것을 막아 줍니다. ‘URL 전체’는 이미 완성된 URL이 있고 안전하지 않은 문자만 정리하고 싶을 때만 쓰세요. URL이 URL로 남도록 구조 문자는 일부러 그대로 둡니다. ‘폼 데이터’는 공백이 %20이 아니라 +가 되는 application/x-www-form-urlencoded 본문을 만들 때 쓰세요.

왜 “&” 때문에 URL이 깨졌나요?

인코딩되지 않았기 때문이며, 쿼리 문자열은 &로 매개변수를 구분합니다. “Smith & Sons”라는 값을 ?company= 뒤에 그대로 붙이면 서버에는 company=Smith와, “Sons”라는 이름의 빈 매개변수가 하나 더 도착합니다. 가장 흔한 URL 버그이며, 해결책은 컴포넌트 인코딩입니다. &를 %26으로 바꿔 값이 하나로 유지되게 합니다.

왜 “+”가 공백이 됐나요?

쿼리 문자열에서 +는 공백을 뜻하기 때문입니다. HTML 폼에서 물려받은 규칙으로, 지금까지 아무도 없애지 못했습니다. 그래서 전화번호나 Base64 문자열처럼 데이터에 든 더하기 기호는 받는 서버에서 공백으로 읽힙니다. 컴포넌트 인코딩은 이를 %2B로 이스케이프하므로 그대로 도착합니다.

한글 같은 다른 언어와 이모지도 처리하나요?

네. 텍스트를 먼저 UTF-8로 바꾼 뒤 바이트 단위로 퍼센트 인코딩하며, 이는 RFC 3986이 요구하고 모든 최신 서버가 기대하는 방식입니다. 일본어, 아랍어, 악센트가 있는 라틴 문자, 이모지 모두 정확히 왕복 변환됩니다.

다른 도구는 그대로 두는 ! ' ( ) *를 여기서는 왜 인코딩하나요?

브라우저에 내장된 encodeURIComponent는 이 다섯 문자를 그대로 두지만, RFC 3986은 이들을 예약 문자로 분류하기 때문입니다. 일부 서버와 프레임워크는 이 문자들을 구조로 취급하므로, 이 문자가 든 값이 잘못 읽힐 수 있습니다. 인코딩해도 해가 없고 어디서나 똑같이 디코딩되며, 드물고 원인을 찾기 어려운 버그 유형 하나를 없애 줍니다. 꼼꼼한 구현은 이렇게 합니다.

제 텍스트가 어딘가에 저장되나요?

아니요. 아무것도 저장하지 않으며 어떤 요청도 보내지 않습니다. 페이지를 불러온 뒤 인터넷 연결을 끊어도 계속 작동합니다.

참고: 올바른 답이 세 가지이므로 이 페이지는 직접 고르게 합니다. 흔히 보는 인코딩 버튼 하나는 세 번 중 두 번 틀리기 때문입니다. URL 전체, 쿼리 매개변수, 경로 세그먼트를 인코딩할 때는 이스케이프하는 문자가 서로 다르며, 잘못 고르면 슬래시, 더하기 기호, 앰퍼샌드가 조용히 깨집니다.

내 웹사이트에 이 도구 넣기

블로그, 수업 페이지, 도움말 글 어디에나 무료로 넣을 수 있습니다. 코드 한 줄만 붙여 넣으면 방문자가 페이지에서 바로 사용할 수 있습니다.