惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
罗磊的独立博客
M
MIT News - Artificial intelligence
G
Google Developers Blog
V
V2EX
D
Docker
博客园_首页
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
WordPress大学
WordPress大学
T
Tailwind CSS Blog
博客园 - 司徒正美
J
Java Code Geeks
L
LangChain Blog
博客园 - 三生石上(FineUI控件)
B
Blog RSS Feed
博客园 - 【当耐特】
小众软件
小众软件
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - Franky

ALBERTAZ

How I Built a Scannable 3D QR Code Generator | Every QR Code OpenStreetMap Data Pipeline for Canvas Maps | EveryCityMap 每日关灯:今天这题理论最少 8 步 OpenStreetMap + Canvas 城市地图实践:EveryCityMap 的五个工程取舍 OpenStreetMap + Canvas 城市地图实践:EveryCityMap 的五个工程取舍 博客 CDN 迁移到 Cloudflare R2 博客 CDN 迁移到 Cloudflare R2 Migrate my website to SvelteKit2 Migrate my website to SvelteKit2 漫谈编辑器 漫谈编辑器 Pure ESM package Pure ESM package 又折腾博客了 又折腾博客了 Rewrite my website with Svelte Rewrite my website with Svelte 字体漫谈-网站字体最佳实践 字体漫谈-网站字体最佳实践 你不知道的 Web Components - 现状 你不知道的 Web Components - 现状 你不知道的 Web Components - 过去和未来 你不知道的 Web Components - 过去和未来 Node 应用本地 HTTPS docker 部署 Gatsby 应用 docker 部署 Gatsby 应用 再提示『您的磁盘几乎已满』算我输 再提示『您的磁盘几乎已满』算我输 G6-Mobile 的前世今生 G6-Mobile 的前世今生
Node 应用本地 HTTPS
https://www.albertaz.com/about · 2022-03-09 · via ALBERTAZ

为了方便做一些模拟验证,我们有时候需要在本地起 https 环境,比如调试验证一些协议是 https 的内嵌页面。

实现自签名证书

最先想到的方法当然是自签名证书,自己签发证书和密钥之后,启动一个 https 服务即可。这块网上资料比较杂乱,下面记录一下过程。

安装 openssl

首先本地要安装一下 openssl,用来生成证书。mac 上的话 homebrew 安装即可,我本地安装过了,查看一下版本:

Bash
┌─(~)─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s004)─┐
└─(14:31:29)──> openssl version                                                                                                                                                         ──(三, 309)─┘
LibreSSL 2.8.3

先用 openssl 生成私钥

Bash
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:14:47)──> openssl genrsa -out server.key 1024                                                                                                                                     ──(五, 211)─┘
Generating RSA private key, 1024 bit long modulus
....++++++
.............++++++
e is 65537 (0x10001)

可以看到 server.key已经有了:

Bash
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:15:08)──> ll                                                                                                                                                                      ──(五, 211)─┘
total 8
drwxr-xr-x  11 albert  staff   352B  2  8 14:03 code
drwxr-xr-x   8 albert  staff   256B  2 11 14:51 demo
drwxr-xr-x   4 albert  staff   128B  1 19 17:00 github
drwxr-xr-x   3 albert  staff    96B 12 20 10:57 gitlab
-rw-r--r--   1 albert  staff   887B  2 11 16:15 server.key

再用私钥生成证书申请文件

Bash
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:15:13)──> openssl req -new -key server.key -out server.csr                                                                                                                        ──(五, 211)─┘
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:CN
State or Province Name (full name) []:Shanghai
Locality Name (eg, city) []:Shanghai
Organization Name (eg, company) []:Company
Organizational Unit Name (eg, section) []:Company
Common Name (eg, fully qualified host name) []:*.localhttps.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:

req 的时候需要根据命令行提示输入必要信息,前几个可以一路回车,直到 Common Name这里需要输入 localhost,也可以天 *.domain.com 申请通配符域名证书。最后的 password也可以放空。

执行完之后可以看到申请文件  server.csr已经生成:

Bash
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:18:02)──> ll                                                                                                                                                                      ──(五, 211)─┘
total 16
drwxr-xr-x  11 albert  staff   352B  2  8 14:03 code
drwxr-xr-x   8 albert  staff   256B  2 11 14:51 demo
drwxr-xr-x   4 albert  staff   128B  1 19 17:00 github
drwxr-xr-x   3 albert  staff    96B 12 20 10:57 gitlab
-rw-r--r--   1 albert  staff   668B  2 11 16:18 server.csr
-rw-r--r--   1 albert  staff   887B  2 11 16:15 server.key

