ASP.NET Web API 콘텐츠 협상
이 문서에서는 ASP.NET Web API ASP.NET 4.x에 대한 콘텐츠 협상을 구현하는 방법을 설명합니다.
HTTP 사양(RFC 2616)은 콘텐츠 협상을 "여러 표현을 사용할 수 있는 경우 지정된 응답에 가장 적합한 표현을 선택하는 프로세스"로 정의합니다. HTTP에서 콘텐츠 협상을 위한 기본 메커니즘은 다음과 같은 요청 헤더입니다.
- 받아들일: 응답에 허용되는 미디어 유형(예: "application/json", "application/xml") 또는 "application/vnd.example+xml"과 같은 사용자 지정 미디어 형식
- Accept-Charset: 허용되는 문자 집합(예: UTF-8 또는 ISO 8859-1)입니다.
- Accept-Encoding: 허용되는 콘텐츠 인코딩(예: gzip)입니다.
- 수락 언어: 기본 설정 자연어(예: "en-us").
서버는 HTTP 요청의 다른 부분을 볼 수도 있습니다. 예를 들어 요청에 AJAX 요청을 나타내는 X-Requested-With 헤더가 포함된 경우 Accept 헤더가 없으면 서버가 기본적으로 JSON으로 설정될 수 있습니다.
이 문서에서는 Web API가 Accept 및 Accept-Charset 헤더를 사용하는 방법을 살펴보겠습니다. (현재는 Accept-Encoding 또는 Accept-Language에 대한 기본 제공 지원이 없습니다.)
Serialization
Web API 컨트롤러가 리소스를 CLR 형식으로 반환하는 경우 파이프라인은 반환 값을 직렬화하고 HTTP 응답 본문에 씁니다.
예를 들어 다음 컨트롤러 작업을 고려합니다.
public Product GetProduct(int id)
{
var item = _products.FirstOrDefault(p => p.ID == id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
클라이언트는 다음 HTTP 요청을 보낼 수 있습니다.
GET http://localhost.:21069/api/products/1 HTTP/1.1
Host: localhost.:21069
Accept: application/json, text/javascript, */*; q=0.01
이에 대한 응답으로 서버는 다음을 보낼 수 있습니다.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 57
Connection: Close
{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}
이 예제에서 클라이언트는 JSON, Javascript 또는 "anything"(*/*)를 요청했습니다. 서버가 개체의 JSON 표현으로 응답했습니다 Product
. 응답의 Content-Type 헤더는 "application/json"으로 설정됩니다.
컨트롤러는 HttpResponseMessage 개체를 반환할 수도 있습니다. 응답 본문에 대한 CLR 개체를 지정하려면 CreateResponse 확장 메서드를 호출합니다.
public HttpResponseMessage GetProduct(int id)
{
var item = _products.FirstOrDefault(p => p.ID == id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return Request.CreateResponse(HttpStatusCode.OK, item);
}
이 옵션을 사용하면 응답의 세부 정보를 더 자세히 제어할 수 있습니다. 상태 코드를 설정하고 HTTP 헤더를 추가하는 등의 작업을 수행할 수 있습니다.
리소스를 직렬화하는 개체를 미디어 포맷터라고 합니다. 미디어 포맷터는 MediaTypeFormatter 클래스에서 파생됩니다. Web API는 XML 및 JSON에 대한 미디어 포맷터를 제공하며 다른 미디어 형식을 지원하는 사용자 지정 포맷터를 만들 수 있습니다. 사용자 지정 포맷터를 작성하는 방법에 대한 자세한 내용은 미디어 포맷터를 참조하세요.
콘텐츠 협상 작동 방식
먼저 파이프라인은 HttpConfiguration 개체에서 IContentNegotiator 서비스를 가져옵니다. 또한 HttpConfiguration.Formatters 컬렉션에서 미디어 포맷터 목록을 가져옵니다.
다음으로 파이프라인은 IContentNegotiator.Negotiate를 호출하여 다음을 전달합니다.
- 직렬화할 개체의 형식입니다.
- 미디어 포맷터 컬렉션
- HTTP 요청
Negotiate 메서드는 다음 두 가지 정보를 반환합니다.
- 사용할 포맷터
- 응답에 대한 미디어 형식
포맷터를 찾을 수 없는 경우 Negotiate 메서드는 null을 반환하고 클라이언트는 HTTP 오류 406(허용되지 않음)을 수신합니다.
다음 코드는 컨트롤러가 콘텐츠 협상을 직접 호출하는 방법을 보여줍니다.
public HttpResponseMessage GetProduct(int id)
{
var product = new Product()
{ Id = id, Name = "Gizmo", Category = "Widgets", Price = 1.99M };
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, // What we are serializing
result.Formatter, // The media formatter
result.MediaType.MediaType // The MIME type
)
};
}
이 코드는 파이프라인이 자동으로 수행하는 것과 동일합니다.
기본 콘텐츠 협상가
DefaultContentNegotiator 클래스는 IContentNegotiator의 기본 구현을 제공합니다. 여러 조건을 사용하여 포맷터를 선택합니다.
먼저 포맷터는 형식을 직렬화할 수 있어야 합니다. MediaTypeFormatter.CanWriteType을 호출하여 확인합니다.
다음으로 콘텐츠 협상가는 각 포맷터를 살펴보고 HTTP 요청과 얼마나 잘 일치하는지 평가합니다. 일치 항목을 평가하기 위해 콘텐츠 협상가는 포맷터에서 다음 두 가지를 확인합니다.
- 지원되는 미디어 형식 목록이 포함된 SupportedMediaTypes 컬렉션입니다. 콘텐츠 협상가가 요청 수락 헤더와 이 목록을 일치시키려고 합니다. Accept 헤더에는 범위가 포함될 수 있습니다. 예를 들어 "text/plain"은 text/* 또는 */*에 대한 일치 항목입니다.
- MediaTypeMapping 개체 목록을 포함하는 MediaTypeMappings 컬렉션입니다. MediaTypeMapping 클래스는 HTTP 요청을 미디어 형식과 일치시킬 수 있는 일반적인 방법을 제공합니다. 예를 들어 사용자 지정 HTTP 헤더를 특정 미디어 형식에 매핑할 수 있습니다.
일치하는 항목이 여러 개 있는 경우 최고 품질의 요소가 있는 매치가 승리합니다. 예:
Accept: application/json, application/xml; q=0.9, */*; q=0.1
이 예제에서 application/json의 묵시적 품질 요소는 1.0이므로 application/xml보다 선호됩니다.
일치하는 항목이 없으면 콘텐츠 협상가가 요청 본문의 미디어 유형(있는 경우)에서 일치를 시도합니다. 예를 들어 요청에 JSON 데이터가 포함된 경우 콘텐츠 협상가가 JSON 포맷터를 찾습니다.
일치하는 항목이 아직 없으면 콘텐츠 협상가가 형식을 직렬화할 수 있는 첫 번째 포맷터를 선택하기만 하면 됩니다.
문자 인코딩 선택
포맷터를 선택한 후 콘텐츠 협상가는 포맷터에서 SupportedEncodings 속성을 보고 요청의 Accept-Charset 헤더와 일치시켜 최상의 문자 인코딩을 선택합니다(있는 경우).