问题: 在本地启动egg.js,使用egg-socket.io,能正常连接到websocket,而放到docker中运行,则无法连接得上,提示Session ID unknown,http报400错误。
原因: 之所以在本地能成功连接,是因为本地启动方式为egg-bin dev
,会针对本地开发做很多处理,而在docker中启动脚本是egg-scripts start
,如果没有在sticky模式下运行,则会出现无法正常连接,同时报错。
值得注意点是Egg框架是以 Cluster 方式启动的,而socket.io 协议实现需要 sticky 特性支持,否则在多进程模式下无法正常工作。
由于socket.io 的设计,在多进程中服务器必须在sticky
模式下工作,故需要给 startCluster 传递 sticky 参数。
添加之后再运行就连接正常了。
修改package.json
中npm scripts
脚本:
{"scripts":{"dev":"egg-bin dev --sticky","start":"egg-scripts start --sticky"}}
Nginx 配置
location / { # 这两行需要开启 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://127.0.0.1:7001; }
简单的说,
其中:
const cluster=require('cluster');const http=require('http');const numCPUs=require('os').cpus().length;if(cluster.isMaster){// Fork workers.for(let i=0; i< numCPUs; i++){ cluster.fork();} cluster.on('exit',function(worker, code, signal){ console.log('worker '+ worker.process.pid+' died');});}else{// Workers can share any TCP connection// In this case it is an HTTP server http.createServer(function(req, res){ res.writeHead(200); res.end("hello world\n");}).listen(8000);}