2010-04-30 6 views
4

웹 서비스를 디자인하고 있습니다. 요청은 멱등수이므로 GET 메서드를 선택했습니다. 응답은 상대적으로 계산하기에 비용이 많이 들지 않고 작지도 않으므로 (프로토콜 수준에서) 올바른 캐싱을 원합니다. (내 부분에 대해 memoisation에 대해 걱정하지 마라. 나는 이미 다루었 다. 나의 질문은 실제로 웹 전체에 대해서도 관심을 기울이고있다.)동일한 응답에 매핑되는 여러 요청을 어떻게 처리합니까?

기본 매개 변수는 하나 뿐이며 옵션 매개 변수는 기본값 누락 된 경우 값. 예를 들어, 다음 두 가지는 응답의 동일한 표현으로 매핑됩니다. (이 더 나은 뭔가를 제안하고, 그것에 대해 인터페이스를 갈 바보 방법입니다 경우.)

GET /service?mandatory_parameter=some_data HTTP/1.1 
GET /service?mandatory_parameter=some_data;optional_parameter=default1;another_optional_parameter=default2;yet_another_optional_parameter=default3 HTTP/1.1 

그러나, 나는 고객이 모르는 별도 따라서 폐기물 캐시 저장을 치료하는 것입니다 상상한다. golden rule of caching을 위반하지 않도록하려면 어떻게해야합니까?

  1. 가 정규의 형식을 확인, 그것은 (예를 들어, 모든 매개 변수가 결국 필요하며 특정 순서로 정렬 될 필요) 문서 필요한 양식이 충족되지 않는 한과 client error을 반환?
  2. 오류 대신 요청의 정규 형식으로 영구적으로 리디렉션 하시겠습니까?
  3. 요청이 어떻게 보이는지 신경 쓰지 않고 동일한 응답으로 동일한 ETag으로 응답하면 충분합니까?
+0

합의가 2를 사용하는 것으로 보입니다. 이쪽으로 가겠습니다. – daxim

답변

4

먼저 쿼리 문자열에서 구분 기호로 세미콜론을 사용하지 마십시오. 쿼리 문자열을 시작하려면 ?을 사용하고 변수/값 쌍을 구분하려면 &을 사용해야합니다. RFC 3986&을 사용해야한다고 명시 적으로 말하지 않았지만 대부분의 기존 코드는 application/x-www-form-urlencoded 선례 때문에이 구분 기호를 사용합니다.

둘째로, 쿼리 문자열의 매개 변수가 다른 URI를 생성하므로 캐시가 관련된 한 다른 리소스가됩니다. 최적의 캐싱 성능을 원한다고 가정 할 때 선택적 매개 변수가 지정되었고 해당 매개 변수가 필요하지 않고 전송 될 표현에 영향을주지 않으면 매개 변수를 생략하는 표준 표현으로 리디렉션해야합니다. 예를 들어, http://example.com:80/이있는 경우 80이 HTTP가있는 포트의 기본값이기 때문에 http://example.com/으로 정규화 할 수 있습니다 (동일한 매개 변수는 URI 공간을 제어하기 때문에 쿼리 매개 변수가 필요합니다.) 표준 또는 다른 순서로 나타나는 매개 변수 (선택 사항 또는 기타 매개 변수)가있는 경우 해당 매개 변수도 리디렉션해야합니다. URI 간의 관계가 안정적이라는 것을 안다면 301 리디렉션이 선호 될 것입니다. 그렇지 않은 경우 적절하게 302/307 리디렉션을 수행하십시오. OAuth과 동일한 방법으로 표준 형식을 정의하는 것이 좋습니다. 각 매개 변수를 알파벳 순으로 정렬하고, 먼저 키로 정렬 한 다음 값으로 정렬합니다. 다른 정규화 작업도 여기서 도움이 될 것입니다. RFC 3986은 당신에게 관련된 URI normalization의 전체 섹션을 가지고 있습니다. 이 기술은 실제로 GET에서만 작동하며 PUT/POST/DELETE에 대한 리디렉션은 일반적으로 권장되지 않습니다.

세 번째로 ETags는 훌륭하고 클라이언트와 서버 모두에서 잘 구현되면 성능이 크게 향상됩니다. 그러나 유감스럽게도 양측 모두 제대로 할 수는 없습니다. 마지막 수정본에 대한 내용입니다. CPU와 대역폭 절약은 효과가있을 때 중요하지만 자체적으로 충분하지 않기 때문에이를 추구해야합니다. Cache-Control과 같은 다른 헤더도 자주 필요합니다. 이 내용에 대해 아주 자세히 들어갈 계획이라면 Section 13 of RFC 2616에 익숙해 질 필요가 있습니다.

