Open jmls opened 9 years ago
Same problem with similar configuration but using sock.js.
I also tried to use raw websockets.
Also I tried using different proxy middlewares: proxy-middleware
, http-proxy-middleware
.
I even tried using express
+ http-proxy-middleware
as middleware of browser-sync
but with no luck. All http requests proxying fine with all this configurations. But not Websocket request.
This is example of my try using express
+ http-proxy-middleware
:
var express = require('express')
, proxy = require('http-proxy-middleware');
$.browserSync({
host: config.host,
open: 'external',
port: config.port,
ws: true,
server: {
baseDir: config.buildDir,
middleware: [
(function () {
var app = express()
, context = '/api'
, options = {
target: 'http://localhost:8080',
changeOrigin: true,
ws: true, // proxy websockets
pathRewrite: {
'^/api': ''
}
};
app.use(proxy(context, options));
return app;
})()
],
ws: true
}
});
The error is
WebSocket connection to 'ws://192.168.250.3:3000/api/ws/023/xddwmfnu/websocket' failed: Connection closed before receiving a handshake response
Websockets are fixed in proxy mode
BrowserSync v2.8.1. (https://github.com/browsersync/browser-sync/commit/40017b4)
Wondering if it is the same issue in server mode
.
Background info on websocket fix in proxy mode: https://github.com/BrowserSync/browser-sync/issues/625#issuecomment-125044205
@jmls or @xak2000 Can someone provide a small sample app showing this problem, this will enable me to debug it much faster
I cloned http-proxy-middleware repository and add example with browser-sync + websocket together.
To run it:
$ git clone https://github.com/xak2000/http-proxy-middleware.git
$ cd http-proxy-middleware
$ npm install
Then run browser-sync-ws example:
$ node examples/browser-sync-ws
You can open browser console and see the error:
WebSocket connection to 'ws://localhost:3000/ws' failed: Connection closed before receiving a handshake response
This example proxies all requests to ws://localhost:3000/ws
to echo.websocket.org
.
I've the same problem, any news about a fix? Here my code, that works except for the error in object
var proxyMiddleware = require('http-proxy-middleware');
[...]
browserSync: {
server: {
bsFiles: {
src: ['./dist/{**/*,*}.js', './dist/{**/*,*}.html', './dist/{**/*,*}.css']
},
options: {
watchTask: true,
logLevel: "info",
logConnections: true,
open: true,
notify: false,
port: 9000,
logFileChanges: false,
server: {
baseDir: './dist',
middleware: [
proxyMiddleware('/appserve/api', {
target: 'http://127.0.0.1:8080',
changeOrigin: false
}),
proxyMiddleware('/ws', {
target: 'http://127.0.0.1:3000',
changeOrigin: false,
ws: true
})
]
}
}
}
}
[...]
WebSocket connection to 'ws://localhost:9000/ws/?EIO=3&transport=websocket&sid=H75IeRaFmZqKFgqwAA' failed: Connection closed before receiving a handshake response
@xak2000 @jmls have you found a solution?
No. But I am using SockJS and when it cannot connet through websocket it emulates it through backup transports (xhr_streaming in my case). Not too convinient in dev mode as I don't see data frames in Chrome's Network tab. But until this bug will be fixed I have no alternatives.
@shakyShane, any progress of this issue? Do my example of this bug suit your needs?
I've seen that using the soket.io it works, also with the error above. So for the development environment is not a problem. In production, I use nginx.
socket.io also uses backup transports so if it works for you, it uses them instead of native websocket. But native websockets still doesn't work.
yes, I know...
This issue has been thorny for me too: https://github.com/chimurai/http-proxy-middleware/issues/37 As you see @chimurai already linked the issue.
Due to this issue, I'm now thinking of using something else other than brower-sync.
I had to move on from browsersync at work because of this issue. Would be nice to see a resolution.
I tried starting up two browersync instances: one for WS only and the other for file serving, reloading etc, but that ended up in port conflicts. Next option would be to start a node server only to forward WS traffic, but I'm researching on how to do this. Websockets are mainstream, and a simpler & default support for WS forwarding/proxying is very desired. No idea why browersync folks are not prioritizing this.
@redi-madhava the problem is that Browsersync is intercepting the upgrade server event.
so this works
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 8000 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
/**
* Setup proxy
* @type {*|exports|module.exports}
*/
var httpProxy = require('http-proxy');
var http = require('http');
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 8000
}
});
/**
* Setup static file server + proxy websockets
*/
var connect = require('connect')();
connect.use(require('serve-static')('app'));
var http = require('http');
var server = http.createServer(connect);
server.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
server.listen(3000);
But swap the last chunk for
var browserSync = require('browser-sync');
browserSync({
server: "app",
files: ["app/*.html", "app/css/*.css"]
}, function (err, bs) {
bs.server.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
});
and it all just breaks!
using the example above, 1 way would be to simply call the correct websocket url and not expect Browsersync to proxy it
// browser
var websocket = new WebSocket("ws://0.0.0.0:8000"); // don't use the same port as Browsersync
var int = setInterval(x => {
if (websocket.readyState === 1) {
clearInterval(int);
wsReady();
}
}, 1000);
function wsReady () {
websocket.send(JSON.stringify({
id: "client1"
}));
}
@shakyShane Thanks! I removed browser-sync and used above code to make it work!
@redi-madhava @shakyShane : sorry, I must be dumb - what do I need to change where to make this work ? thanks!
We use gulp, so my gulp task file for serving up html5 app looks like below based on the tips from @shakyShane above.
When "gulp serve" is run, it starts a node server listening on port 3000 and forwards websocket traffic to a websocket server running on localhost at 9090. It grabs 'upgrade' event in websocket handshake to use proxy created for localhost:9090.
conf below just contains some constants, for eg conf.paths.tmp=/.tmp, conf.paths.src=src and bower_components folder is at the same level as src folder.
Hope that helps!
'use strict';
var gulp = require('gulp'),
conf = require('./conf'),
gutil = require('gulp-util'),
http = require('http'),
httpProxy = require('http-proxy');
gulp.task('serve', ['watch'], function () {
httpProxyInit(conf.paths.tmp + '/serve');
});
var proxy = httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9090
}
});
proxy.on('error', function(e) {
gutil.log('error on proxying websocket');
gutil.log(e);
})
var httpProxyInit = function (baseDir) {
var connect = require('connect')();
connect.use(require('serve-static')(baseDir));
connect.use(require('serve-static')(conf.paths.src));
connect.use('/bower_components', require('serve-static')(conf.paths.src + '/../bower_components'));
var server = http.createServer(connect);
server.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
server.listen(3000);
};
I doesn't understand where is browser-sync
in this solution? The main problem is that browser-sync doesn't work with websocket proxy. Browser-sync is needed to auto-refresh page in browser after js-files was changed. Without browser-sync we could just use connect + http-proxy-middleware and all working fine except auto-refresh of browser.
To make it cleaner:
In my application I have:
1) a client
- bunch of static html files + js-files.
2) a server
- java application that running on some port (just one port for both http and websocket requests). So the server url is http://localhost:SERVER_PORT
In production client files just hosted by apache http server.
Also in apache config there are proxy_pass
from /api/**
url to http://localhost:SERVER_PORT/**
url.
This proxy_pass working fine for http requests and for ws requests.
So js-client can do http and ws requests to port 80 and transparently proxy_passed to java server.
On my development machine I made the same configuration but with browser-sync instead of apache to auto refresh browser page in case of some html/js files changed. Instead of apache's proxy_pass I used http-proxy-middleware
and all working fine except proxying of websocket.
As BrowserSync does not support WebSockets, a simple approach (apart of removing BS) is to serve WS server directly in dev mode.
e.g. with socket.io:
var ioSocket = io('http://localhost:9000', {
path: '/socket.io'
});
I hope this to be fixed soon.
Hi,
I am also having an issue with websockets in server mode. Here is my gulp config:
var proxyMiddleware = require('http-proxy-middleware');
module.exports = function () {
return {
injectChanges: true,
port: 3002,
server: {
baseDir: [
'.tmp',
'src
],
routes: {
'/bower_components': 'bower_components'
},
middleware: [
proxyMiddleware('/api/**', {target: 'http://localhost:8081', changeOrigin: true}),
proxyMiddleware('/ws/**', {target: 'http://localhost:8081', changeOrigin: false, ws: true, logLevel: 'debug'}),
]
},
open: false
};
};
It usually terminates with this error:
Connection closed before receiving a handshake response
It's a shame to leave browser-sync behind but this one's a blocker for me, the solution to provide websockets on a separate port causes issues for me as it breaks the same origin policy on cookies and prevents authentication over ws.
Any update on this?
Use http-proxy-middleware as WebSocket proxy. It works with browser-sync
.
But this issue suggests it doesn't work with websockets? https://github.com/chimurai/http-proxy-middleware/issues/15 How did you make it work?
const browserSync = require('browser-sync');
const proxy = require('http-proxy-middleware');
browserSync(
{
open : 'external',
host : MY_DOMAIN,
server :
{
baseDir : MY_OUTPUT_DIR,
middleware :
[
// Proxy WebSocket requests (identified by their /websocket pathname)
proxy(
'/websocket',
{
target : MY_WEBSOCKET_SERVER_URL,
ws : true
}
)
]
}
});
Thanks a lot!
Can browser sync also work if the json api and websockets are on the same port of my server, that I want to proxy to?
How would it look like then? :)
I have '/api' for api requests and '/ws' for websockets.
@ibc your example does not work! Notice that your example is effectively the same as the OP's.
Still does not work with browser-sync 2.26.x
@ibc your example does not work! Notice that your example is effectively the same as the OP's.
Yes, it does work.
I've logged an issue here (https://github.com/chimurai/http-proxy-middleware/issues/15) where I am having a problem with browser-sync, http-proxy-middleware and websockets
In a nutshell, I have this code
but get these errors :
and obviously, I can't get my websocket connected.
Am I missing something or is it a bug ?
thanks