기술 노트/웹

[웹을 지탱하는 기술] URI의 스펙

Benn.dev 2021. 4. 28. 00:59

URI의 중요성

URI는 Uniform Resource Identifier의 약자로, 직역하자면 '유니폼 리소스 식별자'다.

즉, URI란 '리소스를 통일적으로 식별하는 ID'를 말한다.

통일적이란 모두가 같은 규칙을 따르고 있다는 것이며, 식별자란 어떤 것을 그 밖의 다른 것과 구별하여 가리키기 위한 이름/ID를 말한다.

 

URI를 사용하면 웹상에 존재하는 모든 리소스를 한결같은 방식으로 뵤여줄 수 있다.

즉, URI만 있으면 모든 리소스에 간단하게 접속할 수 있게된다.

 

 

URI의 구문

간단한 URI의 예

http://blog.example.com/entries/1 

이 URI를 구성하는 파트는 다음과 같다.

URI Scheme http
호스트명 blog.examples.com
패스 /entries/1

URI는 URI 스키마(Scheme)로 시작된다. URI 스키마는 그 URI가 이용하는 프로토콜을 나타내는 것이 일반적이다.

하지만 URN등 정확히는 프로토콜을 나타내지 않는 URI 스키마도 존재한다.

이 예에서는 리소스에 http로 접근할 수 있다는 것을 나타낸다.

URI 스키마와 그 뒤에 이어지는 부분은 '://'로 구분된다. 

 

다음으로는 호스트명이 나타난다.

호스트명은 DNS(Domain Name System)에서 이름을 해석할 수 있는 도메인명이나 IP어드레스로 인터넷에서 반드시 하나만 존재한다.

 

호스트명 뒤에는 계층화를 나타내는 경로가 이어진다.

경로는 호스트 안에서 오로지 하나의 리소스를 가리킨다.

 

이처럼 인터넷 상에서 반드시 유일한 호스트명의 구조와 호스트 내에서 유일한 계층적인 경로를 결합함으로써, 어떤 리소스의 URI가 전 세계의 다른 리소스와 절대로 중복되지 않도록 되어있다.

 

복잡한 URI의 예

http://yohei:pass@blog.example.com:8000/search?q=test&debug=true#n10

이 URI는 다음과 같이 나눌 수 있다.

URI Scheme http
사용자 정보 yohei:pass
호스트명 blog.example.com
포트번호 8000
패스 /search
쿼리 파라미터 q=test&debug=true
URI 프래그먼트 #n10

앞의 예에서 없었던 부분을 차례대로 살펴보면,

URI 스키마 다음에 사용자 정보가 들어가 있다.

사용자 정보는 이 리소스에 접근할 때 이용할 사용자 이름과 패스워드로 구성된다. 이는 ':'로 구분된다.

근데 이런 민감 정보를 URI에 노출해도 되는지...

 

사용자 정보 다음에 구분 문자인 '@'가 있고, 그 뒤에 호스트 정보로 이어진다.

호스트 정보는 호스트명과 포트번호로 구성되며, 이 둘은 ':'로 구분된다.

포트번호는 이 호스트에 액세스 할 때, 프로토콜이 사용할 TCP의 포트번호를 나타낸다.

포트번호를 생략한 경우 각 프로토콜의 디폴트 값이 사용된다.

HTTP의 디폴트 값은 80번이다.

 

패스 뒤에는 구분문자인 '?'가 오고, 이름=값의 형식으로 된 쿼리가 이어진다.

이 예시에선 q=test와 debug=true가 각각 쿼리다.

쿼리가 여러개 존재할 때는 '&'로 연결한다.

이 하나 이상의 쿼리의 집합을 '쿼리 파라미터(Query Parameter)' 또는 '쿼리 문자열(Query String)'이라고 부른다.

쿼리 파라미터는 검색 서비스에 검색 키워드를 전달할 때 등 클라이언트에서 동적으로 URI를 생성할 때 사용한다.

 

마지막에 '#'으로 시작되는 문자열은 'URI 프래그먼트(URI Fragment)'라고 한다.

URI 프래그먼트는 #앞에 문자열로 표현한 URI가 가리키는 리소스 내부에서 더 세세한 부분을 특정할 때 이용한다.

예를들어, 이 리소스가 HTML 문서인 경우는 id 속성 값이 'n10'인 요소를 나타내게 된다.

 

 

절대 URI와 상대 URI

URI의 패스는 UNIX의 파일 시스템과 같은 계층구조를 가지고 있다.

