[英]Akka-http: connect to websocket on localhost
I am trying to connect to some server through websocket on localhost. 我正在尝试通过localhost上的websocket连接到某些服务器。 When I try to do it in JS by
当我尝试在JS中通过
ws = new WebSocket('ws://localhost:8137');
it succeeds. 成功。 However, when I use akka-http and akka-streams I get "connection failed" error.
但是,当我使用akka-http和akka-streams时,出现“连接失败”错误。
object Transmitter {
implicit val system: ActorSystem = ActorSystem()
implicit val materializer: ActorMaterializer = ActorMaterializer()
import system.dispatcher
object Rec extends Actor {
override def receive: Receive = {
case TextMessage.Strict(msg) =>
Log.info("Recevied signal " + msg)
}
}
// val host = "ws://echo.websocket.org"
val host = "ws://localhost:8137"
val sink: Sink[Message, NotUsed] = Sink.actorRef[Message](system.actorOf(Props(Rec)), PoisonPill)
val source: Source[Message, NotUsed] = Source(List("test1", "test2") map (TextMessage(_)))
val flow: Flow[Message, Message, Future[WebSocketUpgradeResponse]] =
Http().webSocketClientFlow(WebSocketRequest(host))
val (upgradeResponse, closed) =
source
.viaMat(flow)(Keep.right) // keep the materialized Future[WebSocketUpgradeResponse]
.toMat(sink)(Keep.both) // also keep the Future[Done]
.run()
val connected: Future[Done.type] = upgradeResponse.flatMap { upgrade =>
if (upgrade.response.status == StatusCodes.SwitchingProtocols) {
Future.successful(Done)
} else {
Future.failed(new Exception(s"Connection failed: ${upgrade.response.status}")
}
}
def test(): Unit = {
connected.onComplete(Log.info)
}
}
It works completely OK with ws://echo.websocket.org. 通过ws://echo.websocket.org可以完全正常工作。
I think attaching code of my server is reasonless, because it works with JavaScript client and problem is only with connection, however if you would like to look at it I may show it. 我认为附加服务器代码是没有道理的,因为它可与JavaScript客户端一起使用,而问题仅在于连接,但是,如果您愿意看一下,我可能会展示出来。
What am I doing wrong? 我究竟做错了什么?
I have tested your client implementation with a websocket server from akka documentation , and I did not get any connection error. 我已经从akka文档中使用websocket服务器测试了您的客户端实现,但没有收到任何连接错误。 Your websocket client connects successfully.
您的websocket客户端成功连接。 That is why I am guessing the problem is with your server implementation.
这就是为什么我猜测问题出在您的服务器实现上。
object WebSocketServer extends App {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
import Directives._
val greeterWebSocketService = Flow[Message].collect {
case tm: TextMessage => TextMessage(Source.single("Hello ") ++ tm.textStream)
}
val route =
get {
handleWebSocketMessages(greeterWebSocketService)
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8137)
println(s"Server online at http://localhost:8137/\nPress RETURN to stop...")
StdIn.readLine()
import system.dispatcher // for the future transformations
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
By the way, I noticed that your actor's receive method does not cover all possible messages. 顺便说一句,我注意到您演员的接收方法并未涵盖所有可能的消息。 According to that akka issue , every message, even very small, can end up as
Streamed
. 根据该问题 ,每条消息,即使很小,也都可以最终
Streamed
。 If you want to print all text messages a better implementation of the actor would be: 如果要打印所有文本消息,则可以更好地实现actor:
object Rec extends Actor {
override def receive: Receive = {
case TextMessage.Strict(text) ⇒ println(s"Received signal $text")
case TextMessage.Streamed(textStream) ⇒ textStream.runFold("")(_ + _).foreach(msg => println(s"Received streamed signal: $msg"))
}
}
Please find a working project on my github . 请在我的github上找到一个工作项目。
I found the solution: the server I used was running on IPv6 (as ::1), but akka-http treats localhost as 127.0.0.1 and ignores ::1. 我找到了解决方案:我使用的服务器在IPv6上运行(如:: 1),但是akka-http将localhost视为127.0.0.1,并忽略:: 1。 I had to rewrite server to force it to use IPv4 and it worked.
我不得不重写服务器以强制其使用IPv4,并且它可以正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.