2、MetaMask集成:Web3.js库安装、Provider注入、连接账户、监听账户切换、获取链ID、处理连接错误
好,咱们直接进入正题。MetaMask 是目前最主流的浏览器钱包,没有之一。你想想看,市面上 90% 的 DApp 都在用它做入口。这一节,我会带你手把手把 MetaMask 集成到你的 NFT 平台里。
我个人习惯把集成过程拆成 6 个步骤:安装库、注入 Provider、连接账户、监听切换、获取链 ID、处理错误。咱们一个一个来。
2.1 安装 Web3.js 库
首先,你得装 Web3.js。这是和以太坊节点打交道的桥梁。
npm install web3
或者用 yarn:
yarn add web3
嗯,这里要注意版本。我建议用 ^4.x 版本,因为 4.x 对 TypeScript 支持更好,而且 API 更现代化。我在项目中遇到过有人装了 1.x 版本,结果很多新特性用不了,最后还得降级重装。
2.2 Provider 注入检测
MetaMask 安装后,会在浏览器全局注入一个 window.ethereum 对象。这就是 Provider。
说白了,你的 DApp 得先确认这个对象存在,才能继续往下走。
// 检测 MetaMask 是否安装
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask 已安装');
} else {
console.error('请安装 MetaMask 浏览器扩展');
}
我曾经在一个项目里忘了做这个检测,结果用户没装 MetaMask 就直接报错,体验极差。后来加了个友好的提示弹窗,转化率反而提升了。
window.web3,那个是旧版 MetaMask 注入的,新版已经废弃了。一律用 window.ethereum。
2.3 连接账户
检测通过后,就该请求用户授权了。MetaMask 会弹出一个窗口,让用户选择要连接的账户。
async function connectWallet() {
try {
// 请求用户授权
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
// 获取当前账户
const currentAccount = accounts[0];
console.log('已连接账户:', currentAccount);
return currentAccount;
} catch (error) {
console.error('用户拒绝了连接请求:', error);
}
}
这里有个坑:eth_requestAccounts 只能调用一次。如果用户第一次拒绝了,你再调用它不会再次弹出窗口。你得引导用户手动在 MetaMask 里切换账户。
2.4 监听账户切换
用户可能在 MetaMask 里手动切换账户。你的 DApp 得实时感知到变化,否则会出现「显示的是 A 账户,实际用的是 B 账户」的尴尬情况。
// 监听账户切换
window.ethereum.on('accountsChanged', (accounts) => {
if (accounts.length === 0) {
// 用户断开了连接
console.log('用户断开了钱包连接');
// 重置状态,跳转到连接页面
} else {
// 用户切换了账户
const newAccount = accounts[0];
console.log('账户已切换至:', newAccount);
// 更新全局状态
}
});
我记得有一次线上事故,就是因为没监听 accountsChanged,用户切换账户后还在用旧地址发起交易,结果 gas 费白花了。嗯,从那以后我把这个监听写成了强制校验逻辑。
2.5 获取链 ID
你的 NFT 平台可能部署在以太坊主网,也可能在 Goerli 测试网。获取链 ID 是为了确认用户连接的是正确的网络。
async function getChainId() {
const chainId = await window.ethereum.request({
method: 'eth_chainId'
});
// 返回的是十六进制字符串,比如 '0x5' 代表 Goerli
console.log('当前链 ID:', chainId);
// 转换成十进制
const decimalChainId = parseInt(chainId, 16);
return decimalChainId;
}
常见的链 ID 对照表:
| 网络名称 | 链 ID(十六进制) | 链 ID(十进制) |
|---|---|---|
| 以太坊主网 | 0x1 | 1 |
| Goerli 测试网 | 0x5 | 5 |
| Sepolia 测试网 | 0xaa36a7 | 11155111 |
| Polygon 主网 | 0x89 | 137 |
wallet_switchEthereumChain 方法自动帮用户切换到正确的网络。
2.6 处理连接错误
连接过程中可能遇到各种错误。我总结了几种常见情况:
- 用户拒绝连接:错误码 4001,提示用户手动授权
- MetaMask 未安装:引导用户安装扩展
- 网络请求超时:可能是 RPC 节点挂了,建议重试
- 链 ID 不匹配:提示用户切换网络
async function handleConnection() {
try {
await connectWallet();
const chainId = await getChainId();
// 检查是否在正确的网络
if (chainId !== 5) { // 假设我们要用 Goerli
await switchToCorrectNetwork();
}
} catch (error) {
// 统一错误处理
if (error.code === 4001) {
// 用户拒绝
showToast('请授权连接钱包');
} else if (error.code === -32002) {
// 请求已挂起
showToast('请检查 MetaMask 中的待处理请求');
} else {
// 其他错误
console.error('连接失败:', error);
showToast('连接失败,请重试');
}
}
}
我曾经犯过一个低级错误:把所有错误都笼统地提示「连接失败」。结果用户根本不知道是没装 MetaMask 还是拒绝了授权。后来我针对每种错误码做了不同的提示文案,用户反馈好多了。
eth_requestAccounts 之前调用 eth_accounts。后者只返回已授权的账户,不会弹出授权窗口。很多新手搞混这两个方法,导致用户永远看不到授权弹窗。
小结
这一节的内容其实就一句话:先检测、再连接、后监听、最后兜底。你想想看,MetaMask 集成说白了就是和浏览器里的一个对象打交道,只要把它的生命周期管理好,基本不会出大问题。
下一节我们会讲如何用 Web3.js 发起交易,包括转账和调用合约。到时候你会看到,前面这些准备工作做得越扎实,后面的交易逻辑就越顺畅。