前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# HTTPS

30 秒速记

  • HTTPS = HTTP + TLS:先握手确认对方身份、协商出一把对称密钥,后面的数据用这把密钥加密
  • 证书 = 服务器公钥 + 域名等身份信息 + 上级 CA 的签名;客户端顺着证书链验到本地信任的根证书才放行
  • 现在主流是 ECDHE 密钥交换,证书的私钥只用来签名证明「我是我」,不直接加密会话密钥
  • Node 里 https.createServer({ key, cert }, app) 就能直接起服务;更常见是 nginx 终止 TLS 后转 HTTP 给 Node
  • 线上关注:至少 TLS 1.2、证书链发完整、SAN 写全域名、到期前自动续签

HTTPS 就是在 HTTP 下面垫了一层 TLS,先确认「对面真的是这个网站」,再协商一把只有双方知道的密钥加密通信。 身份靠证书:网站把证书发过来,客户端检查它是不是由自己信任的 CA 签的、域名对不对、有没有过期。密钥协商现在基本是 ECDHE,双方各出一部分随机数算出同一把对称密钥,后续数据都用它加密,所以即便将来服务器私钥泄露,以前录下来的流量也解不开。Node 可以自己处理 TLS,但线上我更习惯让 nginx 或网关去做,证书集中管理。

理解「HTTPS」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

面试官追问

追问 1既然有非对称加密,为什么数据传输还要用对称加密?
参考回答

非对称加密慢好几个数量级,只适合握手阶段做身份认证和密钥协商。协商出对称密钥之后,大量数据用 AES 这类算法加解密,又快又安全。

追问 2Node 里请求一个 HTTPS 接口报错,后端日志完全没有这个请求,说明什么?
参考回答

说明请求死在了 TLS 握手阶段,还没到业务代码。看错误对象的 code,比如 CERT_HAS_EXPIRED、SELF_SIGNED_CERT_IN_CHAIN、ERR_TLS_CERT_ALTNAME_INVALID,基本就能定位是过期、信任链还是域名不匹配。

追问 3TLS 交给 nginx 终止后,Node 里 req.protocol 总是 http,怎么办?
参考回答

nginx 到 Node 这段确实是 HTTP。让 nginx 加 X-Forwarded-Proto 头,Express 里设 app.set('trust proxy', 1),只信任最近一层代理,req.protocol 和 req.secure 就对了。

追问 4证书突然过期导致全站访问失败,怎么避免下次再发生?
参考回答

用 Let's Encrypt + certbot 或 acme.sh 自动续签,免费证书有效期 90 天,脚本会提前续。再加一个监控,证书剩余天数低于 14 天就告警,自动续签挂了也能提前知道。

# 客户端例子:不受信任的证书

30 秒速记

  • 浏览器报「不是私密连接」和 Node 报 SELF_SIGNED_CERT_IN_CHAIN 是同一件事:证书链验不到本地信任的根
  • 常见原因:自签名证书、私有 CA、服务端漏发中间证书、公司代理替换了证书
  • SELF_SIGNED_CERT_IN_CHAIN = 链里有个自签名根但不受信任;DEPTH_ZERO_SELF_SIGNED_CERT = 证书本身就是自签名
  • 正确解法:https.get(url, { ca }) 指定根证书,或启动时设 NODE_EXTRA_CA_CERTS=./ca.pem
  • rejectUnauthorized: false / NODE_TLS_REJECT_UNAUTHORIZED=0 等于关掉身份校验,只能临时本地调试

Node 默认会校验证书,证书链对不上本地信任的根证书,握手直接失败,请求根本发不出去。 浏览器遇到这种情况会弹一个警告页让人决定,Node 没有人可以问,就直接抛错,比如 SELF_SIGNED_CERT_IN_CHAIN。处理思路和浏览器「导入根证书」一样:把这个根证书告诉 Node,用请求选项里的 ca,或者环境变量 NODE_EXTRA_CA_CERTS。网上很多答案教你设 rejectUnauthorized: false,那等于把门锁拆了,中间人随便冒充,生产代码里见到我会直接拦下来。

