본문 바로가기

개발 서적/웹을 지탱하는 기술

[웹을 지탱하는 기술] chapter 05. URI의 설계

 


[목차]
chapter 01. 웹이란 무엇인가?

chapter 02. 웹의 역사
chapter 03. REST 웹의 아키텍처 스타일
chapter 04. URI의 스펙
chapter 05. URI의 설계


 

이 장에서는 좋은 URI란 무엇인지 설명하고 좋은 URI를 설계하기 위한 방법과 힌트를 소개한다.

쿨(Cool)한 URI는 변하지 않는다

좋은 URI와 아름다운 URI를 가리켜 Cool URI라고 부른다. 이 용어의 기원은 웹의 발명자 팀 버너스-리가 1988년에 발표한 ‘Cool URIs don’t change’라는 웹 페이지다.

이 웹페이지가 발표된 당시에는 URI가 변경되는 것은 일상다반사였다. 북마크해둔 링크들이 시간이 지나면 유효하지 않게 되버렸다.

링크가 끊어져버린다는 것은 하이퍼미디어 시스템으로서의 웹의 근간을 뒤흔드는 문제였다. 버너스-리는 이런 상황을 우려해 ‘URI’는 변하지 않아야 한다. 변하지 않는 URI야말로 최고의 URI이다’라는 주장을 Cool URI라는 단어에 담았다.

 

좀처럼 변하지 않는 URI를 만들기 위해서는

웹 서비스의 설계로 회사의 도산으로 인해 바뀌거나 중단된 URI를 막는 것은 무리겠지만, 좀처럼 변하지 않는 URI로 웹 서비스를 구축할 수는 있다.

프로그래밍 언어에 의존적인 확장자와 경로를 포함하지 않는다

특정 언어에 의존하는 문자열을 URI에 포함시키면 그 언어를 변경하자마자 그 URI를 사용할 수 없게 된다.

다음 URI를 example.com라는 사이트의 로그인 페이지라고 가정해보자.

http://example.com/cgi-bin/login.pl

이 URI에는 구현에 의존적인 부분이 두 군데 존재한다.

  • cgi-bin - CGI(Common Gateway Interface)의 잔재, 요청할 때마다 프로세스를 실행하는 CGI 방식은 성능면에서 문제점이 있어 다른 방식으로 대체되어 갔음
  • .pl - Perl로 작성된 파일. CGI 시대에서 대부분의 웹서비스가 채택했었지만, 현재는 선택의 폭이 넓어짐
http://example.com/servlet/LoginServlet
  • 해당 예시는 Java에 의존한 URI다.
  • 경로인 ‘servlet’은 특정 서블릿 컨테이너의 기본 경로이고 시스템을 서블릿에서 PHP로 바꾼 순간 변경된다.
  • ‘LoginServlet’에서 대문자가 나온 점도 문제다. Java에서는 파일명의 시작을 대문자로 하지만, Perl과 Ruby는 소문자로 한다. 변경의 요지가 생기는 요소다.

메서드명과 세션ID를 포함하지 않는다

다음은 URI에 메서드명이 포함된 경우다.

http://example.com/Login.do?action=showPage

웹 애플리케이션 프레임워크로서 오래된 Struts를 채용하면 이와 같은 URI가 될 것이다. Struts 특유의 확장자 ‘.do’도 문제지만 showPage라는 메서드명이 URI에 들어가 있다는 점은 더 큰 문제다. 시스템을 리팩토링하여 메서드명을 변경하면 바로 URI가 바뀌어버리기 때문이다.

다음은 세션ID를 포함한 URI의 예이다.

http://example.com/home.jsp?jessionid=12345678

Java에서 세션ID를 쿠키가 아니라 URI에 집어넣으면 ‘jessionid’라는 파라미터를 포함한 URI를 생성한다. 하지만 세션ID는 로그인할 때마다 바뀌므로 이 URI는 시스템에 다시 로그인하면 변경됨

URI는 리소스를 표현하는 명사로 한다

URI는 리소스의 이름이다. 즉, URI는 명사야 한다.

HTTP에서는 리소스에 대해서 특정 HTTP 메서드만을 적용한다. 그리고 어떤 리소스를 취득할지 갱신할지는 URI로 지정하는 것이 아니라, URI에 적용하는 HTTP메서드로 결정한다. 즉, URI와 HTTP메서드의 관계는 명사와 동사의 관계와 같다. 따라서 URI는 전체적으로 명사가 되도록 설계해야 한다.

URI 설계 지침

결론적으로 Cool한 URI는 심플한 URI다.

  • URI에 프로그래밍 언어에 의존적인 확장자를 이용하지 않는다.
  • URI에 구현에 의존적인 경로명을 이용하지 않는다.
  • URI에 프로그래밍 언어의 메서드명을 이용하지 않는다.
  • URI에 세션ID를 포함하지 않는다.
  • URI는 해당 리소스를 표현하는 명사이다.

 

URI 사용성

심플한 URI의 또다른 장점은 사용성(Usability)이 향상된다는 점이다.

  • 글자 수에서 차이가 난다. URI가 심플하면 기억하는 것도 간단하기 때문에 웹 이외의 미디어에 URI를 기재할 때 유리하다.
  • ‘servlet’ 등 개발자가 아닌 일반인들에게는 친숙하지 않은 단어를 사용하지 않도록 한다.

