하나의 URI이 여러 리소스에 대응할 필요가 있는 경우가 있다.
서버는 영어 사용자에게는 영어 버전을 보내주고 프랑스어 사용자에게는 프랑스어 버전을 보내줄 것이다. HTTP는 클라이언트와 서버가 이러한 판단을 할 수 있도록 내용 협상(content-negotiation) 방법을 제공한다. 이 방법을 이용해서 하나의 URL이 여러 가지 리소스 중 적합한 것에 대응되도록 할 수 있다.
서버에 있는 페이지들 중 어떤 것이 클라이언트에게 맞는지 판단하는 세 가지 다른 방법이 있다.
기법 | 어떻게 동작하는가 | 장점 | 단점 |
---|---|---|---|
클라이언트 주도 | 클라이언트가 요청을 보내면, 서버는 클라이언트에게 선택지를 보내주고 클라이언트가 선택한다. | 서버 입장에서 가장 구현가지 쉽다. 클라이언트는 최선의 선택을 할 수 있다. | 대기시간이 증가한다. 즉, 올바른 콘텐츠를 얻으려면 최소 두 번의 요청이 필요하다. |
서버 주도 | 서버가 클라이언트의 요청 헤더를 검증해서 어떤 버전을 제공할 지 결정한다. | 클라이언트 주도 협상보다 빠르다. HTTP는 서버가 가장 적절한 것을 선택할 수 있도록 q값 메커니즘을 제공하고 서버가 다운스트림 장치에게 요청이 어떻게 평가되는지 말해줄 수 있도록 하기 위해 Vary 헤더를 제공한다. | 만약 결정이 뻔하지 않으면(헤더에 맞는 것이 없으면) 서버는 추측을 해야만 한다. |
투명 | 투명한 중간 장치(주로 프록시 캐시)가 서버를 대신하여 협상을 한다. | 웹 서버가 협상을 할 필요가 없다. 클라이언트 주도 협상보다 빠르다. | 투명 협상을 어떻게 하는지에 대한 정형화된 명세가 없다. |
서버에게 있어 가장 쉬운 방법은 서버가 클라이언트의 요청을 받았을 때 가능한 페이지의 목록을 응답으로 돌려주어 클라이언트가 보고 싶은 것을 선택하게 하는 것이다. 이것은 물론 서버 입장에서 가장 구현하기 쉽고 최선의 사본이 선택될 것이다. 단점은 각 페이지에 두 번의 요청이 필요하다는 것이다. 한 번은 목록을 얻고 두 번째는 선택한 사본을 얻는다. 즉 요청에 대한 응답으로 돌려줄 최적의 페이지를 결정하기 위한 클라이언트와 서버 사이의 커뮤니케이션을 증가시킨다.
서버 주도 협상은 서버가 어떤 페이지를 돌려줄 것인지 결정하게 하는 것이다. 그러나 이렇게 하려면 클라이언트는 반드시 자신의 무엇을 선호하는지에 대한 충분한 정보를 서버에게 주어서 서버가 현명한 결정을 할 수 있게 해 주어야 한다. 서버는 이 정보들을 클라이언트 요청 헤더에서 얻는다.
HTTP 서버가 클라이언트에게 보내줄 적절한 응답을 계산하기 위해 사용하는 메커니즘은 두 가지다
클라이언트는 Accept 헤더들을 이용해서 자신의 선호 정보를 보낼 수 있다.
헤더 | 설명 |
---|---|
Accept | 서버가 어떤 미디어 타입으로 보내도 되는지 알려준다. |
Accept-Language | 서버가 어떤 언어로 보내도 되는지 알려준다. |
Accept-Encoding | 서버가 어떤 인코딩으로 보내도 되는지 알려준다. |
내용 협상 헤더들은 클라이언트와 서버가 선호 정보를 서로 교환하고 문서들의 여러 버전 중 하나를 선택하는 것을 도와, 클라이언트의 선호에 가장 잘 맞는 문서를 제공해 주기 위한 목적으로 사용된다.
서버는 클라이언트의 Accept 관련 헤더들을 적절한 엔터티 헤더들과 짝을 지어준다.
Accept 관련 헤더들 | 엔터티 헤더 |
---|---|
Accept | Content-Type |
Accept-Language | Contnet-Language |
Accept-Encoding | Content-Encoding |
HTTP는 상태가 없는 프로토콜이기 때문에(서버는 클라이언트가 이전 요청에서 보낸 선호 정보를 기억하지 않는다는 의미) 클라이언트는 자신의 선호 정보를 반드시 매 요청마다 보내야 한다.
만약 어떤 두 클라이언트가 자신이 이해할 수 있는 언어를 지정한 Accept-Language 헤더 정보를 보낸다면 서버는 헤더를 기반한 사본을 각 클라이언트에게 돌려줘야 할지 판단할 수 있을 것이다.
또한 HTTP는 클라이언트를 위해 그들의 선호에 대한 풍부한 설명을 품질값(q값)을 이용해 전달할 수 있는 메커니즘을 제공한다.
서버가 자동으로 돌려보낼 문서를 고르도록 하는 것은 클라이언트 주도 모델에서 협상을 위해 메시지가 수차례 오가는 것으로 인해 발생한 커뮤니케이션 대기시간을 줄여준다.
HTTP 프로토콜은 클라이언트가 각 선호의 카테고리마다 여러 선택 가능한 항목을 선호도와 함께 나열할 수 있도록 품질값을 정의하였다.
💡 Accept-Language: ko;q=1.0, en;q=0.9q값은 0.0부터 1.0까지의 값을 가질 수 있다.(0.0이 가장 낮은 선호도, 1.0이 가장 높은 선호도)
때때로 서버는 클라이언트의 선호에 대응하는 문서를 하나도 갖고 있지 않을 수도 있다. 이 경우, 서버는 클라이언트의 선호에 맞추기 위해 문서를 고치거나 트랜스코딩을 할 수 있다.
서버는 또한 User-Agent와 같은 클라이언트의 다른 요청 헤더들을 이용해 알맞은 요청을 만들어내려고 시도할 수 있다.
투명 협상은 클라이언트 입장에서 협상하는 중개자 프록시를 둠으로써 클라이언트와의 메시지 교환을 최소화하는 동시에 서버 주도 협상으로 인한 부하를 서버에서 제거한다. 프록시는 클라이언트의 기대가 무엇인지 알고 있고 클라이언트의 임장에서 협상을 수행할 수 있는 능력이 있는 것으로 가정된다. 투명한 내용 협상을 지원하기 위해, 서버는 클라이언트의 요청에 가장 잘 맞는 것이 무엇인지 판별하려면 어떤 요청 헤더를 검사해야 하는지 프록시에게 반드시 말해줄 수 있어야 한다. HTTP/1.1 명세는 투명 협상에 대한 어떤 메커니즘도 정의하지 않았지만, 대신 Vary 헤더를 정의했다. 서버는 응답에 Vary 헤더를 포함시켜 보냄으로써 중개자에게 내용 협상을 위해 어떤 헤더를 사용하고 있는지 알려줄 수 있다.
캐시 프록시는 단일 URL을 통해 접근할 수 있는 문서의 여러 다른 사본을 저장할 수 있다. 만약 서버가 그들의 캐시에 대한 의사결정 프로세스를 캐시에게 알려주었다면, 캐시는 서버의 입장에서 클라이언트와 협상할 수 있다. 캐시는 또한 콘텐츠를 트랜스코딩하기에 휼륭한 장소인데, 캐시 안에 설치되어 있는 범용 트랜스코더는 특정 서버에 국한되지 않고 어떤 서버의 콘텐츠든 트랜스코딩할 수 있기 때문이다.
콘텐츠를 캐시하는 것은 그 콘텐츠가 나중에 재사용될 것이라고 예상하기 때문이다. 캐시는 클라이언트에게 올바로 캐시된 응답을 돌려주기 위해, 서버가 응답을 돌려줄 때 사용했던 의사결정 로직의 상당 부분을 그대로 사용해야 한다.
캐시는 캐시된 응답을 돌려보낼 때 반드시 이들과 같은 헤더를 사용해야 한다.
캐시는 첫 번째 요청을 서버로 그대로 전달하고, 응답을 저장한다. 두 번째 응답은 캐시가 URL에 대응하는 문서를 찾아서 돌려준다. 만약 캐시된 문서가 영어 문서인데 다음 클라이언트 요청은 한국어 문서를 원한다면 반드시 서버에게 그대로 전달하고 그 URL에 대한 이번의 응답과 지난번의 응답을 모두 저장해야 한다. 서버와 마찬가지로 캐시는 이제 같은 URL에 대해 두 개의 다른 문서를 갖게 된다. 이 다른 버전은 배리언트(variant) 또는 얼터네이트(alternate)로 불린다.
서버가 어떤 페이지를 반환할 것인지 판단하기 위해 다른 헤더들을 사용하고 있다면, 캐시는 반드시 그 헤더들이 무엇인지 알아야 하고 캐시된 페이지 중 어떤 것을 반환할지 선택할 때 서버가 했던 것과 같은 논리를 적용해야 한다.
HTTP Vary 응답 헤더는 서버가 문서를 선택하거나 커스텀 콘텐츠를 생성할 때 고려한 클라이언트 요청 헤더 모두를 나열해야한다. 예로 제공된 문서가 User-Agent 헤더에 의존한다면 Vary 헤더는 반드시 “User-Agent”를 포함해야 한다.
새 요청이 도착했을 때, 캐시는 내용 협상 헤더들을 이용해 가장 잘 맞는 것을 찾는다. 그러나 캐시가 문서를 클라이언트에게 제공해 줄 수 있게 되기 전에, 캐시는 반드시 캐시된 응답 안에 서버가 보낸 Vary 헤더가 들어있는지 확인해야 한다. 만약 Vary 헤더가 존재한다면, 그 Vary 헤더가 명시하고 있는 헤더들은 새 요청과 오래된 캐시된 요청에서 그 값이 서로 맞아야만 한다. 왜냐하면 서버는 클라이언트의 요청 헤더에 따라 그들의 응답이 달라질 수 있기 때문에 투명 협상을 구현하기 위해 캐시는 반드시 캐시된 배리언트(variant)와 함께 클라이언트 요청 헤더와 그에 알맞은 서버 응답 헤더 양쪽 모두를 저장해야 한다. 또한 캐시는 각 배리언트마다 알맞은 문서 버전을 저장해야 한다.
서버가 클라이언트의 요구에 맞는 문서를 아예 갖고 있지 않다면 기본적으로 서버는 에러로 응답해야겠지만, 이론적으론 서버는 기존의 문서를 클라이언트가 사용할 수 있는 무언가로 변환할 수도 있다. 이 옵션을 트랜스코딩이라고 부른다.
트랜스코딩에는 포맷 변환, 정보 합성, 내용 주입의 세 종류가 있다.
포맷 변환은 데이터를 클라이언트가 볼 수 있도록 한 포맷에서 다른 포맷으로 변환하는 것이다.
예로 모바일 단말기가 데스크톱 클라이언트에서 보기 위해 만들어진 문서에 접근하려고 한다면 HTML을 WML로 변환해 줄 필요가 있다.
문서에서 정보의 요점을 추출하는 것을 정보 합성이라고 한다. 이는 트랜스코딩 과정에서 유용할 수 있다. 예로 각 절의 제목에 기반한 문서의 개요 생성이나 페이지에서 광고 및 로고 제거를 들 수 있다.
본문의 키워드에 기반하여 페이지를 분류하는 더 복잡한 기술은 문서의 핵심을 요약할 때도 유용하다. 이 기술은 포털 사이트의 웹페이지 디렉터리와 같은 자동화된 웹페이지 분류 시스템에 의해 종종 사용된다.
포맷 변환이나 정보 합성의 트랜스코딩은 일반적으로 웹 문서의 양을 줄이지만 양을 늘리는 또 다른 종류의 변환인 내용 주입 트랜스코딩이 있다.
예로 자동 광고 생성과 사용자 추적 시스템이 있다. 이런 종류의 트랜스코딩은 현재 관련이 있거나 어떻게든 특정 사용자를 대상으로 하는 광고를 그때그때 효과적으로 삽입하기 위해 동적으로 이루어진다. 사용자 추적 시스템 또한 어떻게 페이지가 보여지고 클라이언트가 웹을 돌아다니는지에 대한 통계를 수집하기 위해 페이지에 동적으로 콘텐츠를 추가할 수 있도록 만들어져 있다.
트랜스코딩의 대안은 웹 서버에서 웹페이지의 여러 가지 사본을 만드는 것이다. 그러나 이것은 여러 가지 이유로 그다지 현실적인 기법이 못 된다. 페이지에 대한 어떠한 작은 변화도 여러 페이지의 수정을 요구하게 되고, 각 페이지의 모든 버전을 저장하기 위해 더 많은 공간이 필요하게 되며, 또한 페이지들을 관리하고 그것들 중 올바른 것을 골라서 제공해주는 웹 서버를 프로그래밍하기 어려워진다.
광고 삽입(특히 타깃 광고 삽입)과 같은 몇몇 트랜스코딩은 정적인 방법으로는 수행될 수 없다. 어떤 광고가 삽입될 것인지는 페이지를 요청한 사용자에게 달려있기 때문이다. 루트 페이지를 그때그때 필요할 때마다 변환하는 것은 정적으로 미리 생성해 놓는 것보다 더 쉬운 해결책이다. 그러나 이는 콘텐츠 제공에 있어 대기시간 증가로 인한 비용을 초래할 수 있다. 그러나 이들 계산 중 몇몇은 제삼자에게 수행하게 하여 웹 서버의 부담을 덜 수 있다. 변환은 더 싼 프록시나 캐시에 있는 외부 에이전트에 의해 수행될 수 있다.