socket.io库如何配置socket及express和http/2

socket.io库如何配置socket及express和http/2

目录

socket.io库如何配置socket及express和http/2

一、配置ms server 2022操作系统上的证书确保web服务器能够访问https

二、检测证书以查看http协议的支持信息及操作系统支持的默认密码套件的默认排序

三、配置MS操作系统的HTTP/2协议

四、根据第二步的证书评估报告的证书支持密码套件及其顺序配置服务器的SSL密码套件顺序

五、最后是你的socket.io应用服务

5.1、安装包及node.js命令行脚本配置package.json

5.2、编写服务端代码server.cjs

5.3、执行效果

5.4、小结-重要的四个环节

六、关于微信小程序等微信环境中使用上述服务

6.1、微信小程序“非webview载入h5页面”仅支持443或全局指定端口

6.2、基于443端口的限制你需要将socket应用部署在你的代理服务器的后面

6.3、修改你的前端代码的"浏览器请求启动器链initiator"

本博客相关博文 

喜欢就点赞、收藏,鼓励我坚持更多原创技术写作


        5月将ms server 2012直接升维越级换成了ms server 2022,tls/ssl证书又多了一些坑。于此同时,socket.io库及express的web服务也有了更多的讲究,本文就这4个方面的问题进行论述,以期能帮助你越过我们遇到的“坑”,帮你节省一两天时间。

        本文详细介绍了如何在MS Server 2022上配置socket.io库和express服务以支持HTTPS和Socket访问,特别是使用TrustAsia的G2版本证书。文章分为四个主要部分:首先,配置MS Server 2022操作系统上的证书以确保Web服务器能够访问HTTPS;其次,检测证书以查看HTTP协议的支持信息及操作系统支持的默认密码套件的默认排序亚数信息;第三,配置MS操作系统的HTTP/2协议,确保与客户端浏览器的兼容性;最后,详细说明了如何配置socket.io应用服务,包括安装包及Node.js命令行脚本配置,以及编写服务端代码。文章强调了四个关键环节,包括关闭HTTP/2协议、正确加载私钥和证书、确保客户端设备安装正确的证书版本,以避免常见的SSL/TLS错误。通过这些步骤,可以帮助开发者顺利部署和运行基于HTTPS和Socket的Web服务。最后,关于微信小程序中使用上述服务,给出了建议的方案。

一、配置ms server 2022操作系统上的证书确保web服务器能够访问https

        (略)。详请参考我的博客:

        《再谈SSL证书及Https应用服务器访问》、《最新ssl证书申请与安装配置2024版》。

二、检测证书以查看http协议的支持信息及操作系统支持的默认密码套件的默认排序

亚数信息-SSL/TLS安全评估报告

并非你的SSL一定能支持http/2协议,这取决于你对购买的证书的【配置】

如果SSL证书配置正确:

三、配置MS操作系统的HTTP/2协议

https://learn.microsoft.com/zh-cn/troubleshoot/windows-server/windows-security/deploy-custom-cipher-suite-ordering

        如果你的证书的配置并不支持HTTP/2协议,请配置并关闭它,重启服务器生效。因为支持http/2协议的浏览器客户端截止2025年已经非常盛行;客户端浏览器会主动尝试以http/2协议去协商请求服务器————而服务器此时没有配置http/2协议那么ms server 2016版及其以上的版本默认是开启的————会造成客户端与服务器协商第1次【握手失败】

四、根据第二步的证书评估报告的证书支持密码套件及其顺序配置服务器的SSL密码套件顺序

          多余密码套件的配置,你配了也不起作用,反而对tcp通讯会带来副作用。

五、最后是你的socket.io应用服务

5.1、安装包及node.js命令行脚本配置package.json

