让 socket.io、express 和 node-http2 通过 HTTP/2 进行通信

Posted

技术标签:

【中文标题】让 socket.io、express 和 node-http2 通过 HTTP/2 进行通信【英文标题】:Getting socket.io, express & node-http2 to communicate though HTTP/2 【发布时间】:2016-12-04 09:34:21 【问题描述】:

我使用 socket.io、node-http2 和 node.js 中的 express 编写了一个 Web Socket 服务器。服务器按预期工作,除了根据 Chrome 的 DevTools socket.io 的协商请求通过 HTTP/1.1(如下所示)这一事实。如果请求是使用 HTTP/2 发送的,则“协议”列应显示 h2

这只发生在 Chrome 中,其他浏览器使用正确的协议。

服务器代码(缩短):

var PORT = 8667,
    config = require('./config'),
    socketioserver = require('socket.io'),
    app = express(),
    https = require('http2'),
    cors = require('cors');

app.use(cors(function(req, callback)
    var corsOptions =  origin: false ;
    if (/^https:\/\/mlpvc-rr\.lc/.test(req.header('Origin')))
        corsOptions.origin = true;
    callback(null, corsOptions);
));

app.get('/', function (req, res) 
  res.sendStatus(403);
);

var server = https.createServer(
    cert: fs.readFileSync(config.SSL_CERT),
    key: fs.readFileSync(config.SSL_KEY),
, app);
server.listen(PORT);
var io = socketioServer.listen(server);
// ...

浏览器连接代码:

var conn = io('https://ws.'+location.hostname+':8667/',  reconnectionDelay: 5000 );
conn.on('connect', function()
    console.log('[WS] Connected');
);
conn.on('disconnect',function()
    console.log('[WS] Disconnected');
);

testssl.sh的输出:

要使 socket.io 请求通过 HTTP/2,我需要进行哪些更改?

【问题讨论】:

嗨。你能给我一个完整的例子吗?我很想仔细看看它。乍一看,它似乎与 websockets (socket.io 使用,并且不受 HTTP/2 支持)有关,但是您显示的请求 似乎 是普通的 Ajax... @dsign 服务器在github.com/ponydevs/MLPVC-WS开源 您使用的是哪个 SSL 库(openssl?),哪个版本支持 ALPN? ma.ttias.be/… @BazzaDP 我也不知道,我只使用默认安装的npm installconfig.* 变量只是指向特定 SSL 密钥/crt 文件的字符串。 是的,需要使用 testssl.sh 来代替。它是否也适用于其他浏览器(例如 Opera?)中的 h2?另外,您是否有任何防病毒软件拦截您的流量,通常会将您降级为 http/1.1 【参考方案1】:

正如 cmets 中所讨论的,Chrome 最近已停止允许 HTTP/2 的旧 NPN 协商,而是坚持使用较新的 ALPN 协议。有关更多信息,请参阅本文:https://ma.ttias.be/day-google-chrome-disables-http2-nearly-everyone-may-31st-2016/

所以你基本上需要 Node.js 来支持 ALPN,它看起来只在 v5 中添加:https://github.com/nodejs/node/pull/2564。另一种方法是通过网络服务器路由 NodeJs 调用,这更容易升级 OpenSSL(例如 nginx 或 Apache)以支持 HTTP/2 over ALPN。

您通过使用testssl.sh 程序确认这是问题所在,该程序确认不支持 ALPN 并且 Firefox 使用 HTTP/2。

【讨论】:

我的服务器在 Node.js 版本 4.4.7 上运行(根据this page)默认带有 OpenSSL 1.0.2,但如果我错了,请纠正我。 在我看来,ALPN 仅适用于节点 5:github.com/nodejs/node/pull/2564。看起来有谈话将其移植到 v4 但未完成:github.com/nodejs/node/pull/5983 谢谢你的信息,我会等到 v6 达到 LTS 之后。【参考方案2】:

有点晚了,但使用 Express4 和 Spdy (npm) 效果很好。

bin/www:

var app = require('../app');
var debug = require('debug')('gg:server');
var spdy = require('spdy');
var fs = require('fs');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var options = 
    key: fs.readFileSync(__dirname + '/server.key'),
    cert: fs.readFileSync(__dirname + '/server.crt')

var server = spdy.createServer(options, app);
var io = app.io
io.attach(server);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
...

app.js:

...
var app = express();
var io = app.io = require('socket.io')();
...

客户端截图:

【讨论】:

以上是关于让 socket.io、express 和 node-http2 通过 HTTP/2 进行通信的主要内容,如果未能解决你的问题,请参考以下文章

Express.js、bin/www 设置和 Socket.io

Socket.io SSL 连接与 Nginx 和 Express

使用 node express 生成器配置 socket.io

简单的游戏循环 Socket.io + Node.js + Express

将 socket.io 添加到现有的 Express 项目(前面有 React)

Socket.io 和 Express 4