后台:使用 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:为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;
}
}
答案 0 :(得分: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);