题目
页面初始化和用户点击“连接钱包”时,分别应该调用 eth_accounts 还是 eth_requestAccounts?两者在授权和用户交互上有什么区别?
考察目标
- 是否理解“读取已经暴露的账户”和“主动申请账户访问权限”是两件事。
- 是否会避免页面加载时自动弹出钱包授权。
- 是否知道空账户数组、用户拒绝和账户变化应如何处理。
考察读取已授权账户与主动请求账户权限的差别,以及连接按钮的正确行为。
页面初始化和用户点击“连接钱包”时,分别应该调用 eth_accounts 还是 eth_requestAccounts?两者在授权和用户交互上有什么区别?
eth_accounts 只读取钱包当前已经授权给站点的账户,不应触发授权弹窗,适合页面初始化时恢复状态。eth_requestAccounts 会主动请求账户访问,通常可能弹出钱包确认,只应由用户点击连接按钮等明确操作触发。前者返回空数组表示当前没有可用账户;后者还可能因为用户拒绝而报错。连接后仍需监听 accountsChanged,不能永久信任第一次拿到的地址。
EIP-1193 把钱包暴露给网页的对象定义为 Provider,DApp 通过 request 发起 RPC 请求。账户是否对某个站点可见由钱包控制。
初始化时调用 eth_accounts,用于判断钱包是否已经向当前站点暴露账户:
应用不应仅凭 localStorage 中保存的地址恢复“已连接”。缓存只能作为界面线索,当前授权事实必须重新向钱包读取。
当用户点击“连接钱包”后调用 eth_requestAccounts。钱包可以展示授权界面,用户也可以拒绝。前端应区分:
请求成功不代表授权永久有效。用户可以在钱包中切换账户、撤销站点权限或断开连接,因此应用需要处理 accountsChanged;收到空数组时应清理账户相关状态和数据。
async function restoreWallet(provider: EIP1193Provider) {
const accounts = await provider.request({ method: "eth_accounts" });
return Array.isArray(accounts) && accounts.length > 0 ? accounts[0] : null;
}
async function connectWallet(provider: EIP1193Provider) {
const accounts = await provider.request({ method: "eth_requestAccounts" });
if (!Array.isArray(accounts) || accounts.length === 0) {
throw new Error("钱包没有提供可用账户");
}
return accounts[0];
}
生产代码还应校验返回值是否为合法地址,并把钱包错误转换成稳定的产品错误类型。
eth_requestAccounts,造成打扰式弹窗。eth_accounts 的实时结果。accountsChanged。eth_accounts 返回空数组时,页面应该清理哪些状态?eth_accounts 是读取现有授权,eth_requestAccounts 是主动请求授权。accountsChanged 并重新校验 chainId。发现这道题有问题? 反馈此题