stomp_dart_client not connecting to server - spring-boot

Trying to set connection to my spring boot server in flutter app
final socketUrl = 'https://10.0.0.6:8443/notifications';
if (stompClient == null) {
stompClient = StompClient(
config: StompConfig.SockJS(
url: socketUrl,
onConnect: onConnect,
onWebSocketError: (dynamic error) => print(error.toString()),
));
print(stompClient.config.url);
stompClient.activate();
}
but function onConnect is never called and i dont get any error message neither. I have tried change url to wss://10.0.0.6:8443/notifications and remove SockJs with same result. Also tried to connect to wss://echo.websocket.org without any success.
Web server is config as follow and it has valid certs
#Configuration
#EnableWebSocketMessageBroker
public class webSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/notification/item");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/notifications");
registry.addEndpoint("/notifications").withSockJS();
}
}
Calling socket from JS web app on same server is working fine.
I have tried other flutter libs (Stomp, Socket_IO, WebSocketChannel) to connect but without any success. Is there something I am missing in configuration ?

You are probably running into problems with CORS. Please try only this line:
registry.addEndpoint("/notifications").setAllowedOrigins("*").withSockJS();
while keeping the client as it is posted here.

Related

Postman, Spring boot, WebSocket doesn't send notification

I'm trying send websocket notification to specific endpoint. I created the following configuration
#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("/my-address");
registry.addEndpoint("/my-address").withSockJS();
}
}
I'm able to connect using postman on address ws://localhost:8080/my-address (session is established). Next I want to send notification to this endpoint within the same application (I'll be generating some messages internally). I use class SimpMessageSendingOperations:
simpMessageSendingOperations.convertAndSend("/my-address", exampleMessage);
None error message is generated and notification does not appear for websocket clients. I also tried
simpMessageSendingOperations.convertAndSend("/topic/my-address", exampleMessage);
and also
simpMessageSendingOperations.convertAndSend("/app/my-address", exampleMessage);
I don't know what I'm doing wrong. Can you help me with this issue?
Thanks in advance for help

websocket spring boot setup

I have a spring boot application. I am trying to add the websocket piece to it. The problem is my angular client can't connect to it. I used smart websocket client google plugin, but still not able to connect. Here is the setup.
I am using Intellij Idea on localhost. the spring boot application is running on localhost:8080. I can see the WebSocketSession is runnign from intellij idea console.
Here is the setup:
#Slf4j
#RestController
public class WebsocketController {
#MessageMapping("/ws-on/hello")
#SendTo("/ws-on/greetings")
public UserStateIndicator greeting(UserStateIndicator indicator) throws Exception {
Thread.sleep(1000); // simulated delay
log.debug("websocket " + indicator.toString());
return indicator;
}
}
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/ws-on");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-on")
.setAllowedOrigins("http://localhost:4200")
.withSockJS();
}
}
my angular is running on localhost:4200.
I used ws://localhost:8080/ws-on as the url from StompJS to connect.
My question is how do I find the websocket url to connect, and how do I know the websocket is running on the spring boot server?
finally I figured it out. Because I am using SockJS on both angular and spring boot, so, the URL is actaully http not ws. the correct url to connect is then http://localost:8080/ws-on

Spring Websocket with SockJs switch from XHR streaming to Websocket

I am using Spring Websocket with SockJs (v1.1.1) over STOMP on client. I create the client with the code below.
SockJS = require('sockjs-client')
Stomp = require('webstomp-client')
stompClient = Stomp.over(new SockJS(url))
It's works fine. But it uses xhr_streaming as transport by default, that is not desirable for me. I want to switch it to websocket tranport.
stompClient = Stomp.over(new SockJS(url, null, {transports:'websocket'}))
But this approach does not work for me. It falls with event:
code: 2000
reason: "All transports failed"
My Spring Websocket configuration is very simple:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> {
#Override
public void configureStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/myEndpoint").setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/app");
}
}
The main problem I face with xhr_streaming is that every stream request updates last access time for user session (I use Spring Session as well). But it's not a desirable behavior for my application. So how I can fix it? And will websocket transport help? Thanks in advance.
So, I've got the reason. I am using a webpack dev server with proxy option. By default it does NOT proxy ws protocol requests (it losts headers). You need toa add ws: true to your config and everything will work fine.
proxy: {
'/api/*': {
target: 'http://localhost:8080',
pathRewrite: {'^/api' : ''},
ws: true
}
}

can i connect client server(localhost:8082) and websocket(localhost:8080)?

