Route SockJS connection at variable URL?

729 views
Skip to first unread message

Imran Hasan

unread,
Jul 18, 2017, 4:19:13 PM7/18/17
to vert.x
Hi,

Let's say I have a bunch of clients who all have their own numeric IDs. Each of them connect to my server through SockJS, with something like:

var sock = new SockJS("localhost:8080/sock/100");

In this case, 100 is that client's numeric ID, but it could be any number with any number of digits. How can I set up a SockJS router in my server-side code that allows for the client to set up a SockJS connection through a URL that varies based on what the user's ID is? Here's a simplified version of what I have on the server-side right now:

public void start() {
   
HttpServer server = vertx.createHttpServer();
   
SockJSHandler sockHandler = SockJSHandler.create(vertx);
    router
.route("/sock/*").handler(sockHandler);
    server
.requestHandler(router::accept).listen(8080);
}

This works fine if the client connects through localhost:8080/sock, but it doesn't seem to work if I add "/100" to the end of the URL. Instead of getting the default "Welcome to SockJS!" message, I just get "Not Found." I tried setting a path regex and I got an error saying that sub-routers can't use pattern URLs. So is there some way to allow for the client to connect through a variable URL, whether it's /sock/100, /sock/15, or /sock/1123123? Ideally, I'd be able to capture the numeric ID that the client uses (like with routing REST API calls, when you could add "/:ID" to the routing path and then capture the value that the client uses), but I can't find anything that works for SockJS connections.

Is this possible to do?

Imran Hasan

unread,
Jul 19, 2017, 2:53:33 PM7/19/17
to vert.x
To re-word my question, if it's not possible to set a pattern routing URL for a sub-router, are there any workarounds for that? Re-routing doesn't seem to be working for me.

Julien Viet

unread,
Jul 20, 2017, 3:04:54 AM7/20/17
to ve...@googlegroups.com
Hi,

you should use a query string as said here : https://github.com/sockjs/sockjs-client#sockjs-client-api

SockJS uses the path, for instance /info gives info about the SockJS server, etc… (http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html)

Julien

--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
Visit this group at https://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/ef095ffb-19b1-480e-8e89-3b96137a587c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Imran Hasan

unread,
Jul 20, 2017, 1:47:41 PM7/20/17
to vert.x
Wouldn't that require a change in the client code? So instead of writing

var sock = new SockJS("localhost:8080/sock/100");

I'd have to write

var sock = new SockJS("localhost:8080/sock&id=100");

Unfortunately, I can only control a small part of the server-side code and it's not really possible for me to change what the client is doing. All I can really do is change what /sock/100 routes to, and the goal is to create a SockJS connection there, so I'm not sure that a query string would work. Am I misunderstanding anything here?

Paulo Lopes

unread,
Jul 24, 2017, 3:16:04 AM7/24/17
to vert.x
Re routing is not technically possible because reroute is happening at the router level and websockets require a protocol upgrade at the protocol handshake level, so you're too late already.

You could mount the sockjs handler at a variable, has it has been said here before:

e.g.:

router.route("/sock/:id/*).handler(sockJSHandler)

however is does not seem right since you're doing the websocket routing yourself, why are you looking at sockjs at all? Shouldn't you just be more interested in plain websockets then?

I mean if you are assigning a address per user and avoiding doing that using the combo: eventbus + sockjs, why not make things simpler and just use the example above and mount a plain websocket to process your requests?

Tim Fox

unread,
Jul 24, 2017, 4:16:00 AM7/24/17
to vert.x
It seems to me that what Julien suggests is the right way to do it. Why can't you change your JS code? Isn't this served from the server too?

Imran Hasan

unread,
Jul 24, 2017, 1:52:12 PM7/24/17
to vert.x
Thanks for the replies. I'm re-writing a very small part of our overall codebase so that it uses Vert.x, and the client JS code (which other people work on) uses SockJS to connect to the server. That's why I can't change the client code and it's also why I can't use plain WebSockets here, because much of the client code depends on SockJS message handling. Making changes to that would require the entire platform to change, and that's a much longer term project than what I'm attempting to do here :)

Paulo, I've tried routing at a variable but it doesn't appear to work. If I route at:

router.route("/sock/:id/*").handler(sockJSHandler);

Then I still run into errors. I can access the "Welcome to SockJS!" page if I open "localhost:8080/sock/:id/*" in my browser, but any other matching URLs throws an exception. For example, "localhost:8080/sock/10/" throws an internal server error, as well as:

Jul 24, 2017 10:49:55 AM io.vertx.ext.web.impl.RoutingContextImplBase


SEVERE: Unexpected exception in route


java.lang.StringIndexOutOfBoundsException: String index out of range: -2


        at java.lang.String.substring(String.java:1931)


        at io.vertx.ext.web.impl.RouteImpl.matches(RouteImpl.java:245)


        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:70)


        at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:148)


        at io.vertx.ext.web.impl.RouterImpl.handleContext(RouterImpl.java:255)


        at io.vertx.ext.web.handler.sockjs.impl.SockJSHandlerImpl.handle(SockJSHandlerImpl.java:89)


        at io.vertx.ext.web.handler.sockjs.impl.SockJSHandlerImpl.handle(SockJSHandlerImpl.java:67)


        at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:217)


        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)


        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:118)


        at io.vertx.ext.web.impl.RouterImpl.accept(RouterImpl.java:79)


        at io.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:285)


        at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:429)


        at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:131)


        at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:630)


        at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:580)


        at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$0(VertxHttpHandler.java:71)


        at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:335)


        at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:193)


        at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:71)


        at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122)


        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)


        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)


        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)


        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)


        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)


        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)


        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)


        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)


        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)


        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)


        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)


        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)


        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)


        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)


        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)


        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)


        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)


        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)


        at java.lang.Thread.run(Thread.java:748)



Reply all
Reply to author
Forward
0 new messages