【问题标题】:Google People API "Request mask cannot be empty"Google People API“请求掩码不能为空”
【发布时间】:2017-05-10 19:58:42
【问题描述】:

我正在尝试请求通过 Google OAuth 登录的用户的个人资料信息。我的请求格式正确,我成功登录,但是当我尝试在 PHP 中发出以下请求时,我收到错误 Request Mask cannot be empty。有效路径是:...

但是,从Google People API people.get documentation 可以清楚地看出,请求掩码值是可选的,如果未通过,will return all values except for people.connections.list。这是我的代码:

// The entire OAuth process works up until this point...
// create the service
$service = new Google_Service_People($this->client);

try {
  $results = $service->people->get('people/me');
} catch(\Exception $exception) {
  echo $exception->getMessage();
  exit;
}

这是我从这个错误中得到的异常消息:

{ "error": { "code": 400, "message": "Request mask can not be empty. Valid paths are: [person.addresses, person.age_ranges, person.biographies, person.birthdays, person.bragging_rights, person.cover_photos, person.email_addresses, person.events, person.genders, person.im_clients, person.interests, person.locales, person.memberships, person.metadata, person.names, person.nicknames, person.occupations, person.organizations, person.phone_numbers, person.photos, person.relations, person.relationship_interests, person.relationship_statuses, person.residences, person.skills, person.taglines, person.urls].", "errors": [ { "message": "Request mask can not be empty. Valid paths are: [person.addresses, person.age_ranges, person.biographies, person.birthdays, person.bragging_rights, person.cover_photos, person.email_addresses, person.events, person.genders, person.im_clients, person.interests, person.locales, person.memberships, person.metadata, person.names, person.nicknames, person.occupations, person.organizations, person.phone_numbers, person.photos, person.relations, person.relationship_interests, person.relationship_statuses, person.residences, person.skills, person.taglines, person.urls].", "domain": "global", "reason": "badRequest" } ], "status": "INVALID_ARGUMENT" } }

谁能帮帮我?


更新 1:

当我尝试为请求掩码传递一些值时,$service->people->get('people/me', array("person.names")); 我收到异常消息:Illegal string offset 'type'

【问题讨论】:

  • 您使用的是最新版本的 PHP 库吗?如果没有,请尝试更新到最新版本。
  • 我遇到了同样的错误,但使用的是 javascript 和网页。但是,我认为自上次工作以来我没有改变任何东西。这对您来说是刚刚开始的新问题,还是只是尝试实施?
  • 我从今天开始在 Go 库中遇到同样的错误。 (我已经好几个星期没碰我的代码了。)也许最近发生了一些变化?
  • 普通的休息电话也会发生这种情况
  • 是的,我使用的是最新版本的 PHP 库。我在 Laravel 框架中使用 composer,所以我的 composer.json 文件中定义的版本是"google/apiclient": "^2.0"。我删除了vendor 文件夹并使用composer install 完全重新安装了依赖项,但仍然遇到同样的问题。我不确定是否发生了变化,但它们的内部 API 逻辑似乎发生了一些变化。

标签: google-oauth google-people-api


【解决方案1】:

为时已晚,但也许这对其他人有用。

使用下面的数组作为第二个参数,通过 api 调用添加 requestMask

$optParams = array('requestMask.includeField'=>'person.names' );

【讨论】:

  • 谢谢,就是这样!我没有意识到 requestMask.includeField 是使用点语法传递的..
【解决方案2】:

我找到了解决办法。我能够从 Plus 服务而不是 People 请求部分用户配置文件信息。我对为什么这似乎已经改变的预感是谷歌已经修改了他们 API 的内部逻辑,并且没有更新他们的文档。 (在撰写本文时,Google 的 PHP OAuth 库处于测试阶段)。

就我而言,我真正想要的是获取用户的用户名和电子邮件地址。我没有使用People 服务来发出配置文件请求,而是使用Plus 服务,并要求提供一些额外的范围来获取电子邮件地址。这是我的 PHP 实现的全部内容。请注意我在构造函数中请求的三个范围:

Google_Service_Plus::USERINFO_PROFILE, Google_Service_People::USERINFO_PROFILE, Google_Service_People::USERINFO_EMAIL

成功验证后,我不再从 People 服务请求 people/me,而是从 Plus 服务请求 me,并附加了几个请求以获取剩余信息:

