症状
本篇调试指南针对“crypto.subtle 为 undefined — 需要安全上下文”。内容涵盖可观察的症状、可复现的诊断路径、根本原因、具体修复方式,以及如何验证修复并防止回归。
可观察到的症状包括:
- TypeError: 无法读取 undefined 的属性(读取 digest)
- Web Crypto 本地可用,预发服务器不可用
- 以纯 http:// 提供的应用无法哈希或加密
诊断
先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。
步骤 1
console.log(window.isSecureContext, window.crypto?.subtle)
isSecureContext 为 false 或 subtle 为 undefined,即确认是环境而非代码问题。
步骤 2
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 1
快速生成自签证书即可使源变为安全,subtle 随之可用。
常见诱因(按出现频率排序):
- 页面非安全上下文(非 localhost 的 HTTP 源)
- 未做特性检查就访问 window.crypto.subtle
- 旧版或内置浏览器不支持 Web Crypto
根因
Web Crypto 仅在安全上下文(HTTPS、localhost 或 file)中暴露 crypto.subtle。在不安全源上,window.crypto 仅供 getRandomValues,subtle 为 undefined,调用即抛错。
修复
在所有非本地环境用 HTTPS 提供服务,使用前探测 crypto.subtle,并在该 API 不可用时提供服务端回退。
注意:为安全目的回退到非加密哈希很危险;仅在非安全用途时回退。
if (window.isSecureContext && window.crypto?.subtle) {
const enc = new TextEncoder();
const hash = await crypto.subtle.digest('SHA-256', enc.encode('data'));
console.log([...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, '0')).join(''));
} else {
// secure context required; fall back or ask the user to use HTTPS
console.warn('crypto.subtle unavailable: secure context required');
}
验证
通过 HTTPS 加载并确认 isSecureContext 为 true 且 crypto.subtle.digest 成功;测试 HTTP 源仍给出清晰回退提示。
修复后补充一条回归测试,复现原始症状,防止问题再次出现。
这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。