Yann Simon の回答に基づいて、ダウンロードしたリモート ファイルをストリーミングし、クライアントにストリーミングすることを許可する単純な CORS プロキシの実装を次に示します。すべてのファイルをメモリにロードするわけではありません。
import play.api.libs.iteratee._
private def getAndForwardStream(requestHolder: WSRequestHolder)(computeHeaders: ResponseHeaders => ResponseHeader): Future[SimpleResult] = {
val resultPromise = scala.concurrent.Promise[SimpleResult]
requestHolder.get { wsResponseHeaders: ResponseHeaders =>
val (wsResponseIteratee, wsResponseEnumerator) = Concurrent.joined[Array[Byte]]
val result = SimpleResult(
header = computeHeaders(wsResponseHeaders),
body = wsResponseEnumerator
)
resultPromise.success(result)
wsResponseIteratee
}
resultPromise.future
}
def corsProxy(url: URL) = Action.async { implicit request =>
val requestHolder = WS.url(url.toString).withRequestTimeout(10000)
getAndForwardStream(requestHolder) { wsResponseHeaders: ResponseHeaders =>
// We use the WS response headers and transmit them unchanged to the client, except we add the CORS header...
val originToAllow = request.headers.get("Origin").getOrElse("*")
val headers = wsResponseHeaders.headers.mapValues(_.head) + ("Access-Control-Allow-Origin" -> originToAllow)
ResponseHeader(
status = wsResponseHeaders.status,
headers = headers
)
}
}
ここで重要な部分は、 の使用ですplay.api.libs.iteratee.Concurrent.joined[Array[Byte]]
。Iteratee/Enumerator のペアを作成して、Iteratee にバイトを追加するたびに、これらのバイトが列挙子によって列挙子になるようにすることができます。
次の理由により、これは欠落していました。
- WS 応答を使用するには Iteratee が必要です。
- play フレームワークのレスポンスを生成するには列挙子が必要です。