◆

Node.js 报错 digital envelope routines unsupported 解决

2024-02-26 08:120

场景

启动 vue 项目报错

Error: error:0308010C:digital envelope routines::unsupported

这个报错最典型的出现时机是:把 Node 从 16 升到 17 或更高版本之后,一个原本跑得好好的老项目(Vue CLI 4/5、webpack 4 的项目居多)突然起不来了,npm run serve 或 npm run build 直接在 webpack 计算文件哈希的阶段崩掉。项目代码一行没改,只换了 Node 版本,这就是判断它的关键特征。

原因

在 node.js V17 版本中最近发布的 OpenSSL3.0, 而 OpenSSL3.0 对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响

具体到这个报错,根子在 md4 上。webpack 4 默认用 crypto.createHash('md4') 来算模块和 chunk 的哈希,而 OpenSSL 3.0 把 md4 这类不安全的老算法从默认 provider 里移出去了,划进了 legacy provider。Node 17 起内置的 OpenSSL 升到 3.0,默认不加载 legacy provider,于是 createHash('md4') 直接抛错,错误码就是我们看到的 0308010C。

理解了这一点,后面几种解法的逻辑就清楚了:要么把 Node 换回内置 OpenSSL 1.x 的版本,要么让 Node 把 legacy provider 加载回来,要么升级构建工具让它不再用 md4。

解决方法

方法一

卸载 Node.js 17+ 版本并重新安装 Node.js 16+ 版本,然后再重新启动

实际操作时不建议真去卸载重装,用版本管理工具切一下更省事,比如 nvm use 16 或者 volta pin node@16。这个方法最稳妥,缺点是把整台机器(或整个项目)的 Node 版本压回旧版,如果同一台机器上还有依赖新版 Node 特性的项目就会互相别扭。所以更推荐的做法是用 .nvmrc、volta 字段这类项目级的版本声明,让每个项目各用各的 Node 版本。

方法二(推荐)

在执行运行项目命令之前,先运行这个命令

  • linux 与 mac 系统
export NODE_OPTIONS=--openssl-legacy-provider
  • windows

Windows 下要分清用的是哪个终端,两种终端的语法不一样。

cmd 用 set:

set NODE_OPTIONS=--openssl-legacy-provider

PowerShell 里 set 不是这个用法,要写成给环境变量赋值:

$env:NODE_OPTIONS = "--openssl-legacy-provider"

这样设置的变量只在当前这个终端会话里有效,关掉窗口就没了,下次开新窗口还得再设一遍。

方法三:把变量写进 npm scripts

每次手动 export 太容易忘,更靠谱的是直接写进 package.json 的 scripts 里,这样团队里所有人、以及 CI 环境都能自动带上:

{
  "scripts": {
    "serve": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
    "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build"
  }
}

这里用了 cross-env(npm i -D cross-env),原因是 NODE_OPTIONS=xxx command 这种前置赋值写法在 Windows 的 cmd 下不成立,cross-env 负责把语法差异抹平。如果确定团队全是 macOS/Linux,可以省掉它直接写 NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve。

方法四:从根上解决,升级构建工具

前面几种都是绕过去,真正的修法是让构建工具别再用 md4。webpack 5 已经把默认哈希算法换成了 md4 之外的实现,不再触发这个问题。如果暂时没法升级 webpack 大版本,也可以在 webpack 配置里显式指定哈希算法:

module.exports = {
  output: {
    hashFunction: 'xxhash64',
  },
};

Vue CLI 项目可以在 vue.config.js 里通过 configureWebpack 改同一个字段。这种改法的好处是不依赖环境变量,换机器、换 CI 都不会漏配。

几个容易踩的点

  • NODE_OPTIONS 里不能塞任意参数。Node 只允许一部分 CLI 选项通过这个环境变量传入,--openssl-legacy-provider 在其列。如果写错了参数名,Node 会直接报 not allowed in NODE_OPTIONS 并退出,看到这个提示先检查拼写。
  • Node 版本太低反而会报错。--openssl-legacy-provider 这个选项是伴随 OpenSSL 3.0 才有的,在 Node 16 及更早版本上并不存在。如果在 Node 16 上设了这个变量,启动会因为无法识别该选项而失败。也就是说方法一和方法二只能选一个,不要同时用。
  • 报错点不一定在 webpack。除了构建工具,一些老的加密/签名相关依赖同样可能调用被 OpenSSL 3.0 禁掉的算法,报出同一个错误码。这时候看完整堆栈定位到具体是哪个包在调 createHash,优先升级那个包。
💬留言板0

还没有留言,来发表第一条吧~

PAGE LOAD / LIVENode.js 报错 digital envelope routines unsupported 解决加载中