I have tried many combinations of the values below, I have no idea why it isn't working. I don't even know if the problem is with frontend or backend setup. I pasted the relevant code parts below.
FLutter says the following when I try to connect (MYIPADDRESS is a valid IP address, the IP address of the pc):
WebSocketChannelException: WebSocketChannelException: WebSocketException: Connection to 'http://MYIPADDRESS:8080/topic/greetings#' was not upgraded to websocket
Here is the backend/spring-boot controller part:
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public String send(final String message) throws Exception {
return message;
}
Here is the backend/spring-boot configuration part:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").withSockJS();
}
}
Here is the frontend/flutter part:
final channel = IOWebSocketChannel.connect(
Uri(
scheme: "ws",
host: "MYIPADDRESS",
port: 8080,
path: "/topic/greetings",
),
);
Related
I am using Angular, Spring Boot, and WebSocket in my project. I'm testing on my local machine socket connection is working fine but when I deployed my build on the production server it is not working properly. sometimes connection was established and sometimes not. I'm new to this technology.
I already configured the message broker and WebSocket application endpoints here is my code
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer, WebSocketConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200", "https://www.xxxxxx.com/").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/chatparticipant", "/messages", "/unAssignedParticipant");
}
#Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxBinaryMessageBufferSize(1024000);
return container;
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHandler(), "/socket").setAllowedOrigins(Pl4ChatConfig.ALLOWED_ORIGIN);
}
}
we're getting error messages:
WebSocket connection to 'wss://xxxxx.com/ws/709/2pjkwf4q/websocket' failed:
I have a spring-boot service that provides a STOMP endpoint like so
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/entityUpdates").withSockJS();
}
}
In the Angular frontend, I use this package to connect to the socket:
const url = 'ws://localhost:8080/entityUpdates';
const webSocketClient = new Client({ brokerURL: url });
webSocketClient.activate();
This throws following errors:
WebSocket connection to 'ws://localhost:8080/entityUpdates' failed:
My best guess is that the URL is somehow wrong, or I missed something when I registered the STOMP endpoint, but I can't figure out what it would be.
Having raw websocket implementation:
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MessageHandler(), "/websocket")
.setAllowedOrigins("*")
.addInterceptors();;
}
}
Handler:
public class MessageHandler extends TextWebSocketHandler {
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
// The WebSocket has been closed
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String auth = (String) session.getAttributes().get("auth");
System.out.println(auth);
session.sendMessage(new TextMessage("You are now connected to the server. This is the first message."));
}
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage) throws Exception {
// A message has been received
}
}
The websocket client connect to server ( handshake etc. ) with /websocket url e.g ws://localhost:8080/websocket
However, now that connection is estabilished is there a way how to route messages? Lets say i have app that provides chat and some pop-up functionality ( for simplicity lets say the user sends pop-up message and some pop-up window shows to all of his friends in app ).
Ofcourse i would like to route chat messages to /chat and popup to /popup.
One way how to achieve this is to send json message to server and parse it there e.g:
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage) throws Exception {
String path = getRouteFromJsonMessage(textMessage);
if( ! "".equals(path) && path.equals("chat")
....
if( ! "".equals(path) && path.equals("popup")
....
}
But this seems too slow, parsing json on every message. Is there some other, better way how to achieve routing?
Thanks for help!
Why don't you just register two different MessageHandlers
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatMessageHandler(), "/chat")
.setAllowedOrigins("*")
.addInterceptors()
.addHandler(new PopUpHandler(), "/popup") //etc;
}
}
I have followed Quetion1 and Quetion2 from stack overflow to send messages to specific client, based on its sessionId but could not find success.
Below is my sample RestController class
#RestController
public class SpringSessionTestApi {
#Autowired
public SimpMessageSendingOperations messagingTemplate;
#MessageMapping("/messages")
public void greeting(HelloMessage message, SimpMessageHeaderAccessor headerAccessor) throws Exception {
String sessionId = (String) headerAccessor.getSessionAttributes().get("SPRING.SESSION.ID");
messagingTemplate.convertAndSendToUser(sessionId,"/queue/test",message, createHeaders(sessionId));
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
return headerAccessor.getMessageHeaders();
}
}
Session Id: when client sends createSession request, new spring sessionId is generated and same is stored in MongoDB as well. After that when client sends web socket connect request, same sessionId is received which was stored in mongoDb as expected. Till This everything is working fine.
Now my job is to send response back to the client based on the sessionId.
For that I have below web socket class:
#Configuration
#EnableScheduling
#EnableWebSocketMessageBroker
public class WebSocketConfig extends
AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> {
#Override
protected void configureStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/messages");
}
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue");
registry.setApplicationDestinationPrefixes("/app");
}
}
and the sample client code that I am using to connect is:
function connect() {
stompClient = Stomp.client('ws://localhost:8016/messages');
stompClient.debug = null;
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/queue/test', function (greeting) {
console.log("Hello "+greeting);
console.log("Greeting body "+JSON.parse(greeting.body));
});
});
}
Please help, Where I am doing wrong in this?
Thanks in Advance!
If you are using /user channel as you do, try to pass the user as stated here.
#MessageMapping("/messages")
public void greeting(HelloMessage message, SimpMessageHeaderAccessor headerAccessor, Principal principal)
throws Exception {
messagingTemplate.convertAndSendToUser(principal.getName(), "/queue/test", message);
}
I've found a full workable Spring Stomp Chat project in git, the link is here. You can refer to it.
https://gist.github.com/theotherian/9906304
I am building a Stateless Spring (4.2.4.RELEASE) Solution using STOMP over Websockets with SockJS and a Rest Endpoint using JWT to connect mobile devices with Full Duplex communication. I am using Tomcat 8.0.33 as a Web Server and testing using html with sockjs javascript client. The stomp protocol works fine using the http fallback but I can't make it using only a websocket protocol. I tried CORS in many ways but I am not sure that is a Tomcat Problem or just bad spring configuration. I tested my html even in the same domain and port and SockJS is still falling back into xhr or iframes.
WebScoketConfig.java
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
RequestUpgradeStrategy upgradeStrategy = new TomcatRequestUpgradeStrategy();
registry.addEndpoint("/ws").setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy))
.setAllowedOrigins("*").withSockJS().setSessionCookieNeeded(false)
.setStreamBytesLimit(512 * 1024)
.setHttpMessageCacheSize(1000)
.setDisconnectDelay(30 * 1000);
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(50);
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry)
{
registry.enableSimpleBroker("/queue/", "/topic/");
// registry.enableStompBrokerRelay("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/myapp");
}
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(500 * 1024);
registration.setSendBufferSizeLimit(1024 * 1024);
registration.setSendTimeLimit(20000);
}
}
WebSecurityConfig.java
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**").permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
}
}
I solved my problem, actually the code was good but the antivirus (Kaspersky) was closing the connection on my client browser just after opened. It forces SockJS to fallback into a different strategy. I tested the client with the antivirus turned off and the Websocket transport was beautifully running. Tested on mac & linux as well.