12

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 プロパティの設定がどのような影響を与えるかは完全には理解していませんが、プロキシを期待どおりに動作させるには、着信応答に明らかに " 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 を明示的に設定しない 2 番目のシナリオです (ただし、プロキシされたサービスから受信した応答ヘッダーにあります)。明らかに、この場合、実際の応答が 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 APIも)を作成する私のWebアプリケーションコントローラー:

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

1 に答える 1

7

HttpClient の観点から見ると、コンテンツのチャンクは本質的にトランスポートの詳細です。response.Content によって提供されるコンテンツは、常に HttpClient によってデチャンクされます。

IIS での実行時に response.Headers.TransferEncodingChunked プロパティによって要求されたときにコンテンツを正しく (再) チャンクしない Web API のバグがあるようです。したがって、問題は、実際にはコンテンツがチャンクされていないのに、ヘッダーを介してプロキシがクライアントにコンテンツがチャンクされていることを伝えていることです。ここでバグを報告しました: https://aspnetwebstack.codeplex.com/workitem/1124

現時点では、あなたの回避策が最良の選択肢だと思います。

また、プロキシ シナリオ用に設計/テストされていない可能性が高い (そして、それをサポートしていない可能性がある) 複数のレイヤーがここにあることに注意してください。HttpClient 側では、その動作をオフにしない限り、自動的に解凍してリダイレクトに従うことに注意してください。少なくとも、次の 2 つのプロパティを設定する必要があります: 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 側では、少なくとも 1 つのバグが見つかりました。他のバグが見つかっても驚くことではありません。主な設計ユース ケース以外でこれらのテクノロジを使用して現在プロキシを作成しているため、このようなバグが発生する可能性があることに注意してください。

于 2013-07-12T18:48:47.330 に答える