Google API php 客户端:发送 etag

Google API php client: send etag

提问人:root66 提问时间:1/6/2015 最后编辑:Linda Lawton - DaImToroot66 更新时间:11/6/2016 访问量:3699

问:

我正在使用最新的Google PHP客户端库。如何使用此库发送 etag?

我已经尝试过这样的事情:

$opt_params = array(
'etag' => 'F9iA7pnxqNgrkOutjQAa9F2k8HY/mOihMVEDLCvdSVCzwDmYHpSV');

$response = $youtube->channels->listChannels('snippet', array('id' => $channel_id), $opt_params);

谢谢!

的YouTube-API 谷歌-API-PHP客户端

评论


答:

0赞 Linda Lawton - DaImTo 1/6/2015 #1

如果您查看 channels.list 的文档,您会注意到 etag 不是可选参数之一。

因此,您无法通过 api 将 etag 发送到列表频道,这不是客户端库的限制。

评论

0赞 root66 1/6/2015
好的,但是为什么 channels.list 会返回 etag?只是为了比较我的本地缓存数据?
0赞 Linda Lawton - DaImTo 1/6/2015
确切地说,这是您查看系统中的数据是否已更改的一种方式。
0赞 root66 1/6/2015
如果任何“部分”(即 brandingSettings->channel->featuredChannelsUrls)发生变化,etag 会改变吗?我问,因为“统计数据”正在永久变化,而 etag 保持不变。
0赞 Linda Lawton - DaImTo 1/6/2015
TBH:我从来没有打扰过 Etag,我从来没有让它工作过。我发现自己比较所有东西,然后依靠它来改变它更容易。根据我对几个 API 的经验,它似乎没有改变。
1赞 Lee Goddard 9/16/2020
从上面看,您似乎没有 etag 工作,并认为没有必要。但是,由于每天有10,000个配额的限制,etag已成为保留配额的最佳方式之一。它似乎对我有用。谢谢
2赞 Coded Monkey 2/4/2015 #2

Google API PHP 客户端没有对 etag 的原生支持。也就是说,您仍然可以更改 curl 请求并应用 etag 作为标头。

不幸的是,当它收到标头时会抛出异常,因此您需要在 -block 中单独处理这些异常。Google_Http_REST304 Not Modifiedcatch

这是生成的PHP代码(注意,这是针对Google API PHP客户端的版本1):

class EmptyResponse { }

$DEVELOPER_KEY = '';

$client = new Google_Client();
$client->setDeveloperKey($DEVELOPER_KEY);

$youtube = new Google_Service_YouTube($client);

// Do some logic, catch some resources
// ..

// Set the "If-None-Match" header for the etag
// This assumes the Google API is using CURL
$client->getIo()->setOptions(array(
    CURLOPT_HTTPHEADER => array('If-None-Match: "4FSIjSQU83ZJMYAO0IqRYMvZX98/OPaxOhv3eeKc9owSnDQugGfL8ss"'),
));

try {
  $response = $youtube->playlists->listPlaylists('snippet', array(
      'id' => 'PLOIvOnfHWjIkiz6fd5KYUXJY6ZpHRqPfW',
  ));
}
catch (Google_Service_Exception $e) {
  if (304 == $e->getCode()) {
      // If the error code is 304 (Not Modified) return an empty response
      $response = new EmptyResponse;
  }
  else {
      // The request was unsuccesful
      $response = null;
  }
}

// After the request set the headers back to default
$client->getIo()->setOptions(array(
    CURLOPT_HTTPHEADER => array(),
));

var_dump($response);

// Catch some more resources
// ...

评论

1赞 Saumini Navaratnam 10/26/2016
新版本的 api 不支持 getIO()。实现上述功能的替代方法是什么。
2赞 RLVillacalos 5/21/2015 #3

这篇文章有点长(如果不是太长的话)。如果您只需要代码,请向下滚动并跳过我的讨论。请按照您的意愿进行。

背景

我不知道是否有人想出了解决这个问题的方法。Coded Monkey 的答案是一个开始。问题在于,他提出的解决方案假设 API 仅使用开发人员密钥/API 密钥而不是 oauth 访问密钥发出请求。如果您使用开发人员密钥尝试他的代码,您将获得以下内容:

调用 GET https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet%2Cstatus&mine=true&maxResults=50&key={developer key here} 时出错: (401) 需要登录

开发者密钥不足以检索用户的 youtube 数据,并且开发者密钥不会授予对任何帐户信息的访问权限。这包括 youtube 数据。要访问 youtube 数据,必须使用 oauth 访问密钥(在此处阅读:api 密钥)

请注意,开发人员密钥将成为查询字符串的一部分。另一方面,当您使用 oauth 密钥时,该密钥将成为请求标头:

授权:持有者 {oauth key here}

但是,如果您尝试使用 oauth 密钥,您仍然会收到与上述相同的错误。这是非常令人沮丧的。我想这就是为什么 Coded Monkey 的回答没有得到赞成的原因。要了解原因,必须了解谷歌客户端如何发送请求。

Google PHP 客户端的工作原理

我对谷歌客户端如何在幕后工作的解释并不完整,只是基于我从弄清楚如何解决这个问题的经验中学到的东西。

