Using Socket.IO server and client on different subdomains - javascript

I have two subdomains:
socket.mydomain.com - The Socket.IO server
app.mydomain.com - A web app that I'd like to connect to my web socket.
In the landing page for app.mydomain.com, I've linked in the Socket.IO client script, and successfully created an IO object, like so:
<script src=https://socket.mydomain.com/socket.io/socket.io.js></script>
<script type=text/javascript>
const socket = io();
socket.on('message', data => console.log(data));
</script>
However, rather than trying to connect to socket.mydomain.com, the client is trying to connect to app.mydomain.com. Because there's no socket at app.mydomain.com, it fails and keeps retrying.
Is there a way to connect my app at app.mydomain.com to my socket at socket.mydomain.com? Or is this impossible?
Update
Most all of the existing answers relating to this question now use outdated code, because Socket.IO has recently upgraded to 1.0 (1.4 in fact). However, even taking these code changes into account, it seems like Socket.IO doesn't allow what I'm trying to do.
When Socket.IO makes the initial connection to the server, it sends an XHR with the withCredentials settings set to true. But you can't have withCredentials set to true and allow CORS on the server. So it seems my question is actually, 'Is there a way around this problem?'

To accomplish what I wanted, several things needed to be configured correctly, and I needed to use the latest Socket.IO syntax:
CORS must be enabled on the socket.mydomain.com server (Access-Control-Allow-Origin header set to *)
Acceptable transports had to be specified on the server (socket.mydomain.com):
const app = express();
const server = http.createServer(app);
const io = require('socket.io')(server, {
transports: ['websocket', 'xhr-polling']
});
The remote server and acceptable transports had to be specified on the client (app.mydomain.com):
const socket = io('socket.mydomain.com', {
transports: ['websocket', 'xhr-polling']
});

Related

NodeJS and web sockets: Check if socket origin is the same as the web socket server

Edit: I'm sending data from app A to app B over web socket, where A is a router app for something else, and B is my web app. When B receives the data, it should send it to any client viewing its home page, also over web socket. But, since the roter app and the home page clients are connected to the same web socket server, I don't know which connections are to the clients viewing the home page, and which connections are to other stuff, like my router. Only the home page clients should receive the data.
I basically want to pass the logging data recieved from my router to my home page in real time so I can view it.
========
I have an express app that server a simple html page. It runs this script:
var host = window.document.location.host.replace(/:.*/, '');
var ws = new WebSocket('ws://' + host + ':5000');
ws.onmessage = function (event) {
console.log(JSON.parse(event.data));
};
In the nodejs backend, I have a simple ws server running, listening for connections:
var WebSocketServer = require("ws").Server;
module.exports.init = function(server) {
var wss = new WebSocketServer({ server: server });
wss.on('connection', function (ws) {
...
});
};
I get connections from, at the moment, 2 different locations.
A router app I have running that is sending this web app logging messages.
The html-page that this web app is serving.
I want to pipe the data from the router app to my html page, but to do that I need to know which of my connections I need to pipe the data to. I can in theory have many connection, but only one of them, at least for now, should be passed the data after it is recieved.
I thought I could compare the origin of the web socket connection to the domain of the web server the web socket server ran on.
I can get the origin of the connection like this: ws.upgradeReq.headers.origin. That will return e.g: localhost:5000. But I don't know the domain name where my web socket server is running. I've tried to google, and it seems like to get the domain name, I need to get it from an http request. What I am looking for is something that just gives me the name, without having to wait for an http request.
I've tried os.hostname(), but it doesn't give me the results I need.
I've also tried server.address(), where server is var server = require("http").createServer(app);, but that gives me this: { address: '::', family: 'IPv6', port: 5000 }.
Isn't there just a way to get the host and port? Can I somehow use the address part above to get the host name?
The web app will probably run on Heroku.
Based on your recent comments, it sounds like each browser client that connects a webSocket should just tell your server what web page it is looking at with an initial message and the server should keep track of that for each active connection.
In socket.io (built on top of webSockets), you could just connect to the /homepage namespace and then that server could broadcast to all sockets connected to that namespace. You could, of course, implement that type of functionality yourself with a plain webSocket.
Then, your server would not only have a list of connected sockets, but could also know what page they were all from. That would allow you to broadcast based on current page. Your server-to-server webSocket would not have sent a message that it's from the home page, so it would not be tagged as such and you could avoid sending to it.
You might find socket.io easier to use for all of this. In additon to namespaces on both client and server, it also gives you automatic reconnection from browsers, a simpler message passing system, server-side broadcast to namsepaces and so on.

Issue: try connect with a Socket.io Server without port using a client application

