如何修复浏览器同步和 socket.io 冲突?
How to fix browser-sync & socket.io conflict?
我似乎在 browser-sync
中使用的套接字与我想在 socket.io
中使用的套接字发生冲突。我通过 gulp
任务(Aurelia CLI
默认项目附带)使用 browser-sync
。发生的情况是只有 browser-sync
套接字似乎可以工作,而服务器端主要使用的 socket.io
完全未读。我确实找到了 GitHub issue #71 which is addressing the problem, and also this other Github issue #241,其中都提到了名称空间的使用。但是我尝试了一些变化,即使它们 运行 有错误,它也没有解决我的任何问题。
我主要在 Aurelia CLI
项目中使用 Gulp
和 browser-sync
,而后端是 NodeJS
和 Koa
。 socket.io@1.6.0
而 browser-sync@2.13.0
的版本使用的端口是前端:4000,后端:5000。
这是文件列表
Gulp - run.js
import gulp from 'gulp';
import browserSync from 'browser-sync';
import historyApiFallback from 'connect-history-api-fallback/lib';
import project from '../aurelia.json';
import build from './build';
import {CLIOptions} from 'aurelia-cli';
import url from 'url';
import proxy from 'proxy-middleware';
var portBackEnd = 5000;
var portFrontEnd = 4000;
var proxyOptionsAccessControl = function(req,res, next){
res.setHeader('Access-Control-Allow-Origin', '*');
next();
};
var proxyOptionsApiRoute = url.parse(`http://localhost:${portBackEnd}/api`);
proxyOptionsApiRoute.route = '/api';
var proxyOptionsAuthRoute = url.parse(`http://localhost:${portBackEnd}/auth`);
proxyOptionsAuthRoute.route = '/auth';
function log(message) {
console.log(message); //eslint-disable-line no-console
}
function onChange(path) {
log(`File Changed: ${path}`);
}
function reload(done) {
browserSync.reload();
done();
}
let serve = gulp.series(
build,
done => {
browserSync({
online: false,
open: false,
port: portFrontEnd,
notify: true,
logLevel: 'silent',
server: {
baseDir: ['.'],
middleware: [
proxyOptionsAccessControl,
proxy(proxyOptionsApiRoute),
proxy(proxyOptionsAuthRoute)
]
},
socket: {
domain: 'localhost:4000',
namespace: '/browsersync'
}
}, function(err, bs) {
let urls = bs.options.get('urls').toJS();
log(`Application Available At: ${urls.local}`);
log(`BrowserSync Available At: ${urls.ui}`);
done();
});
}
);
let refresh = gulp.series(
build,
reload
);
let watch = function() {
gulp.watch(project.transpiler.source, refresh).on('change', onChange);
gulp.watch(project.markupProcessor.source, refresh).on('change', onChange);
gulp.watch(project.cssProcessor.source, refresh).on('change', onChange);
};
let run;
if (CLIOptions.hasFlag('watch')) {
run = gulp.series(
serve,
watch
);
} else {
run = serve;
}
export default run;
使用 Socket.io-Client with Aurelia(前端)
import io from 'socket.io-client';
var socket = io('http://localhost:5000');
// also tried with a namespace instead
//var socket = io('/todo-socket');
// ...
socket.on("todo_update", data => {
let pos = arrayFindObjectIndex(this.items, 'id', data.id);
if(pos >= 0) {
this.items.splice(pos, 1, data);
this.itemDoneCount = this.items.filter(x => x.completed).length;
}
});
带有 Koa 的 NodeJS(后端)
// Middlewares
const app = require('koa')();
const serve = require('koa-static');
const api = require('koa-router')();
const assertTimeout = require('co-assert-timeout');
const http = require('http');
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server);
// or without namespace: io.sockets.on("connection", function(socket) {
var tsp = io.of('/todo-socket');
tsp.on("connection", function(socket) {
console.log('A new WebSocket client connected with ID: ' + socket.client.id);
})
.error(function(err){
console.log("Changefeeds Failure: ", err);
return null;
});
socket.on('disconnect', function(data) {
console.log('A WebSocket client disconnnected with ID: ' + socket.client.id);
return null;
});
我试过使用和不使用命名空间,这似乎没有任何改变。我提到了 browser-sync - socket option
编辑
从更多的测试来看,服务器端的 socket.io
实际上似乎根本不起作用。它不会从服务器输出 console.log('connected with ID: ' + socket.client.id)
,但是它也不会显示或抛出任何错误。服务器端的代码曾经使用 WebPack
,所以我真的认为它与 browserSync
冲突有关。
经过几天的努力,我让它开始工作了。我不得不在 2 个不同的地方更改名称空间,在 browserSync
选项中以及在客户端 (Aurelia) 中我使用另一个必须是不同名称空间的套接字。最后,必须使用 io.of('/clientNamespace')
.
调用 NodeJS Koa
一个重要说明,请注意 browserSync
和客户端名称空间 必须 以完整的 URL:port+namespace (ex.: http://localhost:4000/namespaceBs
), but 在服务器端,namespace 只与不带 URL 的名字一起使用 (ex .: /namespaceClient
).
如果你想知道,我称它为 todoSocket
因为它是一个 TODO 应用程序
为了简短起见,我更改了以下代码:
Gulp - run.js
let serve = gulp.series(
build,
done => {
browserSync({
online: false,
open: false,
port: portFrontEnd,
notify: true,
logLevel: 'silent',
server: {
baseDir: ['.'],
middleware: [
proxyOptionsAccessControl,
proxy(proxyOptionsApiRoute),
proxy(proxyOptionsAuthRoute)
]
},
socket: {
namespace: `http://localhost:4000/bs` // <<<< HERE >>>>
}
}, function(err, bs) {
let urls = bs.options.get('urls').toJS();
log(`Application Available At: ${urls.local}`);
log(`BrowserSync Available At: ${urls.ui}`);
done();
});
}
);
使用 Socket.io-Client with Aurelia(前端)
import io from 'socket.io-client';
var socket = io('http://localhost:5000/todo-socket'); // <<<< HERE >>>>
NodeJS 与 Koa
const http = require('http');
const server = http.createServer(app.callback());
const io = require('socket.io')(server);
// Load config for RethinkDB and koa
const config = require("./config");
// attach on the todo-socket namespace, only the name (not the full URL)
var todoSocket = io.of('/todo-socket'); // <<<< HERE >>>>
todoSocket.on("connection", function(socket) { // <<<< AND HERE >>>>
console.log('A new TODO WebSocket namespace client connected with ID: ' + socket.client.id);
});
对于遇到此 post 的任何其他人,以上内容对他们不起作用。我已经 proxy
在我的配置中像这样设置
proxy: {
target: `${protocol}://localhost:${SERVER__PORT}`,
},
最终让两个套接字一起工作的修复只是添加 ws
proxy: {
target: `${protocol}://localhost:${SERVER__PORT}`,
ws: true,
},
我似乎在 browser-sync
中使用的套接字与我想在 socket.io
中使用的套接字发生冲突。我通过 gulp
任务(Aurelia CLI
默认项目附带)使用 browser-sync
。发生的情况是只有 browser-sync
套接字似乎可以工作,而服务器端主要使用的 socket.io
完全未读。我确实找到了 GitHub issue #71 which is addressing the problem, and also this other Github issue #241,其中都提到了名称空间的使用。但是我尝试了一些变化,即使它们 运行 有错误,它也没有解决我的任何问题。
我主要在 Aurelia CLI
项目中使用 Gulp
和 browser-sync
,而后端是 NodeJS
和 Koa
。 socket.io@1.6.0
而 browser-sync@2.13.0
的版本使用的端口是前端:4000,后端:5000。
这是文件列表
Gulp - run.js
import gulp from 'gulp';
import browserSync from 'browser-sync';
import historyApiFallback from 'connect-history-api-fallback/lib';
import project from '../aurelia.json';
import build from './build';
import {CLIOptions} from 'aurelia-cli';
import url from 'url';
import proxy from 'proxy-middleware';
var portBackEnd = 5000;
var portFrontEnd = 4000;
var proxyOptionsAccessControl = function(req,res, next){
res.setHeader('Access-Control-Allow-Origin', '*');
next();
};
var proxyOptionsApiRoute = url.parse(`http://localhost:${portBackEnd}/api`);
proxyOptionsApiRoute.route = '/api';
var proxyOptionsAuthRoute = url.parse(`http://localhost:${portBackEnd}/auth`);
proxyOptionsAuthRoute.route = '/auth';
function log(message) {
console.log(message); //eslint-disable-line no-console
}
function onChange(path) {
log(`File Changed: ${path}`);
}
function reload(done) {
browserSync.reload();
done();
}
let serve = gulp.series(
build,
done => {
browserSync({
online: false,
open: false,
port: portFrontEnd,
notify: true,
logLevel: 'silent',
server: {
baseDir: ['.'],
middleware: [
proxyOptionsAccessControl,
proxy(proxyOptionsApiRoute),
proxy(proxyOptionsAuthRoute)
]
},
socket: {
domain: 'localhost:4000',
namespace: '/browsersync'
}
}, function(err, bs) {
let urls = bs.options.get('urls').toJS();
log(`Application Available At: ${urls.local}`);
log(`BrowserSync Available At: ${urls.ui}`);
done();
});
}
);
let refresh = gulp.series(
build,
reload
);
let watch = function() {
gulp.watch(project.transpiler.source, refresh).on('change', onChange);
gulp.watch(project.markupProcessor.source, refresh).on('change', onChange);
gulp.watch(project.cssProcessor.source, refresh).on('change', onChange);
};
let run;
if (CLIOptions.hasFlag('watch')) {
run = gulp.series(
serve,
watch
);
} else {
run = serve;
}
export default run;
使用 Socket.io-Client with Aurelia(前端)
import io from 'socket.io-client';
var socket = io('http://localhost:5000');
// also tried with a namespace instead
//var socket = io('/todo-socket');
// ...
socket.on("todo_update", data => {
let pos = arrayFindObjectIndex(this.items, 'id', data.id);
if(pos >= 0) {
this.items.splice(pos, 1, data);
this.itemDoneCount = this.items.filter(x => x.completed).length;
}
});
带有 Koa 的 NodeJS(后端)
// Middlewares
const app = require('koa')();
const serve = require('koa-static');
const api = require('koa-router')();
const assertTimeout = require('co-assert-timeout');
const http = require('http');
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server);
// or without namespace: io.sockets.on("connection", function(socket) {
var tsp = io.of('/todo-socket');
tsp.on("connection", function(socket) {
console.log('A new WebSocket client connected with ID: ' + socket.client.id);
})
.error(function(err){
console.log("Changefeeds Failure: ", err);
return null;
});
socket.on('disconnect', function(data) {
console.log('A WebSocket client disconnnected with ID: ' + socket.client.id);
return null;
});
我试过使用和不使用命名空间,这似乎没有任何改变。我提到了 browser-sync - socket option
编辑
从更多的测试来看,服务器端的 socket.io
实际上似乎根本不起作用。它不会从服务器输出 console.log('connected with ID: ' + socket.client.id)
,但是它也不会显示或抛出任何错误。服务器端的代码曾经使用 WebPack
,所以我真的认为它与 browserSync
冲突有关。
经过几天的努力,我让它开始工作了。我不得不在 2 个不同的地方更改名称空间,在 browserSync
选项中以及在客户端 (Aurelia) 中我使用另一个必须是不同名称空间的套接字。最后,必须使用 io.of('/clientNamespace')
.
NodeJS Koa
一个重要说明,请注意 browserSync
和客户端名称空间 必须 以完整的 URL:port+namespace (ex.: http://localhost:4000/namespaceBs
), but 在服务器端,namespace 只与不带 URL 的名字一起使用 (ex .: /namespaceClient
).
如果你想知道,我称它为 todoSocket
因为它是一个 TODO 应用程序
为了简短起见,我更改了以下代码:
Gulp - run.js
let serve = gulp.series(
build,
done => {
browserSync({
online: false,
open: false,
port: portFrontEnd,
notify: true,
logLevel: 'silent',
server: {
baseDir: ['.'],
middleware: [
proxyOptionsAccessControl,
proxy(proxyOptionsApiRoute),
proxy(proxyOptionsAuthRoute)
]
},
socket: {
namespace: `http://localhost:4000/bs` // <<<< HERE >>>>
}
}, function(err, bs) {
let urls = bs.options.get('urls').toJS();
log(`Application Available At: ${urls.local}`);
log(`BrowserSync Available At: ${urls.ui}`);
done();
});
}
);
使用 Socket.io-Client with Aurelia(前端)
import io from 'socket.io-client';
var socket = io('http://localhost:5000/todo-socket'); // <<<< HERE >>>>
NodeJS 与 Koa
const http = require('http');
const server = http.createServer(app.callback());
const io = require('socket.io')(server);
// Load config for RethinkDB and koa
const config = require("./config");
// attach on the todo-socket namespace, only the name (not the full URL)
var todoSocket = io.of('/todo-socket'); // <<<< HERE >>>>
todoSocket.on("connection", function(socket) { // <<<< AND HERE >>>>
console.log('A new TODO WebSocket namespace client connected with ID: ' + socket.client.id);
});
对于遇到此 post 的任何其他人,以上内容对他们不起作用。我已经 proxy
在我的配置中像这样设置
proxy: {
target: `${protocol}://localhost:${SERVER__PORT}`,
},
最终让两个套接字一起工作的修复只是添加 ws
proxy: {
target: `${protocol}://localhost:${SERVER__PORT}`,
ws: true,
},