如果我有一个名为的控制器HomeController
接收GET /foo
带有 header的请求X-Foo: Bar
,我想创建一个 WS 客户端过滤器,它将RequestHeader
在上下文中读取并将 header 值复制到传出的 WS 请求。
示例控制器:
import play.api.libs.ws.{StandaloneWSRequest, WSClient, WSRequest, WSRequestExecutor, WSRequestFilter}
import play.api.mvc._
import scala.concurrent.ExecutionContext
@Singleton
class HomeController @Inject()(cc: ControllerComponents,
myWsClient: MyWSClient)
(implicit executionContext: ExecutionContext)
extends AbstractController(cc) {
def index = Action.async {
myWsClient.url("http://www.example.com")
.get()
.map(res => Ok(s"${res.status} ${res.statusText}"))(executionContext)
}
}
引入过滤器的 WSClient 包装器:
@Singleton
class MyWSClient @Inject()(delegate: WSClient, fooBarFilter: FooBarFilter) extends WSClient {
override def underlying[T]: T = delegate.underlying.asInstanceOf[T]
override def url(url: String): WSRequest = {
delegate.url(url)
.withRequestFilter(fooBarFilter)
}
override def close(): Unit = delegate.close()
}
最后是 WS 过滤器本身:
@Singleton
class FooBarFilter extends WSRequestFilter {
override def apply(executor: WSRequestExecutor): WSRequestExecutor = {
(request: StandaloneWSRequest) => {
request.addHttpHeaders(("X-Foo", "<...>")) // INSERT CORRECT VALUE HERE!
executor.apply(request)
}
}
}
最后,期望是请求GET http://www.example.com
包含 header X-Foo: Bar
。
使这更有趣的特殊要求是:
- 你可以修改
MyWsClient
类。 - 你可以修改
FooBarFilter
类 - 您可以创建 HTTP 控制器过滤器(
play.api.mvc.(Essential)Filter
如果有帮助的话。 - 您可以创建其他类/对象/等
- 您不能修改控制器(因为在我们的情况下,我们不能期望所有现有的控制器都被修改。
- 即使在控制器和 WSClient 调用之间有一个“服务”层并且不涉及到处传递对象,该解决方案也应该可以工作。
- 该解决方案可以更改其他 Play/Akka 机制,例如默认的 Dispatcher