You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

浏览器无法连接Spring Boot WebSocket(SockJS):跨域问题求助

嘿,这个WebSocket跨域的问题我之前也碰到过,咱们来搞定它!

问题根源

你看到的报错核心是:Spring Boot返回的Access-Control-Allow-Origin头值不对,它返回了http://localhost:8080/ws/info,但浏览器期望的是允许你的React应用所在的http://localhost:3000源,这就触发了同源策略的限制。

解决方案:调整Spring Boot的WebSocket配置

既然你已经创建了WebSocketMessageBrokerConfigurer的实现类,咱们直接修改它的CORS设置就行。下面是完整的配置示例,重点看registerStompEndpoints方法里的设置:

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
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 {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 配置消息代理,这里用简单内存代理,生产环境可以换RabbitMQ之类的
        config.enableSimpleBroker("/topic");
        // 设置应用前缀,前端发消息要以/app开头
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册WebSocket端点,关键是这里的CORS设置
        registry.addEndpoint("/ws")
                // 明确允许React应用的源,新版本Spring Boot推荐用setAllowedOriginPatterns
                .setAllowedOriginPatterns("http://localhost:3000")
                // 启用SockJS,兼容不支持原生WebSocket的浏览器
                .withSockJS();
    }
}

几个关键细节:

  • 别图省事用setAllowedOrigins("*"),虽然能解决问题,但生产环境太不安全,明确指定你的前端地址更稳妥
  • 如果你的Spring Boot版本低于2.4,可能需要用setAllowedOrigins("http://localhost:3000")代替setAllowedOriginPatterns,不过尽量升级到新版本
  • 确保端点路径/ws和你前端连接的路径完全一致
前端React连接代码检查

再确认下你的前端连接代码是不是正确指向了Spring Boot的WebSocket端点:

import SockJS from 'sockjs-client';
import Stomp from 'stompjs';

const connectToWebSocket = () => {
    // 这里的地址要和后端配置的端点一致
    const socket = new SockJS('http://localhost:8080/ws');
    const stompClient = Stomp.over(socket);
    
    stompClient.connect({}, (frame) => {
        console.log('成功连接到WebSocket:', frame);
        // 订阅消息主题,比如/topic/your-topic
        stompClient.subscribe('/topic/messages', (message) => {
            console.log('收到消息:', message.body);
        });
    }, (error) => {
        console.error('连接失败:', error);
    });
};
额外注意事项(如果用了Spring Security)

要是你的项目加了Spring Security,还得在安全配置里放行WebSocket的路径,否则会被拦截:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                // 放行WebSocket相关的所有请求
                .antMatchers("/ws/**", "/ws/info/**").permitAll()
                .anyRequest().authenticated();
    }
}

最后,重启你的Spring Boot服务器和React应用,清除浏览器缓存后再测试,应该就能正常建立WebSocket连接了!

内容的提问来源于stack exchange,提问作者alex

火山引擎 最新活动