我们知道,有些网站的HTTPS证书会被浏览器标识为不受信任,有可能是以下情况导致的:

  • 颁发证书的机构不在操作系统的受信列表里
  • 办法证书的机构在操作系统的受信列表里,但证书的安全级别不够

比如我们访问 12306,chrome就会提示你“您的连接不是私密连接,攻击者可能会试图从kyfw.12306.cn窃取您的信息”。

那么,当我们用node向12306发起请求时,又会是什么状况呢?下面就来试下

var https = require('https');

https.get('https://www.baidu.com', function(res){
    res.on('data', function(data){
        process.stdout.write(data);
    });
}).on('error', function(err){
    console.error(err);
});
@前端进阶之旅: 代码已经复制到剪贴板

运行上面代码,输出如下。可以看到出现报错,提示信息是“self signed certificate in certificate chain”。大意就是说证书是网站自己签发的,不安全。

{ Error: self signed certificate in certificate chain
    at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:1055:38)
    at emitNone (events.js:86:13)
    at TLSSocket.emit (events.js:185:7)
    at TLSSocket._finishInit (_tls_wrap.js:580:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38) code: 'SELF_SIGNED_CERT_IN_CHAIN' }
@前端进阶之旅: 代码已经复制到剪贴板

出现上述错误怎么处理呢?我们知道,如果是在浏览器里访问,有两种处理方式:

  • 忽略浏览器的安全提示,继续访问(浏览器可能会直接禁止你访问)
  • 将网站的根证书导入到操作系统的受信任根证书列表里

面试官追问

追问 1报 SELF_SIGNED_CERT_IN_CHAIN,同事直接加了 NODE_TLS_REJECT_UNAUTHORIZED=0,能接受吗?
参考回答

不接受。这个变量对整个进程生效,所有 HTTPS 请求都不再校验证书,被中间人劫持也发现不了,Node 自己都会打一条警告。正确做法是拿到对方的根证书,用 ca 选项或 NODE_EXTRA_CA_CERTS 加进信任列表。

追问 2内网服务用的是公司私有 CA 签的证书,Node 客户端怎么配?
参考回答

只影响某个请求就用 https.get(url, { ca: fs.readFileSync('company-ca.pem') });整个进程都要信任就启动时设 NODE_EXTRA_CA_CERTS=/path/company-ca.pem。后者是追加到内置根证书列表,不会让公网证书失效。

追问 3同一个 URL,本机请求正常,CI 里报证书错误,先查什么?
参考回答

Node 用的是自己内置的一份根证书列表,不读系统钥匙串。先看本机是不是设了 NODE_EXTRA_CA_CERTS 而 CI 没设;再看 CI 是不是走了公司代理,代理把证书换成了自己的。

追问 4浏览器能正常打开,Node 却报 unable to verify the first certificate,为什么?
参考回答

大概率是服务器没把中间证书发全。浏览器会缓存或自动下载中间证书,Node 不会。用 openssl s_client -connect host:443 -showcerts 看服务端实际发了几张证书,把中间证书拼进服务端的证书文件就好了。

# 入门示例

30 秒速记

  • 最小服务端:https.createServer({ key, cert }, handler).listen(443),比 http 多一个证书参数
  • key 是私钥,cert 是证书;有中间证书时把它们按顺序拼进 cert
  • 和 Express 配合:https.createServer(options, app),app 本身就是一个 handler
  • 客户端:https.get / fetch,自签名证书用 ca 指定信任的根证书
  • 本地开发推荐 mkcert 一条命令生成受信任的 localhost 证书

Node 起 HTTPS 服务和起 HTTP 服务几乎一样,只是多传一个包含私钥和证书的配置对象。 https.createServer 的第二个参数和 http.createServer 完全相同,所以 Express 的 app 直接传进去就能用。真正要花心思的是证书从哪来:公网用 CA 签发的,本地开发用 mkcert 生成并让系统信任,测试自签名证书时客户端要用 ca 选项告诉 Node

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
      • 客户端例子:不受信任的证书
      • 入门示例
      • 基础讲解
      • 本地证书
      • 服务器:自签名证书
      • 私有CA签名的证书
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