我称之为 的 google 客户端使用类实例 (我将调用 )来发送请求。可以获取当前实例并使用 和 方法更改它。 是一个抽象类。PHP Google API 库中可用的一个具体子类是 。顾名思义,该类使用 .$clientGoogle_IO_Abstract$io$io$client->setIo()$client->getIo()Google_IO_AbstractGoogle_IO_Curlcurl

从现在开始,我将假设这是一个实例。以下内容(来自 Code Mokey 的解决方案):$ioGoogle_IO_Curl

$client->getIo()->setOptions(array(
    CURLOPT_HTTPHEADER => array('If-None-Match: "4FSIjSQU83ZJMYAO0IqRYMvZX98/OPaxOhv3eeKc9owSnDQugGfL8ss"'),
));

If-None-Match HTTP 标头添加到 curl 的标头选项中。只有在调用时才会实际添加标头。 是需要发送的请求。$io->executeRequest($request)$request$client

设置 curl 的标头是通过 完成的,其中 是一个 curl 实例,是一个标头数组。curl_setopt($curl, CURLOPT_HTTPHEADER, $headers)$curl$headers

如果您将阅读实现。您将看到大多数部分用于设置 curl 的选项。一个重要的部分是将 http 标头收集到如下所示的数组中(这是来自源代码)。标题也在此处添加。executeRequest$request$curlHeadersGoogle_IO_CurlAuthorization

    $requestHeaders = $request->getRequestHeaders();
    if ($requestHeaders && is_array($requestHeaders)) {
      $curlHeaders = array();
      foreach ($requestHeaders as $k => $v) {
        $curlHeaders[] = "$k: $v";
      }
      curl_setopt($curl, CURLOPT_HTTPHEADER, $curlHeaders);
    }

请注意,在收集标头后,调用它来设置 curl 的标头选项。现在问题来了,在这些代码行之后是设置其他选项的部分。使用该方法设置的选项,这意味着将有另一个调用,但这次$headers仅包含 If-None-Match 标头。第二次调用将替换所有以前的标头。瞧!标头不见了。我不确定是否有人报告过这件事。我不确定这是否是故意的。但对于像我这样的初学者来说,这真的很令人沮丧curl_setopt()setOptions()curl_setopt($curl, CURLOPT_HTTPHEADER, $headers)Authorization

无论如何,我想出了一个快速的解决方案。

我的解决方案

我将在这里停止我的讨论,而是给你代码(Google_IO_Curl_Mod.php):

<?php
/**
 * Wrapper class for Google_IO_Curl.
 *
 * This class fixes issues involving request headers added using setOptions()
 * 
 * @author Russel Villacarlos<cvsurussel_AT_gmail.com>
 */

if (!class_exists('Google_Client')) {
  require_once 'Google/autoload.php';
}

class Google_IO_Curl_Mod extends Google_IO_Curl
{

  //Google_IO_Curl instance
  private $io;

  //Array for additional headers added using setOptions()
  private $headers;

  public function __construct(Google_IO_Curl $io)
  { 
      $this->io = $io;
      $this->headers=[];
  }

  /**
   * Execute an HTTP Request
   *
   * @param Google_Http_Request $request the http request to be executed
   * @return array containing response headers, body, and http code
   * @throws Google_IO_Exception on curl or IO error
   */
  public function executeRequest(Google_Http_Request $request)
  {    
      foreach ($this->headers as $value) {
          if(is_string($value) && strpos($value,":")!==false){
            $header = split(":\s*",$value);

            $request->setRequestHeaders(array($header[0]=>$header[1]));              
          }
      }
      $result = $this->io->executeRequest($request); 
      return $result;
  }

  /**
   * Set options that update the transport implementation's behavior.
   * @param $options
   */
  public function setOptions($options)
  {
      if($options){
          if(array_key_exists(CURLOPT_HTTPHEADER, $options)){
              $this->headers= array_merge($this->headers, $options[CURLOPT_HTTPHEADER]);              
              unset($options[CURLOPT_HTTPHEADER]);
          }    
          $this->io->setOptions($options);
      }
  }

  /**
   * Set the maximum request time in seconds.
   * @param $timeout in seconds
   */
  public function setTimeout($timeout)
  {
    $this->io->setTimeout($timeout);
  }

  /**
   * Get the maximum request time in seconds.
   * @return timeout in seconds
   */
  public function getTimeout()
  {
    return $this->io->getTimeout();
  }

  /**
   * Test for the presence of a cURL header processing bug
   *
   * {@inheritDoc}
   *
   * @return boolean
   */
  protected function needsQuirk()
  {
    return $this->io->needsQuirk();
  }
}

要使用它,只需执行以下操作:

$client = new Google_Client();
//codes for setting the oauth credential appears here
$io = new Google_IO_Curl_Mod(new Google_IO_Curl($client));
$client->setIo($io);
$client->getIo()->setOptions(array(
                    CURLOPT_HTTPHEADER => 
                           array('If-None-Match: "NO6QTeg0-3ShswIeqLchQ_mzWJs/wtg8du-olFPZ73k6UW7Jk5JcwpQ"'),
                   ));
//codes for calling youtube api or any google api goes here

请注意,双引号对是 etag 的一部分。