error:0308010C digital envelope routines::unsupported 怎么解决?Node 17+ 跑老项目的三种修法
现象:项目昨天还能跑,今天 npm run dev 直接炸
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:130:10)
at BulkCacheDecorator.cheaderHash (...) ← webpack 4 内部调用栈
一行结论:你的 Node 版本升到 17+ 了,而项目里的 webpack 4 还在用 OpenSSL 3.0 已移出默认 provider 的 MD4 哈希。业务代码多半没坏;是运行时和打包器不合。
常见触发场景:
- 换电脑 / 重装,
nvm/fnm默认最新 LTS(18 / 20 / 22) - CI 基础镜像升级(
node:16→node:20) - Dockerfile 写了
FROM node:latest - 接手老项目(Vue CLI 4、create-react-app 4、裸 webpack 4)
先确认:
node -v
npm ls webpack
Node ≥ 17 且 webpack 为 4.x,基本就是这一类。
根因:OpenSSL 3.0 与 MD4
Node 17 起捆绑 OpenSSL 3.0。OpenSSL 3.0 把 MD4 等算法挪进「legacy provider」,默认不加载。webpack 4 用 crypto.createHash('md4') 算模块 hash——第一次调用就抛错。
错误码 0308010C 即 ERR_OSSL_EVP_UNSUPPORTED。受影响的不只是 webpack 4:老版本 grunt、gulp-rev、部分 crypto-js 也会踩中。
修法一:开启 legacy provider(快速解阻塞)
给 Node 加上 --openssl-legacy-provider,把 MD4 重新放进来:
# macOS / Linux
export NODE_OPTIONS=--openssl-legacy-provider
npm run dev
# Windows CMD
set NODE_OPTIONS=--openssl-legacy-provider
# Windows PowerShell
$env:NODE_OPTIONS="--openssl-legacy-provider"
更稳妥是写进 package.json(需 cross-env):
{
"scripts": {
"dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build"
}
}
适用:项目生命周期短,或今天必须先绿。代价:继续跑在弃用哈希路径上——适合过渡,不适合终点。该参数在当前 LTS(含 Node 22)仍可用,但清不掉技术债。
修法二:升级到 webpack 5(耐久方案)
| 项目类型 | 升级路径 |
|---|---|
| Vue CLI 4 | vue upgrade 到 Vue CLI 5(内置 webpack 5) |
| CRA 4 | 迁 CRA 5,或直接 Vite |
| 自维护 webpack 4 | npm i webpack@5 webpack-cli@4 -D 后逐项处理 breaking changes |
webpack 5 默认改用 xxhash64 / sha256,与 OpenSSL 3 兼容,并带来持久化缓存等收益。
升级后高频坑:缺 assert / buffer / process——webpack 5 不再自动 polyfill Node 核心模块,需按报错补 resolve.fallback 或 npm shim。
修法三:锁定旧 Node(仅过渡)
nvm install 16
nvm use 16
node -v # v16.x
仓库根目录加 .nvmrc,并在 CI / Docker 同步:
16
FROM node:16-alpine
注意:Node 16 已于 2023 年 9 月 EOL,无安全补丁。只适合作为升 webpack 5(或 Vite)之前的桥,不要当终点。
三种方案怎么选
| 方案 | 成本 | 风险 | 典型用途 |
|---|---|---|---|
--openssl-legacy-provider | 分钟级 | 低(仅本进程) | 今天先跑起来、短维护窗口 |
| 升级 webpack 5 | 小时到数天 | 中(构建行为漂移) | 还要继续发版的项目 |
| 锁定已 EOL Node | 分钟级 | 高(无安全补丁) | 升级排期前的 CI 对齐 |
Node 22、Next.js 与相邻栈
- Next.js App Router / Turbopack 现代栈很少踩这个坑——它们不在 webpack 4 上。若 monorepo 里出现
0308010C,到失败的 workspace 跑npm ls webpack,找出仍拖着 4.x 的包。 - Next 自定义 webpack(
next.config.js→webpack)可能重新引入调用遗留哈希的旧插件——先审插件。 - Electron / NW.js 内嵌 Node 17+ 配老打包器时,同一 OpenSSL 拒绝会出现在打包器的 Node 里,不只是宿主机 CLI。
- 用
.nvmrc+engines+(可选)Volta /packageManager把工具链钉死,避免每人一台「神秘 Node」。
预防:把 Node 版本钉死在项目里
本质是运行环境漂移。三道防线:
.nvmrc+package.json的engines:
{
"engines": { "node": ">=20 <21" }
}
- CI 开严格校验(
.npmrc加engine-strict=true),版本不对直接失败,而不是拖出难懂的 crypto 错 - Dockerfile 永远不用
node:latest,钉住大版本(更好连小版本一起钉)
这错误为什么成了 2022–2023 的流行病
OpenSSL 3.0 从默认 provider 移除遗留算法(MD4 在列)——webpack 4 的哈希用了 MD4,Node 17+ 跑 webpack 4 项目同一时刻全体命中。报错几乎不解释(digital envelope routines::unsupported——provider 拒绝包装成密码学谜语)。优先序:升级打包器(去掉 MD4 依赖)→ legacy-provider 旗标(今天解阻塞)→ 钉 EOL Node(推迟一切)。教训:构建工具里的哈希是隐形依赖——「我们应用不用 MD4」对应用可为真,对构建可为假。
和「Cannot find module」怎么区分
ERR_OSSL_EVP_UNSUPPORTED / digital envelope routines 出在已经加载到的 crypto/webpack 代码路径上;模块根本没装好时是 Cannot find module。若同时升级 Node 与清过 node_modules,先确认 node_modules/webpack 还在,再决定是 OpenSSL 兼容问题还是依赖树坏了。急救旗标 NODE_OPTIONS=--openssl-legacy-provider 只掩盖 OpenSSL 3 拒签遗留摘要,不能修缺包。
排查清单
node -v— 是否 ≥17?npm ls webpack是否为 4.x?- 报错含
0308010C/digital envelope routines— 确认是本问题 - 急救:
NODE_OPTIONS=--openssl-legacy-provider先跑起来 - 排期升级 webpack 5(或 Vite);EOL Node 只作桥
- 复查
.nvmrc、engines、Dockerfile 的 Node 大版本一致
排查注记
三种修法的选择表按成本/风险/典型用途切,但正文反复强调同一句话:legacy provider 和锁定 EOL Node 都只是过渡、不是终点,优先序是升级打包器去掉 MD4 依赖。开篇的触发场景清单(换电脑、CI 基镜像升级、FROM node:latest)全指向同一个判断——本质是运行环境漂移,所以预防的三道防线(.nvmrc、engine-strict、钉死 Dockerfile 基镜像)全部在钉版本。流行病一节的教训值得重读:构建工具里的哈希是隐形依赖,「我们应用不用 MD4」对应用可为真、对构建可为假。
本文由 ToolVault 工具匣提供。相关阅读:npm 依赖冲突 ERESOLVE 排查、npm 网络问题换源指南、Cannot find module 排查。访问 首页 查看更多开发者工具。
相关工具
相关文章
Linux crontab 定时任务实战:命令、日志与排查
crontab 不只是写表达式:三个必会命令、/etc/cron.d 与用户 crontab 的区别、任务没跑的五步排查法、PATH/时区/% 转义、MAILTO,以及秒级任务的正确解法。
docker run 转 docker-compose 完全指南:为什么转、怎么转、参数对照表
把 docker run 命令迁移到 docker-compose.yml 的完整指南:compose 相比裸 run 的五大优势、参数逐项对照表(端口/卷/环境变量/重启策略/网络)、常见坑(裸 -e 透传、匿名卷、--rm 语义),附在线转换器用法。
Permission denied (publickey) 怎么解决?Git 推送失败的 6 种原因与修复
git clone/push 报 Permission denied (publickey) fatal: Could not read from remote repository?覆盖公钥没生成、没加载进 agent、没添加到 GitHub/Gitee、多账号配错密钥、deploy key 权限、remote URL 写错六种根因,附 ssh -v 诊断方法。