마지막으로 경고 할 단어가 있습니다. 이러한 리디렉션에 대해 알고 있어야하는 문제가 있습니다. 리소스에 액세스하려는 클라이언트가 다른 위치로 자주 리디렉션 될 수 있습니다. 클라이언트가 동일한 리소스에 대해 후속 요청을하고 상태를 유지하면 후속 리디렉션이 발생하지 않으므로 오버 헤드가 발생합니다. 캐싱 최적화를 활용하는 참조 클라이언트 구현을 공개 소스로 사용하지 않는 한 이러한 조정을 통해 결코 이익을 얻을 수 없습니다.

+0

[HTML4 §B.2.2] (http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.2)로 인해 '&'을 거부합니다. +1 OAuth에서 표준화를 지적하기 위해, 나는 이것을 훔칠 것이다. 참조 구현이 필요하다는 점에 관해서는 어떤 문제도 보이지 않습니다. 그것은 결국 HTTP 일뿐입니다. 또 다른 대답에 따르면 영구적 인 리디렉션은 값 싸고 캐시 가능합니다. – daxim

+0

해당 권장 사항은 URI가 HTML 또는 XML 내에 직접 나타나는 경우에만 적용됩니다. 그러나 이러한 경우에도 콘텐츠에 URI를 삽입하기 전에 URI를 이스케이프 처리하지 않은 경우 잘못 처리하고있는 것입니다. 이 규격의 권장 사항은 손으로 코딩 한 결과물과는 무관하다. –

+0

참조 구현에 관해서는 API를 사용할 사람들을 너무 많이 믿고 있다고 생각합니다. 캐싱을 설정하지 않고 작동하는 경우 사람들은 캐싱을 설정하지 않습니다. –

1

목록에서 옵션 (2)을 선택합니다. RPC 대신 RESTful 요청을합니다.

e.e. 이 경우 요청 경로의 매개 변수 부품의 모든 만들 경우 다음의 경우 경우

/서비스/mandatory_parameter/some_data/optional_parameter/DEFAULT1/another_optional_parameter/default2/yet_another_optional_parameter/default3

모든를 선택적 매개 변수가 지정되면 기본값이 채워진 전체 리소스 이름에 301 (영구 리디렉션)을 반환합니다.이 값은 클라이언트와 웹 캐시에 의해 적절히 캐시 될 것입니다. 그리고 백엔드로 가져 오더라도 301은 너를 위해 아주 싸야한다.

어느 시점에서 URI에 대해 하나의 표준 양식이 있으며 캐싱은 정상/예상대로 작동합니다.

이것은 매개 변수의 모든 조합이 별도로 (301로) 캐시된다는 것을 의미합니다. 그러나 비표준 요청은 전체 요청에 대한 독립적 캐시 정책을 가지며 추가 클라이언트에 대해 걱정하는 클라이언트는 실제로 괜찮습니다. 왕복은 모든 매개 변수 자체를 채울 수 있습니다.

옵션 (3)은 예상대로 작동하지 않습니다. 각 양식은 서로 다른 URI이므로 독립적으로 캐시됩니다.

또한 다운 스트림 캐시의 많은/소프트웨어 내가 '적절한'자원으로 돌려 제안 이유입니다 인해 쿼리 매개 변수에 대한 모든에 응답 를 캐시하지 않습니다 주목해야한다

..

+0

제안한 URI가 RESTful이 아니며 쿼리 매개 변수를 사용하여 URI가 "RPC와 유사한"것은 아닙니다. 실제로이 많은 매개 변수가있는 경우 실제로 이렇게하는 것이 좋습니다. 기껏해야화물을 키우는 것입니다. REST 아키텍처 스타일의 실제 정의에 대한 Roy Fielding의 논문을 읽어보십시오. –

+0

t0m, Bob A.이 맞습니다. 내 디자인이 건축 스타일의 기준을 위반했다는 아이디어를 얻은 것은 무엇인지 모르지만 그대로 적용됩니다. Catalyst에 대한 REST의 관리자로서 이것을 인식해야합니다. 대다수의 슬래시는 하나도없는 계층 구조를 의미합니다. 즉 매개 변수는 동등한 기초 위에 있습니다. – daxim

+0

URL 구조를 변경하고 서비스를 RESTful하게 만들 수 없으며, RESTful이 아닌 것이 좋습니다. – EralpB

0

