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); }); };
问题排查与解决方案
核心原因
- 代理配置失效:
secure: true仅适用于HTTPS目标地址,后端使用HTTP协议时会导致代理不转发请求,前端直接访问4200端口的路径引发404。 - Security路径匹配不完整:
/greeting/*仅匹配一级子路径,无法覆盖SockJS自动发起的/greeting/info等深层请求。 - 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
相关产品推荐
相关产品推荐

