Error using socket.io along with webpack-dev-server - socket.io

Quick question guys, I am trying to use webpack-dev-server with socketio, but after trying different things, i figured both of the clients are listening to the same port '3000' and I end up with some kind of handshake error that goes away if I dont use webpack-dev-server on the same port.. here is my server config
const PORT = process.env.PORT || 3000;
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
setup(app) {
const server = require('http').Server(app);
let onlineUsers = 0;
const io = require('socket.io')(server);
io.on('connection', (socket) => {
console.log(`A client is connected:${socket.id}`);
onlineUsers++;
io.sockets.emit('onlineUsers', {
onlineUsers
});
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
}
}).listen(PORT, 'localhost', (err) => {
if (err) {
console.log(err);
}
console.log(`Listening at localhost: ${PORT}`);
});
and webpack config
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'react-hot-loader/patch',
'./src/app.js'
],
these are the error(s)
WebSocket connection to 'ws://localhost:3000/sockjs-
node/608/jsbr0a0r/websocket' failed: Connection closed
before receiving a handshake response
T http://localhost:3000/sockjs-node/225/qvolyk2n/eventsource
iframe.js?ea3f:102 GET http://localhost:3000/sockjs-node/iframe.html 404 (Not Found)
createIframe # iframe.js?ea3f:102
IframeTransport # iframe.js?7dcb:42
IframeWrapTransport # iframe-wrap.js?7e29:11
SockJS._connect # main.js?45b8:219
SockJS._transportClose # main.js?45b8:299
g # emitter.js?927b:30
EventEmitter.emit # emitter.js?927b:50
(anonymous) # sender-receiver.js?620a:28
g # emitter.js?927b:30
EventEmitter.emit # emitter.js?927b:50
(anonymous) # polling.js?97d6:41
g # emitter.js?927b:30
EventEmitter.emit # emitter.js?927b:50
(anonymous) # eventsource.js?d407:58
VM776:66[HMR] Waiting for update signal from WDS...
VM1157:49Warning: [react-router] Location "/sockjs-node/225/ucoowxum/htmlfile?c=_jp.alfvbqm" did not match any routes
I was trying is to proxy the request to a different port
proxy: {
"http://localhost:3000": "http://localhost:4000"
}
and then listen to that in the configurations
entry: [
'webpack-dev-server/client?http://localhost:4000',
'webpack/hot/only-dev-server',
'react-hot-loader/patch',
'./src/app.js'
],
but I don't know if that is the way to go, anyone know how to fix this?

The issue is your proxy is not correctly configured. By default when you call the socket.io constructor, this line
const io = require('socket.io')(server);
All socket.io requests will go to your webpack dev server http://localhost:3000/socket.io (note the end of the URL - important) in your case. You want to proxy those requests to http://localhost:4000/socket.io, not every request that hits http://localhost:3000. You're also missing the ws: true line. So actually the correct configuration is the following:
proxy: {
'/api': {
target: 'http://localhost:4000',
pathRewrite: {"^/api": ""}
},
'/socket.io': {
target: 'http://localhost:4000',
ws: true
}
}
You don't need the first '/api' part if you don't have have a backend API that is listening to other requests. I'm just assuming you do. It's possible you just have all sockets in which case you can ignore that line. In most cases, people will have sockets and other http requests.
Hope this helps anyone trying to set up webpack-dev-server and socket.io with a proxy.

just to be thorough, here's the full nodejs implementation of it.
nodejs:
const http = require("http").createServer(app);
const io = require('socket.io')(http);
io.set('transports', ['websocket']);
http.listen(3002, () => console.log(`socket: http://${ip.address()}:3002`, "Time:", moment(new Date().getTime()).format("DD日 h:mm:ss")));
frontend:
var server = "/";
var connectionOptions = {
"force new connection": true,
"reconnectionAttempts": "Infinity", //avoid having user reconnect manually in order to prevent dead clients after a server restart
"timeout": 10000, //before connect_error and connect_timeout are emitted.
"transports": ["websocket"]
};
store.state.socket = io(server, connectionOptions);
store.state.socket.on('connect', () => {
console.log('socket connected ----');
});
webpack:
const target = "http://" + "localhost" + ":" + "3001";
const socket = "http://" + "localhost" + ":" + "3002";
module.exports = {
devServer: {
https: true,
key: fs.readFileSync('./src/localhostcert/key.pem'),
cert: fs.readFileSync('./src/localhostcert/cert.pem'),
host: 'localhost',
hot: true,
compress: true,
port: 8080,
proxy: {
"/socket.io": {
target: socket,
ws: true
}
}
}
}

