Spring boot Websocket不适用于spring boot应用程序和角度前端
我看了很多,尝试了很多,但我找不到问题的原因。。。 我有一个JHipster生成的应用程序,它由一个spring引导应用程序和一个角度前端组成,我想使用WebSocket进行更新。为此,我使用Stomp和SockJs 连接本身已不工作。 我得到以下错误:Spring boot Websocket不适用于spring boot应用程序和角度前端,spring-boot,websocket,jhipster,sockjs,Spring Boot,Websocket,Jhipster,Sockjs,我看了很多,尝试了很多,但我找不到问题的原因。。。 我有一个JHipster生成的应用程序,它由一个spring引导应用程序和一个角度前端组成,我想使用WebSocket进行更新。为此,我使用Stomp和SockJs 连接本身已不工作。 我得到以下错误: WebSocket connection to 'ws://localhost:9000/updates/websocket/447/xxudq4ni/websocket' failed: WebSocket is closed before
WebSocket connection to 'ws://localhost:9000/updates/websocket/447/xxudq4ni/websocket' failed: WebSocket is closed before the connection is established.
这是对端口9000的调用,然后它被代理到端口8080下的实际后端。
如果我直接调用端口8080下的后端,我会得到:
WebSocket connection to 'ws://localhost:8080/updates/websocket/156/mg0dspp2/websocket' failed: Error during WebSocket handshake: Unexpected response code: 200
我真的看不出实际的响应是什么,但我假设它是JHIpster错误消息“发生了错误”,并且返回的这个html的http状态码是200
我不知道实际的问题是什么。。。我跟踪了这个和其他几个。。。
这是我的后端:
WebsocketConfig:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
public static final String IP_ADDRESS = "IP_ADDRESS";
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/updates/websocket")
//.setHandshakeHandler(defaultHandshakeHandler())
.setAllowedOrigins("*")
.withSockJS()
.setClientLibraryUrl("https://cdn.jsdelivr.net/npm/sockjs-client@1.5.0/dist/sockjs.min.js");
//.setInterceptors(httpSessionHandshakeInterceptor());
}
private DefaultHandshakeHandler defaultHandshakeHandler() {
return new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
Principal principal = request.getPrincipal();
if (principal == null) {
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
principal = new AnonymousAuthenticationToken("WebsocketConfiguration", "anonymous", authorities);
}
return principal;
}
};
}
@Bean
public HandshakeInterceptor httpSessionHandshakeInterceptor() {
return new HandshakeInterceptor() {
@Override
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
attributes.put(IP_ADDRESS, servletRequest.getRemoteAddress());
}
return true;
}
@Override
public void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception
) {}
};
}
}
@Controller
public class UpdateController {
private static final Logger log = LoggerFactory.getLogger(UpdateController.class);
@MessageMapping("/updates/websocket")
@SendTo("/topic/trucks")
public UpdateDto send(UpdateDto dto) {
return dto;
}
}
connect(): void {
if (this.stompClient?.connected || this.called) {
return;
}
this.called = true;
// building absolute path so that websocket doesn't fail when deploying with a context path
let url = '/updates/websocket';
url = this.location.prepareExternalUrl(url);
var socket = new SockJS(url);
this.stompClient = Stomp.over(socket);
this.stompClient.connect({}, (frame) => {
this.connectionSubject.next();
this.sendActivity();
this.routerSubscription = this.router.events
.pipe(filter((event: Event) => event instanceof NavigationEnd))
.subscribe(() => this.sendActivity());
}, error => {
console.log(error);
});
}
前端:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
public static final String IP_ADDRESS = "IP_ADDRESS";
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/updates/websocket")
//.setHandshakeHandler(defaultHandshakeHandler())
.setAllowedOrigins("*")
.withSockJS()
.setClientLibraryUrl("https://cdn.jsdelivr.net/npm/sockjs-client@1.5.0/dist/sockjs.min.js");
//.setInterceptors(httpSessionHandshakeInterceptor());
}
private DefaultHandshakeHandler defaultHandshakeHandler() {
return new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
Principal principal = request.getPrincipal();
if (principal == null) {
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
principal = new AnonymousAuthenticationToken("WebsocketConfiguration", "anonymous", authorities);
}
return principal;
}
};
}
@Bean
public HandshakeInterceptor httpSessionHandshakeInterceptor() {
return new HandshakeInterceptor() {
@Override
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
attributes.put(IP_ADDRESS, servletRequest.getRemoteAddress());
}
return true;
}
@Override
public void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception
) {}
};
}
}
@Controller
public class UpdateController {
private static final Logger log = LoggerFactory.getLogger(UpdateController.class);
@MessageMapping("/updates/websocket")
@SendTo("/topic/trucks")
public UpdateDto send(UpdateDto dto) {
return dto;
}
}
connect(): void {
if (this.stompClient?.connected || this.called) {
return;
}
this.called = true;
// building absolute path so that websocket doesn't fail when deploying with a context path
let url = '/updates/websocket';
url = this.location.prepareExternalUrl(url);
var socket = new SockJS(url);
this.stompClient = Stomp.over(socket);
this.stompClient.connect({}, (frame) => {
this.connectionSubject.next();
this.sendActivity();
this.routerSubscription = this.router.events
.pipe(filter((event: Event) => event instanceof NavigationEnd))
.subscribe(() => this.sendActivity());
}, error => {
console.log(error);
});
}
我在Windows上运行Im,我使用Chrome进行开发。但它在FireFox中也不起作用,所以我认为它与平台无关。
任何帮助都将不胜感激。多谢各位 状态代码为200的错误无论如何都很奇怪。。但是:除了setClientLibraryUrl之外,您的配置看起来很好,与我的配置相似。检查的一个想法是:Jhipster创建一个安全配置,定义谁可以访问端点。当前用户(或者您可以使用permitAll)应该可以访问您的端点(更新/**)?!您的代码中是否有此更改?否则,websocket端点将被发送到
/index.html
在您的情况下,它可能需要更新
而不是websocket
,因为它与JHipster的websocket实现不同,状态代码为200的错误无论如何都很奇怪。。但是:除了setClientLibraryUrl之外,您的配置看起来很好,与我的配置相似。检查的一个想法是:Jhipster创建一个安全配置,定义谁可以访问端点。当前用户(或者您可以使用permitAll)应该可以访问您的端点(更新/**)?!您的代码中是否有此更改?否则,websocket端点将被发送到/index.html
,在您的情况下,它可能需要更新
,而不是websocket
,因为它与JHipster的websocket实现不同