我有一个带有 Stomp WebSocket 的 Spring 应用程序,但是当我尝试使用 Postman 或 wscat 连接到它时,我收到“错误:意外的服务器响应:400”
这是我使用的配置代码:
在 WebSocketConfig
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
System.out.println("Registering Stomp Endpoints");
try {
registry.addEndpoint("/chat-service")
.setAllowedOrigins("*")
.addInterceptors(new HandshakeDebugInterceptor())
.withSockJS();
System.out.println("Stomp Endpoints Registered Successfully");
} catch (Exception e) {
System.out.println("Error registering Stomp Endpoints: " + e.getMessage());
}
}
在安全配置
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.cors(Customizer.withDefaults())
.authorizeHttpRequests((authorize) -> {
authorize
.requestMatchers("/api/auth/*").permitAll()
.requestMatchers("/chat-service/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
//.anyRequest().authenticated();
.anyRequest().permitAll();
}
)
.sessionManagement((configurer) -> {
configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.logout(Customizer.withDefaults()
);
http.addFilterBefore((request, response, chain) -> {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
System.out.println("Request to: " + httpRequest.getRequestURI());
System.out.println("Method: " + httpRequest.getMethod());
System.out.println("Headers: " + httpRequest.getHeaderNames());
System.out.println("User Principal: " + httpRequest.getUserPrincipal());
System.out.println("Authentication: " + SecurityContextHolder.getContext().getAuthentication());
chain.doFilter(httpRequest, httpResponse);
}, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
所有其他端点(例如注册或登录)均正常工作 我在
securityFilterChain
和 OncePerRequestFilter
过滤器中添加了很多日志记录,但我可以找到导致 400 响应的任何有用信息。
这是我运行时来自服务器的日志(http:// 和 ws:// 的响应相同)
wscat -c ws://localhost:8081/chat-service
: Securing GET /chat-service
Request to: /chat-service
Method: GET
Headers: org.springframework.security.web.firewall.StrictHttpFirewall$StrictFirewalledRequest$2@5118325e
User Principal: null
Authentication: null
2024-04-01T21:11:26.365+03:00 DEBUG 21456 --- [messenger] [nio-8081-exec-7] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-04-01T21:11:26.366+03:00 DEBUG 21456 --- [messenger] [nio-8081-exec-7] o.s.security.web.FilterChainProxy
: Secured GET /chat-service
2024-04-01T21:11:26.367+03:00 INFO 21456 --- [messenger] [nio-8081-exec-7] c.m.m.c.RequestResponseLoggingFilter
: Request: GET /chat-service
2024-04-01T21:11:26.367+03:00 DEBUG 21456 --- [messenger] [nio-8081-exec-7] o.s.web.servlet.DispatcherServlet
: GET "/chat-service", parameters={}
2024-04-01T21:11:26.368+03:00 DEBUG 21456 --- [messenger] [nio-8081-exec-7] o.s.web.servlet.DispatcherServlet
: Completed 400 BAD_REQUEST
2024-04-01T21:11:26.369+03:00 INFO 21456 --- [messenger] [nio-8081-exec-7] c.m.m.c.RequestResponseLoggingFilter
: Response: 400 null
因此,我提高了日志记录级别并在
application.properties
中为整个 .web 启用 TRACE,我在日志中得到了一些有趣的结果:
2024-04-02T13:07:02.461+03:00 TRACE 9164 --- [messenger] [nio-8081-exec-1] o.s.w.s.s.s.WebSocketHandlerMapping
: Mapped to HandlerExecutionChain with [org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler@3c1afe71] and 1 interceptors
2024-04-02T13:07:02.477+03:00 DEBUG 9164 --- [messenger] [nio-8081-exec-1] o.s.w.s.s.t.h.DefaultSockJsService
: Processing transport request: GET http://localhost:8081/chat-service
2024-04-02T13:07:02.479+03:00 TRACE 9164 --- [messenger] [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet
: No view rendering, null ModelAndView returned.
2024-04-02T13:07:02.482+03:00 DEBUG 9164 --- [messenger] [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet
: Completed 400 BAD_REQUEST, headers={masked}
2024-04-02T13:07:02.485+03:00 INFO 9164 --- [messenger] [nio-8081-exec-1] c.m.m.c.RequestResponseLoggingFilter
在 DispatcherServlet 400 响应之前是来自 SockJS 的一些日志,所以我从 WebSocketConfig 中删除 .withSockJS() ,现在我可以从 postman 或 wscat 连接到我的应用程序,但我认为当应用程序客户端准备就绪时,必须将这个东西带回来