我一直在使用Web API(Web Host)作为代理服务器,并且遇到了我的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
在浏览基于Web API的代理时,除非我将响应标头上的TransferEncodingChunked属性显式重置为false,否则我的请求会挂起:
response.Headers.TransferEncodingChunked = false;
我承认,我并不完全了解设置TransferEncodingChunked属性有什么影响,但我觉得奇怪的是,为了使代理按预期工作,我需要在明确传入响应时将此属性设置为false有一个“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或Web API中的错误。
以下是我正在运行的代码的简化版本:
代理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;
}
}
我的Web应用程序控制器创建了一个“分块”响应(也是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;
}
}
答案 0 :(得分:6)
从HttpClient的角度来看,内容分块本质上是传输的细节。响应.Content提供的内容总是由HttpClient为您解除阻塞。
看起来Web API中存在一个错误,当在IIS上运行时,响应请求时,它没有正确(重新)响应内容.Headers.TransferEncodingChunked属性。所以问题是代理通过标题告诉客户端内容被分块,而事实上并非如此。我在这里提交了错误: 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方面,您至少发现了一个错误,找到其他错误并不令人惊讶。只是预先警告可能存在这样的错误,目前正在使用这些技术在其主要设计用例之外编写代理。