我按照those instructions为我的网络服务(Play 2.4)中的所有响应启用了gzip压缩。易于设置,我可以看到它就像一个用curl和wireshark检查过的响应被压缩发送的魅力。
现在我想成为一名优秀的开发人员并添加集成测试,以确保下周没有人破解HTTP压缩。这里有趣的地方!我的测试看起来像这样:
"use HTTP compression" in {
forAll(endPoints) { endPoint =>
val response = await(
WS.url(Localhost + port + "/api" + endPoint).withHeaders("Accept-Encoding" -> "gzip").get()
)
response.header("Content-Encoding") mustBe Some("gzip")
}
}
但是,测试失败,因为WS的响应标头不包含内容enconding信息,并且正文以纯文本形式返回,未压缩。
[info] - should use HTTP compression *** FAILED ***
[info] forAll failed, because:
[info] at index 0, None was not equal to Some("gzip") (ApplicationSpec.scala:566)
运行此测试时检查wireshark中的流量我可以清楚地看到服务器正在返回gzip编码的响应,所以看起来WS在某种程度上透明地解压缩响应并剥离内容编码头?有没有办法可以获得带有完整标题的普通压缩响应,这样我就可以检查响应是否被压缩了?
答案 0 :(得分:1)
我认为你不能那样做。如果我没有弄错的话,这里的问题是Netty返回已经解压缩的内容,因此标题也会被删除。
AsyncHTTPClient中有一个配置来设置它(setKeepEncoding),但不幸的是,这仅适用于2.0及更高版本,而Play 2.4 WS lib使用版本1.9.x。
无论哪种方式,客户端Play都会给你配置,我不知道你是否能够调整它。但您可以创建一个新客户端来模拟该行为:
// Converted from Java code: I have never worked with those APi's in Scala
val cfg = new AsyncHttpClientConfig.Builder().addResponseFilter(new ResponseFilter {
override def filter[T](ctx: FilterContext[T]): FilterContext[T] = {
val headers = ctx.getRequest.getHeaders
if (headers.containsKey("Accept-Encoding")) {
ctx.getResponseHeaders.getHeaders.put("Content-Encoding", List("gzip"))
}
ctx
}
}).build()
val client: NingWSClient = NingWSClient(cfg)
client.url("...") // (...)
同样,这只是模仿你需要的结果。此外,可能是一个更聪明的逻辑,而不仅仅是将gzip
添加为Content-Encoding
(例如:放置“接受编码”中请求的第一个算法)。
答案 1 :(得分:1)
事实证明,我们无法真正使用Play-WS进行此特定测试,因为它已经返回未压缩的内容并剥离了标题(请参阅@ Salem的深刻见解),因此无法检查响应是否已压缩。
然而,编写一个使用标准Java类检查HTTP压缩的测试很容易。我们关心的是服务器在发送Accept-Encoding: gzip
请求时是否以(有效)GZIP形式回答。这就是我最终的结果:
forAll(endPoints) { endPoint =>
val url = new URL(Localhost + port + "/api/" + endPoint)
val connection = url.openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestProperty("Accept-Encoding", "gzip")
Try {
new GZIPInputStream(connection.getInputStream)
} must be a 'success
}