React向Node.js传递以太坊签名遇BigInt序列化问题求解
解决BigInt序列化与签名验证的问题
问题根源
你遇到的两个错误本质都是JSON不原生支持BigInt类型:
- 直接发送
signMessage对象时,JSON.stringify无法处理r、s的BigInt值,抛出序列化错误 - 把整个
signMessage转成字符串(比如String(signMessage))会得到"[object Object]",服务端用BigInt()转换这个字符串自然报错
正确处理方案
1. 客户端:结构化序列化签名数据
不要把整个对象转成字符串,而是保留JSON结构,仅将BigInt字段转为字符串后再序列化:
// 客户端代码(假设用ethers.js生成签名) const signMessage = await signer.signMessage(transactionMessage); // 转换BigInt字段为字符串,保留对象结构 const serializableSignature = { r: signMessage.r.toString(), s: signMessage.s.toString(), recovery: signMessage.recovery // recovery是普通数字,直接保留 }; // 发送POST请求 await fetch('/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(serializableSignature) });
如果不想手动逐个字段处理,也可以用JSON.stringify的replacer函数自动处理所有BigInt:
const serializedSignature = JSON.stringify(signMessage, (key, value) => { return typeof value === 'bigint' ? value.toString() : value; });
2. 服务端:还原BigInt并验证签名
接收JSON数据后,将对应的字符串字段转回BigInt,再进行验证:
// 服务端Express示例代码 const ethers = require('ethers'); const express = require('express'); const app = express(); app.use(express.json()); // 解析JSON请求体 app.post('/send', async (req, res) => { const { r, s, recovery } = req.body; try { // 把字符串转回BigInt const signature = { r: BigInt(r), s: BigInt(s), recovery: Number(recovery) }; // 执行签名验证(替换为你的验证逻辑) const verifiedAddress = await ethers.verifyMessage(yourOriginalMessage, signature); res.status(200).json({ success: true, verifiedAddress }); } catch (err) { res.status(400).json({ error: err.message }); } });
关键注意事项
- 始终保留JSON的结构化传输,不要直接把对象转成非结构化字符串
- 验证时要确保服务端使用的原始消息和客户端签名的消息完全一致,否则验证会失败
内容的提问来源于stack exchange,提问作者Matias Salimbene
相关产品推荐
相关产品推荐