Related

Getting "connect_error due to xhr poll error" while connecting socket server

I am trying to connect socket.io client which inside react app to the socket.io server but i am getting xhr poll error. I am unable to figure out what is going wrong? client & server code is as follow:
import io from 'socket.io-client';
const socket = io("ws://loacalhost:5000");
socket.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
const express = require('express');
const app = express();
app.use(require('cors')());
const http = require('http');
const server = http.createServer(app);
const io = require("socket.io")(server, {
rejectUnauthorized: false,
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"]
}
})
io.on("connection", (socket) => {
console.log(socket.id)
})
server.listen(5000, () => {
console.log('Server is listening on Port 5000');
});
Everything is ok in server file as well as everything is ok in client file except there is syntax mistake in client code i.e.
const socket = io("ws://loacalhost:5000");
replaced with:
const socket = io("ws://localhost:5000");
then it is worked fine, successfully connected to server
Your localhost spelling is incorrect.
const socket = io("ws://loacalhost:5000");
Replaced with
const socket = io("ws://localhost:5000");

Socket IO forbidden 403

I have a simple socket.io app and it works just fine on local and also it's installed successfully on AWS server using plesk admin dashboard but when I connect to the app I always get forbidden {"code":4,"message":"Forbidden"} .. the entry point seems to work great http://messages.entermeme.com .. any idea what could be wrong with it ?
Frontend code
import io from 'socket.io-client'
const socket = io('https://messages.entermeme.com', {
transports: ['polling'],
})
socket.emit('SUBSCRIBE')
Backend code
const cors = require('cors')
const app = require('express')()
const server = require('http').Server(app)
const io = require('socket.io')(server)
server.listen(9000)
app.use(cors())
io.set('transports', [
'polling'
])
io.origins([
'http://localhost:8000',
'https://entermeme.com',
])
io.on('connection', (socket) => {
socket.on('SUBSCRIBE', () => {
//
})
})
had a similar issue but when using nginx. So in case you still need some help:
In the end it turned out to be the URL I specified as socket origins. I didn't specify the port since the origin for me was also running on port 80 (443 for SSL) like in your example above:
io.origins([
'http://localhost:8000',
'https://entermeme.com', // <--- No port specified
])
I updated my config and added the port. So for you it would be:
io.origins([
'http://localhost:8000',
'https://entermeme.com:80', // <--- With port (or 443 for SSL)
])

Apollo GraphQL: Setting Port for HTTPBatchedNetworkInterface?

I'm trying to connect to a local dev environment via an IP address. I'm getting an error because HTTPBatchedNetworkInterface shows:
_uri: "http://10.0.1.10/graphql"
...when it needs to be:
"http://10.0.1.10:3000/graphql"
Here's my server-side setup code:
const localHostString = '10.0.1.10';
const METEOR_PORT = 3000;
const GRAPHQL_PORT = 4000;
const server = express();
server.use('*', cors({ origin: `http://${localHostString}:${METEOR_PORT}` }));
server.use('/graphql', bodyParser.json(), graphqlExpress({
schema,
context
}));
server.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `ws://${localHostString}:${GRAPHQL_PORT}/subscriptions`
}));
// Wrap the Express server
const ws = createServer(server);
ws.listen(GRAPHQL_PORT, () => {
console.log(`GraphQL Server is now running on http://${localHostString}:${GRAPHQL_PORT}`);
console.log(`GraphiQL available at http://${localHostString}:${GRAPHQL_PORT}/graphiql`);
// Set up the WebSocket for handling GraphQL subscriptions
new SubscriptionServer({
execute,
subscribe,
schema
}, {
server: ws,
path: '/subscriptions',
});
});
What is the correct way to get the port number into HTTPBatchedNetworkInterface._uri?
Thanks in advance to all for any info.
Fixed. My framework is Meteor and I had to set ROOT_URL = 10.0.1.10:3000/.

