You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中在getInitialProps内调用web3.eth.getAccounts()返回undefined的问题

问题解答

为什么getInitialProps里调用web3.eth.getAccounts()返回undefined

getInitialProps 在Next.js中是服务端/静态渲染阶段执行的代码,这个环境下没有浏览器端的用户钱包(比如MetaMask)上下文。web3.eth.getAccounts() 依赖浏览器钱包注入的提供者(provider)来获取用户授权的账户,服务端环境无法访问浏览器的钱包状态,所以会返回undefined。而你在其他位置(比如组件的客户端生命周期方法、事件回调)调用正常,是因为那些代码运行在浏览器端,能访问到钱包提供者。

可行的实现方式

方式1:客户端侧获取账户后再请求合约数据

放弃在服务端获取用户地址,改为在客户端组件挂载后获取账户,再调用合约接口:

import { useEffect, useState } from 'react';
import web3 from '../utils/web3';
import YourContract from '../utils/YourContract';

function YourPage() {
  const [userData, setUserData] = useState(null);
  const [account, setAccount] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      // 在客户端获取账户
      const accounts = await web3.eth.getAccounts();
      if (accounts.length === 0) {
        alert('请连接你的钱包');
        return;
      }
      setAccount(accounts[0]);
      // 调用合约获取数据
      const contract = new web3.eth.Contract(YourContract.abi, YourContract.address);
      const data = await contract.methods.getUserData(accounts[0]).call();
      setUserData(data);
    };

    fetchData();
  }, []);

  if (!account) return <div>请连接钱包...</div>;
  if (!userData) return <div>加载中...</div>;

  return (
    <div>
      <p>你的地址:{account}</p>
      <p>合约数据:{JSON.stringify(userData)}</p>
    </div>
  );
}

export default YourPage;

方式2:使用动态导入+客户端渲染组件

如果需要页面初始展示加载状态,然后在客户端完成数据获取,可以把相关逻辑封装到客户端组件,通过动态导入禁用服务端渲染:

// pages/your-page.js
import dynamic from 'next/dynamic';

// 禁用服务端渲染,组件只会在客户端加载
const UserDataComponent = dynamic(() => import('../components/UserDataComponent'), {
  ssr: false,
  loading: () => <div>加载中...</div>
});

function YourPage() {
  return <UserDataComponent />;
}

export default YourPage;

然后在UserDataComponent.js里实现账户和数据获取逻辑:

// components/UserDataComponent.js
import { useEffect, useState } from 'react';
import web3 from '../utils/web3';
import YourContract from '../utils/YourContract';

export default function UserDataComponent() {
  const [userData, setUserData] = useState(null);
  const [account, setAccount] = useState(null);

  useEffect(() => {
    const init = async () => {
      const accounts = await web3.eth.getAccounts();
      if (!accounts.length) {
        try {
          // 触发钱包连接请求(如果用户还没连接)
          await window.ethereum.request({ method: 'eth_requestAccounts' });
          const newAccounts = await web3.eth.getAccounts();
          setAccount(newAccounts[0]);
        } catch (err) {
          console.error('用户拒绝连接钱包', err);
          return;
        }
      } else {
        setAccount(accounts[0]);
      }

      if (account) {
        const contract = new web3.eth.Contract(YourContract.abi, YourContract.address);
        const data = await contract.methods.getUserData(account).call();
        setUserData(data);
      }
    };

    init();
  }, [account]);

  if (!account) return <div>请连接钱包...</div>;
  if (!userData) return <div>加载数据中...</div>;

  return (
    <div>
      <h3>你的账户数据</h3>
      <p>地址:{account}</p>
      <p>合约返回数据:{JSON.stringify(userData)}</p>
    </div>
  );
}

方式3:使用Session或Cookie传递账户(仅限信任场景)

如果你的场景是用户已通过其他方式授权(比如登录时绑定钱包地址),可以在服务端通过Session或Cookie获取已存储的账户地址,再调用合约:

function YourPage({ userData }) {
  return (
    <div>
      <p>你的账户数据:{JSON.stringify(userData)}</p>
    </div>
  );
}

YourPage.getInitialProps = async ({ req }) => {
  // 从Session或Cookie中获取已存储的用户地址
  const userAddress = req.session?.walletAddress;
  if (!userAddress) {
    return { userData: null };
  }

  // 服务端使用web3连接合约(这里的web3是连接到节点的实例,不是客户端钱包的)
  const web3 = new Web3(process.env.ETHEREUM_NODE_URL);
  const contract = new web3.eth.Contract(YourContract.abi, YourContract.address);
  const userData = await contract.methods.getUserData(userAddress).call();

  return { userData };
};

export default YourPage;

注意:这种方式只适用于你已经在服务端存储了用户的钱包地址(比如用户主动绑定并验证过),不能直接在服务端获取未授权的用户钱包地址。

内容的提问来源于stack exchange,提问作者LocoScotch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 07:35:10