Я играл с использованием веб-интерфейса (веб-хоста) в качестве прокси-сервера и столкнулся с проблемой того, как мой прокси-сервер 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;
}
}