먼저 다른 방법은 캐싱을 지원하지 않기 때문에 선택하는 것이 좋습니다. 내가 아는 한 브라우저는 매개 변수와 관련하여 캐시 URI를 캐시하므로 canonical 양식을 사용하는 것이 좋습니다.
여기에 진술하지 않은 한 가지는이 서비스가 어떻게 사용되는지입니다.이러한 요청이 브라우저에서 이루어진다면 (스크립트에서 발급 한 것일 수도 있음) 요청은 두 번 이상 요청한 경우에도 똑같이 보일 것입니다. 따라서 URI를 생성하는 모든 항목이 동일한 입력 데이터에 대해 동일한 URI로 끝나야합니다 (기본 매개 변수 제거 또는 항상 포함).
ETag에 관해서는 어떻게 작동하는지 명확히 설명하고 싶지만이 것이 좋습니다. 요청을 받으면 "비싼 계산"을 모두 처리 한 다음 처리 된 응답과 동일한 해시 (ETag)가있는 If-None-Match 헤더가 있으면 304 Not-Modified를 반환 할 수 있습니다. 그래서 ETag는 클라이언트가 이미 응답을 전송하는 것을 피하기 위해 사용됩니다. (물론 서버 측에서 캐싱을 구현할 수 있지만 입력 매개 변수를 기반으로하는 것이 더 좋습니다.
클라이언트 쪽에서 캐시 히트를 향상 시키려면 적절한 캐싱 헤더를 설정하는 것이 좋습니다.

+0

이 답변은 새로운 통찰력을 제공하지 않습니다. – daxim

+0

두 번째 답변이 게시되었을 때 그랬습니다. – MyGGaN

0

나는 몇 달 전에 나에게 거의 같은 질문을했다. 나의 대답은 나의 실현의 예를 설명한다.서버 측에

나는

GET /Service/RequestedData?param1=data1&param2=data2… 
GET /Service/RequestedData/IdOfData?param1=data1&param2=data2… 
PUT /Service/RequestedData/IdOfData // with param1=data1&param2=data2… in body 
POST /Service/RequestedData/IdOfData // with param1=data1&param2=data2… in body 
DELETE /Service/RequestedData/IdOfData 

그래서 요청에 대한 REST에 다음 형식 중 하나에 요청을받을 WFC 서비스를 가지고 있지만, GET 요청은 몇 가지 옵션 매개 변수가 있습니다. 특히이 부분은 관심있는 항구입니다. WFC는 URL 템플릿을 지원하기 때문에

는 클라이언트 요청에 응답 함수의 프로토 타입은

GET /Service/RequestedData?param1=&param2=data2 
GET /Service/RequestedData?param2=data2&param1= 
GET /Service/RequestedData?param2=data2 

같은

[WebGet (UriTemplate = "RequestedData?param1={myParam1}&param2={myParam2}", 
     ResponseFormat = WebMessageFormat.Json)] 
[OperationContract] 
MyResult GetData (string myParam1, int myParam2); 

같은 모든 요청이 측면에서 동일한 호출로 매핑됩니다 보인다 내 WCF 서비스. 그래서 나는 한 가지 문제를 덜 갖는다.

이제 응답 내가 HTTP 헤더 "캐시 제어 : 최대 사용 기간 = 0"로 설정 GET 요청을하여 HTTP하기 위해 모든 방법의 구현의 시작 부분에. 클라이언트가 인 경우 항상은 클라이언트 브라우저 캐시를 확인하려고 시도하며, ajax 요청은 Internet Explorer처럼 로컬 캐시에서 쉽게 응답하지 않습니다.

다음으로 나는 내 데이터에 따라 항상 ETag을 계산합니다. 정확한 알고리즘은 별도의 토론 주제이지만 중요한 것은 HTTP GET 요청에 대한 모든 응답에서 HTTP 헤더에 ETag이 존재한다는 것입니다.

그래서 클라이언트는 항상 로컬 캐시를 확인하고 서버에 GET 요청을 보냅니다. 그들은 로컬 캐시의 "If-None-Match"HTTP 헤더 안에있는 ETag을 보냅니다. 서버는이 GET 요청으로 다시 전송 될 데이터가있는 ETag을 계산합니다. 데이터의 ETag은 클라이언트 요청 서버에서와 같이 비어있는 본문과 "304 Not Modified"코드와 함께 응답을 되돌려 보내는 것과 같습니다. 이 경우 브라우저는 로컬 캐시에서 데이터를 제공합니다.

알려지지 않은 이유로 동일한 클라이언트가 웹 브라우저에서 URL로 해석 할 새 버전의 URL 요청을 생성하면 웹 브라우저는 로컬 캐시에서 이전 서버 응답을 찾지 않고 전송합니다. 한 번 더 서버에 동일한 요청을 보냅니다. 진짜 문제인가? 서버는 데이터를 한 번 더 보냅니다. 서버 측 캐싱을 사용하면 좀 더 최적화 할 수 있습니다. 대부분의 경우 GET 요청의 URL은 클라이언트 측 JavaScript에 의해 생성되므로 시간이 없어도 이러한 상황이 발생합니다.

ETag의 계산과 "Cache-Control: max-age=0"와 Etag 헤더뿐만 아니라 설정의 설정은 "304 Not Modified"코드는 WFC 서비스를해야하지만, 그것은 매우 간단합니다.

가장 중요한 것은 ETag 계산은 데이터베이스 서버에서 전체 데이터를 가져 와서 계산 MD5 캐시를 계산하는 것만 큼 커지는 것이 아니라는 것입니다. SQL Server 데이터베이스의 모든 데이터 행에 영구적으로 rowversion 데이터 형식을 사용합니다. 이 rowversion은 데이터베이스의 변경 카운터입니다. 하나의 데이터 행을 변경하면 해당 행의 값 rowversion 값이 증가합니다. 따라서 최대 값이 rowversionSELECT 문장을 이전 요청과 비교하여 변경하지 않으면이 기간 동안 데이터가 변경되지 않았 음을 확인할 수 있습니다.ETa g의 계산 알고리즘은 테이블에서 데이터를 삭제하는 경우에만 민감해야합니다. 그러나 그것은 또한 해결 된 문제입니다. 이것에 관해서는 Concurrency handling of Sql transactrion에서 더 읽을 수 있습니다.

나는 ETag을 최선의 선택으로 추천하고 싶지 않으며, 단지 ETag의 계산은 전체 데이터로부터 계산 MD5로 훨씬 더 저렴할 수 있습니다.

오류의 경우 서버는 throw 문에서 정의한 HTTP 코드에 매핑되는 예외를 throw합니다. 본문 WFC로 표준 JSON 개체 {"description":"My error text"} 보냅니다. 사용자 정의 오류 객체도 가능합니다 (Is WebProtocolException included in .net 4.0? 참조). 클라이언트 측에서는 jQuery를 사용하고 오류 이벤트 처리기 내부의 jQuery.ajax에 오류 메시지가 디코딩되어 사용자에게 표시됩니다.

내 권장 사항 : 모든 HTTP GET 요청에 대해 Cache-Control: max-age=0과 함께 ETag을 사용하십시오. 다른 모든 요청에 ​​대해서는 RESTfull 서비스를 구현하는 것이 좋습니다. 오류 구현을 위해서는 서버 및 클라이언트 구현에 사용되는 소프트웨어가 지원하는 가장 원시적 인 방법을 살펴보고이를 사용해야합니다.

업데이트 됨 : URL 구조를 지우려면 다음을 추가해야합니다. 내 서비스에서 GET /Service/RequestedData/IdOfData과 같은 주요 부분은 요청 된 데이터 객체를 설명합니다. 매개 변수 param1=data1&param2=data2은 대부분 에 대한 정보 인, 페이징의 데이터를 나타냅니다. 나는 jQuery에 대한 활성 jqGrid 플러그인을 사용하고 최종 사용자가 그리드에서 다음 페이지로 스크롤하는 경우 열 머리글 (데이터 정렬)을 클릭하거나 검색 기능과 관련하여 필터를 설정하면 이들 모두가 다른 선택적 매개 변수가 기본 URL에 추가되었습니다.

+0

모든 수단을 통해 웹 서비스에 대한 결과를 공유하지만 자신의 블로그에서 확인하십시오. 당신은 묻습니다.»실제 문제입니까? "예, 그렇습니다. 그래서 제가이 특정한 질문을했습니다! -1 그것에주의를 기울이지 않기 때문에. – daxim

+0

내 답변이 너무 길어서 블로그가 생겼다면 죄송합니다.나는 단지 당신을 돕기를 원하고, 짧은 대답을 줄뿐만 아니라 예제에 대한 나의 대답을 설명합니다. 귀하의 질문에 대한 짧은 대답은 다음과 같습니다 : 1) 정규 양식이 필요하지 않습니다 클라이언트 요청이 클라이언트 소프트웨어에 의해 생성 될 경우 2) 오류 발생시 2 리디렉션 없음 오류 메시지가있는 추가 div를 표시 3) Etags를 사용하지만 좋은 답변일지도 모르겠다. 요청이 어떻게 생겼는지 염두에 두지 말것. – Oleg

+0

내 대답이 도움이되지 않는다고 생각하면 내 블로그라고 대답 할 수있다. 나는 너에게 짧은 대답을 기다린다. – Oleg

관련 문제