2015-12-22 104 views
1

如何使用Play Framework執行完整代理?Play Framework中的代理請求

我想保持請求和響應的標題和正文不變。基本上,一個透明的代理層到客戶端和服務器。

注:我有一些工作。當SO允許我時,會發布它。

回答

1

這就是我最終得到的。

隨着我(不全面)的測試,這適用於各種身體類型的所有方法。

請注意我使用_.head。我還沒有探討爲什麼標題的類型爲Map[String, Seq[String]]。我可能會丟棄重複的標題內容(例如,在標題中具有多於Content-Type)。也許加入Seq[String];是更好的方法。

import play.api.libs.ws._ 
import play.api.libs.iteratee.Enumerator 
import play.api.mvc._ 

def proxy(proxyUrl: String) = Action.async(BodyParsers.parse.raw) { request => 
    // filter out the Host and potentially any other header we don't want 
    val headers: Seq[(String, String)] = request.headers.toSimpleMap.toSeq.filter { 
    case (headerStr, _) if headerStr != "Host" => true 
    case _ => false 
    } 
    val wsRequestBase: WSRequestHolder = WS.url(s"http://localhost:9000/$proxyUrl") // set the proxy path 
    .withMethod(request.method) // set our HTTP method 
    .withHeaders(headers : _*) // Set our headers, function takes var args so we need to "explode" the Seq to var args 
    .withQueryString(request.queryString.mapValues(_.head).toSeq: _*) // similarly for query strings 
    // depending on whether we have a body, append it in our request 
    val wsRequest: WSRequestHolder = request.body.asBytes() match { 
    case Some(bytes) => wsRequestBase.withBody(bytes) 
    case None => wsRequestBase 
    } 
    wsRequest 
    .stream() // send the request. We want to process the response body as a stream 
    .map { case (responseHeader: WSResponseHeaders, bodyStream: Enumerator[Array[Byte]]) => // we want to read the raw bytes for the body 
     // Content stream is an enumerator. It's a 'stream' that generates Array[Byte] 
     new Result(
     new ResponseHeader(responseHeader.status), 
     bodyStream 
    ) 
     .withHeaders(responseHeader.headers.mapValues(_.head).toSeq: _*) 
    } 
} 

routes文件條目將是這個樣子:

GET  /proxy/*proxyUrl     @controllers.Application.proxy(proxyUrl: String) 

您需要其他線路,以支持其他方法(例如POST)

隨意提出修改建議。