{
  "name": "server",
  "version": "1.0.0",
  "description": "Cannot find module node:internal/modules/cjs/loader:1215 ",
  "main": "index.js",
  "scripts": {
    "start": "node src/server.cjs",
    "tls8080": "node src/server.cjs",
    "tlsstart": "node src/nodeOption.cjs --inspect=www.cpuofbs.com:8080  & node src/server.cjs",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "packageManager": "pnpm@10.6.2",
  "dependencies": {
    "cjs": "^0.0.11",
    "preload": "^0.1.0",
    "express": "^4.21.2",
    "socket.io": "^4.8.1"
  },
  "devDependencies": {
    "@types/express": "^5.0.1"
  }
}

        这是你最终启动服务的命令:

        npm run tls8080

5.2、编写服务端代码server.cjs

//  server.cjs
//关键1————对于ms server 2016以上的服务器os,应当配置关闭http/2协议————因为支持http/2协议的浏览器客户端截止2025年已经非常盛行
//    客户端浏览器会主动尝试以http/2协议去协商请求服务器————而服务器此时没有配置http/2协议那么ms server 2016版及其以上的版本默认是开启的————会造成客户端与服务器协商第1次【握手失败】
//    如何在 Windows Server 2016 中部署自定义密码套件排序 https://learn.microsoft.com/zh-cn/troubleshoot/windows-server/windows-security/deploy-custom-cipher-suite-ordering 
//关键2————npm run tls8080  即node src/server.cjs
const os = require('os');
const express = require('express'); 
const createServerHttp = require('http').createServer;
const createServerHttps = require('https').createServer;
const { Server } = require('socket.io');
const {tlsCipherList} = require('./tls-cipher-list');
const fs = require('node:fs');
const crypto = require('crypto');

const serverLocalIP = '10.1.20.6';

// 计算服务器本机IP:
function getLocalIP() { // 不适用于v8环境只适用node环境
  const networkInterfaces = os.networkInterfaces();
  for (const name of Object.keys(networkInterfaces)) {
      for (const net of networkInterfaces[name]) {
          if (net.family === 'IPv4' && !net.internal) {
              return net.address;
          }
      }
  }
  return null; // 如果没有找到合适的IP地址,返回null
};
const calcLocalIP = getLocalIP();
// 判断是否为生产环境:
const isProductionEnv = calcLocalIP===serverLocalIP?true:false;
const protocal = isProductionEnv?"https:":"http:"; // 相当于v8环境的window.Location.protocol
const host = isProductionEnv?"你的域名":calcLocalIP;
const corsAllowOrigin = protocal+'//'+host;
const createServerEnv = isProductionEnv?createServerHttps:createServerHttp;

const WhiteListHost = ['你的域名','cpuofbs.com'];
const corsNeedHeaders = `HeadersStrict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: no-referrer,no-referrer-when-downgrade,origin-when-cross-origin,strict-origin-when-cross-origin
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method`;
// 用于配置客制化请求的响应头:
const corsResHeaders = `
`;
const headersNeedExposed = `Access-Control-Allow-Origin: ${corsAllowOrigin}
Access-Control-Allow-Credentials: true
access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: User-Agent, Accept-Encoding, Accept-Language, Content-Type,Content-Disposition,Content-Transfer-Encoding,Accept, Authorization, Credentials, sessionID, signature, myBody-DataType,
Host, Origin, Cache-Control, Pragma, Cookie,Range,Content-Range,Content-Length,
Connection, Sec-WebSocket-Version, Sec-WebSocket-Key, Sec-WebSocket-Extensions, Sec-WebSocket-Accept
`;
const exposedHeaders = (corsAllowOrigin in WhiteListHost)?corsNeedHeaders:'';
// 配置Socket.IO
const cors =  {
  origin: corsAllowOrigin, //'*',注意*是非常错误的做法
  allowedHeaders: headersNeedExposed,
  exposedHeaders: exposedHeaders,
  methods: ['GET', 'POST'],
};
console.log(`isProductionEnv`,isProductionEnv,`cors=`,cors);
// 尝试加载私钥和证书
let httpsServerOptions = { // require("engine-io/server").ServerOptions
  // https://你的域名:8080/socket.io/?EIO=4&transport=polling&t=othzpiv7 
  //  连接connection默认polling轮询客户端浏览器会自动最多6次将停止执行socket.io-client客户端的轮询请求:
  //transports: ["polling"], // 只能polling或不给参数轮询 错误取决于socket.io-client客户端的配置需要一致transports: ["websocket"],//GET http://192.168.3.242:8080/socket.io/?EIO=4&transport=polling&t=c19eezxn 400 (Bad Request)
  allowEIO3: true, // 
  cors: cors // 跨域选项
};
if (isProductionEnv===true) {
  console.log(`tlsCipherList=`,tlsCipherList);
  // 从文件加载私钥和证书
  const key = fs.readFileSync('./src/cpuofbs.com.key'); // net::SSL版本错误或密码错误
  const cert = fs.readFileSync('./src/cpuofbs.com.pem.cer');// cpuofbs.com.pem.cer我导出的服务端部署的自己的证书  net::SSL版本错误或密码错误
  const ca = fs.readFileSync('./src/cpuofbs.com_bundle.crt'); // 证书链
  //关键2【最为关键的】————
  // 若有中间证书——caTrustAsia.pem.cer是我导出的服务端部署的亚信证书不含密钥
  Object.assign(httpsServerOptions, {
    key: key, // net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH
    cert: cert,
    ca: ca,
    // minVersion: 'TLSv1.2', // 可以依据服务器本身的Schannel通道中的协议优先顺序
    // ciphers: tlsCipherList//+':'+'HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA'//要不然不配要不然就要正确
  })
} else {};

console.log(`httpsServerOptions=`,httpsServerOptions);

// 创建express应用
const app = express();
let httpServer;
try {
  httpServer = isProductionEnv?createServerEnv(httpsServerOptions,app):createServerEnv(app); // createServerEnv(app); 
} catch (error) {
  console.error('启动expresse的web服务错误:', error);
}
const port = 8080;  // 来超 3000; 8080

const io = new Server(httpServer, httpsServerOptions); // Server:socket.io

// 手动的mock数据:
const merchants = [
  "商家1",
  "商家2",
  "商家3",
  "商家4",
  "商家5",
  "商家6",
]

function generateSalesData() { 
  return merchants.map(name => {
    return {
      name,
      value: Math.floor(Math.random() * 200) + 100
    }
  })
}
// 作为测试————可以激活https端口8080它会触发底层tcp的io在8080上的下面的io连接connection 
// 测试访问: https://你的域名:8080/:
//   看看8080端口上的证书是否存在有问题
// app.get('/', (req, res) => {
//   res.send('Hello World');
// });

// websocket生产环境socket.io连接提示net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH https://www.baidu.com/s?wd=socket.io%E8%BF%9E%E6%8E%A5%E6%8F%90%E7%A4%BAnet%3A%3AERR_SSL_VERSION_OR_CIPHER_MISMATCH&rsv_spt=1&rsv_iqid=0xcaed957500017eea&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_dl=tb&rsv_enter=1&oq=net%253A%253A%2526gt%253BRR_SSL_V%2526gt%253BRSION_OR_%2526lt%253BIPH%2526gt%253BR_MISMAT%2526lt%253BH&rsv_t=29efJdI0oP%2FcnIejTtdwtxQ61OTMk1fEJSHFW2nswdO8OLZhJkerPQIL%2BKVmYyTnlgND&rsv_btype=t&inputT=19708&rsv_pq=a60af12a000666ed&rsv_sug3=88&rsv_sug1=40&rsv_sug7=100&rsv_sug2=0&rsv_sug4=19708 
io.on('connection', (socket) => { 
  //const reqPath = socket.request.url;
  //const headersDistinct = socket.request.headersDistinct;
  console.log('客户端已经连接:' + socket.id);//  /socket.io/?EIO=4&transport=polling&t=ayk800lz
  socket.emit('salesData', generateSalesData());

  const interval = setInterval(() => { 
    socket.emit('salesData', generateSalesData());
  }, 5000);

  socket.on('disconnect', () => { 
    console.log('客户端已经断开:' + socket.id);
    clearInterval(interval);
  });
});

//关键4————客户端的设备不能安装你的证书【或者安装了与你的证书及证书链不吻合的证书版本】
//   【以上关键4点】或没做到将导致————net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH
httpServer.listen(port, () => { 
  const httpServerListenUrl = `${corsAllowOrigin}:${port}`;
  console.log(`web服务已启动 监听地址=`,httpServerListenUrl);
  // console.log(`calcLocalIP=`,calcLocalIP,`serverLocalIP=`,serverLocalIP,`是否生产环境isProductionEnv=`,isProductionEnv,`web服务监听地址=`,httpServerListenUrl);
});

5.3、执行效果

5.4、小结-重要的四个环节

        关键1————对于ms server 2016以上的服务器os,如果证书未能成功配置HTTP/2,应当配置关闭http/2协议————因为支持http/2协议的浏览器客户端截止2025年已经非常盛行。 客户端浏览器会主动尝试以http/2协议去协商请求服务器————而服务器此时没有配置http/2协议那么ms server 2016版及其以上的版本默认是开启的————会造成客户端与服务器协商第1次【握手失败】。

        如何在 Windows Server 2016 中部署自定义密码套件排序 https://learn.microsoft.com/zh-cn/troubleshoot/windows-server/windows-security/deploy-custom-cipher-suite-ordering

        关键2————npm run tls8080  即node src/server.cjs

        注意package.json中 cjs及preload包的安装

        关键3【最为关键的】————

        从文件加载私钥和证书:

  const key = fs.readFileSync('./src/cpuofbs.com.key'); // net::SSL版本错误或密码错误

  const cert = fs.readFileSync('./src/cpuofbs.com.pem.cer');// cpuofbs.com.pem.cer我导出的服务端部署的自己的证书  net::SSL版本错误或密码错误

  const ca = fs.readFileSync('./src/cpuofbs.com_bundle.crt'); // 证书链

        若有中间证书——caTrustAsia.pem.cer是我导出的服务端部署的亚信证书不含密钥

  Object.assign(httpsServerOptions, {

    key: key, // net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH

    cert: cert,

    ca: ca,

    // minVersion: 'TLSv1.2', // 可以依据服务器本身的Schannel通道中的协议优先顺序

    // ciphers: tlsCipherList  //不要配

  });

        关键4————客户端的设备不能安装你的证书【或者安装了与你的证书及证书链不吻合的证书版本】

六、关于微信小程序等微信环境中使用上述服务

6.1、微信小程序“非webview载入h5页面”仅支持443或全局指定端口

6.2、基于443端口的限制你需要将socket应用部署在你的代理服务器的后面

        比如使用你自己的服务器作为上述socket服务的代理服务,或使用nginx代理服务。

6.3、修改你的前端代码的"浏览器请求启动器链initiator"

        5.3的前端代码的"浏览器请求启动器链initiator"如下所示:

       如上图所示,wss://www.cpuofbs.com:8080/socket.io/ 请求是由其最邻近的父请求 https://www.cpuofbs.com:8080/socket.io所触发的。

       而请求https://www.cpuofbs.com:8080/socket.io在server.cjs服务上监听,这就导致了【微信小程序中使用默认端口的限制】而服务访问。

       所以你需要修改你的前端代码,让请求 https://www.cpuofbs.com:8080/socket.io在端口443的应用服务A下触发https://www.cpuofbs.com/socket.io 。然后由应用服务A内部路由拦截将请求【转发给端口8080】https://www.cpuofbs.com:8080/socket.io,从而解决问题。

本博客相关博文 

         《再谈SSL证书及Https应用服务器访问》、《最新ssl证书申请与安装配置2024版》。

喜欢就点赞、收藏,鼓励我坚持更多原创技术写作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专讲冷知识

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值