HTTPS|Nodejs专题系列

# HTTPS

30 秒速记

  • HTTPS = HTTP + TLS:先握手确认对方身份、协商出一把对称密钥,后面的数据用这把密钥加密
  • 证书 = 服务器公钥 + 域名等身份信息 + 上级 CA 的签名;客户端顺着证书链验到本地信任的根证书才放行
  • 现在主流是 ECDHE 密钥交换,证书的私钥只用来签名证明「我是我」,不直接加密会话密钥
  • Node 里 https.createServer({ key, cert }, app) 就能直接起服务;更常见是 nginx 终止 TLS 后转 HTTP 给 Node
  • 线上关注:至少 TLS 1.2、证书链发完整、SAN 写全域名、到期前自动续签

HTTPS 就是在 HTTP 下面垫了一层 TLS,先确认「对面真的是这个网站」,再协商一把只有双方知道的密钥加密通信。 身份靠证书:网站把证书发过来,客户端检查它是不是由自己信任的 CA 签的、域名对不对、有没有过期。密钥协商现在基本是 ECDHE,双方各出一部分随机数算出同一把对称密钥,后续数据都用它加密,所以即便将来服务器私钥泄露,以前录下来的流量也解不开。Node 可以自己处理 TLS,但线上我更习惯让 nginx 或网关去做,证书集中管理。

理解「HTTPS」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

面试官追问

追问 1既然有非对称加密,为什么数据传输还要用对称加密?
参考回答

非对称加密慢好几个数量级,只适合握手阶段做身份认证和密钥协商。协商出对称密钥之后,大量数据用 AES 这类算法加解密,又快又安全。

追问 2Node 里请求一个 HTTPS 接口报错,后端日志完全没有这个请求,说明什么?
参考回答

说明请求死在了 TLS 握手阶段,还没到业务代码。看错误对象的 code,比如 CERT_HAS_EXPIRED、SELF_SIGNED_CERT_IN_CHAIN、ERR_TLS_CERT_ALTNAME_INVALID,基本就能定位是过期、信任链还是域名不匹配。

追问 3TLS 交给 nginx 终止后,Node 里 req.protocol 总是 http,怎么办?
参考回答

nginx 到 Node 这段确实是 HTTP。让 nginx 加 X-Forwarded-Proto 头,Express 里设 app.set('trust proxy', 1),只信任最近一层代理,req.protocol 和 req.secure 就对了。

追问 4证书突然过期导致全站访问失败,怎么避免下次再发生?
参考回答

用 Let's Encrypt + certbot 或 acme.sh 自动续签,免费证书有效期 90 天,脚本会提前续。再加一个监控,证书剩余天数低于 14 天就告警,自动续签挂了也能提前知道。

# 客户端例子:不受信任的证书

30 秒速记

  • 浏览器报「不是私密连接」和 Node 报 SELF_SIGNED_CERT_IN_CHAIN 是同一件事:证书链验不到本地信任的根
  • 常见原因:自签名证书、私有 CA、服务端漏发中间证书、公司代理替换了证书
  • SELF_SIGNED_CERT_IN_CHAIN = 链里有个自签名根但不受信任;DEPTH_ZERO_SELF_SIGNED_CERT = 证书本身就是自签名
  • 正确解法:https.get(url, { ca }) 指定根证书,或启动时设 NODE_EXTRA_CA_CERTS=./ca.pem
  • rejectUnauthorized: false / NODE_TLS_REJECT_UNAUTHORIZED=0 等于关掉身份校验,只能临时本地调试

Node 默认会校验证书,证书链对不上本地信任的根证书,握手直接失败,请求根本发不出去。 浏览器遇到这种情况会弹一个警告页让人决定,Node 没有人可以问,就直接抛错,比如 SELF_SIGNED_CERT_IN_CHAIN。处理思路和浏览器「导入根证书」一样:把这个根证书告诉 Node,用请求选项里的 ca,或者环境变量 NODE_EXTRA_CA_CERTS。网上很多答案教你设 rejectUnauthorized: false,那等于把门锁拆了,中间人随便冒充,生产代码里见到我会直接拦下来。

