CORS error with Spring boot, javascript and web socket - javascript

I'm working on a little test project with a simple html page (using javascript) as Frontend and a Spring Boot application for my apis as Backend. I use websocket with stomp and sockJS to keep alive my connection between front and back. My problem is the following : when I test my connection with Postman i have no problems but when I call the api from my javascript I have the following error :
I tried every solutions I've found on internet and now i'm just stuck
Here is my Spring boot App_controller :
#RestController
#CrossOrigin(origins = "*")
public class App_Controller {
int id = 0;
ArrayList<Player> players = new ArrayList<Player>();
public void addTab(Player p){
players.add(p);
}
#MessageMapping("/batch-socket")
#SendTo("/topic/messages")
public String send(String message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return (message + " : " + time);
}
#RequestMapping (value = "/error", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public String error(){
return "erreur";
}
}
Here is my corsConfiguration :
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600);
}
};
}
}
Here is my WebSocketConfiguration :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/topic")
.enableSimpleBroker("/app");
}
#Override public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/batch-socket");
registry.addEndpoint("/batch-socket")
.setAllowedOrigins("*")
.withSockJS();
}
}
And finally here is my function to connect to this WebSocket :
function connect(){
var socket = new SockJS("http://localhost:8080/batch-socket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame){
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/messages', function(msgOutput){
console.log(msgOutput);
})
})
}
I tried to just add the #CrossOrigin(origins="*") and #CrossOrigins(origins="http://localhost:63342") and I test multiple possibilities with my CorsConfig.
Thank you for your help in advance
(sorry for my english)

You didn't say how your HTML page with JS is loaded. Is it the same localhost:8080 or maybe local file?
For testing you can tell Chrome to ignore cors restrictions:
chrome --disable-web-security --user-data-dir={some dir}
In your code you are doing registry.addEndpoint() twice, remove one and replace "*" with "http://localhost:63342". Remove all other CORS related code.

I think that you don’t need to create the #bean WebMvcConfigurer corsConfigurer, if it is for a simple test. Could you please do a test removing the registration of that bean and change the order of the annotations?
#CrossOrigin(origins = "http://localhost:63342")
#RestController

Related

WebSockets fails to connect because of lost connection