Ajax With ReactJS to NodeJS

I'm using webpack-dev-server while developing in ReactJS.
I also want to add a backend which will be written in NodeJS.
When I run the webpack-dev-server it binds to port 8080.
When I run node, it can't bind to the same port.
Therefore, I'm unable to perform $.ajax requests due to the SOP.
How do I get over this issue?
NodeJS:
const express = require('express');
const app = express();
app.get('/messages', function(req, res){
res.send('hello world!');
});
let server = app.listen(8081, function() {
const host = server.address().address;
const port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
React/JS/Ajax:
$.getJSON('/messages', function(data) {
this.setState({
messages: data
});
}.bind(this));
And I'm running webpack-dev-server without any parameters.
the port of app is different from the portof your server. if you want to keep save port, you can try to use webpack proxy
module.exports = {
// the other config of your webpack
devServer: {
hot: true,
historyApiFallBack: true,
proxy: {
'/message': {
target: 'http://localhost:8081',
secure: false,
changeOrigin: true
},
},
},
}
when you fetch http://localhost:8080/messages, webpack-dev-server will proxy to http://localhost:8080/messages.
Your app is on port 8080.
Your server is on 8081.
If you want to request from the server, you need to specify the port to the server. If not, it will request to the port your app is running to, which is 8080.
$.getJSON('https://localhost:8081/messages', function(data) {
this.setState({
messages: data
});
}.bind(this));

http to https node proxy

I would like to know the easiest way to set up a proxy where I can make HTTP requests in (i.e.) localhost:8011 and the proxy makes a HTTPS request in localhost:443 (the HTTPS answer from the server should be translated to HTTP by the proxy as well)
I'm using node.js
I've tried http-proxy like this:
var httpProxy = require('http-proxy');
var options = {
changeOrigin: true,
target: {
https: true
}
}
httpProxy.createServer(443, 'localhost', options).listen(8011);
I have also tried this:
httpProxy.createProxyServer({
target: {
host:'https://development.beigebracht.com',
rejectUnauthorized: false,
https: true,
}
}).listen(port);
But when I'm trying to connect I'm getting this error
/Users/adrian/Development/beigebracht-v2/app/webroot/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:103
var proxyReq = (options.target.protocol === 'https:' ? https : http).reque
^
TypeError: Cannot read property 'protocol' of undefined
I would like to do it with node, but, other solutions can be valid.
(The proxy will be used in localhost just with testing purposes so security is not a problem)
I needed a HTTP->HTTPS node proxy for unit testing. What I ended up doing was creating the HTTP proxy and then have it listen for and handle the connect event. When the server receives the CONNECT request, it sets up a tunnel to the HTTPS target URL and forwards all packets from the client socket to the target socket and vice versa.
Sample code:
var httpProxy = require('http-proxy');
var net = require('net');
var url = require('url');
var options = {
host: 'localhost',
port: 3002
};
var proxy = httpProxy.createProxyServer();
proxy.http = http.createServer(function(req, res) {
var target = url.parse(req.url);
// The `path` attribute would cause problems later.
target.path = undefined;
proxy.web(req, res, {
target: target
});
}).listen(options.port, options.host);
// This allows the HTTP proxy server to handle CONNECT requests.
proxy.http.on('connect', function connectTunnel(req, cltSocket, head) {
// Bind local address of proxy server.
var srvSocket = new net.Socket({
handle: net._createServerHandle(options.host)
});
// Connect to an origin server.
var srvUrl = url.parse('http://' + req.url);
srvSocket.connect(srvUrl.port, srvUrl.hostname, function() {
cltSocket.write(
'HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n'
);
srvSocket.write(head);
srvSocket.pipe(cltSocket);
cltSocket.pipe(srvSocket);
});
});

Resources