Подтвердить что ты не робот

Веб-API как прокси-сервер и кодирование с кодировкой передачи

Я играл с использованием веб-интерфейса (веб-хоста) в качестве прокси-сервера и столкнулся с проблемой того, как мой прокси-сервер Web API обрабатывает ответы с заголовком "Transfer-Encoding: chunked".

При обходе прокси-сервера удаленный ресурс отправляет следующие заголовки ответов:

Cache-Control:no-cache
Content-Encoding:gzip
Content-Type:text/html
Date:Fri, 24 May 2013 12:42:27 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/8.0
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

Когда я просматриваю свой прокси-сервер на основе веб-API, мой запрос зависает, если я явно не reset свойство TransferEncodingChunked в заголовке ответа на false:

response.Headers.TransferEncodingChunked = false;

Я признаю, что я не совсем понимаю, какое влияние оказывает на свойство TransferEncodingChunked, но мне кажется странным, что для обеспечения работы прокси-сервера, как и ожидалось, мне нужно установить это свойство как ложное, когда ясно, что входящий ответ имеет заголовок "Transfer-Encoding: chunked". Я также обеспокоен побочными эффектами, чтобы явно установить это свойство. Может ли кто-нибудь помочь мне понять, что происходит, и почему требуется установка этого свойства?

ОБНОВЛЕНИЕ: Таким образом, я сделал немного больше вникания в разницу в ответе при прохождении через прокси против нет. Я явно устанавливаю для свойства TransferEncodingChunked значение false, заголовки ответов при прохождении через прокси-серверы точно такие же, как при отсутствии прокси-сервера. Однако содержание ответа отличается. Вот несколько примеров (я отключил кодировку gzip):

// With TransferEncodingChunked = false
2d\r\n
This was sent with transfer-encoding: chunked\r\n
0\r\n

// Without explicitly setting TransferEncodingChunked
This was sent with transfer-encoding: chunked

Очевидно, что содержимое, отправленное с TransferEncodingChunked, установлено в false, фактически передается кодировкой. На самом деле это правильный ответ, так как это то, что было получено от запрашиваемого ресурса за прокси. То, что по-прежнему остается странным, - это второй сценарий, в котором я явно не указываю TransferEncodingChunked на ответ (но он находится в заголовке ответа, полученном от проксированной службы). Ясно, что в этом случае ответ не является фактически передачей, кодируемой IIS, несмотря на то, что фактический ответ. Странно... это начинает ощущаться как разработанное поведение (в этом случае мне бы хотелось узнать, как/почему) или ошибка в IIS, ASP.Net или веб-API.

Вот упрощенная версия кода, который я запускаю:

Приложение Proxy Web API:

// WebApiConfig.cs
config.Routes.MapHttpRoute(
    name: "Proxy",
    routeTemplate: "{*path}",
    handler: HttpClientFactory.CreatePipeline(
        innerHandler: new HttpClientHandler(), // Routes the request to an external resource
        handlers: new DelegatingHandler[] { new ProxyHandler() }
    ),
    defaults: new { path = RouteParameter.Optional },
    constraints: null
);

// ProxyHandler.cs
public class ProxyHandler : DelegatingHandler
{
    protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        // Route the request to my web application
        var uri = new Uri("http://localhost:49591" + request.RequestUri.PathAndQuery);
        request.RequestUri = uri;

        // For GET requests, somewhere upstream, Web API creates an empty stream for the request.Content property
        // HttpClientHandler doesn't like this for GET requests, so set it back to null before sending along the request
        if (request.Method == HttpMethod.Get)
        {
            request.Content = null;
        }

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

        // If I comment this out, any response that already has the Transfer-Encoding: chunked header will hang in the browser
        response.Headers.TransferEncodingChunked = false;

        return response;
    }
}

И мой контроллер веб-приложений, который создает "chunked" response (также Web API):

public class ChunkedController : ApiController
{
    public HttpResponseMessage Get()
    {
        var response = Request.CreateResponse(HttpStatusCode.OK);

        var content = "This was sent with transfer-encoding: chunked";
        var bytes = System.Text.Encoding.ASCII.GetBytes(content);
        var stream = new MemoryStream(bytes);

        response.Content = new ChunkedStreamContent(stream);

        return response;
    }
}

public class ChunkedStreamContent : StreamContent
{
    public ChunkedStreamContent(Stream stream)
        : base(stream) { }

    protected override bool TryComputeLength(out long length)
    {
        length = 0L;
        return false;
    }
}
4b9b3361

Ответ 1

С точки зрения HttpClient фрагментация контента является, по сути, деталью транспорта. Содержимое, предоставленное response.Content всегда отключается для вас HttpClient.

Похоже, что в веб-интерфейсе есть ошибка в том, что он не корректно (перезагружает содержимое) по запросу свойства response.Haders.TransferEncodingChunked при работе в IIS. Таким образом, проблема заключается в том, что прокси-сервер сообщает клиенту, через заголовки, что содержимое разделяется, а на самом деле это не так. Я подал ошибку здесь: https://aspnetwebstack.codeplex.com/workitem/1124

Я думаю, что ваш способ обхода является лучшим вариантом на данный момент.

Также обратите внимание, что здесь есть несколько уровней, которые, вероятно, не были спроектированы/протестированы для сценариев проксирования (и могут не поддерживать его). На стороне HttpClient обратите внимание, что она будет автоматически распаковываться и следовать переадресации, если вы не отключите это поведение. Как минимум, вы захотите установить эти два свойства: http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.allowautoredirect.aspx http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.automaticdecompression.aspx

На стороне WebApi/IIS вы обнаружили по крайней мере одну ошибку, и не было бы сюрпризом находить и других. Просто имейте в виду, что в этом случае могут возникать ошибки, связанные с созданием прокси-сервера с использованием этих технологий вне их основных случаев использования дизайна.