ESA Pages 体验之旅(7):适配 Node.js 依赖
运行时探测确认了原生 crypto、buffer 的部分行为可用,也找到了文件与网络模块的缺口。适配依赖时,可以保留已验证的原生能力,为缺少的接口选择其他实现。
TableStore SDK 同时负责签名、协议编码和网络传输。原型继续使用它的协议实现,将宿主模块和 HTTP 传输集中适配。
原生模块、Web API 和 JavaScript 实现
| 依赖需要什么 | 优先处理方式 | 验证重点 |
|---|---|---|
| ESA 已支持的 Node 模块 | 显式导入对应模块 | 具体成员与固定输入结果 |
| 标准 URL、Fetch、流等能力 | 使用适合当前语义的 Web API | 编码、边界和错误行为 |
| 缺少的纯计算接口 | 选择成熟 JS 实现 | 行为覆盖、体积与许可证 |
| Node HTTP 客户端 | 换成 fetch 传输 | 原始字节、签名头、超时、错误与重试 |
| 文件、进程、TCP 等宿主操作 | 改接口或放到支持它的独立服务 | 连接与资源生命周期,不能靠空实现伪装成功 |
例如 Web URL 与 Node 旧式 url 接口并非逐项等价。SDK 要求旧接口时,要么调整调用,要么采用成熟实现;不能只因为两个名字里都有 URL 就直接替换。
保留 SDK 的协议实现
SDK 已实现请求签名、protobuf 和 PlainBuffer 编解码,原型保留这些实际协议代码。
隔离原型采用以下组合:
- 用实测可用的
node:crypto做 MD5 和 HMAC,node:buffer处理二进制。 - 旧式 URL 行为采用
url@0.11.4。 - 将网络发送集中为 fetch,保留真实请求体、签名头和服务端错误解析。
- 对不应执行的主机 I/O 明确报错,避免空模块被误调用后静默成功。
构建仍输出 ESM。遇到 CommonJS 对宿主模块的 require,采用限定到已知模块的导入桥接;任意动态 require 和目录扫描不在它的处理范围内。桥接控制的是加载方式,实际算法仍由对应实现提供。
用 fetch 替换网络传输
TableStore HTTP 请求含二进制协议与签名。适配层必须让参与摘要和签名的字节,与最终发送的字节一致;文本重新编码、头字段变化或自动修改 URL 都可能使服务器拒绝请求。
返回路径要保留原始状态、协议错误及响应字节。验证时使用非空记录检查编解码,并加入服务错误,确认调用方能够识别失败。
自动重试也需要显式决定。边缘请求预算有限,写入超时还可能意味着「服务端成功,客户端没收到」。原型和现有存储封装都需要限制重试;恢复是否安全取决于条件更新与幂等设计,而不仅是重发一次 HTTP。
原型的验证范围
原型运行了真实 SDK 的签名、protobuf 与非空 PlainBuffer 编解码,用固定协议响应检查 Put、Get、Delete,以及账号与业务记录涉及的读取路径。固定向量验证算法,非空记录验证数据转换。
这些测试没有访问真实数据库,也没有发送邮件。因此它证明的是选定实现能够完成这些协议路径,不能当作生产 TableStore、并发与邮件的完整验收。源码与结果见原生接口适配原型弹窗。
SDK 六处变量声明修复仍然需要。原生 crypto 能工作,不会修掉严格模式中的隐式全局赋值。适配原型的报告里曾将第三方代码标为未修改,但它使用的依赖已带现有 pnpm 补丁;这里以实际依赖状态为准。相关缺陷、依赖补丁及官方修复后的撤除条件,在前面的 SDK 修复中说明,原始检查另见变量声明与依赖记录弹窗。
生产构建仍使用兼容层
截至 2026-10-29,业务构建脚本仍使用 neutral 与 Node polyfill;原生模块方案没有完成生产切换。现有兼容层针对已观察到的 navigator、Deno 成员假设做了补丁,真实站点验证过业务记录的读取、新增与删除。
原生方案还需要在同一最终包上验证签名、非空协议、服务错误、真实存储与请求次数,完成后再替换生产构建。
选择适配范围时,可以用维护成本判断:少量纯计算和 HTTP 传输差异,适合集中处理;如果核心依赖持续要求文件系统、TCP 或任意动态模块,则应重新比较 HTTP 数据服务或独立后端。打包器能改变代码形态,不能凭空增加宿主能力。
原生接口、成熟 URL 库与真实协议原型
工作区固定 SDK、URL 实现与构建配置,使用协议响应替身,不连接生产数据库。实际 SDK 已带补丁,报告中的未修改标记与输入状态不一致,应以依赖补丁和输入核对为准。
SDK 变量声明修复与依赖检查
打开原文件 sdk-local-variables.json
记录严格模式问题的最小修复与回归范围。完整的维护源、npm 版本和历史定位见 SDK 修复一篇。