akka-http 没有在请求中添加 Remote-Address headers
akka-http does not add Remote-Address in request headers
根据akka-http extractClientIP and Documentation:
The akka-http server engine adds the Remote-Address header to every
request automatically if the respective setting
akka.http.server.remote-address-header is set to on. Per default it is
set to off.
application.conf已相应设置
akka {
http {
server {
remote-address-header = on
}
}
}
下面的测试无法从请求 headers
中提取 Remote-Address
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.client.RequestBuilding
import akka.http.scaladsl.model._
import akka.http.scaladsl.testkit.ScalatestRouteTest
"Remote-Address added to request header by akka-http" in {
val request = RequestBuilding.Get("/").withHeaders(`User-Agent`(this.getClass.getSimpleName))
val miniRoute: Route = { ctx => ctx.complete("Always Succeed") }
request ~> miniRoute ~> check {
assert(responseAs[String] == "Always Succeed")
}
//confirm akka config setting is correct
assert(ConfigFactory.load().getString("akka.http.server.remote-address-header") == "on", "FAILED: please set application.conf: akka.http.server.remote-address-header = on")
val remoteIP: Option[HttpHeader] = request.headers.find(_.name == "Remote-Address")
assert(remoteIP.nonEmpty, "FAILED: Remote-Address missing in Request Headers")
}
问题是否应该akka-http在请求headers中自动注入Remote-Address
?另外,如果您能展示如何重写此测试,我将不胜感激,其中可以通过编程方式设置 akka.http.server.remote-address-header
配置。
您遇到这个问题是因为 testkit 的 ScalatestRouteTest
没有自动添加 Remote-Address
。它仅发生在 Http()
对象级别(有关详细信息,请参阅 source)。
如果您想实际查看它,可以启动服务器 运行
object Tmp extends App {
implicit val sys = ActorSystem("tmp")
implicit val mat = ActorMaterializer()
val route = headerValueByName("Remote-Address") { complete(_) }
Http().bindAndHandle(route, "localhost", 8080)
}
并且根据您的配置(这在您的问题中是正确的)您应该得到 200 OK
(如果设置为 on
)或 400 Bad Request
(如果设置为 off
).
根据您的建议,我进行了下面的测试,它按预期工作。希望这对其他人有用。
import akka.http.scaladsl.Http
import akka.stream.ActorMaterializer
import akka.http.scaladsl.server.directives.{HeaderDirectives, RouteDirectives}
import com.typesafe.config.ConfigFactory
/** Verify that akka-http engine injects the "Remote-Address" header in the request headers
* if the config key "akka.http.server.remote-address-header = on"
*
* TESTING (set config on/off via command line argument)
* 1. Run the mini web server
* sbt "runMain blabla.AkkaRemoteAddressTest on"
*
* 2. Open Git-Bash and type:
* $ curl -s http://localhost:2017
* (console output) Remote-Address = 127.0.0.1:58208 (Thursday, 02 Mar 2017 - 18:54:55)
* $ curl -s http://$COMPUTERNAME:2017
* (console output) Remote-Address = 10.5.34.101:58285 (Thursday, 02 Mar 2017 - 18:57:30)
*/
object AkkaRemoteAddressTest {
def main(args: Array[String]): Unit = {
val configValue =
if (args.isEmpty) "on"
else if (args(0).toLowerCase != "on" && args(0).toLowerCase != "off") "on"
else args(0)
val miniConfig = ConfigFactory.parseString(
s"""
|akka.http.server.remote-address-header = $configValue
""".stripMargin)
implicit val sys = ActorSystem("AkkaRemoteAddressTest", miniConfig)
implicit val mat = ActorMaterializer()
val sdfmt = new java.text.SimpleDateFormat("EEEE, dd MMM yyyy - HH:mm:ss")
val route = HeaderDirectives.headerValueByName("Remote-Address") {
remaddr => RouteDirectives.complete(s"Remote-Address = $remaddr (${sdfmt.format(java.util.Calendar.getInstance.getTime)})")
}
Http().bindAndHandle(route, "0.0.0.0", 2017)
}
}
根据akka-http extractClientIP and Documentation:
The akka-http server engine adds the Remote-Address header to every request automatically if the respective setting akka.http.server.remote-address-header is set to on. Per default it is set to off.
application.conf已相应设置
akka {
http {
server {
remote-address-header = on
}
}
}
下面的测试无法从请求 headers
中提取Remote-Address
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.client.RequestBuilding
import akka.http.scaladsl.model._
import akka.http.scaladsl.testkit.ScalatestRouteTest
"Remote-Address added to request header by akka-http" in {
val request = RequestBuilding.Get("/").withHeaders(`User-Agent`(this.getClass.getSimpleName))
val miniRoute: Route = { ctx => ctx.complete("Always Succeed") }
request ~> miniRoute ~> check {
assert(responseAs[String] == "Always Succeed")
}
//confirm akka config setting is correct
assert(ConfigFactory.load().getString("akka.http.server.remote-address-header") == "on", "FAILED: please set application.conf: akka.http.server.remote-address-header = on")
val remoteIP: Option[HttpHeader] = request.headers.find(_.name == "Remote-Address")
assert(remoteIP.nonEmpty, "FAILED: Remote-Address missing in Request Headers")
}
问题是否应该akka-http在请求headers中自动注入Remote-Address
?另外,如果您能展示如何重写此测试,我将不胜感激,其中可以通过编程方式设置 akka.http.server.remote-address-header
配置。
您遇到这个问题是因为 testkit 的 ScalatestRouteTest
没有自动添加 Remote-Address
。它仅发生在 Http()
对象级别(有关详细信息,请参阅 source)。
如果您想实际查看它,可以启动服务器 运行
object Tmp extends App {
implicit val sys = ActorSystem("tmp")
implicit val mat = ActorMaterializer()
val route = headerValueByName("Remote-Address") { complete(_) }
Http().bindAndHandle(route, "localhost", 8080)
}
并且根据您的配置(这在您的问题中是正确的)您应该得到 200 OK
(如果设置为 on
)或 400 Bad Request
(如果设置为 off
).
根据您的建议,我进行了下面的测试,它按预期工作。希望这对其他人有用。
import akka.http.scaladsl.Http
import akka.stream.ActorMaterializer
import akka.http.scaladsl.server.directives.{HeaderDirectives, RouteDirectives}
import com.typesafe.config.ConfigFactory
/** Verify that akka-http engine injects the "Remote-Address" header in the request headers
* if the config key "akka.http.server.remote-address-header = on"
*
* TESTING (set config on/off via command line argument)
* 1. Run the mini web server
* sbt "runMain blabla.AkkaRemoteAddressTest on"
*
* 2. Open Git-Bash and type:
* $ curl -s http://localhost:2017
* (console output) Remote-Address = 127.0.0.1:58208 (Thursday, 02 Mar 2017 - 18:54:55)
* $ curl -s http://$COMPUTERNAME:2017
* (console output) Remote-Address = 10.5.34.101:58285 (Thursday, 02 Mar 2017 - 18:57:30)
*/
object AkkaRemoteAddressTest {
def main(args: Array[String]): Unit = {
val configValue =
if (args.isEmpty) "on"
else if (args(0).toLowerCase != "on" && args(0).toLowerCase != "off") "on"
else args(0)
val miniConfig = ConfigFactory.parseString(
s"""
|akka.http.server.remote-address-header = $configValue
""".stripMargin)
implicit val sys = ActorSystem("AkkaRemoteAddressTest", miniConfig)
implicit val mat = ActorMaterializer()
val sdfmt = new java.text.SimpleDateFormat("EEEE, dd MMM yyyy - HH:mm:ss")
val route = HeaderDirectives.headerValueByName("Remote-Address") {
remaddr => RouteDirectives.complete(s"Remote-Address = $remaddr (${sdfmt.format(java.util.Calendar.getInstance.getTime)})")
}
Http().bindAndHandle(route, "0.0.0.0", 2017)
}
}