2017-05-25 4 views
0

私はウサギの穴に落ちたと思うし、私が試みているものよりはるかに簡単な解決策があると思われる。基本的に私の.netのコアMVCアプリケーション内で、私は外部のAPIからストリーミングビデオファイルを取得したい。.netコアのリモートサーバからの応答を転送するには?

これは、私の行動へのリクエストに対して、私は外部API関数を呼び出したいと思っています。リクエストにヘッダーを追加する必要がありますが、リクエストされている他のヘッダーをすべて渡してから、APIから返信したら、レスポンス全体をコンシューマーに転送します。これは、基本的にStatusCodeのないリダイレクトのようなもので、リダイレクトされたソースにヘッダを追加します。

私がやっているやり方は次のとおりです。

var client = await this.FileAssetsApiContext.GetHttpClient(); 
//Copy the Headers 
foreach (var header in Request.Headers) 
{ 
    header.Value.ToList().ForEach(p => { 
     if (client.DefaultRequestHeaders.Contains(header.Key)) 
     { 
      client.DefaultRequestHeaders.Remove(header.Key); 
      client.DefaultRequestHeaders.Add(header.Key, p); 
     } 
     else 
     { 
      client.DefaultRequestHeaders.Add(header.Key, p); 
     }}); 
    } 

    var fullPath = Url.Combine(VideosRootPath, path); 
    var response = await client.GetAsync(url); 
    return new ForwardedResponseResult(response);  

そして私は、転送クラスを持っている:私のコントローラでは、私はForwardedResponseResultを呼び出す

public class ForwardedResponseResult : ActionResult 
{ 
    public override void ExecuteResult(ActionContext context) 
    { 
     throw new NotImplementedException(); 
    } 
    public ForwardedResponseResult(HttpResponseMessage httpResponseMessage) 
    { 
     this.HttpResponseMessage = httpResponseMessage; 
    } 

    public override async Task ExecuteResultAsync(ActionContext context) 
    { 
     var responseToCopy = this.HttpResponseMessage; 
     var responseToCopyHeaders = responseToCopy.Headers.ToArray(); 
     var responseToCopyContentHeaders = responseToCopy.Content.Headers.ToArray(); 
     var streamToCopy = await responseToCopy.Content.ReadAsStreamAsync(); 
     var responseToReturnTo = context.HttpContext.Response; 
     var streamToCopyTo = responseToReturnTo.Body; 

     var headers = responseToCopy.Headers.ToArray(); 
     var contentHeaders = responseToCopy.Content.Headers.ToArray(); 
     var headersTo = responseToReturnTo.Headers.ToArray(); 

     foreach (var header in responseToCopy.Headers) 
     { 
       header.Value.ToList().ForEach(p => responseToReturnTo.Headers.Add(header.Key, p)); 
     } 
     responseToReturnTo.StatusCode = (int) responseToCopy.StatusCode; 

     foreach (var header in responseToCopy.Content.Headers) 
     { 
      header.Value.ToList().ForEach(p => responseToReturnTo.Headers.Add(header.Key, p)); 
     } 

     //Copy to the output buffer 
     var remainingBytes = streamToCopy.Length; 

     while (remainingBytes > 0) 
     { 
      //var bufferSize = 1024; 
      var bufferSize = 8096; 
      var buffLen = remainingBytes > bufferSize ? bufferSize : remainingBytes; 
      var buffer = new byte[buffLen]; 
      streamToCopy.Read(buffer, 0, (int)buffLen); 
      streamToCopyTo.Write(buffer, 0, (int)buffLen); 
      remainingBytes -= buffLen; 
     } 
     //streamToCopy.CopyTo(streamToCopyTo); 
     //await streamToCopyTo.FlushAsync(); 

    } 
    public HttpResponseMessage HttpResponseMessage { get; } 

} 

これは、大規模なやり過ぎのように思える、と範囲要求のパフォーマンスは悲惨です。私は明白な何かを欠いていますかもっと簡単にこれを行う方法はありますか?

答えて

1

私は、外部APIからストリーミングビデオファイルを取得します。

大きなダウンロードの場合は、HttpCompletionOption.ResponseHeadersReadを必ず使用します。 Otherwise, the GetAsync call is actually loading the entire response content into memory (and the .Content.ReadAsStreamAsync is not actually asynchronous)

また、the existing FileStreamResult typeを使用することもできます。この動作するはずのような何か:

var client = await this.FileAssetsApiContext.GetHttpClient(); 
... // Copy Request.Headers to client.DefaultRequestHeaders. 

var fullPath = Url.Combine(VideosRootPath, path); 
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); 
var stream = await client.Content.ReadAsStreamAsync(); 

... // Copy response.Headers/response.Content.Headers to Response.Headers 
return File(stream, "application/octet-stream"); 

私がリクエスト/レスポンスヘッダをコピーするきれいな方法を知りませんが、それはユーティリティメソッドのカップルのための良い場所のように思えます。

+0

スティーブンありがとうございます。その変更ははるかに良く機能します。私はこれを行うための直接的な方法はないと思っていますが、少なくとも私はそれを働かせています –

関連する問題