$plus = new Google_Service_Plus($this->client);

try {
  $plus_results = $plus->people->get('me');
} catch(\Exception $exception) {
  echo $exception->getMessage();
  exit;
}

<?php

namespace App\Auth;
require_once '/var/www/html/oauth/vendor/google/apiclient-services/src/Google/Service/People.php';
require_once '/var/www/html/oauth/vendor/google/apiclient-services/src/Google/Service/Plus.php';
require_once '/var/www/html/oauth/vendor/google/apiclient/src/Google/Client.php';
require_once 'Session.php';
use Google_Client;
use Google_Service_People;
use Google_Service_Plus;
use App\Auth\Session;

/**
 * This class performs a basic oauth authentication
 * using Google sign in and upon calling the handle_auth
 * method, retrieves the user's profile and sets session
 * variables for use throughout an application.
 */
class GoogleAuth {

  private static $DOMAIN = 'google';

  /**
   * Google auth client
   * @var Google_Client
   */
  public $client;

  /**
   * Config json filepath
   * @var String
   */
  public $config_json;

  /**
   * The URI to redirect to after succesful oauth
   * @var String
   */
  public $redirect_uri;

  /**
   * The authorization url
   * @var String
   */
  public $auth_url;

  /**
   * Logout url to redirect to after logout
   * @var String
   */
  public $logout_url;

  /**
   * The name of the application as listed in the Google
   * app Dashboard.
   * @var String
   */
  public $application_name;

  /**
   * The developer hash key available in the Google
   * App Credentials dashboard.
   * @var String
   */
  public $developer_key;

  /**
   * Scopes to request in the oauth request.
   * @var [type]
   */
  public $scope;

  /**
   * Url to redirect to upon successful authentication
   * @var String
   */
  public $auth_success_url;

  public function __construct($config) {
    // Eventually we can extend the scope to handle different
    // values or multiple values. For now, this class only
    // supports user profile information.
    $config['scope'] = array(
      Google_Service_Plus::USERINFO_PROFILE,
      Google_Service_People::USERINFO_PROFILE,
      Google_Service_People::USERINFO_EMAIL
    );

    $this->init($config);
  }

  private function init($config) {
    
    if(!isset($config)) {
      throw new \Exception('Config is not valid.');
    }
    if(!isset($config['config_json'])) {
      throw new \Exception('Path to config json is invalid.');
    }
    if(!file_exists($config['config_json'])) {
      throw new \Exception('Config JSON file could not be found: ' . $config['config_json']);
    }
    if(!isset($config['application_name'])) {
      throw new \Exception('Application name is invalid.');
    }
    if(!isset($config['developer_key'])) {
      throw new \Exception('Developer Key is invalid.');
    }
    if(!isset($config['scope'])) {
      throw new \Exception('Scope is invalid.');
    }
    if(!isset($config['redirect_uri'])) {
      throw new \Exception('Redirect URL is invalid.');
    }
    if(!isset($config['logout_url'])) {
      throw new \Exception('Logout URL is invalid.');
    }

    $this->client = new Google_Client();
    $this->config_json = $config['config_json'];
    $this->redirect_uri = $config['redirect_uri'];
    $this->application_name = $config['application_name'];
    $this->developer_key = $config['developer_key'];
    $this->scope = $config['scope'];
    $this->logout_url = $config['logout_url'];

    // Let the session know where we want to go on logout.
    Session::set_logout_url($this->logout_url, self::$DOMAIN);

    $this->client->setAuthConfig($this->config_json);

    foreach($this->scope as $scope) {
      $this->client->addScope($scope);
    }
    
    $this->client->setApplicationName($this->application_name);
    $this->client->setDeveloperKey($this->developer_key);
    $this->client->setRedirectUri($this->redirect_uri);
    $this->client->setPrompt('select_account');
    $this->auth_url = $this->client->createAuthUrl();
  }

  public static function auth_failure(\Exception $exception) {
    return Session::auth_failure(
      $exception->getMessage(), 
      self::$DOMAIN
    );
  }

  public static function logout() {
    return Session::logout(self::$DOMAIN);
  }

