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

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

问题描述

我正在尝试编写一个 Akka HTTP 微服务(akka 版本 2.4.11,Scala 版本 2.11.8,在撰写本文时都是最新版本),它知道客户端服务的 IP(即远程地址),并且我无法让它工作.

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!"))
          }
        }
      }
    }

我已经构建了一个与上面类似的路由,并对其进行了扩展,以便知道客户端的 IP 地址.

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

我注意到我需要编辑 application.conf 文件并设置 'remote-address-header = on' 以启用添加一个 Remote-Address 头来保存客户端(远程)IP地址.我已经这样做了,以防万一.

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.

路线如下:

    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.'.

看起来我在上面的例子中弄错了 Akka-http DSL 语法糖.如果您能让我走上正确的道路,我将不胜感激!

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!

为了回应 Ramon 的有用回答,我尝试了以下程序.不幸的是,它不能编译,我看不出我需要做什么才能编译它.

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))
    })
  }
}

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

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

推荐答案

使用extractClientIp

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

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

提供 X-Forwarded-For、Remote-Address 或 X-Real-IP 的值标头作为 RemoteAddress 的一个实例.

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:

akka-http 服务器引擎将 Remote-Address 标头添加到每个如果相应的设置自动请求akka.http.server.remote-address-header 设置为 on.默认情况下是设置为关闭.

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.

通用解决方案

如果您希望它适用于任何 HttpRequest,而不仅仅是具有正确标头设置的那些,那么您必须在 HttpExt 而不是 bindAndHandle:

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))
})

编辑

如评论中所述:由于 akka 10.0.13 使用 conn.handleWith.

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

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

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