2015-08-18 33 views
2

HTTP請求可以包含一個Accept標頭,指示客戶端可以接受的響應的媒體類型。服務器應通過提供匹配(請求的媒體類型之一)Content-Type響應來響應請求。媒體類型可以包括參數。 HTTP是否要求這個內容協商過程尊重參數HTTP內容協商是否尊重媒體類型參數

也就是說,如果客戶端請求

Accept: application/vnd.example; version=2 

(這裏的version參數具有2的值),而服務器可以作爲媒體類型application/vnd.example; version=1,但不application/vnd.example; version=2,是OK服務器爲用戶提供

Content-Type: application/vnd.example; version=1 

響應是否確定爲服務器提供標記的響應

Content-Type: application/vnd.example; version=2 

但是對於實際被編碼爲媒體類型的響應正文application/vnd.example; version=1?也就是說,對於媒體類型的響應的參數是對響應主體的不準確描述?

看來,Spring MVC 4.1.0在進行內容協商時並不尊重媒體類型參數,並給出了響應的媒體類型參數是對響應主體的不準確描述的響應。這似乎是因爲org.springframework.util.MimeType.isCompatibleWith(MimeType)方法不檢查MimeType對象的參數。

回答

3

的相關標準,RFC 7231 section 3.1.1.1說以下有關媒體類型:

的類型/子類型可以以 名稱=值對的形式來隨後的參數。

因此,AcceptContent-Type標題可能包含媒體類型參數。它增加了:

一個 參數的存在或不存在可能是一個媒體類型,這取決於它的媒體類型註冊表中定義的處理中, 顯著。

這表明,使用參數類型的服務器代碼要注意他們,而不是簡單地丟棄他們,因爲對於一些媒體類型,他們是顯著。它必須在是否考慮媒體類型參數是否重要時實施一些智慧。

因此,Spring MVC 4.1.0因此在做內容協商時完全忽略參數似乎是錯誤的:類org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor不正確使用org.springframework.util.MimeType.isCompatibleWith(MimeType),或MimeType.isCompatibleWith(MimeType)方法不正確。如果您爲Spring提供了幾個僅支持其媒體類型參數不同的HTTP消息轉換器,Spring將無法可靠地選擇媒體類型與請求的媒體類型完全匹配的HTTP消息轉換器。


section 3.1.1.5,在那裏它描述了Content-Type頭,它說:

指示的媒體類型定義兩個數據 格式和數據是如何旨在由接收者處理

由於一般媒體類型的參數可能會改變數據格式,Spring MVC 4.1.0的行爲是錯誤的,因爲提供的參數是不準確的描述答案的正文:當兩種類型具有同等特定性時,方法AbstractMessageConverterMethodProcessor.getMostSpecificMediaType(MediaType, MediaType)錯誤地返回acceptType而不是produceTypeToUse


然而,section 3.4.1,討論內容協商(主動協商),指出:

用戶代理不能依靠積極的談判喜好是 一貫榮幸,因爲原始服務器可能不執行 對所請求的資源進行主動協商,或者可能決定發送不符合用戶代理 首選項的響應比發送406(不可接受)的迴應。

所以服務器允許以得到不準確匹配請求的媒體類型參數的響應,作爲後備,當它不能提供精確匹配。也就是說,它可能會選擇響應application/vnd.example; version=1響應正文,其中Content-Type: application/vnd.example; version=1標題,儘管請求說Accept: application/vnd.example; version=2,如果且只有生成有效的application/vnd.example; version=2響應將是不可能的。


這個表面看來不正確的行爲已經有Spring bug報告SPR-10903。Spring開發人員將其關閉爲「Works With Designed」,注意

我不知道任何有效比較媒體類型與參數的規則。這實際上取決於媒體類型......如果您實際上試圖通過媒體類型實現REST版本化,似乎最常見的解決方案是使用不同的媒體類型,因爲它們的格式在版本之間明顯改變:

  • application/vnd.spring.foo.v1+json
  • application/vnd.spring.foo.v2+json
0

HTTP/1.1中內容協商的相關規範是RFC2616, Section 14.1

它包含以下示例中,有關你的問題:

Accept: text/*, text/html, text/html;level=1, */* 

,並給出了優先級爲

1) text/html;level=1 
2) text/html 
3) text/* 
4) */* 

所以我認爲它是安全地說,text/html;level=1text/html是不同的媒體類型。 我也會認爲text/html;level=1text/html;level=2不同。

因此,在您的示例中,我認爲以406錯誤進行響應並且不使用其他介質類型進行響應是正確的。