Google API php client: send etag



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

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

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

谢谢!

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

背景

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

调用 GET 时出错 https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet%2Cstatus&mine=true&maxResults=50&key={此处的开发人员密钥}: (401) 需要登录

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

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

授权:持有者 {此处的 oauth 密钥}

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

Google PHP 客户端如何工作

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

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

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

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

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

设置 curl

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

如果您将阅读executeRequest实现。您将看到大多数部分用于设置 curl 的选项。一个重要的部分是将 http 标头从$request收集到一个名为 $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 的一部分。

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

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

这是生成的 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
// ...

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

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

相关内容

  • 没有找到相关文章

最新更新