everyone!
I'm in an issue.
I'm trying to connect in a server with my client application.
My server is hosting by Modulus that have no port to access URL.
When I try to call io('my-application.onmodulus.net'), the browser (chrome) returns me a failed GET net::ERR_CONNECTION_REFUSED with a PORT setted in GET URL.
I tested the URL without the PORT in the browse and works.
There's a way to GET socket.io connect from then client without socket.io set a PORT in URL?
Here's my code:
I try of different ways to call this method, and I don't find OPTIONS parameter documentation.
var socket = io('my-application.onmodulus.net', {multiplex: false, path: '/socket.io'});
Thank you all so much!
In socket.io, if you pass anything as the first argument to io() to specify the hostname, then it should be in URL form, not just a hostname.
If you don't pass anything (e.g. you just call io()), then socket.io will connect to the same host and port as the current web page.
So, you could use:
var socket = io('http://my-application.onmodulus.net/socket.io', {multiplex: false});
or, if you're connecting to the same host and port as your web page, you could just leave out the URL and use:
var socket = io({multiplex: false});

Notification in javascript - similar to new emails in gmail

I am creating a widget which will update some live NEWS happening. I want to push notification to the widget everytime I get some new information in my database. It is similar to live feed. I am unsure how to start this one in javascript.
I donot want to poll every nth second to get the information. I want the server to push information to the client everytime the server gets a new information.
It is similar to gmail. You get an email even without refreshing the page.
Any pointers will be definitely helpful.
You basically have 2 choices, what I can think of:
Using HTTP, you can ask the server every x second, if it has any new information, and if it does, then load & show it. If you are using HTTP, the server can't contact the client, it can only answer the clients requests.
Using sockets, you can create a 2 way communication, both the client can send data to the server, and the server can send data to the client. This way the server can send the information as soon, as possible. Here you can find information about the supported browsers.
Intermediate Node server can help to separate the business logic from polling operations.
Needs to install these packages - socket.io, express, request
npm install <package_names>
To get request data from node :
var socket = io.connect('http://localhost:3000');
socket.emit('pollNodeServer',JSON.stringify(requestToServer));
On server :
var http = require('http'),
request = require('request'),
app = require('express')(),
server = require('http').Server(app),
io = require('socket.io')(server);
server.listen(3000);
console.log('Server started at port 3000');
var options = {
headers : {
'Content-Type' : 'application/json',
'User-Agent' : 'request'
}
};
socket.on('pollNodeServer', function(data, callbackfn) {
requestServer(data,socket,callbackfn);
});
Reply from server :
socket.emit('returnJobs',JSON.parse(body));

How do I serve socket.io over HTTPS with Node?

The problem:
I just successfully got my Node.js server all working properly and setup with SSL, great. But then I see this:
[blocked] The page at 'https://www.mywebsite.com/' was loaded over
HTTPS, but ran insecure content from
'http://54.xxx.xxx.77:4546/socket.io/socket.io.js': this content
should also be loaded over HTTPS.
I tried just changing the socket.io URL to https, but of course that doesn't work because socket.io insists on serving it's own generated file, a process that I don't think I control. I can change the port that socket.io listens on, that's it.
The question:
So how do I securely serve socket.io (1.0)?
The codez:
var port = 4546;
var io = require('/node_modules/socket.io')(port);
As a side note, I think socket.io (its back and forth communication) should run over HTTPS properly without any extra work; I read that somewhere. Perhaps someone can confirm. It is important that the web socket's communications be securely transferred.
This is one of those occasions where the questions aren't quite duplicates, but the selected answer to a question answers this one as well.
It's simple: Just pass your https server object as socket.io's port parameter.
// ... require stuff
var app = express();
// ... set up your express middleware, etc
var server = https.createServer(sslOptions, app);
// attach your socket.io server to the express server
var io = require("socket.io").listen(server);
server.listen(port);
code by aembke

Socket.io and Webscocket listen on the same server

I need to share same http server between socket.io and websocket (from 'ws' package) handlers.
Unfortunatelly, despite that they are listening to diffrent prefixes, the first is listening to /socket.io and the second to /websocket urls, for some reasons if they are running on the same server the websocket is not working properly.
I did some debugging, but it seems that the requests are properly handled by both libraries but in the end only socket.io works properly.
Any idea how to solve that?
The way sockets work in node.js is quite a bit different from the way normal requests work. There is no routing, so rather than listening to a url, you have to listen to all sockets. The default behavior of socket.io is to close any socket connections that it doesn't recognize. To fix this, you'll need to add the flag 'destroy upgrade': false to the options (server is an express server):
require('socket.io').listen(server, {'destroy upgrade': false, ...})
You'll also need to check the url when a client connects (in the code handling /websocket) and ignore it if it looks like it belongs to socket.io. You can find the url from the client object (passed in to the on connection handler) as client.upgradeReq.url.
Ok solution is simple (unfortunately half day of debugging and now it's simple :)).
There is an option 'destroy upgrade' for upgrade requests coming from non-socketio clients. Since Websocket (module 'ws') is using the same requests some of them might be for 'ws' not for 'socket.io'. So this option should be disabled.
io = require('socket.io').listen(server, { log: false, 'resource':'/socket.io' });
io.disable('destroy upgrade')
Update for 2016:
io.disable('destroy upgrade');
seems not to be available anymore.
But I succeeded by assigning the websocket module ws a path (using Express):
var wss = new WebSocketServer({ server: server, path: '/ws' }); //do not interfere with socket.io
Of course the client has the same path ws://theserver.com/ws
I did not have to alter the socket.io side at all.

Categories