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

SpringBoot WebSocket连接Angular时出现404错误求助

问题现象

前端Angular连接Spring Boot的WebSocket服务时出现404错误:

websocket.service.ts:19        
        GET http://localhost:4200/greeting/info?t=1691450261423 404 (Not Found)

关键代码片段

WebSocket配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/greeting")
                .setAllowedOriginPatterns("http://localhost:4200","*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app")
                .enableSimpleBroker( "/topic/","/queue/");
    }
}

Spring Security配置

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authz) -> authz
                        .requestMatchers("/", "/index.html", "*.ico", "*.css", "*.js", "/api/user","/greeting/*","/chat/*").permitAll()
                        .anyRequest().authenticated())
                .oauth2Login(withDefaults())
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(withDefaults()))
                .csrf((csrf) -> csrf
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                        .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()))
                .addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class)
                .addFilterAfter(new SpaWebFilter(), BasicAuthenticationFilter.class);

        return http.build();
    }
}

Angular代理配置

const PROXY_CONFIG = [
  {
    context: ["/api", "/oauth2", "/login", "/greeting", "/chat"],
    target: "http://localhost:8080",
    secure: true,
    logLevel: "debug",
  },
];

module.exports = PROXY_CONFIG;

Angular WebSocket连接代码

connect() {
    console.log("Initialize WebSocket Connection");
    let ws = new SockJS("/greeting");
    this.stompClient = Stomp.over(ws);
    const THAT = this;
    THAT.stompClient.connect({}, function () {
      THAT.stompClient.subscribe(THAT.topic, function (message: any) {
        console.log(message)
        THAT.showGreeting(message.body);
      });
    }, (error:Error) => {
      console.log("errorCallBack -> " + error)
      setTimeout(this.connect, 5000);
    });
  };

问题排查与解决方案

核心原因

  1. 代理配置失效:secure: true仅适用于HTTPS目标地址,后端使用HTTP协议时会导致代理不转发请求,前端直接访问4200端口的路径引发404。
  2. Security路径匹配不完整:/greeting/*仅匹配一级子路径,无法覆盖SockJS自动发起的/greeting/info等深层请求。
  3. CSRF token缺失:启用CSRF保护后,SockJS请求未携带token,可能被拦截(表现为404而非明确的CSRF错误)。

分步修复

1. 修复Angular代理配置

将secure改为false,确保HTTP目标地址的代理生效:

const PROXY_CONFIG = [
  {
    context: ["/api", "/oauth2", "/login", "/greeting", "/chat"],
    target: "http://localhost:8080",
    secure: false,
    logLevel: "debug",
  },
];

module.exports = PROXY_CONFIG;

修改后重启Angular应用,确保请求转发到后端8080端口。

2. 调整Spring Security路径规则

将/greeting/*改为/greeting/**以覆盖所有子路径,同时添加/greeting本身:

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authz) -> authz
                        .requestMatchers("/", "/index.html", "*.ico", "*.css", "*.js", "/api/user","/greeting","/greeting/**","/chat/**").permitAll()
                        .anyRequest().authenticated())
                .oauth2Login(withDefaults())
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(withDefaults()))
                .csrf((csrf) -> csrf
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                        .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()))
                .addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class)
                .addFilterAfter(new SpaWebFilter(), BasicAuthenticationFilter.class);

        return http.build();
    }
}

3. 在Angular连接时携带CSRF Token

从cookie中获取CSRF token并添加到SockJS请求头:

// 添加获取CSRF token的工具函数
private getCsrfToken(): string | null {
  const name = 'XSRF-TOKEN';
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop()?.split(';').shift() || null;
  return null;
}

connect() {
    console.log("Initialize WebSocket Connection");
    const csrfToken = this.getCsrfToken();
    const headers = {};
    if (csrfToken) {
      headers['X-XSRF-TOKEN'] = csrfToken;
    }
    // 携带CSRF头初始化SockJS
    let ws = new SockJS("/greeting", null, { headers: headers });
    this.stompClient = Stomp.over(ws);
    const THAT = this;
    THAT.stompClient.connect({}, function () {
      THAT.stompClient.subscribe(THAT.topic, function (message: any) {
        console.log(message)
        THAT.showGreeting(message.body);
      });
    }, (error:Error) => {
      console.log("errorCallBack -> " + error)
      // 修复this指向问题
      setTimeout(() => THAT.connect(), 5000);
    });
  };

4. 验证后端端点

重启Spring Boot后,直接访问http://localhost:8080/greeting/info,若返回如下格式JSON,说明后端端点正常:

{"entropy":12345,"origins":["*:*"],"cookie_needed":true,"websocket":true}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:55:20