关于端口
形如下面的代码:
const Koa = require('koa');
const app = new Koa();
// TODO: app.use(...);
app.listen(3000);
koa 通过 3000 端口响应 HTTP,我们要新加的 WebSocketServer 还能否使用 3000 端口?
答案是可以。
虽然 WebSocketServer 可以使用别的端口,但是统一端口有个最大的好处:HTTP 和 WebSocket 都使用标准的 80 和 443 端口,不需要暴露新的端口,也不需要修改防火墙规则。
那么,在 3000 端口被 koa 占用后,WebSocketServer 如何使用该端口?
实际上,3000 端口并非由 koa 监听,而是 koa 调用 Node 标准的 http 模块创建的 http.Server 监听的。koa 只是把响应函数注册到该 http.Server 中了。
类似的,WebSocketServer 也可以把自己的响应函数注册到 http.Server 中,这样,同一个端口,根据协议,可以分别由 koa 和 ws 处理:
扩展:
const http = require(‘http’);
const https = require(‘https’);
http.createServer(app.callback()).listen(3000);
https.createServer(app.callback()).listen(3001);
app.listen(…) 实际上是以下代码的语法糖。
app.callback() 返回一个适合 http.createServer() 方法的回调函数用来处理请求。您也可以使用这个回调函数将您的app挂载在 Connect/Express 应用上。
联袂WebSocket
// 服务端:app.js
const Koa = require('koa');
const WebSocket = require('ws');
// npm install --save ws
const app = new Koa();
let server = app.listen('3000');
console.log('应用在3000端口启动...');
const WebSocketServer = WebSocket.Server;
let wss = new WebSocketServer({ server: server });
wss.on('connection', function (ws) {
console.log(`[SERVER] connection()`);
ws.on('message', function (message) {
console.log(`[SERVER] Received: ${message}`);
ws.send(`ECHO: ${message}`, (err) => {
if (err) {
console.log(`[SERVER] error: ${err}`);
}
});
});
});
参考资料:
1、https://github.com/websockets/ws
2、https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
3、和 ws(推荐) 一样,socket.io 也是很常用的WebSocket库。
js.js
接着在命令行输入 npm start 或者 node app.js 即可运行 app.js,也可以在编辑器 VS Code 中执行 app.js 。 或者通过pm2让程序常驻系统。
Nginx配置反向代理
配置示例如下:
server {
listen 80;
server_name localhost;
# 处理静态资源文件:
location ^~ /static/ {
root /path/to/ws-with-koa/static;
}
# 处理WebSocket连接:
location ^~ /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 其他所有请求:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
注意:如果你对普通 web 请求不想做反向代理,请把上面 location / 的规则改为如下代码,或者使用 nginx 默认规则,改完后要记得重启 nginx。
location / {
index index.html;
}
结果演示及问题说明
我们在浏览器打开站点localhost,再打开开发人员工具,刷新一下页面,ws请求、响应如下截图:
因为我们在Nginx配置了反向代理,所以,上面的 js.js 文件里的:
this.ws = new WebSocket('ws://localhost:3000/ws/chat');
可以改为:
this.ws = new WebSocket('ws://localhost/ws/');
这样,从而只需要对外放开 80 端口就行了。
如果在 HTML 里建立不了 WebSocket 连接,可能的原因:
- Nodejs 运行 Koa 程序本身就出错了
- 以为用了反向代理,就用 http 协议了,如 ‘http://localhost/ws/’
更多的原因,请分别进行 Koa 调试、web浏览器调试。比起十几二十年前,现在在敲代码、调试上简直是太方便了。