网络API作为代理服务器和块传输编码 [英] Web API as a Proxy and Chunked Transfer Encoding

查看:243
本文介绍了网络API作为代理服务器和块传输编码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在玩弄使用Web API(虚拟主机)作为代理服务器,并遇到了一个问题,怎么我的Web API代理处理的答复传输编码:分块头。

在绕过代理,远程资源发送下列响应报头:

的Cache-Control:no-cache的 内容编码:gzip 内容类型:text / html的 日期:星期五,2013 12时42分27秒格林尼治标准​​时间5月24日 到期日:-1 杂注:无缓存 服务器:Microsoft-IIS / 8.0 传输编码:分块 有所不同:接受编码 的X ASPNET-版本:4.0.30319 的X已启动方式:ASP.NET

在通过我的基于Web的API代理去,我的要求挂,除非我明确重置TransferEncodingChunked财产上的响应头为false:

response.Headers.TransferEncodingChunked = FALSE;

我承认,我不完全了解什么样的影响设置TransferEncodingChunked酒店,但它似乎很奇怪,我认为,为了使代理工作不如预期,我需要这个属性设置为false时,清楚地传入响应有一个传送编码:分块头。我还担心副作用明确设置该属性。谁能帮助我了解是怎么回事,为什么设置该属性是必需的?

更新:所以,我做了一点挖掘在响应的差异在通过代理时,对不。无论是我的TransferEncodingChunked属性明确设置为false,通过代理到来时的响应头是完全一样时,不会通过代理。然而,该响应的内容是不同的。这里有几个样品(我关掉gzip编码):

//随着TransferEncodingChunked = FALSE 2D \ r \ñ 这是发送的传输编码:分块\ r \ñ 0 \ r \ñ //如果没有明确设置TransferEncodingChunked 这是发送的传输编码:分块

显然,与TransferEncodingChunked发送的内容设置为false,实际上是在传输连接codeD。这实际上是正确的响应,因为它是从代理后面所请求的资源收到什么。什么仍然是奇怪的是,我没有明确的回应设定TransferEncodingChunked第二个场景(但它是从代理服务收到的响应头)。显然,在这种情况下,响应不处于实际上由IIS转印烯$ C $光盘,在尽管实际反应是。奇怪......这是开始觉得设计的行为(在这种情况下,我很想知道如何/为什么),或在IIS中,ASP.Net或Web API的错误。

这里是code我运行一个简化版本:

代理Web API应用程序:

// WebApiConfig.cs config.Routes.MapHttpRoute(     名:代理,     routeTemplate:{*}路径,     处理:HttpClientFactory.CreatePipeline(         innerHandler:新HttpClientHandler(),//路由请求到外部资源         处理器:新DelegatingHandler [] {新ProxyHandler()}     ),     默认:新{PATH = RouteParameter.Optional},     制约:空 ); // ProxyHandler.cs 公共类ProxyHandler:DelegatingHandler {     保护覆盖异步System.Threading.Tasks.Task< Htt的presponseMessage> SendAsync(Htt的prequestMessage要求,System.Threading.CancellationToken的CancellationToken)     {         //请求路由到我的web应用程序         VAR URI =新的URI(HTTP://本地主机:49591+ request.RequestUri.PathAndQuery);         request.RequestUri = URI;         //对于GET请求,上游某处,网络A​​PI创建的request.Content财产空流         // HttpClientHandler不喜欢这样的GET请求,因此沿着请求在发送前将其设置为null         如果(request.Method == HttpMethod.Get)         {             request.Content = NULL;         }         VAR响应=等待base.SendAsync(请求的CancellationToken);         //如果我评论了这一点,已经有传输编码任何回应:分块标题将在浏览器挂起         response.Headers.TransferEncodingChunked = FALSE;         返回响应;     } }

和我创造了分块web应用控制器响应(也的Web API):

公共类ChunkedController:ApiController {     公众的Htt presponseMessage获取()     {         VAR响应= Request.CreateResponse(的HTTPStatus code.OK);         VAR内容=这是发送的传输编码:分块;         VAR字节= System.Text.Encoding.ASCII.GetBytes(内容);         VAR流=新的MemoryStream(字节);         response.Content =新ChunkedStreamContent(流);         返回响应;     } } 公共类ChunkedStreamContent:StreamContent {     公共ChunkedStreamContent(流流)         :基座(流){}     保护覆盖布尔TryComputeLength(出长度长)     {         长度= 0L;         返回false;     } }