用私钥对申请文件签名从而生成证书

Bash
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:18:05)──> openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650                                                                                         ──(五, 211)─┘
Signature ok
subject=/C=CN/ST=Shanghai/L=Shanghai/O=Company/OU=Company/CN=*.localhttps.com
Getting Private key

这里可以通过-days设置有效期,比如我这里生成了一个十年有效的 server.crt

Bash
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:18:19)──> ll                                                                                                                                                                      ──(五, 211)─┘
total 24
drwxr-xr-x  11 albert  staff   352B  2  8 14:03 code
drwxr-xr-x   8 albert  staff   256B  2 11 14:51 demo
drwxr-xr-x   4 albert  staff   128B  1 19 17:00 github
drwxr-xr-x   3 albert  staff    96B 12 20 10:57 gitlab
-rw-r--r--   1 albert  staff   883B  2 11 16:18 server.crt
-rw-r--r--   1 albert  staff   668B  2 11 16:18 server.csr
-rw-r--r--   1 albert  staff   887B  2 11 16:15 server.key

nodejs 起 https 服务

由于要响应静态资源,并且起 https 服务的时候我不想再写端口,所以比起 https.createServer我们还要再多写点代码。
方便起见,我就用 koa 了,先起一个大家经常写的 http 服务:

JavaScript
const path = require('path');
const fs = require('fs');
const Koa = require('koa');
const BodyParser = require('koa-bodyparser');
const serve = require('koa-static');
const mount = require('koa-mount');
const cors = require('@koa/cors');
const Router = require('@koa/router');

const PORT = 3002;

const sdkConfig = {...};

const app = new Koa();
const static_pages = new Koa();
static_pages.use(serve(__dirname + '/build'));
app.use(mount('/', static_pages));

app.use(BodyParser());
app.use(cors());

const router = new Router();

router.get('/api/data',async (ctx, next)=>{
  ctx.status = 200;
  ctx.body = { data: 1 };
  await next();
});

app.use(router.routes()).use(router.allowedMethods());

app.listen(PORT, function () {
  console.log("==> Listening on port %s. Visit http://localhost:%s/", PORT, PORT);
});

再把他改造成 https 服务:

Diff
+ const http = require('http');
+ const https = require('https');
const path = require('path');
const fs = require('fs');
const Koa = require('koa');
const BodyParser = require('koa-bodyparser');
const serve = require('koa-static');
const mount = require('koa-mount');
const cors = require('@koa/cors');
const Router = require('@koa/router');

const PORT = 3002;

const sdkConfig = {...};

const app = new Koa();
const static_pages = new Koa();
static_pages.use(serve(__dirname + '/build'));
app.use(mount('/', static_pages));

app.use(BodyParser());
app.use(cors());

const router = new Router();

router.get('/api/data',async (ctx, next)=>{
  ctx.status = 200;
  ctx.body = { data: 1 };
  await next();
});

app.use(router.routes()).use(router.allowedMethods());

- app.listen(PORT, function () {
-  console.log("==> Listening on port %s. Visit http://localhost:%s/", PORT, PORT);
- });

+ http.createServer(app.callback()).listen(PORT);

+ const options = {
+   key: fs.readFileSync('./config/server.key', 'utf-8'),
+   cert: fs.readFileSync('./config/server.cert', 'utf-8'),  
+ };

+ https.createServer(options, app.callback()).listen(443, () => {
+   console.log('==> Listening on port 443. Visit https://localhost');
+ });

相比之前这里稍作了改动。先照常启动一个 http 服务,把之前生成的签名证书和密钥读取之后,在启动一个相同的 https server 监听 443端口。这样就可以通过 https://localhost ,不用加端口直接访问服务了。

浏览器查看

直接用 chrome 访问试试,大概率会显示 SSL error: ERR_CERT_INVALID,老版本 chrome 可以选择跳过,新版 chrome 对这方面限制的并且无法跳过。

  • 解法一是去 chrome://flags/#allow-insecure-localhost开启允许无效证书选项。
  • 解法二是在当前提示错误的页面,输入 thisisunsafe告诉 chrome 你知道的,不用管。

我比较喜欢解法二。 image.png