2017-02-19 27 views
1

Я хочу обрабатывать HEAD-запросы в приложении Web API 2. Я копировать-вставить код из блоге StrathWeb в Adding HTTP HEAD support to ASP.NET Web API:Content-Length 0 при обработке запроса HEAD в Web API 2

public class HeadHandler : DelegatingHandler 
{ 
    private const string Head = "IsHead"; 

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
    { 
     if (request.Method == HttpMethod.Head) 
     { 
      request.Method = HttpMethod.Get; 
      request.Properties.Add(Head, true); 
     } 

     var response = await base.SendAsync(request, cancellationToken); 

     object isHead; 
     response.RequestMessage.Properties.TryGetValue(Head, out isHead); 

     if (isHead != null && ((bool) isHead)) 
     { 
      var oldContent = await response.Content.ReadAsByteArrayAsync(); 
      var content = new StringContent(string.Empty); 
      content.Headers.Clear(); 

      foreach (var header in response.Content.Headers) 
      { 
       content.Headers.Add(header.Key, header.Value); 
      } 

      content.Headers.ContentLength = oldContent.Length; 
      response.Content = content; 
     } 

     return response; 
    } 
} 

Когда я сделать запрос на голову от Скрипач:

HEAD http://localhost:54225/api/books/5 HTTP/1.1 
User-Agent: Fiddler 
Host: localhost:54225 

я получаю следующий ответ обратно:

HTTP/1.1 200 OK 
Cache-Control: no-cache 
Pragma: no-cache 
Content-Length: 0 
Content-Type: application/json; charset=utf-8 
Expires: -1 
Server: Microsoft-IIS/10.0 
X-AspNet-Version: 4.0.30319 
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcc2ltb25lXERvY3VtZW50c1xTaW1vbnNEb2N1bWVudHNcSVRcQyNcRGVtb0NvZGVcUkVTVGZ1bFdlYlNlcnZpY2VDbGllbnRERU1PXEJvb2tTZXJ2aWNlXGFwaVxib29rc1w1?= 
X-Powered-By: ASP.NET 
Date: Sun, 19 Feb 2017 12:09:52 GMT 

Content-Length равно 0, но должно быть 104 байта.

Когда я добавляю точку останова к HeadHandler и просматриваю код, он, кажется, правильно устанавливает значение заголовка Content-Length, до 104 байтов, перед возвратом ответа.

Может ли быть какой-то другой шаг в конвейере, который запускается после HeadHandler, который распознает ответ, не имеет тела и устанавливает Content-Length в 0? Единственные вещи в WebApiConfig.cs, которые появляются после добавления HeadHandler, - это сопоставление маршрутов HttpAttribute и настройка маршрута по умолчанию, ни один из которых, по-видимому, не может привести к сбросу заголовка Content-Length. В качестве альтернативы, может ли параметр конфигурации повлиять на длину содержимого, возвращаемую в ответе?

+0

Вы пытались настроить заголовки для HttpResponseMessage, созданные заголовками содержимого, которые вы отправляете обратно клиенту? – Chizh

+0

@ Чиж: Я не уверен, что вы имеете в виду. Насколько мне известно, заголовок Content-Length определен только в HttpResponseMessage.Content.Headers, а не в HttpResponseMessage.Headers. Положив точку останова на строку «return response;», я подтвердил, что значение HttpResponseMessage.Content.Headers.ContentLength было установлено равным 104 байтам в момент возврата кода из метода SendAsync. –

+0

, но вы попробовали 'response.Headers.Add (« Content-Length », Int32.MaxValue)' например? Дело в том, что при отклике ответа заголовок Content-Length [* может не быть *] (http://stackoverflow.com/a/32111201/225389) обязательно сгенерирован с использованием 'HttpResponseMessage.Content.Headers.ContentLength', но из фактического содержимого - длина, которая равна нулю – Chizh

ответ

2

Все, что вам нужно сделать, это установить Content-Length для Content.Headers ответа - нет необходимости создавать новый контент для ответа. Акт запроса HEAD удаляет содержимое тела из ответа в любом случае.

Это может быть изменение, так как статья цитируете была написана (2013), и больше не нужно создавать контент с нуля ...

Так что это все, что вам нужно понадобится:

public class HeadHandler : DelegatingHandler 
{ 
    private const string Head = "IsHead"; 

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
    { 
     if (request.Method == HttpMethod.Head) 
     { 
      request.Method = HttpMethod.Get; 
      request.Properties.Add(Head, true); 
     } 

     var response = await base.SendAsync(request, cancellationToken); 

     object isHead; 
     response.RequestMessage.Properties.TryGetValue(Head, out isHead); 

     if (isHead != null && ((bool)isHead)) 
     { 
      var oldContent = await response.Content.ReadAsByteArrayAsync(); 

      response.Content.Headers.ContentLength = oldContent.Length; 
      return response; 
     } 

     return response; 
    } 
} 
+0

Работала отлично, спасибо. –