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

Google People API回调返回Undefined,无法获取联系人数据求助

问题分析与解决方案

你的问题核心是异步回调的返回值无法同步获取,导致接口里拿到undefined,而实际数据只在回调函数内部存在。下面一步步拆解问题并给出修复方案:

问题根源

  1. fs.readFile、authorize里的文件读取、Google API请求都是异步回调操作,回调函数里的return不会传递到外层函数,所以authorize和listConnectionNames本身没有返回值,自然allcontact是undefined。
  2. Express路由需要调用res.json()这类方法返回响应,你原来的return allcontact完全无效,因为路由函数的返回值不会被Express处理。

修复方案:Promise化异步操作 + async/await

把所有回调式的异步操作改成Promise,这样就能用async/await同步风格获取结果,再返回给客户端。

1. 改造authorize函数为Promise版本

function authorize(credentials) {
  return new Promise((resolve, reject) => {
    const {client_secret, client_id, redirect_uris} = credentials.installed;
    const oAuth2Client = new google.auth.OAuth2(
        client_id, client_secret, redirect_uris[0]);

    fs.readFile(TOKEN_PATH, (err, token) => {
      if (err) {
        // 同时要把getNewToken也改成Promise版本(见下方)
        getNewToken(oAuth2Client).then(resolve).catch(reject);
      } else {
        oAuth2Client.setCredentials(JSON.parse(token));
        resolve(oAuth2Client);
      }
    });
  });
}

2. 改造getNewToken为Promise版本(如果你的原函数是回调式)

function getNewToken(oAuth2Client) {
  return new Promise((resolve, reject) => {
    const authUrl = oAuth2Client.generateAuthUrl({
      access_type: 'offline',
      scope: ['https://www.googleapis.com/auth/contacts.readonly'],
    });
    console.log('授权请访问:', authUrl);

    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    });
    rl.question('输入授权码: ', (code) => {
      rl.close();
      oAuth2Client.getToken(code, (err, token) => {
        if (err) return reject('获取token失败: ' + err);
        oAuth2Client.setCredentials(token);
        fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
          if (err) return reject(err);
          console.log('token已保存到', TOKEN_PATH);
        });
        resolve(oAuth2Client);
      });
    });
  });
}

3. 改造listConnectionNames为Promise版本

function listConnectionNames(auth) {
  return new Promise((resolve, reject) => {
    const service = google.people({version: 'v1', auth});
    service.people.connections.list({
      resourceName: 'people/me',
      pageSize: 50,
      personFields: 'names,emailAddresses,phoneNumbers',
    }, (err, res) => {
      if (err) return reject('API请求失败: ' + err);
      const connections = res.data.connections;
      resolve(connections || []); // 没有联系人返回空数组
    });
  });
}

4. 改造路由处理函数

用async/await处理所有异步操作,并用res.json()返回结果:

app.get('/contacts', async function(req, res){
  try {
    // 用Promise版的文件读取替代回调式fs.readFile
    const content = await fs.promises.readFile('credentials.json');
    const credentials = JSON.parse(content);
    
    const authClient = await authorize(credentials);
    const allContacts = await listConnectionNames(authClient);
    
    console.log(allContacts);
    res.json(allContacts); // 把联系人数据返回给客户端
  } catch (err) {
    console.error('错误:', err);
    res.status(500).json({ error: err.message }); // 错误时返回500状态码和错误信息
  }
})

关键注意点

  • 所有异步操作必须用Promise封装,才能通过await获取结果。
  • Express路由里必须调用res.json()/res.send()返回响应,不能靠return值。
  • 一定要加错误捕获(try/catch),避免单个请求的错误导致整个服务器崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:03:30