→ 기억하기 쉽고, 개발자가 아닌 보통 사람들도 사용하기 쉽다는 것. 이것이 Cool URI의 좋은 점이다.

 

URI를 변경하고 싶을 때

좀처럼 변경되지 안히는 URI는 심플하고, 아릅답고, 사용성도 향상됨을 알게 되었다. 하지만 시스템을 교체함으로 인한 URI 변경이 불가피한 경우가 생기기 마련이다. → 어떻게든 URI를 변경해야 할 때는 가능한 한 Redirect하도록 한다.

 

URI 설계의 테크닉

URI를 설계할 때 사용할 수 있는 테크닉으로서 확장자로 표현을 지정하는 방법인 매트릭스 URI를 소개한다.

확장자로 표현을 지정한다

확장자 포함된 URI가 좋지 않았던 건 구현에 의존하는 설계였기 때문. 구현에 의존하지 않는 확장자는 좋은 측면도 가지는 경우가 있음.

콘텐트 네고시에이션

  • HTTP에는 콘텐트 네고시에이션(Content Negotiation)이라는 편리한 기능이 있음
  • 한국어판 OS를 사용하는 유저에게는 한국어를, 영어판을 사용하는 유저에게는 영어를 반환해준다.
  • HTTP 헤더에 Accept-Language에 클라이언트가 희망하는 언어를 지정하면, 서버 측에서는 이 요청 조건에 따라 한국어를 응답으로 돌려준다.
  • Accept 헤더를 사용해 미디어 타입을 사용해 미디어 타입을 지정하거나, Accept-Charset 헤더를 사용해 문자 인코딩을 지정할 수도 있다.

언어를 지정하는 확장자

  • 콘텐트 네고시에션의 경우, 한국어 OS 이용자가 영어판 프레스 릴리스를 가져오기 위해서는 브라우저 설정을 따로 변경해줘야 한다.
  • 이를 간단히 하려면, 릴리스 언어를 URI에 확장자로서 명시적으로 지정해 사용하면 된다.
// 한국어판
http://example.com/2022/03/15/press.ko
// 영어판
http://example.com/2022/03/15/press.en
  • 하나의 리소스가 복수의 표현을 가질 때, 각 리소스의 표현을 나타내는 URI에 확장자를 사용하는 것은 W3C에서도 실천하고 있는 테크닉이다.
  • 이는 형식도 포함되는 이야기다. 리소스를 html, 텍스트, json으로 표현 가능한 경우 각각의 확장자를 붙여 나누는 것이 좋다.

매트릭스 URI

URI는 슬래시(/)를 사용해 리소스를 계층적으로 표현한다. 하지만, 모든 정보를 계층적으로 관리할 수는 없다. (지도의 위경도, 표시축적, 지도인지 항공사진인지 등) 복수의 파라미터가 필요하고, 이 파라미터들은 각각 독립적인 축을 가지기 때문에 계층구조로 표현할 수 없다.

여러 파라미터의 조합으로 표현하는 리소스에는 매트릭스 URI(Matrix URI)를 사용한다. 슬래시 대신에 각각의 파라미터를 세미콜론(;)으로 구분해 리소스를 표현한다.

http://example.com/map/lat=35.705471;lng=139.751898

현재 일반적으로 매트릭스 URI를 표현할 때는 세미콜론(;)이나 콤마(,)가 사용되고 있다.

  • 세미콜론(;) - 파라미터의 순서가 의미를 가지지 않는 경우에 사용
  • 콤마(,) - 파라미터의 순서가 의미를 가지는 경우에 사용. 이 경우에는 ‘이름=’을 생략 가능하다.

 

URI의 불투명성

지금까지는 서버 측에서 URI를 어떻게 설계할 것인지 알아봤다면, 이번에는 클라이언트를 만들 때 중요한 URI의 성질에 대해서 알아본다.

웹에서의 리소스 조작은 HTML 같은 리소스 내의 링크를 따라가며 이루어진다. 즉, 클라이언트는 어디까지나 서버가 제공하는 URI를 그대로 사용할 뿐이다.

URI의 내부구조를 상상해 조작하거나, 클라이언트 쪽에서 URI를 구축해서는 안된다. 왜냐하면 서버 쪽에서 URI의 구조를 변경하는 순간 시스템이 동작하지 않게 되는, 이른바 밀결합(tight coupling) 상태가 되기 때문이다.

이렇게 URI를 클라이언트 쪽에서 구성하거나 확장자로 리소스의 내용을 추단하거나 할 수 없는 특성을 **‘URI는 클라이언트에 있어 불투명(Opaque)하다’**고 한다.

클라이언트를 만들 때는 URI가 불투명하다는 것을 의식해서 구현해야 한다.

 

URI를 강하게 의식하기

URI는 다음과 같은 점에서 중요하다.

  • URI는 리소스의 이름이다
  • URI는 수명이 길다
  • URI는 브라우저가 어드레스 란에 표시한다
반응형