2015-12-22 107 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)

随意提出修改建议。