我们知道,有些网站的HTTPS证书会被浏览器标识为不受信任,有可能是以下情况导致的:

  • 颁发证书的机构不在操作系统的受信列表里
  • 办法证书的机构在操作系统的受信列表里,但证书的安全级别不够

比如我们访问 12306,chrome就会提示你“您的连接不是私密连接,攻击者可能会试图从kyfw.12306.cn窃取您的信息”。

那么,当我们用node向12306发起请求时,又会是什么状况呢?下面就来试下

var https = require('https');

https.get('https://www.baidu.com', function(res){
    res.on('data', function(data){
        process.stdout.write(data);
    });
}).on('error', function(err){
    console.error(err);
});
@前端进阶之旅: 代码已经复制到剪贴板

运行上面代码,输出如下。可以看到出现报错,提示信息是“self signed certificate in certificate chain”。大意就是说证书是网站自己签发的,不安全。

{ Error: self signed certificate in certificate chain
    at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:1055:38)
    at emitNone (events.js:86:13)
    at TLSSocket.emit (events.js:185:7)
    at TLSSocket._finishInit (_tls_wrap.js:580:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38) code: 'SELF_SIGNED_CERT_IN_CHAIN' }
@前端进阶之旅: 代码已经复制到剪贴板

出现上述错误怎么处理呢?我们知道,如果是在浏览器里访问,有两种处理方式:

  • 忽略浏览器的安全提示,继续访问(浏览器可能会直接禁止你访问)
  • 将网站的根证书导入到操作系统的受信任根证书列表里

面试官追问

追问 1报 SELF_SIGNED_CERT_IN_CHAIN,同事直接加了 NODE_TLS_REJECT_UNAUTHORIZED=0,能接受吗?
参考回答

不接受。这个变量对整个进程生效,所有 HTTPS 请求都不再校验证书,被中间人劫持也发现不了,Node 自己都会打一条警告。正确做法是拿到对方的根证书,用 ca 选项或 NODE_EXTRA_CA_CERTS 加进信任列表。

追问 2内网服务用的是公司私有 CA 签的证书,Node 客户端怎么配?
参考回答

只影响某个请求就用 https.get(url, { ca: fs.readFileSync('company-ca.pem') });整个进程都要信任就启动时设 NODE_EXTRA_CA_CERTS=/path/company-ca.pem。后者是追加到内置根证书列表,不会让公网证书失效。

追问 3同一个 URL,本机请求正常,CI 里报证书错误,先查什么?
参考回答

Node 用的是自己内置的一份根证书列表,不读系统钥匙串。先看本机是不是设了 NODE_EXTRA_CA_CERTS 而 CI 没设;再看 CI 是不是走了公司代理,代理把证书换成了自己的。

追问 4浏览器能正常打开,Node 却报 unable to verify the first certificate,为什么?
参考回答

大概率是服务器没把中间证书发全。浏览器会缓存或自动下载中间证书,Node 不会。用 openssl s_client -connect host:443 -showcerts 看服务端实际发了几张证书,把中间证书拼进服务端的证书文件就好了。

# 入门示例

30 秒速记

  • 最小服务端:https.createServer({ key, cert }, handler).listen(443),比 http 多一个证书参数
  • key 是私钥,cert 是证书;有中间证书时把它们按顺序拼进 cert
  • 和 Express 配合:https.createServer(options, app),app 本身就是一个 handler
  • 客户端:https.get / fetch,自签名证书用 ca 指定信任的根证书
  • 本地开发推荐 mkcert 一条命令生成受信任的 localhost 证书

Node 起 HTTPS 服务和起 HTTP 服务几乎一样,只是多传一个包含私钥和证书的配置对象。 https.createServer 的第二个参数和 http.createServer 完全相同,所以 Express 的 app 直接传进去就能用。真正要花心思的是证书从哪来:公网用 CA 签发的,本地开发用 mkcert 生成并让系统信任,测试自签名证书时客户端要用 ca 选项告诉 Node 信任它。

← express+session实现简易身份认证log4js入门实例 →

fe