본문 바로가기

CS/네트워크

[HTTP] URL 인코딩, 또는 Percent-encoding

Java-Spring 환경에서 URL을 다루다가, URL 인코딩이 두번 중복해서 수행되는 문제를 접하고, URL 인코딩이 무엇인지 제대로 파헤치기 위해 이 글을 작성합니다.

 

 


 

 

 URL 인코딩이란, URI에서 구분자로 사용되는 예약어들과, 예약어와 동일한 문자이지만 단순한 문자로서 사용되는 것들을 구분하여, 혼동을 없애기 위해 도입된 Spec이다. 예약어와 동일하지만 구분자 역할을 수행하지 않는 문자를 ‘%’ + ‘16진수’ + ‘16진수’ 형태( ex. %25 )로 인코딩한다.

 

URI에서는 특수한 목적을 위해 사용될 예약어들을 정의해 두었다. 만약 URI 컴포넌트에서 예약어들이 포함될 경우, 해당 문자가 URI 컴포넌트들을 구분하는 ‘구분자’의 역할을 하는 녀석인지, 아니면 단순한 문자인지를 알 수가 없다. 이러한 혼동을 막기위해 도입된 개념이 URL 인코딩이다. 정확하게는 Percent-encoding 이라고 말한다. URI에서 예약어로 사용되는 문자는 아래와 같다.

 

문자 인코딩
: (콜론) %3A
/ (슬래시) %2F
? %3F
# %23
[ %5B
] %5D
@ %40
! %21
$ %24
& %26
‘ (작은 따옴표) %27
( %28
) %29
* %2A
+ %2B
, (쉼표) %2C
; (세미콜론) %3B
= %3D
% (퍼센트) %25
띄어쓰기 %20 or +

 

 

예를 들어, URI가 'http://hello.com'(schme과 도메인) 그리고 '/world?/test'(경로) 그리고 'key=123&value=a/b'(쿼리)로 구성되있다고 가정하자. 위에 세 URI 컴포넌트를 URL 인코딩 없이 합치게 되면 아래와 같은 URI가 만들어진다.

 

http://hello.com/world?/testkey=123&value=a/b

 

의도는 쿼리 파라미터로 key = 123 과 value = a/b 가 될 것을 예상하였겠지만, 경로 컴포넌트에 포함된 '?'가 URL 인코딩 되지 않아, 경로와 쿼리를 구분하는 구분자로서 인식될 것이다. 즉, /testkey = 123 과 value = a/b 의 쿼리로 인식될 것이다.. URL 인코딩을 수행하지 않으면 이러한 혼동이 발생한다.

 

 

URL 인코딩을 수행한 결과는 아래와 같다.

 

http://hello.com /world%3F/test?key=123&value=a/b

 

 

? 가 %3F 로 인코딩되었다. 이때, 인코딩은 URI 컴포넌트들을 모두 조합한 이후 수행하는 것이 아니라, 각각의 컴포넌트에 대해 인코딩을 수행한 이후, 컴포넌트를 조합한다는 점을 유의하자. URL 인코딩을 수행하는 구현체를 사용할 때, 위 사항을 유의하면서 개발해야 한다.

 

 

URL 인코딩을 다룰 때 유의할 점!

어떤 문자가 인코딩 되는가?

 일반적으로 'ASCII' 문자에 해당되는 알파벳은 인코딩되지 않으며, 예약된 문자 또는 ASCII에 포함되지 않는 문자(ex. 유니코드) 가 URL 인코딩된다. RFC 3986에 따르면, 인코딩 시, UniCode에 해당되는 문자라면 먼저 UTF-8로 인코딩되어야 하고, 이후 UniCode에 포함되지 않으면서 예약어인 문자가 Percent-encoding 되어야 한다고 말한다.

 

 

예약어 문자는 각 URI 컴포넌트 마다 다르다

 경로 컴포넌트에서 ' '(공백) 은 '+'가 아닌, '%20'으로 인코딩되어야 하며, '+' 문자는 인코딩되지 않는다.

반면, 쿼리 컴포넌트에서 '  '(공백) 은 '+' 또는 '%20'으로 인코딩될 수 있지만, '+'는 '%2B'로 인코딩되어야 한다. 이처럼, 각 컴포넌트 마다, 예약어가 인코딩되는 방식과 인코딩되어야 하는 예약어가 다를 수 있다.

 

 

URI 컴포넌트 마다 이스케이프 되지 않아도 되는 예약어가 다르다

  • 경로 컴포넌트에서, '+'는 이스케이프 되지 않는다.
  • query 컴포넌트에서, '?' , '/' 는 이스케이프 되지 않는다.
  • '경로 파라미터' or '쿼리 파라미터의 value' or '경로 세그먼트'에서, '=' 는 이스케이프 되지 않는다.

더 구체적인 사항은 아래와 같다. 아래 Value는 각 컴포넌트에서 인코딩하지 않고 사용가능한 예약어를 나타낸다. (Scheme 과 Host 는 무시하자.)

 URL 내부에 예약어가 존재한다고 해서, 무작정 URL 인코딩해야 하는 것이 아니다. 각 URI 컴포넌트에서 이스케이프 되어야하는 예약어 일때 URL 인코딩을 수행해야 한다.

 

그 외 유의할 점

  • 디코딩된 이후, URL은 정상적으로 분석되지 않을 수 있다. 디코딩 이후에는 각 URI 컴포넌트 구분이 달라질 수 있기 떄문이다.
  • 디코딩된 URL은, 동일한 형태로 다시 인코딩되지 못할 수 있다.

 

 

 

참고자료

 

Percent-encoding(퍼센트 인코딩) - MDN Web Docs 용어 사전: 웹 용어 정의 | MDN

Percent-encoding 은 URL 맥락에서 특정 의미를 갖는 8비트 문자로 인코딩하는 메커니즘입니다. URL 인코딩이라고도 합니다. 인코딩은 '%' 다음에 변경할 문자를 ASCII 값으로 표현되는 16진수가 위치하는

developer.mozilla.org

 

 

RFC 3986: Uniform Resource Identifier (URI): Generic Syntax

A Uniform Resource Identifier (URI) is a compact sequence of characters that identifies an abstract or physical resource. This specification defines the generic URI syntax and a process for resolving URI references that might be in relative form, along wit

datatracker.ietf.org

 

 

Java URL encoding of query string parameters

Say I have a URL http://example.com/query?q= and I have a query entered by the user such as: random word £500 bank $ I want the result to be a properly encoded URL: http://example.com/query?q=ra...

stackoverflow.com

 

 

Lunatech Blog: What every web developer must know about URL encoding

Table of contents Introduction There are a number of technologies we use everyday when we browse the web. There is the data itself (the web pages) obviously, the formatting of this data, the transport mechanism which allows us to retrieve this data, and th

www.talisman.org