all. I'm new to Spring Boot and Websocket. This is my first integrated React and Spring Boot project and I'm currently building a chat app with a backend using WebSocket.
As mentioned, my front end is built in React (localhost:3000), but when trying to call the backend/chat app, I get an error:
Access to XMLHttpRequest at 'http://localhost:9090/ws/info?t=1652731448126' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I've tried looking up a few possible solutions, such as using @CrossOrigin(origins = "https://localhost:3000")
and @CrossOrigin(origins = "http://localhost:3000")
but that didn't change anything. I also tried (@CrossOrigin(origins = "*")
with no luck. Both efforts resulted in the same error message.
Chat Controller:
package com.project2.chatapi.controller;
import com.project2.chatapi.models.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
@CrossOrigin(origins = "https://localhost:3000")
@Controller
public class ChatController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
/**
* Handles messages coming into the public chatroom
* @param message
* @return message
*/
@MessageMapping("/message") // /app/message
@SendTo("/chatroom/public")
public Message receivePublicMessage(@Payload Message message) {
return message;
}
/**
* Handles messages being sent to a private chat
* Receives the message from a user and sends to another user
* @param message
* @return message
*/
@MessageMapping("/private-message")
public Message receivePrivateMessage(@Payload Message message) {
simpMessagingTemplate.convertAndSendToUser(message.getReceiverName(), "/private", message); // listens to /user/name/private
return message;
}
}
WebsocketConfig class:
package com.project2.chatapi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* Adding endpoint to the chat
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOriginPatterns("http://localhost:3000")
.withSockJS();
}
/**
* Configuring application destination prefixes
* Adding topic prefixes - chatroom, and user
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/chat");
registry.enableSimpleBroker("/chatroom","/user");
registry.setUserDestinationPrefix("/user");
}
@Bean
public WebMvcConfigurer corsConfig() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowedOrigins("http://localhost:3000");
}
};
}
}
React Method that calls the backend:
const connect = (e) => {
e.preventDefault();
setUserData({...userData, "username": username});
let Sock = new SockJS('http://localhost:9090/ws');
stompClient = over(Sock);
stompClient.connect({},onConnected, onError);
}
I've also tried implementing different possible solutions regarding setAllowedOrigins. I've tried a handful of combinations including ("http://localhost:3000") and ("*")-- but again, it doesn't seem to change my error message.
I've been stuck on this for days now. Any help would be greatly appreciated. Thank you!
UPDATE: These are the additional things I've tried since posting this question originally. Unfortunately, I'm still getting the same errors with these attempts.
- I tried adding a filter
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 {
final Logger logger = LoggerFactory.getLogger(SimpleCORSFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
logger.info("Initializing 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() {
Filter.super.destroy();
}
}
- I tried adding cors mapping in my config file
- Also tried adding a CorsConfirgurationSource to my config file
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
// can possibly delete
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowCredentials(false)
.maxAge(3600)
.allowedHeaders("Accept", "Content-Type", "Origin",
"Authorization", "X-Auth-Token")
.exposedHeaders("X-Auth-Token", "Authorization")
.allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
}
/**
* Adding endpoint to the chat
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws/*")
.setAllowedOrigins("http://localhost:3000")
.withSockJS();
}
/**
* Configuring application destination prefixes
* Adding topic prefixes - chatroom, and user
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/chat");
registry.enableSimpleBroker("/chatroom","/user");
registry.setUserDestinationPrefix("/user");
}
//
@Bean
public WebMvcConfigurer corsConfig() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/ws/**")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowedOrigins("http://localhost:3000");
}
};
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setExposedHeaders(Arrays.asList("Authorization"));
configuration.addAllowedOrigin("http://localhost:3000");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.applyPermitDefaultValues();
return source;
}
}
- adding the cors mapping and WebMvcConfigurer to my main app
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*").allowedOrigins("http://localhost:3000");
}
};
}
I've checked the network logs in my google chrome browser and it is still showing Access-Control-Allow-Origin: *
despite all the configuration.
.allowCredentials(false)
to.allowCredentials(true)
since you already have theAuthorization
header set?