我正在尝试使用Java SpringBoot设置一个简单的WebSocket服务器,虽然我已经定义了CORS配置(以及SockJS的STOP)以允许从本地主机:8080(以及之前的星号)进行起源,但我仍然看到标题中缺少‘Access-Control-Allow-Origin’,并且我得到了403状态代码错误。
在客户端,我有一个简单的SockJS设置,通常通过普通的HTML和JS连接到WebSocket。以下是我的Java代码(请注意,我曾多次尝试定义CORS允许起源)……
WebSocket Broker配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp")
.setAllowedOrigins("http://localhost:8080")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
和另一个类,我在其中定义了SpringBoot的CORS配置和安全规则(由于目前没有更好的名称,我将这个类称为WebSocketSecurity):
@Configuration
@EnableWebSecurity
public class WebSocketSecurity {
private CorsConfiguration corsConfiguration() {
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.addAllowedOrigin("http://localhost:8080");
corsConfig.addAllowedHeader("*");
corsConfig.addAllowedMethod(HttpMethod.GET);
corsConfig.addAllowedMethod(HttpMethod.POST);
corsConfig.applyPermitDefaultValues();
return corsConfig;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> corsConfiguration());
http.headers().frameOptions().sameOrigin();
return http.build();
}
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/images/**", "/js/**");
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD")
.allowedHeaders("*");
//.allowCredentials(true); // this is disabled if CORS allow origin is set to "*"
}
};
}
@Bean
public CookieSameSiteSupplier cookieSameSiteSupplier(){
return CookieSameSiteSupplier.ofNone();
}
}
我的pom.xml具有以下依赖项和构建配置:
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${project.parent.version}</version>
</plugin>
</plugins>
</build>
SpringBoot的主启动类:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class WSExampleApplication {
public static void main(String[] args) {
SpringApplication.run(WSExampleApplication.class, args);
}
}
以下是我在前端使用的SockJS部分:
function connect(event) {
username = document.querySelector('#name').value.trim();
if(username) {
var socket = new SockJS('http://localhost:8080/stomp');
stompClient = Stomp.over(socket);
stompClient.connect({}, onConnected, onError);
}
event.preventDefault();
}
function onConnected() {
stompClient.subscribe('/topic/public', onMessageReceived); // Subscribe to the Public Topic
stompClient.send("/app/chat.register", // Tell your username to the server
{},
JSON.stringify({sender: username, type: 'JOIN'})
)
}
function onError(error) {
connectingElement.textContent = 'Could not connect to WebSocket server!';
connectingElement.style.color = 'red';
}
CORS error in browser consoleCORS error in browser network tab
CORS/WebSocket配置有问题吗?或者我需要在SockJS的前端进行一些更改吗?
我使用的是Spring Boot版本2.7.4和Java版本18.0.2.1,我使用的是Tomcat。
1条答案
按热度按时间kr98yfug1#
由于缺乏关于如何提供前端服务的信息,这可能是三种方式之一。我将在下面逐一发言。
BE和FE是单独的Web服务器,监听不同的本地主机端口
我假设后端正在监听端口8080,因为这是您尝试在前端代码中连接到的端口。
在CORS配置中,您需要允许前端对应的源站。我通过以下修改获得了WebSocket连接(对于FE,我在端口5000上使用了一个简单的Reaction应用程序):
WebSocketConfiguration.java
Java(在您的帖子中是WebSocketSecurity)
理想情况下,允许的来源列表(以及所有其他CORS配置参数)应该来自自定义属性,以便使它们在Web和WebSocket配置中统一,而不是在字符串文字中统一。
FE通过BE Web服务器提供
如果您通过后端(资源中的静态内容)为前端应用程序提供服务,那么CORS应该完全不是问题,因为前端和后端都有相同的基本URI。在FE中,只指没有它的后端,即简称为
/stomp
。通过文件系统路径在浏览器中直接打开FE index.html
如果您在没有Web服务器的情况下测试前端(即通过文件系统路径直接在浏览器中打开html文件),那么对于CORS来说,这不是最好的位置。我强烈建议您也为FE启动一台Web服务器(或通过BE为其提供服务),即使是用于本地测试--这会让您回到我的答案的前两部分。