在Akka-http中获取客户端IP [英] Obtaining the client IP in Akka-http

查看:200
本文介绍了在Akka-http中获取客户端IP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个知道客户端服务的IP(即远程地址)的Akka HTTP微服务(akka版本2.4.11,Scala版本2.11.8,在撰写本文时均为最新版本),我



我可以使用以下路线创建并运行一个服务,上面写着 Hello!:

  val routeHello:Route = path( SayHello){
get {
实体(as [String]){
body = >完成{
HttpResponse(entity = HttpEntity( Hello!))
}
}
}
}

我已经构建了与上述路由类似的路由,并对其进行了扩展,以使其了解客户端的IP地址。



我注意到我需要编辑application.conf文件并设置'remote-address-header = on'以启用添加 Remote-Address 标头,包含客户端(远程)IP地址。



这是路线:

  val routeHelloIp:Route = path( SayHelloIp){
get {
// extractClientIp似乎在充当过滤器
//而不是提取程序-为什么?
extractClientIp {
clientIp => {
实体(as [String]){
主体=>完成{
HttpResponse(entity = HttpEntity( Hello!))
}
}
}
}
}
}

但是,当我运行此路由时,会收到一条消息找不到所请求的资源。。 / p>

在上面的示例中,我似乎弄错了Akka-http DSL语法糖。如果您能使我走上正确的道路,将不胜感激!



编辑:



我已经尝试过以下程序以响应Ramon的有用答案。不幸的是,它无法编译,而且我看不到需要进行什么编译。

  import akka.actor.ActorSystem 
导入akka.http.scaladsl.Http
导入akka.http.scaladsl.Http.IncomingConnection
导入java.net.InetSocketAddress
导入akka.stream.ActorMaterializer
导入akka.stream.scaladsl.Sink
导入akka.http.scaladsl.server.Directives._
导入java.net.InetSocketAddress


对象TestHttp {
def main(args:Array [String]){

隐式val系统= ActorSystem( my-system)
隐式val实体化器= ActorMaterializer()

//允许来自任何IP的连接
val接口= 0.0.0.0

//来自问题
def createRoute(address:InetSocketAddress)= path( SayHelloIp ){
get {
extractRequestEntity {实体=>
entity(as [String]){body =>
complete(entity = s Hello $ {address.getAddress()。getHostAddress()})
}
}
}
}

Http()。bind(interface).runWith(Sink foreach {conn =>
val address = conn.remoteAddress
conn.handleWithAsyncHandler(createRoute(address))
})
}
}

我有以下build.sbt来确保使用了最新版本的Scala和akka-http:

  import sbt.Keys._ 

名称:=查找我的IP

版本:= 1.0

scalaVersion:= 2.11.8

