A pitfall of socket.io-client to be avoided
When I was debugging a CI/CD open source project called piplin(http://piplin.com), I failed setting up a web socket connection between node.js server and the browser.
The browser is using cocket.io-client npm package. See its package.json
file.
"dependencies": {
...
"socket.io": "^2.0.4",
"socket.io-client": "^2.0.3"
And the package is combined in vendor.js
. See its webpack.mix.js
file.
mix
.options({
processCssUrls: false
})
...
.scripts([
...
`${paths.socketio_client}/dist/socket.io.js`,
`${paths.localization}/resources/js/config.js`,
`${paths.localization}/resources/js/localization.js`,
...
], `${dist_path}/js/vendor.js`)
....
And in the fronend html template resources\views\layouts\dashboard.blade.php
, it is included as below:
<!DOCTYPE html>
<html>
<head>
...
<meta name="socket_url" content="{{ config('piplin.socket_url') }}" />
<meta name="jwt" content="{{ Session::get('jwt') }}" />
...
</head>
<body class="hold-transition skin-default {{ isset($sub_menu) ? 'has-sub-sidebar' : null }}">
...
<div class="alert alert-danger" id="socket_offline">
<h4><i class="icon piplin piplin-warning"></i> {{ trans('app.socket_error') }}</h4>
{!! trans('app.socket_error_info') !!}
...
<script src="{{ cdn('js/vendor.js') }}"></script>
...
</body>
</html>
Please also note that there’s jquery code to control the socket error message in public\js\app.js
.
// Socket.io
Piplin.listener = io.connect($('meta[name="socket_url"]').attr('content'), {
// path: "/hok",
query: 'jwt=' + $('meta[name="jwt"]').attr('content')
});
Piplin.connection_error = false;
Piplin.listener.on('connect_error', function(error) {
if (!Piplin.connection_error) {
$('#socket_offline').show();
}
Piplin.connection_error = true;
});
Piplin.listener.on('connect', function() {
$('#socket_offline').hide();
Piplin.connection_error = false;
});
Piplin.listener.on('reconnect', function() {
$('#socket_offline').hide();
Piplin.connection_error = false;
});
When I ran this project , I always got the error socket server connection failed.

And the console said:

Notice that there’s always a section of url string “socket.io” added for the io.connect
function.
That’s the reason the web socket connection was failed and the nginx server returned error 404.
The socket.io
string added anonymously in the url is exactly what I say a pitfall. After checking the source code of socket.io-client
package, I found that it is set by default when the socket client is initialized if without setting a path
parameter in connect
function. The code is in lib\manager.js
.
module.exports = Manager;
/**
* `Manager` constructor.
*
* @param {String} engine instance or engine uri/opts
* @param {Object} options
* @api public
*/
function Manager (uri, opts) {
if (!(this instanceof Manager)) return new Manager(uri, opts);
if (uri && ('object' === typeof uri)) {
opts = uri;
uri = undefined;
}
opts = opts || {};
opts.path = opts.path || '/socket.io';
So indeed, when using socket.io-client
package, it is necessary to make sure a path
value is given to connect
or open
function. I changed my code as below:
// Socket.io
Piplin.listener = io.connect($('meta[name="socket_url"]').attr('content'), {
path: "/",
query: 'jwt=' + $('meta[name="jwt"]').attr('content')
});

The url is correct now though there’re still a 500 error.
The 500 error is given by my nginx server as I have not configured it correctly.
To get rid of it, add the corresponding code into nginx.conf
in the piplin.test.
upstream websocket {
server 127.0.0.1:7001;
}
...
location /your_path_in_the_connect_function(e.g:socket.io) {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://websocket;
}