Node.js 实现同端口监听HTTP与HTTPS

Node.js 实现同端口监听HTTP与HTTPS

之前一直在考虑一个简单的小优化。
同事们在本地启动 Node.js HTTPS 服务后,然后在浏览器里面访问服务的页面时,总是忘了先写协议名https,看到浏览器的出错提示时,才恍然大悟。

我就想实现一个功能:只监听一个端口,实现 HTTPS 与 HTTP 请求的监听,且自动将 HTTP 请求 Redirect 到 HTTPS

stackoverflow找到了对应的方法:https://stackoverflow.com/a/42019773

实现代码:

纯 Node.js 原生

const path = require('path');
const fs = require('fs');
const http = require('http');
const https = require('https');
const net = require('net');

/**
* Enable request handler being in HTTPS mode.
* @param handler {RequestListener}
* @param httpsConfig {{keyPath: string, certPath: string, [forceHttpsWhenEnabled]: boolean}}
* @return {Server & { https: Server, http: Server } }
*/
function enableHandlerHttps(handler, httpsConfig) {
  const options = {
    key: fs.readFileSync(path.resolve(httpsConfig.keyPath)),
    cert: fs.readFileSync(path.resolve(httpsConfig.certPath))
  };

  // If no need to forcibly redirect HTTP requests to same path HTTPS route.
  if (!httpsConfig.forceHttpsWhenEnabled) {
    // OK. Normal flow.
    return https.createServer(options, handler);
  }

  /**
   * Automatically redirect http request to https.
   * Only change the protocol.
   * @see https://stackoverflow.com/a/42019773
   */
  const net = require('net');
  const server = net.createServer(conn => {
    conn.once('data', buffer => {
      // Pause the socket.
      conn.pause();

      const firstByte = buffer[0];
      const httpReqFirstByteRange = [32, 127];
      const httpsReqFirstByte = 22;

      // Determine what proxy we need to use.
      let protocol;

      if (firstByte === httpsReqFirstByte) {
        protocol = 'https';
      } else if (
        httpReqFirstByteRange[0] < firstByte &&
        firstByte < httpReqFirstByteRange[1]
      ) {
        protocol = 'http';
      }

      const proxy = server[protocol];
      if (proxy) {
        // Push the buffer back onto the front of the data stream.
        conn.unshift(buffer);
        // Emit the socket to the HTTP(s) server.
        proxy.emit('connection', conn);
      }

      // As of NodeJS 10.x the socket must be
      // resumed asynchronously or the socket
      // connection hangs, potentially crashing
      // the process. Prior to NodeJS 10.x
      // the socket may be resumed synchronously.
      process.nextTick(() => {
        conn.resume();
      });
    });
  });

  // HTTP server proxy.
  server.http = http.createServer((req, res) => {
    // Force redirect.
    const host = req.headers['host'];
    // Use 301 - Moved Permanently.
    // To notify browsers that update the bookmarks and cache the redirection.
    res.writeHead(301, { Location: 'https://' + host + req.url });
    res.end();
  });

  // HTTPS server proxy.
  server.https = https.createServer(options, handler);

  return server;
}

我们项目使用的 Koa,所以联调上方的基础方法:

const app = new Koa();

const server = enableHandlerHttps(app.callback(), {
  keyPath: '', // HTTPS cert key path.
  certPath: '', // HTTPS cert file path.
  forceHttpsWhenEnabled: true // Enable.
});

server.listen(3000, function () {
  // Server already started.
});
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值