  public function authenticate($request) {
    if (!$request->has('code')) {

      // User is unauthenticated, send them through the auth process
      return filter_var($this->auth_url, FILTER_SANITIZE_URL);

    } else {
      $code = $request->input('code');

      // process the code received from the auth process
      $token_response = $this->process_code($code);
      
      // Ensure the token response is valid
      Validator::token_response($token_response);
      
      // Process and retrieve the access token
      $raw_token = $this->process_token_response($token_response);

      if(isset($raw_token)) {
        // Handle the token and process the id_token
        $this->handle_id_token($raw_token);
         
        // Create the people service and make requests
        return $this->make_profile_request();

      } else {
        throw new \Exception('Failed to retrieve the access token');
      }
    }
  }

  private function process_code($code) {
    // grab the code from the URL and generate an access token
    $response = $this->client->fetchAccessTokenWithAuthCode($code);

    if(!is_array($response)) {
      throw new \Exception('Token response was invalid.');
    }

    return $response;
  }

  private function process_token_response($token_response) {
    $this->client->setAccessToken($token_response);
    return $this->client->getAccessToken();
  }

  private function handle_id_token($token) {

    $id_token = null;

    try {
      $id_token = $this->client->verifyIdToken($token['id_token']);
    } catch(\Exception $exception) {
      // clear the access token to disable any
      // approved permissions for the user's account
      $this->client->revokeToken();
      
      throw new \Exception('Google Login failed');
    }

    if(!$id_token) {
      throw new \Exception('Id Token is null or undefined');
    }

    // grab the domain from the id_token
    $email = $id_token['email'];

    // Stuff it into the session
    Session::set_email($email, self::$DOMAIN);
  }

  private function make_profile_request() {
    // create the service
    $plus = new Google_Service_Plus($this->client);

    try {
      $plus_results = $plus->people->get('me');
    } catch(\Exception $exception) {
      echo $exception->getMessage();
      exit;
    }
    
    if(!$plus_results) {
      throw new \Exception('No matching profile results.');
    }

    // Get the user's display name
    $username = $plus_results->getDisplayName();

    // Stuff it into the session
    Session::set_username($username, self::$DOMAIN);
      
    // Login. Session handles the redirect
    return Session::login(
      $username, 
      Session::get_email(self::$DOMAIN), 
      self::$DOMAIN
    );
  }
}
?>

【讨论】:

  • 感谢丹尼发布您的解决方案。正如我上面提到的,我正在使用 javascript api,但你的解决方案让我找到了我的解决方案。如果有人正在阅读这篇文章并想知道,我也从people api 切换到plus api。我把:gapi.client.people.people.get({ resourceName: "people/me" }).then( ... )改成了gapi.client.plus.people.get({ userId: 'me' }).then( ... )
【解决方案3】:

自 5 月 11 日起,我开始在 Go 库中遇到同样的错误。在 Google API 更改之前,我没有 includeField 的代码运行良好。该字段是可选的。

在 Google 文档中,现在“includeField”是必填字段。我在其他地方找不到任何公告。

https://developers.google.com/people/api/rest/v1/RequestMask

包括字段

必填。要包含在响应中的人员字段的逗号分隔列表。每条路径都应以 person. 开头:例如,person.names 或 person.photos。

最后更新时间:2017 年 5 月 19 日

为了解决我的 golang 案例,我必须在拨打 People.Get 电话之前提供 RequestMaskIncludeField 字段。

people_get_call := peopleService.People.Get("people/me").RequestMaskIncludeField("person.addresses,person.age_ranges,person.biographies,person.birthdays,person.bragging_rights,person.cover_photos,person.email_addresses,person.events,person.genders,person.im_clients,person.interests,person.locales,person.memberships,person.metadata,person.names,person.nicknames,person.occupations,person.organizations,person.phone_numbers,person.photos,person.relations,person.relationship_interests,person.relationship_statuses,person.residences,person.skills,person.taglines,person.urls")
google_account, err := people_get_call.Do()

【讨论】:

    【解决方案4】:

    就像@gonbe 指出的那样,RequestMaskIncludeField 不是必需的,但在一段时间内它是必需的。对于最新的 java 库(目前是 rev139-1.22.0),您只需将方法 setRequestMaskIncludeField() 添加到请求中,例如

     peopleService.people().get("people/me").setRequestMaskIncludeField("person.email_addresses").execute();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多