创建Vertx JS Eventbus连接然后关闭

时间:2017-03-06 20:49:52

标签: javascript websocket proxy vert.x

后台:使用 vertx-web-3.3在Java端使用 Vertx 3.3.3 Core Web 作为服务器.3-client.js 作为客户端 sockjsclient1.1.2.js

问题:我在本地计算机或局域网上成功地从客户端连接到事件总线。当我通过代理时,wss eventbus连接被阻止(在Firefox中我看到" Firefox无法与&#34建立连接; wss:// ... &#34 ;;在Chromium中我看到" WebSocket连接到wss:// ...失败:WebSocket握手期间出错:意外的响应代码:400 ",然后我请参阅" https://.../eventbus/.../xhr_send?t = ...无法加载资源:服务器响应状态代码为500 &#34 )。但是, onopen 会触发并收到一些数据(连接降级为已接受的协议?)。在此之后, onclose 立即触发,我失去了联系。我知道我已成功到达Java vertx服务器,因为我的静态Web和API调用正在运行。

问题:我已经广泛浏览了Vertx和SockJS文档。是吗:

  1. 有关vertx如何在JS Eventbus连接中尝试不同传输协议的文档?
  2. JS Vertx Eventbus通过业务代理工作的一个例子吗?
  3. 实现Eventbus连接的另一种方法,也许指定要尝试/使用的SockJS协议? (我正在尝试创建eventbus连接的最简单方法,如文档中的许多地方所示)
  4. 我需要在SockJS / Eventbus设置的Java端做些什么?
  5. 提前感谢任何建议/帮助!

    编辑1:为Java服务器和JavaScript Web客户端添加以下代码。网络方面非常基础(以及失败的方面)。 Java方面使用Spring进行依赖注入和应用程序配置,具有Eventbus连接,一个API调用,并提供静态Web内容。

    从客户端到服务器的API调用正常工作,服务器正确地提供Web内容,因此访问该工具正在运行。但是,代理导致wss失败(如预期的那样),但降级到xhr-streaming失败了(我认为)

    使用Javascript:

    var EB;
    var URL;
    var APICall = "api/eventbus/publish/";
    var IncomingAddress = "heartbeat-test";
    var OutgoingAddress = "client-test";
    
    function createConnection(){
        URL = $("#serveraddressinput").val(); //Getting url from html text box
        console.log("Creating Eventbus connection at " + URL + "eventbus"); //Eventbus address is '<link>/eventbus'
        EB = new EventBus(URL + "eventbus");
    
        testAPICall();
    
        EB.onopen = function(){
            console.log("Eventbus connection successfully made at " + URL + "eventbus");
            console.log("Registering Eventbus handler for messages at " + IncomingAddress);
    
            EB.registerHandler(IncomingAddress, function(error, message){
                console.log("Received Eventbus message " + JSON.stringify(message));
        };
    
        EB.onclose = function(){
            console.log("Eventbus connection at " + URL + " has been lost");
            URL = "";
        };
    }
    
    function testAPICall(){
        var link = URL + APICall + "heartbeat-test";
        console.log("Testing API call to " + link);
        $.ajax({
            url: link,
            type: 'POST',
            data: JSON.stringify({"testFromClient": "Test message sent from Client via API Call"}),
            dataType: 'json',
            success: function (data, textStatus) {
                console.log("API Call Success: " + JSON.stringify(data));
            },
            error: function (request, error) {
                console.log("API Call ERROR: " + JSON.stringify(request) + " " + error);
            }
        });
    }
    
    function sendTestMessage(){
        console.log("Sending test message to address " + OutgoingAddress);
        EB.send(OutgoingAddress, "Testing 1, 2, 3...");
    }
    

    爪哇:

    ...
    
    import io.vertx.core.AbstractVerticle;
    import io.vertx.core.Future;
    import io.vertx.core.eventbus.EventBus;
    import io.vertx.core.http.HttpMethod;
    import io.vertx.core.http.HttpServerOptions;
    import io.vertx.core.json.Json;
    import io.vertx.core.json.JsonObject;
    import io.vertx.core.net.JksOptions;
    import io.vertx.ext.web.Router;
    import io.vertx.ext.web.RoutingContext;
    import io.vertx.ext.web.handler.BodyHandler;
    import io.vertx.ext.web.handler.CorsHandler;
    import io.vertx.ext.web.handler.StaticHandler;
    import io.vertx.ext.web.handler.sockjs.BridgeEvent;
    import io.vertx.ext.web.handler.sockjs.BridgeEventType;
    import io.vertx.ext.web.handler.sockjs.BridgeOptions;
    import io.vertx.ext.web.handler.sockjs.PermittedOptions;
    import io.vertx.ext.web.handler.sockjs.SockJSHandler;
    import org.apache.logging.log4j.Level;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.slf4j.Marker;
    import org.slf4j.MarkerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MyTestVerticle extends AbstractVerticle {
    
        private final static Logger log = LoggerFactory.getLogger(MyTestVerticle.class);
    
        final Level ACCESS = Level.forName("ACCESS", 450);
    
        private boolean started;
    
        private int port;
    
        @Value("${webserver.testpath.enabled}")
        private boolean testPathEnabled;
    
        @Value("${webserver.urlpath.test}")
        private String testUrlPath;
    
        @Value("${webserver.filepath.test}")
        private String testFilePath;
    
        @Value("${webserver.caching.enabled}")
        private boolean cachingEnabled;
    
        @Value("${webserver.ssl.enabled}")
        private boolean sslEnabled;
    
        private BridgeOptions bridgeOptions;
    
        private SockJSHandler sockJsHandler;
    
        private Router router;
    
        private JksOptions sslKeyStoreOptions;
    
        private JksOptions sslTrustStoreOptions;
    
        public MyTestVerticle() {
            this.started = false;
        }
    
        @Override
        public void start(Future<Void> fut) throws Exception {
            log.info("start() -- starting Vertx Verticle with eventbus, API handler, and static file handler");
    
            // grab the router
            router = getRouter();
    
            // enable CORS for the router 
            CorsHandler corsHandler = CorsHandler.create("*");  //Wildcard(*) not allowed if allowCredentials is true
            corsHandler.allowedMethod(HttpMethod.OPTIONS);
            corsHandler.allowedMethod(HttpMethod.GET);
            corsHandler.allowedMethod(HttpMethod.POST);
            corsHandler.allowedMethod(HttpMethod.PUT);
            corsHandler.allowedMethod(HttpMethod.DELETE);
            corsHandler.allowCredentials(false);
            corsHandler.allowedHeader("Access-Control-Request-Method");
            corsHandler.allowedHeader("Access-Control-Allow-Method");
            corsHandler.allowedHeader("Access-Control-Allow-Credentials");
            corsHandler.allowedHeader("Access-Control-Allow-Origin");
            corsHandler.allowedHeader("Access-Control-Allow-Headers");
            corsHandler.allowedHeader("Content-Type");
    
            // enable handling of body
            router.route().handler(BodyHandler.create());
            router.route().handler(corsHandler);
            router.route().handler(this::handleAccessLogging);
    
            // publish a payload to provided eventbus destination
            router.post("/api/eventbus/publish/:destination").handler(this::publish);
    
            // open up all for outbound and inbound traffic
            bridgeOptions = new BridgeOptions();
            bridgeOptions.addOutboundPermitted(new PermittedOptions().setAddressRegex(".*"));
            bridgeOptions.addInboundPermitted(new PermittedOptions().setAddressRegex(".*"));
    //        sockJsHandler = SockJSHandler.create(vertx).bridge(bridgeOptions);   
             sockJsHandler = SockJSHandler.create(vertx);
             sockJsHandler.bridge(bridgeOptions, be -> {
                try {
                    if (be.type() == BridgeEventType.SOCKET_CREATED) {
                        handleSocketOpenEvent(be);
                    }
                    else if(be.type() ==BridgeEventType.REGISTER) {
                        handleRegisterEvent(be);
                    }
                    else if(be.type() ==BridgeEventType.UNREGISTER) {
                        handleUnregisterEvent(be);
                    }
                    else if(be.type() ==BridgeEventType.SOCKET_CLOSED) {
                        handleSocketCloseEvent(be);
                    }
                } catch (Exception e) {
    
                } finally {
                    be.complete(true);
                }
            });
            router.route("/eventbus/*").handler(sockJsHandler);
    
            if(testPathEnabled){
                router.route("/" + testUrlPath + "/*").handler(StaticHandler.create(testFilePath).setCachingEnabled(cachingEnabled));
            }
    
            // create periodic task, pushing all current EventBusRegistrations
            vertx.setPeriodic(1000, handler -> {
                JsonObject obj =new JsonObject();
                obj.put("testMessage", "Periodic test message from server...");
                vertx.eventBus().publish("heartbeat-test", Json.encodePrettily(obj));
            });
    
            EventBus eb = vertx.eventBus();
            eb.consumer("client-test", message -> {
                log.info("Received message from client: " + Json.encodePrettily(message.body()) + " at " + System.currentTimeMillis());
            });
    
            HttpServerOptions httpOptions = new HttpServerOptions();
            if(sslEnabled){
                    httpOptions.setSsl(true);
                    httpOptions.setKeyStoreOptions(sslKeyStoreOptions);
            }
    
            log.info("starting web server on port: " + port);
            vertx
                    .createHttpServer(httpOptions)
                    .requestHandler(router::accept).listen(
                    port,
                    result -> {
                        if (result.succeeded()) {
                            setStarted(true);
                            log.info("Server started and ready to accept requests");
                            fut.complete();
                        } else {
                            setStarted(false);
                            fut.fail(result.cause());
                        }
                    }
            );
        }
    
        private void handleSocketOpenEvent(BridgeEvent be){
            String host =be.socket().remoteAddress().toString();
            String localAddress = be.socket().localAddress().toString();
            log.info("Socket connection opened! Host: " + host + " Local address: " + localAddress);
        }
    
        private void handleRegisterEvent(BridgeEvent be){
            String host =be.socket().remoteAddress().toString();
            String localAddress = be.socket().localAddress().toString();
            String address = be.getRawMessage().getString("address").trim();
            log.info("Eventbus register event! Address: " + address + " Host: " + host + " Local address: " + localAddress);
        }
    
        private void handleUnregisterEvent(BridgeEvent be){
            String host =be.socket().remoteAddress().toString();
            String localAddress = be.socket().localAddress().toString();
            String address = be.getRawMessage().getString("address").trim();
            log.info("Eventbus unregister event! Address: " + address + " Host: " + host + " Local address: " + localAddress);
        }
    
        private void handleSocketCloseEvent(BridgeEvent be){
            String host =be.socket().remoteAddress().toString();
            String localAddress = be.socket().localAddress().toString();
            log.info("Socket connection closed! Host: " + host + " Local address: " + localAddress);
        }
    
        //Method handles logging at custom level for access logging to files
        private void handleAccessLogging(RoutingContext routingContext){
            Marker accessMarker = MarkerFactory.getMarker("ACCESS");
    
            if(routingContext.normalisedPath().contains("/api")){
                log.info(accessMarker, "Api access log: request= " + routingContext.normalisedPath() + " source=" + routingContext.request().remoteAddress());
            }
            else{
                log.info(accessMarker, "Web access log: path= " + routingContext.normalisedPath() + " source= " + routingContext.request().remoteAddress());
            }
    
            routingContext.next();
        }
    
        /**
         * Accept a payload (anything) and publish to the provided destination
         *
         * @param routingContext
         */
        private void publish(RoutingContext routingContext) {
            String destination = routingContext.request().getParam("destination");
            String payload = routingContext.getBodyAsString();
            if ((destination == null) || (payload == null)) {
                Exception e = new Exception("Missing arguments");
                routingContext.response().setStatusCode(406);
                routingContext.fail(e);
            } else {
                log.info("API Call -> Publishing to destination: " + destination + " payload: " + payload);
                vertx.eventBus().publish(destination, payload);
                routingContext
                        .response()
                        .setStatusCode(200)
                        .putHeader("content-type", "application/json; charset=utf-8")
                        .end(payload);
            }
        }
    
        public boolean isStarted() {
            return started;
        }
    
        public void setStarted(boolean started) {
            this.started = started;
        }
    
        public int getPort() {
            return port;
        }
    
        public void setPort(int port) {
            this.port = port;
        }
    
        public Router getRouter(){
            if(router == null){
                router = Router.router(vertx);
            }
            return router;
        }
    
        public void setRouter(Router router){
            this.router = router;
        }
    
        public void setSslOptions(JksOptions keyStoreOptions, JksOptions trustStoreOptions) {
            this.sslKeyStoreOptions = keyStoreOptions;
            this.sslTrustStoreOptions = trustStoreOptions;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

可以通过执行以下操作来解决此错误:

  1. 在Java Verticle中,在任何其他处理程序之前将Eventbus处理程序移动到顶部。我相信BodyHandler或CorsHandler正在弄乱它并造成500错误。

    ...
    router.route("/eventbus/*").handler(sockJsHandler);
    ...
    // enable handling of body
    router.route().handler(BodyHandler.create());
    router.route().handler(corsHandler);
    router.route().handler(this::handleAccessLogging);
    
    // publish a payload to provided eventbus destination
    router.post("/api/eventbus/publish/:destination").handler(this::publish);