解决方案

从HttpClient的角度来看,内容分块基本上是运输的细节。通过response.Content提供的内容总是去分块为您的HttpClient。

它看起来像有它在被response.Headers.TransferEncodingChunked属性在IIS上运行时,要求不正确(重新)块内容的Web API的错误。所以,问题是,代理告诉客户端,通过头,那个时候,其实它不是内容分块。我已经申请了错误的位置: <一href="https://aspnetwebstack.$c$cplex.com/workitem/1124">https://aspnetwebstack.$c$cplex.com/workitem/1124

我觉得你的解决方法是目前最好的选择。

另请注意,你在这里多层次的可能不是设计/测试的代理的情况(且可能不支持它)。在HttpClient的一面,请注意,它会自动DECOM preSS和跟踪重定向,除非你把这种行为关闭。至少,你要设置这两个属性: <一href="http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.allowautoredirect.aspx">http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.allowautoredirect.aspx <一href="http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.automaticdecom$p$pssion.aspx">http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.automaticdecom$p$pssion.aspx

在的WebAPI / IIS的一面​​,你已经找到至少一个错误,它不会令人惊奇发现其他人。只要事先警告可能有这样的虫子正在写使用他们的主要设计用例之外的这些技术的代表。

I have been playing around with using Web API (Web Host) as a proxy server and have run into an issue with how my Web API proxy handles responses with the "Transfer-Encoding: chunked" header.

When bypassing the proxy, the remote resource sends the following response headers:

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

When going through my Web API based proxy, my request hangs unless I explicitly reset the TransferEncodingChunked property on the response header to false:

response.Headers.TransferEncodingChunked = false;

I admit, I don't fully understand what impact setting the TransferEncodingChunked property has, but it seems strange to me that in order to make the proxy work as expected, I need to set this property to false when clearly the incoming response has a "Transfer-Encoding: chunked" header. I am also concerned about side effects to explicitly setting this property. Can anyone help me understand what is going on and why setting this property is required?

UPDATE: So I did a little more digging into the difference in the response when going through the proxy vs. not. Whether I explicitly set the TransferEncodingChunked property to false, the response headers when coming through the proxy are exactly the same as when not going through the proxy. However, the response content is different. Here are a few samples (I turned off gzip encoding):

// 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

Clearly, the content sent with TransferEncodingChunked set to false is in fact transfer encoded. This is actually the correct response as it is what was received from the requested resource behind the proxy. What continues to be strange is the second scenario in which I don't explicitly set TransferEncodingChunked on the response (but it is in the response header received from the proxied service). Clearly, in this case, the response is NOT in fact transfer encoded by IIS, in spite of the fact that the actual response is. Strange...this is starting to feel like designed behavior (in which case, I'd love to know how / why) or a bug in IIS, ASP.Net, or Web API.

Here is a simplified version of the code I am running:

Proxy Web API application:

// 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;
    }
}

And my web application controller which creates a "chunked" response (also 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;
    }
}

解决方案

From an HttpClient standpoint, content chunking is essentially a detail of the transport. The content provided by response.Content is always de-chunked for you by HttpClient.

It looks like there's a bug in Web API that it doesn't correctly (re-)chunk content when requested by the response.Headers.TransferEncodingChunked property when running on IIS. So the problem is that the proxy is telling the client, via the headers, that the content is chunked when in fact it is not. I've filed the bug here: https://aspnetwebstack.codeplex.com/workitem/1124

I think your workaround is the best option at the moment.

Also notice that you have multiple layers here that likely weren't designed/tested for proxying scenarios (and may not support it). On the HttpClient side, note that it will automatically decompress and follow redirects unless you turn that behavior off. At a minimum, you'll want to set these two properties: 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

On the WebApi/IIS side, you've found at least one bug, and it wouldn't be suprising to find others as well. Just be forewarned there may be bugs like this currently writing a proxy using these technologies outside their main design use cases.

这篇关于网络API作为代理服务器和块传输编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