즉, '/'를 루트로 하고, 디렉터리 명을 '/'로 구분하고 필요하면 마지막에 파일명을 연결하는 기법이다.

OS의 파일 시스템에서는 루트에서부터 전체 경로를 기술한 것을 '절대 경로(Absolute Path)'라고 부른다.

/foo/bar/baz

 

파일 시스템의 경우에는 매번 절대 경로를 기술하면 너무 길어지므로, 커맨드 라인에서 디렉터리나 파일의 위치를 지정할 때는 커렌트 디렉터리(현재 디렉터리)부터의 상대 경로(Relative Path)로 나타내는 것이 일반적이다.

http://example.com/foo/bar 

 

 

URI와 문자

URI에서 사용할 수 있는 문자

URI 스펙에 따르면, 다음의 문자들을 URI의 경로에 사용할 수 있다고 정해져 있다.

알파벳 A-Za-z
숫자 0-9
기호 -.~:@!$&'()

이 문자열은 소위 ASCII(American Standard Code for Information Interchange) 문자다.

즉, URI에는 그 밖의 문자들은 직접 입력할 수 없다.

한글이나 일어 등 ASCII 이외의 문자를 URI에 넣을 때는 %인코딩(%-Encoding) 이라는 방식을 이용한다.

 

%인코딩

URI 스펙에서 허용하는 문자 이외의 것을 입력하기 위해서는 %인코딩으로 그 문자를 인코딩해야 한다.

예를들어, Wikipedia의 URI를 봤을 때 '가'를 설명한 페이지를 보면 어드레스 란에는 다음의 URI가 표시될 것이다.

http://ko.wikipedia.org/wiki/가

외견상으로 이렇게 보이는 URI는 실제로는 다음의 문자열로 전개되어 브라우저와 서버 사이에서 전송된다.

http://ko.wikipedia.org/wiki/%EA%B0%80

단 한글자였던 '가'가 '%EA%B0%80'이라는 아홉 글자가 되었다.

이것은 '가'라는 문자가 UTF-8에서는 0xEA 0xB0 0x80의 3바이트로 이루어지는 것에 기인한다.

%인코딩에서는 UTF-8 문자를 구성하는 각 바이트를 '%xx(xx는 16진수)'로 기술하여 URI에 사용할 수 없는 문자를 표현한다.

 

일반적으로 URI에서는 알파벳 대문자와 소문자를 구별해 사용하지만, %인코딩에 사용하는 문자는 대문자든 소문자든 같은 의미를 가지도록 되어있다.

단, URI의 스펙에서는 대문자의 사용을 권장하고 있다.

 

덧붙여 '%'라는 문자는 %인코딩에서 사용하고 있기 때문에, URI에 직접 입력할 수는 없다.

URI에 '%'를 넣을 때는 UTF-8과 EUC-KR 등 ASCII를 기본으로 한 문자 인코딩 방식인 경우 '%25'라고 표기한다.

 

요즘은 많은 웹 사이트에서 문자 인코딩으로 UTF-8로 %인코딩하는 경우가 대부분이다.

앞으로 웹 사이트를 구축할 경우는 특별한 이유가 없는 한 UTF-8을 사용하는 것이 무난하다.

 

URI의 길이 제한

스펙상으로는 URI의 길이에 제한은 없다.

그러나 구현상으로는 제한이 존재한다.

특히, Internet Explorer는 버전을 불문하고 2,038 바이트까지라는 제한이 있어

사실상 이 이 길이에 맞추어 구현하는 일이 많아지고 있다.

 

URI 구현에서 주의할 점들

웹 서비스와 웹 API를 구현함에 있어 URI의 스펙상 주의해야 할 것은 상대 URI의 해석%인코딩을 다루는 2가지 사항이다.

클라이언트에서 상대 URI를 해석하기 위해서는 번거로운 처리가 필요하기 때문에 웹 서비스와 웹 API를 구현하는 경우에는 가능한 절대 URI를 사용하는 편이 클라이언트에게 도움이 된다.

또한, URI에 ASCII 이외의 문자를 넣을 경우에는 문자 인코딩의 혼란을 피하기 위해서 %인코딩의 문자 인코딩으로 될 수 있는 한 UTF-8을 이용하는 것이 바람직하다.


ASCII(American Standard Code for Information Interchange)

7비트로 표현할 수 있는 코드에 할당된 알파벳과 기호를 말한다.

현재 사용되는 많은 문자 코드들의 기본이 되고 있다.