Spring 启动 sockjs + stomp,无法连接
Spring Boot sockjs + stomp, cannot get a connection
我正在尝试将 sockjs + stomp 连接到我的 spring 启动 websockets。这是我的配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
private final String MESSAGE_BROKER_PREFIX = "/topic";
private final String WEBSOCKET_PREFIX = "/sockjs-node";
private final String REQUEST_PREFIX = "/";
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint(WEBSOCKET_PREFIX)
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker(MESSAGE_BROKER_PREFIX);
config.setApplicationDestinationPrefixes(REQUEST_PREFIX);
}
}
以及我的端点定义:
@Controller
public class Foo {
@SubscribeMapping("/{pipelineId}/{topic}")
private void subscribe(
HttpSession session,
@PathVariable String pipelineId,
@PathVariable String topic
) {
System.out.println(session.getId());
}
@EventListener
public void onApplicationEvent(SessionConnectEvent event) {
System.out.println(event.getSource());
}
@EventListener
public void onApplicationEvent(SessionDisconnectEvent event) {
System.out.println(event.getSessionId());
}
}
从javascript这边:
var ws = new SockJS('/sockjs-node');
var client = Stomp.over(ws);
var subscription = client.subscribe("/topic/foo/bar", () => {
console.log("asdas");
});
但连接没有发生,none 方法被调用。在 javascript 控制台中我可以看到:
>>> SUBSCRIBE
id:sub-0
destination:/topic/lala
stomp.js:199 Uncaught TypeError: Cannot read property 'send' of undefined
at Client._transmit (webpack:///./node_modules/@stomp/stompjs/lib/stomp.js?:199:26)
at Client.subscribe (webpack:///./node_modules/@stomp/stompjs/lib/stomp.js?:468:12)
at Object.eval (webpack:///./src/index.js?:128:27)
我可以使用 wscat --connect ws://localhost:8080/sockjs-node/902/phebsu4o/websocket
进行连接,但有趣的是只有断开连接处理程序被调用而连接处理程序没有。我在这里错过了什么?
我找到了一个在 github.
上实际工作的 js 客户端
import React from "react";
import SockJS from "sockjs-client";
import Stomp from "stompjs";
import PropTypes from "prop-types";
class SockJsClient extends React.Component {
static defaultProps = {
onConnect: () => {},
onDisconnect: () => {},
getRetryInterval: (count) => {return 1000 * count;},
headers: {},
autoReconnect: true,
debug: false
}
static propTypes = {
url: PropTypes.string.isRequired,
topics: PropTypes.array.isRequired,
onConnect: PropTypes.func,
onDisconnect: PropTypes.func,
getRetryInterval: PropTypes.func,
onMessage: PropTypes.func.isRequired,
headers: PropTypes.object,
autoReconnect: PropTypes.bool,
debug: PropTypes.bool
}
constructor(props) {
super(props);
this.state = {
connected: false
};
this.subscriptions = new Map();
this.retryCount = 0;
}
componentDidMount() {
this.connect();
}
componentWillUnmount() {
this.disconnect();
}
render() {
return (<div></div>);
}
_initStompClient = () => {
// Websocket held by stompjs can be opened only once
this.client = Stomp.over(new SockJS(this.props.url));
if (!this.props.debug) {
this.client.debug = () => {};
}
}
_cleanUp = () => {
this.setState({ connected: false });
this.retryCount = 0;
this.subscriptions.clear();
}
_log = (msg) => {
if (this.props.debug) {
console.log(msg);
}
}
connect = () => {
this._initStompClient();
this.client.connect(this.props.headers, () => {
this.setState({ connected: true });
this.props.topics.forEach((topic) => {
this.subscribe(topic);
});
this.props.onConnect();
}, (error) => {
if (this.state.connected) {
this._cleanUp();
// onDisconnect should be called only once per connect
this.props.onDisconnect();
}
if (this.props.autoReconnect) {
this._timeoutId = setTimeout(this.connect, this.props.getRetryInterval(this.retryCount++));
}
});
}
disconnect = () => {
// On calling disconnect explicitly no effort will be made to reconnect
// Clear timeoutId in case the component is trying to reconnect
if (this._timeoutId) {
clearTimeout(this._timeoutId);
}
if (this.state.connected) {
this.subscriptions.forEach((subid, topic) => {
this.unsubscribe(topic);
});
this.client.disconnect(() => {
this._cleanUp();
this.props.onDisconnect();
this._log("Stomp client is successfully disconnected!");
});
}
}
subscribe = (topic) => {
let sub = this.client.subscribe(topic, (msg) => {
this.props.onMessage(JSON.parse(msg.body));
});
this.subscriptions.set(topic, sub);
}
unsubscribe = (topic) => {
let sub = this.subscriptions.get(topic);
sub.unsubscribe();
this.subscriptions.delete(topic);
}
// Below methods can be accessed by ref attribute from the parent component
sendMessage = (topic, msg, opt_headers = {}) => {
if (this.state.connected) {
this.client.send(topic, opt_headers, msg);
} else {
console.error("Send error: SockJsClient is disconnected");
}
}
}
export default SockJsClient;
我正在尝试将 sockjs + stomp 连接到我的 spring 启动 websockets。这是我的配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
private final String MESSAGE_BROKER_PREFIX = "/topic";
private final String WEBSOCKET_PREFIX = "/sockjs-node";
private final String REQUEST_PREFIX = "/";
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint(WEBSOCKET_PREFIX)
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker(MESSAGE_BROKER_PREFIX);
config.setApplicationDestinationPrefixes(REQUEST_PREFIX);
}
}
以及我的端点定义:
@Controller
public class Foo {
@SubscribeMapping("/{pipelineId}/{topic}")
private void subscribe(
HttpSession session,
@PathVariable String pipelineId,
@PathVariable String topic
) {
System.out.println(session.getId());
}
@EventListener
public void onApplicationEvent(SessionConnectEvent event) {
System.out.println(event.getSource());
}
@EventListener
public void onApplicationEvent(SessionDisconnectEvent event) {
System.out.println(event.getSessionId());
}
}
从javascript这边:
var ws = new SockJS('/sockjs-node');
var client = Stomp.over(ws);
var subscription = client.subscribe("/topic/foo/bar", () => {
console.log("asdas");
});
但连接没有发生,none 方法被调用。在 javascript 控制台中我可以看到:
>>> SUBSCRIBE
id:sub-0
destination:/topic/lala
stomp.js:199 Uncaught TypeError: Cannot read property 'send' of undefined
at Client._transmit (webpack:///./node_modules/@stomp/stompjs/lib/stomp.js?:199:26)
at Client.subscribe (webpack:///./node_modules/@stomp/stompjs/lib/stomp.js?:468:12)
at Object.eval (webpack:///./src/index.js?:128:27)
我可以使用 wscat --connect ws://localhost:8080/sockjs-node/902/phebsu4o/websocket
进行连接,但有趣的是只有断开连接处理程序被调用而连接处理程序没有。我在这里错过了什么?
我找到了一个在 github.
上实际工作的 js 客户端import React from "react";
import SockJS from "sockjs-client";
import Stomp from "stompjs";
import PropTypes from "prop-types";
class SockJsClient extends React.Component {
static defaultProps = {
onConnect: () => {},
onDisconnect: () => {},
getRetryInterval: (count) => {return 1000 * count;},
headers: {},
autoReconnect: true,
debug: false
}
static propTypes = {
url: PropTypes.string.isRequired,
topics: PropTypes.array.isRequired,
onConnect: PropTypes.func,
onDisconnect: PropTypes.func,
getRetryInterval: PropTypes.func,
onMessage: PropTypes.func.isRequired,
headers: PropTypes.object,
autoReconnect: PropTypes.bool,
debug: PropTypes.bool
}
constructor(props) {
super(props);
this.state = {
connected: false
};
this.subscriptions = new Map();
this.retryCount = 0;
}
componentDidMount() {
this.connect();
}
componentWillUnmount() {
this.disconnect();
}
render() {
return (<div></div>);
}
_initStompClient = () => {
// Websocket held by stompjs can be opened only once
this.client = Stomp.over(new SockJS(this.props.url));
if (!this.props.debug) {
this.client.debug = () => {};
}
}
_cleanUp = () => {
this.setState({ connected: false });
this.retryCount = 0;
this.subscriptions.clear();
}
_log = (msg) => {
if (this.props.debug) {
console.log(msg);
}
}
connect = () => {
this._initStompClient();
this.client.connect(this.props.headers, () => {
this.setState({ connected: true });
this.props.topics.forEach((topic) => {
this.subscribe(topic);
});
this.props.onConnect();
}, (error) => {
if (this.state.connected) {
this._cleanUp();
// onDisconnect should be called only once per connect
this.props.onDisconnect();
}
if (this.props.autoReconnect) {
this._timeoutId = setTimeout(this.connect, this.props.getRetryInterval(this.retryCount++));
}
});
}
disconnect = () => {
// On calling disconnect explicitly no effort will be made to reconnect
// Clear timeoutId in case the component is trying to reconnect
if (this._timeoutId) {
clearTimeout(this._timeoutId);
}
if (this.state.connected) {
this.subscriptions.forEach((subid, topic) => {
this.unsubscribe(topic);
});
this.client.disconnect(() => {
this._cleanUp();
this.props.onDisconnect();
this._log("Stomp client is successfully disconnected!");
});
}
}
subscribe = (topic) => {
let sub = this.client.subscribe(topic, (msg) => {
this.props.onMessage(JSON.parse(msg.body));
});
this.subscriptions.set(topic, sub);
}
unsubscribe = (topic) => {
let sub = this.subscriptions.get(topic);
sub.unsubscribe();
this.subscriptions.delete(topic);
}
// Below methods can be accessed by ref attribute from the parent component
sendMessage = (topic, msg, opt_headers = {}) => {
if (this.state.connected) {
this.client.send(topic, opt_headers, msg);
} else {
console.error("Send error: SockJsClient is disconnected");
}
}
}
export default SockJsClient;