解析器++ = Seq (
Typesafe Repository位于 http://repo.typesafe.com/typesafe/releases/


libraryDependencies ++ = {
Seq(
com.typesafe.akka %% akka-actor% 2.4.11,
com.typesafe.akka %% akka-stream% 2.4.11,
com.typesafe.akka %% akka-http-experimental% 2.4.11,
com.typesafe.akka %% akka-http -core% 2.4.11

}

我明白了以下编译时错误:

  [错误] / Users / tilopa / temp / akka-test / src / main / scala /Test.scala:24:akka.http.scaladsl.model.RequestEntity不接受参数
[错误]实体(as [字符串]){主体=>
[错误] ^
[错误] /Users/tilopa/temp/akka-test/src/main/scala/Test.scala:25:重新分配给val
[错误]完成(实体= s你好$ {address.getAddress()。getHostAddress()})
[错误] ^
[错误]找到两个错误
[错误](compile:compileIncremental)编译失败的


解决方案

使用extractClientIp



extractClientIp 对您不起作用,因为发件人未指定必需的标头字段之一。从文档


提供X-Forwarded-For,Remote-Address或X-Real-IP $ b的值$ b标头作为RemoteAddress的实例。


您只需在发送者中打开正确的设置:


如果各自设置
akka.http.server,则akka-http服务器引擎会自动将Remote-Address标头添加到每个
请求中。 .remote-address-header设置为on。默认情况下,已将
设置为关闭。


通用解决方案



如果您希望此方法适用于任何HttpRequest,而不仅仅是具有正确标头设置的HttpRequest,则必须使用 bind 方法在 HttpExt 而不是 bindAndHandle

 导入akka.actor.ActorSystem 
导入akka.http.scaladsl.Http
导入akka.http.scaladsl.Http.IncomingConnection

导入java.net.InetSocketAddress

隐式val actorSystem:ActorSystem = ???
隐式val actorMat = ActorMaterializer()


//允许来自任何IP的连接
val接口= 0.0.0.0

//从问题
def createRoute(address:InetSocketAddress)= path( SayHelloIp){
get {
extractRequestEntity {实体=>
entity(as [String]){body =>
complete(entity = s Hello $ {address.getAddress()。getHostAddress()})
}
}
}
}

Http()。bind(interface).runWith(Sink foreach {conn =>
val address = conn.remoteAddress

conn.handleWithAsyncHandler(createRoute(address))
})

编辑



如注释中所述:由于akka 10.0.13 使用 conn.handleWith


I am trying to write an Akka HTTP microservice (akka version 2.4.11, Scala version 2.11.8, both latest versions at time of writing) which is aware of the client service's IP (i.e., remote address), and I cannot get this to work.

I can create and run a service which says 'Hello!' using a route like this:

    val routeHello: Route = path("SayHello") {
      get {
        entity(as[String]) {
          body => complete {
            HttpResponse(entity = HttpEntity("Hello!"))
          }
        }
      }
    }

I have constructed a similar route to the one above, which is extended so that it is aware of the client's IP address.

I noted that I need to edit the application.conf file and set 'remote-address-header = on' to enable the addition of a Remote-Address header holding the clients (remote) IP address. I have done this in case it is required.

Here is the route:

    val routeHelloIp: Route = path("SayHelloIp") {
      get {
        // extractClientIp appears to be working as a filter
        // instead of an extractor - why?
        extractClientIp {
          clientIp => {
            entity(as[String]) {
              body => complete {
                HttpResponse(entity = HttpEntity("Hello!"))
              }
            }
          }
        }
      }
    }

However when I run this route, I get a message 'The requested resource could not be found.'.

It looks like I have got the Akka-http DSL syntactic sugar wrong in the example above. I would be grateful if you could put me on the right path!

EDIT:

I have tried the following program in response to Ramon's helpful answer. Unfortunately it does not compile and I cannot see what I need to do to make it compile.

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.Http.IncomingConnection
import java.net.InetSocketAddress
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Sink
import akka.http.scaladsl.server.Directives._
import java.net.InetSocketAddress


object TestHttp {
  def main(args: Array[String]) {

    implicit val system = ActorSystem("my-system")
    implicit val materializer = ActorMaterializer()

    // allow connections from any IP
    val interface = "0.0.0.0"

    //from the question
    def createRoute(address: InetSocketAddress) = path("SayHelloIp") {
      get {
        extractRequestEntity { entity =>
          entity(as[String]) { body =>
         complete(entity = s"Hello ${address.getAddress().getHostAddress()}")
          }
        }
      }
    }

    Http().bind(interface).runWith(Sink foreach { conn =>
  val address = conn.remoteAddress
   conn.handleWithAsyncHandler(createRoute(address))
    })
  }
}

I have the following build.sbt to ensure that the latest version of Scala and akka-http are used:

import sbt.Keys._

name := "Find my IP"

version := "1.0"

scalaVersion := "2.11.8"

resolvers ++= Seq(
  "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
)

libraryDependencies ++= {
  Seq(
    "com.typesafe.akka" %% "akka-actor" % "2.4.11",
    "com.typesafe.akka" %% "akka-stream" % "2.4.11",
    "com.typesafe.akka" %% "akka-http-experimental" % "2.4.11",
    "com.typesafe.akka" %% "akka-http-core" % "2.4.11"
  )
}

I get the following compile-time errors:

[error] /Users/tilopa/temp/akka-test/src/main/scala/Test.scala:24: akka.http.scaladsl.model.RequestEntity does not take parameters
[error]           entity(as[String]) { body =>
[error]                 ^
[error] /Users/tilopa/temp/akka-test/src/main/scala/Test.scala:25: reassignment to val
[error]             complete(entity = s"Hello ${address.getAddress().getHostAddress()}")
[error]                             ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed

解决方案

Using extractClientIp

extractClientIp is not working for you because the sender has not specified one of the required header fields. From the documentation:

Provides the value of X-Forwarded-For, Remote-Address, or X-Real-IP headers as an instance of RemoteAddress.

You just have to turn on the right setting in your sender:

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.

generic solution

If you want this to work for any HttpRequest, not just the ones with the correct header settings, then you have to use the bind method on an HttpExt instead of bindAndHandle:

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.Http.IncomingConnection

import java.net.InetSocketAddress

implicit val actorSystem : ActorSystem = ???
implicit val actorMat = ActorMaterializer()


//alow connections from any IP
val interface = "0.0.0.0"

//from the question
def createRoute(address : InetSocketAddress) = path("SayHelloIp") {
  get {
    extractRequestEntity { entity =>
      entity(as[String]) { body =>
        complete(entity = s"Hello ${address.getAddress().getHostAddress()}")
      }
    }
  }
}

Http().bind(interface).runWith(Sink foreach { conn =>
  val address =  conn.remoteAddress

  conn.handleWithAsyncHandler(createRoute(address))
})

Edit

As noted in the comments: since akka 10.0.13 use conn.handleWith.

这篇关于在Akka-http中获取客户端IP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