You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity WebGL端Spring WebSocket连接异常排查求助

Spring WebSocket与Unity WebGL跨域连接问题排查

问题背景

  • Spring WebSocket服务在Postman、Unity编辑器中均可正常连接
  • Unity打包为WebGL后,无法连接ngrok提供的wss://unbiased-evenly-worm.ngrok-free.app/game地址,但能正常连接本地ws://localhost:8080/game
  • ngrok的wss地址可被Postman正常连接,怀疑是CORS配置问题

相关代码

Unity WebGL连接代码

async void Start()
{
    Debug.Log("Starting WebSocket connection...");

    clientId = System.Guid.NewGuid().ToString();
    ws = new WebSocket("wss://unbiased-evenly-worm.ngrok-free.app/game");

    ws.OnOpen += () =>
    {
        Debug.Log("WebSocket connected!");
    };

    ws.OnMessage += (byte[] msg) =>
    {
        string message = Encoding.UTF8.GetString(msg);
        Debug.Log("Message received: " + message);
        OnMessageReceived(message);
    };

    ws.OnError += (string errMsg) =>
    {
        Debug.LogError("WebSocket error: " + errMsg);
    };

    ws.OnClose += (WebSocketCloseCode code) =>
    {
        Debug.LogWarning("WebSocket closed with code: " + code.ToString());
    };

    Debug.Log("Attempting to connect WebSocket...");
    try
    {
        await ws.Connect();
        Debug.Log("WebSocket connection successful.");
    }
    catch (System.Exception ex)
    {
        Debug.LogError("WebSocket connection failed: " + ex.Message);
    }

    targetPosition = transform.position;

    Cursor.lockState = CursorLockMode.Locked;
    Cursor.visible = false;
}

Spring 配置代码

@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private final JWTUtil jwtUtil;

    public SecurityConfig(JWTUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring()
                .requestMatchers("/error", "/favicon.ico");
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .formLogin(formLogin -> formLogin.disable())
                .httpBasic(httpBasic -> httpBasic.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/login", "/", "/join", "/verify-id", "/register", "/check-email", "/verify-email", "/verify-test", "/oauth/google", "/oauth/kakao", "/oauth","/profile/**","/refresh", "/reset-password","/reset-password-auth","/game/**","upload","/image","/game").permitAll()
                        .anyRequest().authenticated()
                )
                .addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                );
        return http.build();
    }
}

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new GameWebSocketHandler(), "/game")
                .setAllowedOrigins("*"); 
    }
}

问题分析与解决方案

核心问题点

  1. WebSocket的CORS配置独立于普通HTTP:你配置的CorsConfig只对普通HTTP请求生效,WebSocket的握手请求(HTTP GET升级请求)受WebSocketConfig中的跨域配置控制。
  2. setAllowedOrigins("*")与凭证兼容性问题:Spring Boot 2.4+后,setAllowedOrigins("*")在搭配allowCredentials(true)时会违反CORS规范,导致浏览器拒绝连接。WebGL在浏览器环境下默认会携带凭证,触发了这个冲突。

具体修复步骤

1. 修改Spring WebSocket跨域配置

将WebSocketConfig中的setAllowedOrigins("*")替换为setAllowedOriginPatterns("*"),后者支持通配符且兼容凭证配置:

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(new GameWebSocketHandler(), "/game")
            .setAllowedOriginPatterns("*"); // 替代setAllowedOrigins,兼容CORS凭证规则
}

如果你的Unity WebGL部署在固定域名,建议指定具体源(如"https://your-webgl-domain.com"),既安全又避免潜在冲突。

2. 验证Spring Security放行规则

当前SecurityConfig已将/game加入permitAll,确保WebSocket握手请求不会被JWT拦截。可额外检查JWTFilter是否排除了/game路径,避免握手请求被强制验证token。

3. 浏览器调试定位

在WebGL运行的浏览器中打开开发者工具(F12),查看Network面板的WebSocket握手请求:

  • 检查响应头是否包含Access-Control-Allow-Origin,值是否匹配WebGL的部署域名
  • 查看Console面板是否有明确的CORS错误提示,进一步定位问题

补充说明

  • Postman不受浏览器同源策略限制,因此能正常连接ngrok地址;Unity编辑器运行时也并非严格遵循浏览器CORS规则,这就是本地测试正常但WebGL打包后失败的原因。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:49:51