Google API php客户端:发送etag

时间:2015-01-06 13:47:57

标签: php youtube-api google-api-php-client

我正在使用最新的Google PHP Client library。如何将etag与此库一起发送?

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

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

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

谢谢!

3 个答案:

答案 0 :(得分:1)

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

不幸的是,Google_Http_REST在收到304 Not Modified标题时会引发异常,因此您需要在catch - 块中单独处理这些异常。

这是生成的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 :(得分:1)

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

背景

我不知道是否有人为此找到了解决方案。编码猴子的答案是一个开始。问题是他提出的解决方案假设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 keys

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

  

授权:持票人 {oauth key here}

但是,如果您尝试使用oauth键,您仍会得到与上述相同的错误。 这非常令人沮丧。而且我猜这就是为什么Coded Monkey的答案没有获得赞成。要了解原因,必须了解Google客户端如何发送请求。

Google PHP客户端如何运作

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

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

从这一点开始,我将假设$ioGoogle_IO_Curl个实例。以下(来自Code Mokey'解决方案):

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

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

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

如果您将阅读executeRequest实施。您将看到大多数部件都用于设置卷曲选项。一个重要的部分是将$request中的http标头收集到名为$curlHeaders的数组中,如下所示(这来自Google_IO_Curl源代码)。此处还添加了Authorization标题。

    $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_setopt()来设置curl的标题选项。现在出现问题,在这些代码行出现后,设置了其他选项的部分。使用setOptions()方法设置的选项,这意味着将会有另一个curl_setopt($curl, CURLOPT_HTTPHEADER, $headers)调用,但这次$ headers只包含If-None-Match标头。 第二次调用将替换所有以前的标题。瞧! 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的一部分。

答案 2 :(得分:0)

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

所以你不能通过api将etag发送到列表频道,而不是客户端库的限制。