让我先说应该拒绝访问我的场景。使用 Spring Security 4 内置 Spring Boot。我允许任何人连接到 websocket 并订阅主题,但我使用以下 web 套接字安全配置来确保向主题发送消息的能力:
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpSubscribeDestMatchers("/main-page-feed/thought-queue/**").permitAll()
.simpDestMatchers("/thought-bubble/push-to-queue/**").authenticated();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,当您尝试/thought-bubble/push-to-queue在未经身份验证的情况下向其发送消息时,它会拒绝您(这是正确的,我想强调这一点,因为我能找到的唯一其他问题是当异常被错误抛出时)并抛出一个AccessDeniedException. 我不明白的是,与 websocket 安全性相反,Spring HTTP 安全性何时锁定某些内容并拒绝访问,它不会抛出异常,它只是发送一个 HTTP 状态。我试过使用@ExceptionHandler, AccessDenied 处理程序,但我尝试过的任何东西都无法捕获和处理此异常。下面是堆栈跟踪和其他相关文件,任何想法都值得赞赏,因为我很困惑。我试过在调试中单步调试源代码,但我并没有真正看到问题是什么。
堆栈跟踪:
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:298) …Run Code Online (Sandbox Code Playgroud) 使用用于 Web 套接字消息传递的 Stomp 代理中继,我可以订阅目的地/topic/mydest。这将创建一个代理订阅并接收系统中的某些内容为此代理目标触发的所有消息,当系统中发生某些事件时会发生这种情况。
我可以订阅一个 destination /app/mydest,并且@SubscribeMapping("mydest")会调用一个控制器方法,并且返回值仅作为消息在此套接字上发回。据我所知,这是此订阅将发送的唯一消息。
有没有办法将其组合在单个订阅中,即为某个/topic目的地创建一个代理订阅,并触发一些直接将消息发送回订阅者的代码?
用例:当系统中发生错误时,将带有当前错误计数的消息发送到/topic/mydest。当新客户订阅时,我只想向他发送最后已知的错误计数。其他人此刻不感兴趣,因为计数没有改变。
我当前的解决方案是订阅两者/app/mydest并/topic/mydest在客户端使用相同的消息处理程序。但它确实是一种逻辑订阅,并且它有点容易出错,因为客户端需要记住同时订阅两者。
我在这种情况下的问题:是否会有进一步的/app/订阅消息?有什么可以调用来触发的吗?我还能如何向订阅者发送主题的初始信息,而不向现有订阅者发送冗余消息?
根据要求,这是我的 Websocket 配置类。
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue/", "/topic/", "/exchange/");
registry.setApplicationDestinationPrefixes("/app");
}
}
Run Code Online (Sandbox Code Playgroud) 我有支持 Spring Websocket 的 Spring 服务器。我想使用 STOMP 子协议来处理通过 Web 套接字的通信,因此 STOMP 端点的配置如下所示:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat")
.setAllowedOrigins("*")
.withSockJS();
}
}
Run Code Online (Sandbox Code Playgroud)
Spring 文档以及我能找到的有关该主题的基本上任何资源都展示了如何使用 SockJS + StompJS 创建 STOMP 客户端。它有效,但据我所知根本不需要它 - 因为 STOMP 只是一个子协议,我应该能够通过使用 STOMP 消息语法基本上从任何 Web 套接字客户端与我的服务器进行通信。
假设我只想从 Google Chrome Simple Web Socket Client 插件连接到我的 STOMP 服务器。根据 STOMP 规范,我做的第一件事是打开 Web 套接字连接。我这样做
ws://my.server.here/chat/websocket
关联。这部分工作,我的连接建立。现在我想使用STOMP。再次正如 STOMP 规范所说,我现在应该发送如下所示的 CONNECT 命令(STOMP 1.1):
CONNECT
accept-version:1.0,1.1
host:my.host.here
^@
Run Code Online (Sandbox Code Playgroud)
然后我希望服务器使用 CONNECTED 命令做出响应,但我什么也没得到。如果我将使用一些不存在的命令(如“WRONG_COMMAND”)而不是“CONNECT”,那么我可以看到有关未知命令的 Spring 异常被抛出,所以我想我的消息命中了 Spring 的 Websocket …
我目前正在使用该类配置我的 Spring Websocket
public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport
Run Code Online (Sandbox Code Playgroud)
现在我遇到了建议 Spring STOMP Websockets: any way to enable permessage-deflate on server side?
这利用
public class SampleJettyWebSocketsApplication implements WebSocketConfigurer
Run Code Online (Sandbox Code Playgroud)
并覆盖
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry)
Run Code Online (Sandbox Code Playgroud)
并提供
@Bean
public DefaultHandshakeHandler handshakeHandler()
Run Code Online (Sandbox Code Playgroud)
问题,WebSocketConfigurer和WebSocketMessageBrokerConfigurationSupport是什么关系?换句话说,我是否可以通过第一类 WebSocketMessageBrokerConfigurationSupport 的 API 从 WebSocketConfigurer 实现中添加配置,以便所有配置都保留在一个文件中?
我有一个使用 SockJs 启用 Websocket 的 Spring Boot 应用程序。一切正常,但它一直在控制台中记录以下消息。
2017-09-19 11:04:48.164 INFO 8856 --- [MessageBroker-4] o.s.w.s.c.WebSocketMessageBrokerStats : WebSocketSession[1 current WS(1)-HttpStream(0)-HttpPoll(0), 3 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(3)-CONNECTED(3)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 45], outboundChannelpool size = 0, active threads = 0, queued tasks = 0, completed tasks = 22], sockJsScheduler[pool size = 4, active threads = 1, queued tasks = 2, …Run Code Online (Sandbox Code Playgroud) 我正在尝试通过 Spring MVC 项目中的 Spring-Websockets 将消耗的 Kafka 数据发送到前端(JavaScript)。
为了建立服务器和客户端之间的通信,我有以下内容。
客户端(app.js)
function connect() {
var socket = new SockJS('/kafka-data-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.send("/app/fetchData");
stompClient.subscribe('/data/records', function (message) {
console.log(JSON.parse(message.body).content);
});
});
}
Run Code Online (Sandbox Code Playgroud)
服务器(KafkaController.java)
@Controller
public class KafkaController {
@MessageMapping("/fetchData")
@SendTo("/data/records")
public String fetchMetrics() {
//...
}
}
Run Code Online (Sandbox Code Playgroud)
要使用来自特定 Kafka 主题的数据,我正在使用 @KafkaListener 注释,如下所示:
public class KafkaReceiver {
@KafkaListener(topics = "mytopic")
public void receive(ConsumerRecord<?, ?> record) {
MyRecord m = new MyRecord(new Long(record.offset()), record.key().toString(), record.value().toString());
//... …Run Code Online (Sandbox Code Playgroud) 我的项目是使用spring-boot web socket和嵌入式tomcat来实现聊天服务器。一切正常,但有时我收到 EOFException,然后客户端无法向聊天服务器发送消息,直到我重新启动 tomcat,然后一切正常。我不知道什么时候会发生 EOFException。请帮助我
[TRACE] 2017-10-23 06:17:10.707 [http-nio-7755-exec-4] NativeWebSocketSession - 发送 TextMessage payload=[{"result":...], byteCount=164, last=true], StandardWebSocketSession [id=42b, uri=/chat] [DEBUG] 2017-10-23 06:17:29.670 [http-nio-7755-exec-8] LoggingWebSocketHandlerDecorator - StandardWebSocketSession[id=42b, uri=/chat] 中的传输错误java.io.EOFException: 在 org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1242) ~[tomcat-embed-core-8.5.16.jar!/:8.5.16] 处为 null在 org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1182) ~[tomcat-embed-core-8.5.16.jar!/:8.5.16] 在 org.apache.tomcat。 websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:72) ~[tomcat-embed-websocket-8.5.16.jar!/:8.5.16] 在 org.apache.tomcat.websocket.server。WsFrameServer.doOnDataAvailable(WsFrameServer.java:171) ~[tomcat-embed-websocket-8.5.16.jar!/:8.5.16] at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151) ) ~[tomcat-embed-websocket-8.5.16.jar!/:8.5.16] 在 org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148) [tomcat-embed-websocket-8.5 .16.jar!/:8.5.16] 在 org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) [tomcat-embed-core-8.5.16.jar!/:8.5.16 ] 在 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.16.jar!/:8.5.16] 在 org.apache.coyote.AbstractProtocol$ConnectionHandler.process( AbstractProtocol.java:868) [tomcat-embed-core-8.5.16.jar!/:8.5.16] 在 org.apache.tomcat.util。net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.16.jar!/:8.5.16] 在 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase. java:49) [tomcat-embed-core-8.5.16.jar!/:8.5.16] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_131] 在 java。 util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_131] 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed -core-8.5.16.jar!/:8.5.16] …
我正在为我的一个基于 spring 的项目使用 Spring WebSocket 服务器实现。我遇到了一个错误说The remote endpoint was in state [TEXT_PARTIAL_WRITING] which is invalid state. 我发现问题是同时从不同的线程写入 websocket。
我如何临时修复它:考虑我已经实现了以下方法
void sendMessageToSession(WebsocketSession session,String message);
Run Code Online (Sandbox Code Playgroud)
它将 TextMessage 发送到 websocket 会话。我无法使整个方法同步,因为多个线程可以为不同的 websocketSessions 和消息调用它。我也不能把会话放在同步块中(尝试过但没有用)
虽然,我像这样解决了我的问题
synchronized(session.getId()){
//sending message;
}
Run Code Online (Sandbox Code Playgroud)
我不再面临这个问题。但是在同步块中使用字符串似乎不是一个好习惯。那么我还有什么其他解决方案?发送异步消息的最佳方式是什么?
PS:ConcurrentWebSocketSessionDecorator建立连接后我已经使用了,我正在使用更新的websocket。没有帮助。
session = new ConcurrentWebSocketSessionDecorator(session, (int) StaticConfig.MAXIMUM_WS_ASYNC_SEND_TIMEOUT, StaticConfig.MAXIMUM_WS_BINARY_BUFFER_SIZE * 2);
Run Code Online (Sandbox Code Playgroud)
注意 我将我的 websocet 会话保存在地图中,其中键是 session.getId,值是会话本身。
与其他一些 websocket 实现不同,Spring websocket 引用在每条消息上似乎并不相等。我通过他们的 ID 将会话保存在地图中,并且在每条消息上我检查传递的 websocket 与我已经放在我的地图上的 websocket 的相等性,它是错误的。
在我的应用程序中,我需要向特定用户发送实时通知。我的WebSocketConfig课如下,
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/websocket-example")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
}
}
Run Code Online (Sandbox Code Playgroud)
大多数时候信息会由服务器端发送。所以我还没有设置应用程序目的地。
在客户端,我订阅了目标“/topic/user”,
function connect() {
var socket = new SockJS('/websocket-example');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/user', function (greeting) {
// showGreeting(JSON.parse(greeting.body).content);
console.log("Received message through WS");
});
});
}
Run Code Online (Sandbox Code Playgroud)
在RestController我的一个方法中,我有一种方法可以将消息广播给所有连接的客户端。
@GetMapping("/test")
public void test()
{
template.convertAndSend("/topic/user", "Hurray");
}
Run Code Online (Sandbox Code Playgroud)
直到这部分一切正常。我收到消息并正在登录到控制台。
现在,如果我只想将通知发送给特定用户,则必须使用template.convertAndSendToUser(String user, String …
我正在尝试将带有 Web 套接字的 Spring Boot (2.0.5) Web 应用程序 (war) 部署到 Tomcat 8.5.37 服务器,它以前与 Tomcat 7 一起使用。我的 Web 套接字配置抛出异常并阻止应用程序启动. 我是否在 Spring 或 Tomcat 中缺少某种类型的配置?升级Tomcat后不再可用的东西?
我能够在本地运行(通过 eclipse 和 eclipse 的 Tomcat v8.5),但是当我尝试在我们的 qa 环境中部署到我们的 Tomcat 服务器时,我得到以下信息:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'createWebSocketContainer' defined in class path resource [com/soft/core/app/configuration/WebSocketConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Attribute 'javax.websocket.server.ServerContainer' not found in ServletContext
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1699)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:573)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:740)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) …Run Code Online (Sandbox Code Playgroud) spring-websocket ×10
java ×7
spring ×7
spring-boot ×5
stomp ×2
websocket ×2
javascript ×1
jetty ×1
logging ×1
sockjs ×1
spring-kafka ×1
tomcat8 ×1
tomcat8.5 ×1