My problem is I need to connect different port or server!
websocket server(localhost:8080) client server(localhost:random)
(failed: Error during WebSocket handshake: Unexpected response code: 403)
why?? I'm tired...
I already tried same port and I can success!
I can connect client(localhost:8080) and websocekt(localhost:8080).
I want to use websocket using (server side: java sts, tomcat 8.0).
questions
1. websocket can connect only same server and port???!!!!(no! please!)
2. If I can... what's the problem :(? Do u have any example?
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("*");
}
#Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
Sounds like this is related to CORS https://en.wikipedia.org/wiki/Cross-origin_resource_sharing.
I assume you are using spring websocket as you didn't mention.
You will need to disable same origin policy in your websocket config class as below example,
#Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
}
#Override
protected boolean sameOriginDisabled() {
//disable CSRF for websockets
return true;
}

Spring WebSocket Connecting with SockJS to a different domain

WebSockets in Spring is a rather new topic that I;m tiring to find a bit more.
My problem is with connecting to a service from a different domain, I'm working on with Lineman building the front-end side and Spring Boot when doing the back-end side, with that I have these apps on two different ports : 8000 and 8080 on localhost.
I had issues with the 'Access-Control-Allow-Origin' header but I have resolved it by adding a filter on the server side which added the allowed origin to the header. After this I started to get the following error on connection:
GET http://localhost:8080/socket/info 403 (Forbidden)
AbstractXHRObject._start # sockjs-0.3.4.js:807
(anonymous function) #sockjs-0.3.4.js:841
I don't have Spring Security in the project so this is not an authorization issue, the error points to sockJS :
that.xhr.send(payload); - where payload is never defined.I tried but couldn't find the root of the call where is may began.
I was thinking if I need to add some additional information to either SockJS and Stomp when setting the connection, but there is not much of examples and notes in both wiki pages of this tools.
Bellow you will find the connection JS code.
var socket = new SockJS("http://localhost:8080/socket");
client = Stomp.over(socket);
client.connect({'login': BoatsGame.userName,
'passcode': 'guest'},
function (frame) {
....
The Server Side has a MessageBroker configured :
#Configuration
#EnableWebSocketMessageBroker
public class MessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//config.enableStompBrokerRelay("/queue", "/topic");
config.enableSimpleBroker("/queue", "/topic","/user");
config.setApplicationDestinationPrefixes("/BoatBattleGame");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/socket").withSockJS();
}
}
I Also tried setting up a MessageHandler as it has the option to set OriginAllowe when configuring, but I'm not sure how it is connected to the broker.
Last think, this setup works correctly when running on one port.
Jax's anwesr was correct :)
The registerStompEndpoints method gives us the opportunity to set the Allowed Origins.
We need to add it before the "withSockJs()" option.
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/BO/socket").setAllowedOrigins("*").withSockJS();
}
To anyone getting to this ticket because of the 403 Forbidden answer when trying to connect through a SockJsClient to a different domain:
The problem arises when trying to make a GET to the /info Url, as part of the handshaking. The response actually returns a 200 via WGET as well as via browser. Only through SockJsClient it doesn't work.
After trying different solutions, the only one that really fixed the issue is to write a class that implements Transport and InfoReceiver. In this way the developer can directly handle this part of the handshake.
Basically you make the work in the executeInfoRequest() method:
#Override
public String executeInfoRequest(URI infoUrl, HttpHeaders headers) {
HttpGet getRequest = new HttpGet(infoUrl); // eventually add headers here
HttpClient client = HttpClients.createDefault();
try {
HttpResponse response = client.execute(getRequest);
List<String> responseOutput = IOUtils.readLines(response.getEntity().getContent());
return responseOutput.get(0);
} catch (IOException ioe) {
...
}
}
I defined TransportType.XHR as transport type.
In my case, I had to add these configuarations to get SockJS / STOM to work with CORS:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer
{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(false)
.maxAge(3600)
.allowedHeaders("Accept", "Content-Type", "Origin",
"Authorization", "X-Auth-Token")
.exposedHeaders("X-Auth-Token", "Authorization")
.allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
}
}
i found this solution by creating a Filter
package com.diool.notif.config;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class SimpleCORSFilter implements Filter {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SimpleCORSFilter.class);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
LOGGER.info("Initilisation du Middleware");
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest requestToUse = (HttpServletRequest)servletRequest;
HttpServletResponse responseToUse = (HttpServletResponse)servletResponse;
responseToUse.setHeader("Access-Control-Allow-Origin",requestToUse.getHeader("Origin"));
filterChain.doFilter(requestToUse,responseToUse);
}
#Override
public void destroy() {
}
}

Resources