I'm using spring boot in my backend and vuejs in my front-end . I've defined everything in the guide yet I still don't get my project to work.
FrontEnd
connectToWS() {
this.socket = new Sock("http://localhost:8754/stomp-endpoint");
this.stompClient = Stomp.over(this.socket);
this.stompClient.connect(
{},
frame => {
this.connected = true;
console.log(frame);
this.stompClient.subscribe("/topic/greetings", tick => {
console.log(tick);
this.received_messages.push(JSON.parse(tick.body).content);
});
},
error => {
console.log(error);
this.connected = false;
}
);
},
Backend
WebSocketConfiguration Class :
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements
WebSocketMessageBrokerConfigurer
{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
// with sockjs
registry.addEndpoint("/stomp-endpoint")
.setAllowedOrigins("http://localhost:8081")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/topic");
}
}
WebSecurityConfigClass :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/v*/registration/**").permitAll()
.antMatchers("/topic**").permitAll()
.antMatchers("/stomp-endpoint").permitAll()
UPDATE :
The error is actually coming out from the browser . It actually changes the route of the api because it has sockjs integrated into it. I couldn't figure out why the API always gets a /info?t=RandomNumber after it. I need the route to remain the same as I typed it in the front-end.
How can I stop the browser from updating my path. Thanks for helping !

Spring STOMP - No matching message handler

My goal is to notify, if a player joins a team in real-time.
Since the player will be created in the controller, i want to notify the team about this change via socket.
This has been my first attempt in doing that:
#RestController
#RequestMapping("/api/secure/players/")
public class PlayerController {
#Autowired
private SimpMessagingTemplate simpMessageTemplate;
#PostMapping
public ResponseEntity<PlayerDTO> createPlayer() {
// ...
// data is being processed
// notify team about the change
simpMessageTemplate.convertAndSend("/teams/" + selectedTeam.getId() + "/", player);
return ...
}
}
#Controller
public class TeamSocket {
private static final Logger logger = LoggerFactory.getLogger(TeamSocket.class);
#MessageMapping("/teams/{team}")
#SendTo("/teams/{team}")
public void teamEvent(#DestinationVariable String team) {
logger.debug("Received message -> {}", team);
}
}
#Configuration
#ComponentScan
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// I still dont fully understand this. Do i have to enable it? (It does not fix the issue).
// config.enableSimpleBroker("/teams/");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/api/secure/stomp/").withSockJS();
}
}
However, Spring tells me, that it was unable to map the request. What am i doing wrong?
DEBUG 29487 --- [nboundChannel-4] .WebSocketAnnotationMethodMessageHandler : Searching methods to handle SUBSCRIBE /teams/16 id=sub-0 session=0nkqv1km, lookupDestination='/teams/16'
DEBUG 29487 --- [nboundChannel-4] .WebSocketAnnotationMethodMessageHandler : No matching message handler methods.
DEBUG 29487 --- [nboundChannel-2] org.springframework.web.SimpLogging : Processing SUBSCRIBE /teams/16 id=sub-0 session=0nkqv1km
const client = new SockJS(`${REST_API}/api/secure/stomp/`);
const stompClient = Stomp.over(client);
stompClient.connect({}, (frame) => {
stompClient.subscribe(`/teams/${teamId}`, (message) => {
...
});
});
I see you are using path "/teams/" + selectedTeam.getId() + "/" in your convertAndSend method while you are subscribing to /teams/${teamId}. Do you need to add additional slash while subscribing or you may need to remove additional slash from convertAndSend?

Spring Boot Websocket with SockJS and StompJS connect function does not work, always error

I try to build a chat application with HTML,JS,CSS with the libraries STOMPJS and SOCKJS as the frontend and Spring Boot as backend.
My connect code in the frontend looks like this:
function connect() {
var socket = new SockJS("http://localhost:8080/chat");
stompClient = Stomp.over(socket);
stompClient.connect(
{},
function (frame) {
console.log("2");
setConnected(true);
console.log("Connected: " + frame);
stompClient.subscribe("/topic/messages", function (messageOutput) {
showMessageOutput(JSON.parse(messageOutput.body));
});
},
console.log("error")
);
}
As far as I know is the connect function of STOMPJS like this: headers, connectCallback, errorCallback.
It never reach the console.log "2" and it gives me the console.log "error" back.
I activated CORS like this in my backend with setAllowedOriginPatterns("*") in my Spring Boot application:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat");
registry.addEndpoint("/chat").setAllowedOriginPatterns("*").withSockJS();
}
}
And the controller looks like this:
#Controller
public class MController {
#MessageMapping("/chat")
#SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return new OutputMessage(message.getFrom(), message.getText(), time);
}
}
In the screenshot you can see the console.log when I execute the function "connect":
I checked all the documentation of SockJS and StompJS but I couldn't find a solution.
Thank you very much for your answer in advance. :)

SignalR methods in WebApi controller not called in specific setup

Well, I have a signalR hub:
public class ReportHub : Hub
{
private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportHub>();
public void SendMessage(string text)
{
Clients.All.sendMessage(text);
}
public static void ServerSendMessage(string text)
{
hubContext.Clients.All.sendMessage(text);
}
}
Also I have the client code in js, on some view
report.client.sendMessage = message => {
alert('message from server: '+ message);
}
And I have webapi action, like this:
[HttpGet]
[Route("api/Report/test")]
public int GetTest()
{
ReportHub.ServerSendMessage("message");
return 42;
}
When I open the view with signalR-catching js code in one browser, and in another browser window requesting the webapi action, by typing http://../api/report/test - all working, and alert is appearing
But when I calling webapi action via postman, or any other rest client, no effect at all, report.client.sendMessage = message => {
alert('message from server: '+ message);
} - not working
Can anyone help?
ReportHub.ServerSendMessage("message");
It is wrong.
You should return ReportHubContext for the connection before pushing the data to clients;
[HttpGet]
[Route("api/Report/test")]
public int GetTest()
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportHub>();
hubContext.ServerSendMessage("message");
return 42;
}

Notify registered clients using Websockets with AngularJS (angular-websocket-service) and Spring Boot

I am new in AngularJS as well as FullStack development. The architecture of my current app is already set up and should not change preferably (for security reasons). So far, I can emit messages to the server using angular-websocket-service. Here is the code snippet of the service from the front-end:
proxiMiamApp.service('WebSocketService', function ($websocket) {
var wsEndpoint = {};
this.openWsEndpoint = function () {
wsEndpoint = $websocket.connect("ws://localhost:9000/proximiamHandler");
console.log(wsEndpoint);
return wsEndpoint;
}
this.sendMessage = function(){
if($.isEmptyObject(this.wsEndpoint)){
this.openWsEndpoint();
}
eventUser = {
idEvent : '1',
idUser : '49'
};
wsEndpoint.register('/eventUser', function(){
console.log('Register OK!');
});
console.log('Ready!');
wsEndpoint.emit('/eventUser',eventUser);
}});
As for the back-end, I am using an implementation of the WebSocketHandler interface:
#Controller
public class ProximiamHandler implements WebSocketHandler {
#Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
System.out.println("afterConntectionEstablished called");
}
#Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
System.out.println("handleMessage called");
// My code here...
}
#Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
System.out.println("handleTransportError called");
}
#Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
System.out.println("afterConnectionClosed called");
}
#Override
public boolean supportsPartialMessages() {
return true;
}}
The Implementation of the WebSocketHandler is called via Spring WebSocketConfigurer
#Configuration
#EnableWebSocket
#Controller
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/proximiamHandler").setAllowedOrigins("*");
}
#Bean
public WebSocketHandler myHandler() {
return new ProximiamHandler();
}}
My questions are:
Can I notify subscribed clients using this architecture?
If yes, how can I do it?
Is there a way to return something to subscribed clients from the server? (an Object or a String for instance)
Thanks in advance for your help
Can I notify subscribed clients using this architecture?
=> Yes.
If yes, how can I do it?
=> Based on the Spring web socket APIs, you have to retain the ' WebSocketSession' passed to you via "afterConnectionEstablished" callback.
Use the sendMessage() API of Web socket session to send notifications to client.
Is there a way to return something to subscribed clients from the server? (an Object or a String for instance)
=> You can format your data in either JSON or XML & wrap it using "WebSocketMessage" and pass it to client.
I never worked on spring, however, I am answering this based on my knowledge on web socket. See if it helps.

Categories

Resources