Im having something like the below code.
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io('http://localhost:8080');
socket.on('connect', function(){
socket.on('some-event', function(data) {});
});
socket.on('disconnect', function(){});
</script>
Inside the connect callback I have some code that responds to messages. This works perfectly fine on chrome. On first page load it works fine on firefox. If you reload the page then the connect event does not get called.
Im using 1.4.8 version of server and js client
I solved it using the following code. Not very clean but for the time being this helped us to progress with the project. As you can see the problem is the connect event not firing after a page reload, so I decided to attach the events after a timeout if connect was never fired.
function attachEventListners() {
socket.on('some-event', function(data) {});
}
var attached = false;
socket.on('connect', function(){
attachEventListners();
attached = true;
});
setTimeout(function() {
if (!attached) {
attachEventListners();
}
}, 1000);
You don't have to declare event listeners inside a connect listener, so even though I don't know a direct solution to your problem, I think this'll work around it:
<script>
var socket = io('http://localhost:8080');
socket.on('some-event', function(data) {});
socket.on('disconnect', function(){});
</script>
Because being able to receive messages implies that the socket is connected.
Instead of a timeout, you should use the load event listener on window
window.addEventListener("load",attachEventListners);
Related
I am having problems with SvelteKit and SocketIO. I'm connecting to a NestJS back-end with a default SocketIO gateway and connecting works fine, but executing a socket.emit inside a function fails to trigger entirely. Not sure if this is SocketIO or SvelteKit related, but executing an emit outside of a function works. Here is my code snippet.
<script>
import io from 'socket.io-client';
let socket = io('http://localhost:5000');
socket.on("connect", () => {
console.log(socket.id);
});
socket.on("messages", (arg) => {
console.log(arg);
});
socket.emit("messages", "executes at load", (err) => {
console.log(err);
});
function onSendMessage() {
console.log('executing function');
socket.emit("messages", "test", (err) => {
console.log(err);
});
}
</script>
<button on:click={onSendMessage}>
Send Message
</button>
In this situation ''executes at load'' is printed to the console because it is emitted and the server sends the response back which the socket.on catches. It also prints the ID of the connection through socket.on("connect"). but it never will print ''test'' if i press the button. Pressing the button does console log the ''executing function''. Tested all functionality on Postman as well and the server works. Executing the function manually directly in the script tag without the button onclick results in the same behaviour of the emit not executing. Anyone has an idea?
After a long time of agony I discovered the problem. I think it has to do with the fact that it was trying to establish an XHR Polling connection on the clientside but not on the SSR side of SvelteKit, and it seems that XHR Polling does not support CORS but websockets do.
All I had to do was specify the transport as ''websocket'' on both the frontend and backend and it works perfectly!
Usually, the web socket is started from the main.js. Now, I use the following:
import VueNativeSock from 'vue-native-websocket'
vue.use(VueNativeSock, 'ws://localhost:4113', { format: 'json' });
In this case, the web socket is started when I load the page.
I wonder if it would be possible to open the web socket after a button has been pressed rather than when a page has been loaded. For instance, in HelloWorld.js the generic VueJS component where I have added the following:
<md-button class="md-raised md-primary" #click="submit" v-model="buttonInput">Submit</md-button>
I would like to have something like the following but it does not work.
methods: {
submit: function(val){
this.use(VueNativeSock, 'ws://localhost:4113', { format: 'json' });
this.$socket.sendObj({website: this.urlInput});
}
}
It is currently impossible to to what you need, because VueNativeSock is a plugin.
An Vue Plugins can only be used through the global Vue.use():
Using a Plugin
Use plugins by calling the Vue.use() global method:
js // calls `MyPlugin.install(Vue)` Vue.use(MyPlugin)
You can optionally pass in some options:
js Vue.use(MyPlugin, { someOption: true })
There have been some discussions about allowing locally, mostly for testing purposes, so that possibility only exist in vue-test-utils at the moment.
Note: VueNativeSock also currently doesn't provide another way (say a method) to start the webSocket. It is opened upon Plugin Install method and the install happens the moment you do Vue.use().
Fix
Use Vue.use(VueNativeSock, 'ws://localhost:4113', { format: 'json' }); (instead of this.use(...).
But mind the time the socket will take to open. So your this.$socket.sendObj may not be readily available right after the Vue.use() call. Here's a demo that waits for the WebSocket connection to open before sending the message:
/* workaround because we are not using via <script> and not via require()/import */
VueNativeSock = VueNativeSock.default;
new Vue({
el: '#app',
methods: {
createAndSend() {
Vue.use(VueNativeSock, 'wss://echo.websocket.org/', { format: 'json' });
this.$socket.onopen = () => {
console.log('WebSocket opened');
// registering listeners
this.$socket.onmessage = (data) => console.log('Received data:', data.data);
// sending data
console.log('Sending data');
this.$socket.sendObj({awesome: 'data'});
}
}
}
})
<script src="https://unpkg.com/vue#2.5.13/dist/vue.min.js"></script>
<script src="https://rawgit.com/nathantsoi/vue-native-websocket/master/dist/build.js"></script>
<div id="app">
<h3>Check the console</h3>
<button #click="createAndSend">Create WebSocket and Send Message</button>
</div>
I've been trying to make a basic notification system that uses rooms in Socket.io. However, for some reason, it only works every other time you refresh the page.
I've simplified the code to make it easier to debug, but the issue remains. Each time I refresh the page, everything seems to work except joining a room (which only works half the time). What could be going on?
edit: I'm using Socket.io version 1.1.0 and Node.js version 0.10.31
edit2: Added FunnyLookinHat's suggestion (but it still doesn't solve the problem)
Client-Side Code:
socket = io.connect('example.com:8081'),
socket.on('connect', function () {
socket.on('startup', function(data) {
console.log(data.message);
});
socket.emit('joinRoom');
});
Server-Side Code:
var io = require('socket.io').listen(8081);
io.sockets.on('connection', function (socket) {
console.log(socket.id + ' connected!');
socket.emit('startup', { message: 'Socket started!' });
socket.on('joinRoom', function(){
console.log(socket.id + ' joining room lobby'); // prints on every other request
socket.join('lobby');
});
socket.on('disconnect', function() {
console.log(socket.id + ' disconnected!');
});
});
Client Console:
Socket started!
(refreshed page)
Socket started!
Server Console:
UIBqVuOiF1fegMIMAAAB connected!
UIBqVuOiF1fegMIMAAAB joining room lobby
UIBqVuOiF1fegMIMAAAB disconnected!
(refreshed page)
x3nMilBOjjFVjBFJAAAC connected!
(after about a minute once the client window has been closed or refreshed)
x3nMilBOjjFVjBFJAAAC disconnected!
Race condition! Try doing the following in your client code:
socket = io.connect('example.com:8081'),
socket.on('connect', function () {
socket.on('startup', function(data) {
console.log(data.message);
});
socket.emit('joinRoom');
});
Error: The connection to <websocket> was interrupted while the page was loading.
Source File: localhost/socket.io/node_modules/socket.io-client/dist/socket.io.js
Line: 2371
I am new to socket.io and I have tried to search for this, but I didn't get an answer.
Websocket is interrupted when I refresh page on Firefox. That's why server side is waiting to authorise client.
Here is code:
server.js
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs')
app.listen(8080);
function handler(req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
socket.emit('news', {
hello: 'world'
});
socket.on('my other event', function (data) {
//alert(JSON.stringify(data));
console.log(data);
});
});
index.html
<script src="node_modules/socket.io-client/dist/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
socket.on('news', function (data) {
alert(JSON.stringify(data));
console.log(data);
socket.emit('my next event', { my: 'data' });
});
</script>
It happens because, you are not closing your open websocket.
This code would remove this error:
$(window).on('beforeunload', function(){
socket.close();
});
This seems to be an open bug in Firefox (as of 2015-03-29):
https://bugzilla.mozilla.org/show_bug.cgi?id=712329
The workaround (for now) is to call close() on the websocket on beforeunload, as Alexander pointed out.
Update 2016-04: According to Bugzilla, this will be fixed in Firefox 48
I was just running through the Socket.IO tutorials and I ran into this exact problem. I tried the posted solutions but they didn't seem to work at all.
After some fiddling and some screaming and some rubber-ducking, I finally figured out what the issue was. The issue is that it's trying to connect to the socket before the socket variables have been properly initialized. Javascript boo boo #1.
If you will ammend your file to include jQuery and then wrap your functions like so:
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script>
$(function(){
var socket = io.connect('http://localhost:8080');
socket.on('news', function (data) {
alert(JSON.stringify(data));
console.log(data);
socket.emit('my next event', { my: 'data' });
});
});
</script>
You will have much more success.
What impact does this have on your application? My guess is that it's just not great to see an error in the console.
The problem here is that you are seeing Firefox loggin this error and there's nothing you can do about it. It's not possible to capture this error with a try...catch block or via websocket.onerror/websocket.onclose.
See: How do I catch a WebSocket connection interruption?
Related:
Should WebSocket.onclose be triggered by user navigation or refresh?
Firefox - Race condition allows ghost WebSocket connections to live after tab closed
I've had this problem with our custom Undertow-based webserver for years -- my problem was that my server was not responding to the socket close message.
Based on a comment by Jan Wielemaker I checked my socket close handler code for AbstractReceiveListener.onFullCloseMessage and realized I had not called the super method. After adding super.close() the socket closes cleanly on the client and no error is emitted.
One solution is to put a timeout on the disconnect event.
setTimeout(() => {
$('#offlineModal').modal('show')
}, 5000)
Is there any callback for the io.connect() method on the client side? I would like to print some text about connection failure, otherwise proceed normally with the site's socket interactions.
Sure, checkout the documentation for Socket.IO-client with the examples there:
https://github.com/LearnBoost/socket.io-client#sockets-for-the-rest-of-us
socket.on('connect', function () {
// socket connected
});
In the current release of socket.io (1.3.x) you can use the connect_error event or the reconnect_failed event:
var socket = io(serverUrl);
socket.on('connect_error', function() {
console.log('Connection failed');
});
socket.on('reconnect_failed', function() {
console.log('Reconnection failed');
});
See: https://github.com/Automattic/socket.io-client#events