NodeJS全栈WEB3面试题——P5全栈集成与 DApp 构建
5.1 如何实现一个完整的 Web3 登录流程(前端 + 后端)?
✅ 核心机制:钱包签名 + 后端验签
Web3 登录是基于“消息签名”来验证用户链上身份,而非传统用户名/密码。
💻 前端(使用 MetaMask):
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const address = await signer.getAddress();// 获取 nonce(防重放)
const { nonce } = await fetch('/api/nonce').then(res => res.json());
const signature = await signer.signMessage(`Login nonce: ${nonce}`);// 发回后端验证
await fetch('/api/verify', {method: 'POST',body: JSON.stringify({ address, signature, nonce }),
});
🛠 后端(以 Express 为例):
app.post('/api/verify', async (req, res) => {const { address, signature, nonce } = req.body;const recovered = ethers.utils.verifyMessage(`Login nonce: ${nonce}`, signature);if (recovered.toLowerCase() === address.toLowerCase()) {const token = jwt.sign({ address }, JWT_SECRET, { expiresIn: '1h' });res.send({ token });} else {res.status(401).send('Signature invalid');}
});
5.2 如何使用 MetaMask 调用合约函数?
✅ 步骤:
-
连接 MetaMask(请求账户权限)
-
获取合约实例
-
调用合约函数(读 / 写)
💡 写操作(如 mint、transfer)代码示例:
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();const contract = new ethers.Contract(contractAddress, abi, signer);
const tx = await contract.transfer(toAddress, amount);
await tx.wait();
📍注意事项:
-
写操作需要 gas 费,MetaMask 会弹窗确认;
-
ABI 与合约地址必须正确,网络必须匹配;
5.3 如果你要构建一个 NFT 市场,需要考虑哪些功能与技术选型?
✅ 功能模块:
-
用户认证(钱包登录)
-
NFT 铸造、展示、上架、购买、转移
-
收藏夹 / 我的藏品
-
支付 / 分账 / 版税支持
-
IPFS 文件存储
-
搜索 & 排序
🧩 技术选型建议:
模块 | 技术 |
---|---|
前端 | Next.js + Ethers.js / Wagmi + Tailwind CSS |
后端 | Node.js + NestJS / Express |
合约 | Solidity (ERC-721 + Marketplace) |
存储 | IPFS / Pinata / Web3.Storage |
数据索引 | The Graph / Moralis / Alchemy NFT API |
数据库 | PostgreSQL / MongoDB(缓存链上数据) |
钱包支持 | MetaMask / WalletConnect |
部署平台 | Vercel + Infura / Alchemy |
5.4 如何用 Next.js + Web3.js 构建一个链上数据展示页面?
✅ 目标:展示某合约的链上数据(如 NFT 列表、余额、合约状态等)
步骤:
-
安装依赖:
ethers
/web3.js
-
创建合约读取逻辑
-
通过
useEffect
获取数据并渲染
💡 示例:获取当前账户余额并显示
// pages/index.tsx
import { useEffect, useState } from 'react';
import { ethers } from 'ethers';export default function Home() {const [balance, setBalance] = useState('');useEffect(() => {async function fetchBalance() {const provider = new ethers.providers.Web3Provider(window.ethereum);const signer = provider.getSigner();const address = await signer.getAddress();const bal = await provider.getBalance(address);setBalance(ethers.utils.formatEther(bal));}fetchBalance();}, []);return <div>Your Balance: {balance} ETH</div>;
}
5.5 IPFS 是什么?如何结合 IPFS 上传文件并在合约中引用?
✅ IPFS 简介:
-
IPFS(InterPlanetary File System)是分布式文件存储系统,文件通过其内容的哈希(CID)来访问;
-
区块链适合存储不可变数据的指针,大文件用 IPFS 存储,合约中保存哈希引用;
✅ IPFS 上传文件(使用 Pinata):
import axios from 'axios';
const formData = new FormData();
formData.append("file", fileInput.files[0]);const res = await axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", formData, {headers: {'pinata_api_key': 'xxx','pinata_secret_api_key': 'xxx'}
});const cid = res.data.IpfsHash; // 保存此CID
✅ 合约中引用方式:
function mintNFT(address to, string memory tokenUri) public {_safeMint(to, tokenId);_setTokenURI(tokenId, tokenUri); // 如: "ipfs://Qm123abc..."
}
📌 总结:
全栈开发者需要具备:
-
熟练使用 Ethers.js 与前端集成 MetaMask;
-
能构建后端签名验证、合约交互服务;
-
熟悉 NFT、IPFS、链上数据展示;
-
有一定架构能力构建 DApp,如 NFT 市场、DAO 等;