目錄
- 1、内容協商的定義
- 2、内容協商工作方式
- 3、自定義内容協商
- 4、總結
1、内容協商的定義
1、内容協商(Content Negotiation)的定義是:
當存在多個表示形式時,為給定響應選擇最佳表示形式的過程
。也就是說
Request
請求可接受
xml
、
json
、
text
等格式的内容,選擇哪種最合适,并傳回給請求的過程就是
内容協商
。
2、内容協商的主要依據是request請求中的:
Accept
、
Accept-Charset
、
Accept-Encoding
、
Accept-Language
。一個典型的request請求如下:
GET /webapidemo/api/products/getResponseMessage HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh,zh-CN;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
而内容協商就是根據request中提到的header,決定最後的響應方式。
最後響應如下:
HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Date: Tue, 13 Apr 2021 07:56:22 GMT
Content-Length: 82
通過對request中accept中最優的選擇,進行了響應。這就是内容協商。
2、内容協商工作方式
1、管道從
HttpConfiguration
對象中擷取
内容協商執行個體對象
、支援的媒體格式清單
2、管道調用
内容協商執行個體對象
中
Negotiate
方法,并傳入:
要序列化的對象(即傳回給用戶端的資料對象)
、
Request
、
媒體格式清單
3、
内容協商執行個體對象
的
Negotiate
方法,傳回一個
ContentNegotiationResult對象
。而這個對象中包含了:使用哪種格式化程式和要響應的媒體類型
下面的代碼示範了如何直接調用内容協商
public HttpResponseMessage GetProduct(int id)
{
var product = new Product()
{ Id = id, Name = "Gizmo", Category = "Widgets", Price = 1.99M };
//通過HttpConfiguration對象擷取内容協商對象
IContentNegotiator negotiator = this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult result = negotiator.Negotiate(
typeof(Product), this.Request, this.Configuration.Formatters);
if (result == null)
{
var response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
throw new HttpResponseException(response));
}
return new HttpResponseMessage()
{
Content = new ObjectContent<Product>(
product, //需要序列化的對象
result.Formatter, //序列化格式器
result.MediaType.MediaType //媒體類型
)
};
}
本質上,内容協商就是一個序列化格式器的選擇程式。
3、自定義内容協商
了解了内容協商,可以看一下如何自定義内容協商
public class JsonContentNegotiator : IContentNegotiator
{
private readonly JsonMediaTypeFormatter _jsonFormatter; //使用系統自帶的格式化器(本質是一個序列化程式)
public JsonContentNegotiator(JsonMediaTypeFormatter formatter)
{
_jsonFormatter = formatter;
}
//傳入參數,然後實作Negotiate方法
public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
var result = new ContentNegotiationResult(_jsonFormatter, new MediaTypeHeaderValue("application/json"));
return result;
}
}
在配置檔案中,再将預設的替換掉
var jsonFormatter = new JsonMediaTypeFormatter();
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));
這樣就能夠實作了自定義内容協商。
以上自定義的方法中,隻是使用了系統自帶的json序列化器(系統自帶json和xml的序列器),若想自定義序列器,可參考MSDN的樣例:自定義序列器MSDN的說明
4、總結
本質上内容協商是一個根據請求中的accept,對發送給用戶端的資料,進行了指定格式的序列化的過程