如何在php中为json api实现缓存系统

Posted

技术标签:

【中文标题】如何在php中为json api实现缓存系统【英文标题】:How to implement cache system in php for json api 【发布时间】:2013-10-04 18:14:33 【问题描述】:

我的网站上有一些自定义社交按钮,我使用 API 中的 json 为其获取分享号/关注者号。 我试图实现一个缓存系统来减少加载时间并消除因过度使用 API 而被“警告”的风险。但是,我在这方面没有成功,主要是因为我不太了解集成步骤。 我希望有人可以帮我集成一个缓存系统。

以下是 Twitter、Google Plus 和 Instagram 的 php 代码:

推特 ob_start(); $twittershare = 'http://cdn.api.twitter.com/1/urls/count.json?url='.$product["href"] .''; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $twittershare); curl_setopt($ch, CURLOPT_HEADER, 0); $jsonstring = curl_exec($ch); curl_close($ch); $bufferstr = ob_get_contents(); ob_end_clean(); $json = json_decode($bufferstr); 回声$json->计数; 谷歌加号 $url = ''.$product["href"] .''; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://clients6.google.com/rpc?key=xxxxxxxxxx"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, '["method":"pos.plusones.get","id":"p","params":"nolog":true,"id":"' . $url '","source":"widget","userId":"@viewer","groupId":"@self","jsonrpc":"2.0","key":"p","apiVersion" :"v1"]'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json')); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $curl_results = curl_exec($ch); curl_close($ch); $json = json_decode($curl_results, true); $count = intval($json[0]['result']['metadata']['globalCounts']['count']); $数据 = 数组(); $data['plus_count'] = (string) $count; $data['url'] = $url; 回声 $data['plus_count']; Instagram(获取关注者编号) ob_start(); $insta = 'https://api.instagram.com/v1/users/00000000?access_token=token'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $insta); curl_setopt($ch, CURLOPT_HEADER, 0); $jsonstring = curl_exec($ch); curl_close($ch); $bufferstr = ob_get_contents(); ob_end_clean(); $json = json_decode($bufferstr); echo $json->data->counts->followed_by;

希望大家可以一步步指导我如何为上面的代码sn-ps实现缓存系统。

【问题讨论】:

您提到“消除因过度使用 API 而被‘警告’的风险”,我问自己:这些限制是什么?您的网站收到这么多请求吗?至于缓存系统:这取决于:您可以将请求的结果存储在数据库中或带有时间戳的 memcached 中,并且仅根据需要更新它们(通过不同的服务,例如通过 cron 作业)。您的页面只是从数据后端读取并在它不可用时获取它。 @nietonfir 老实说,我不知道限制,但主要问题是页面加载时间长。是的,我读过它,我只是不知道如何实际实现它。数据库将结果存储在服务器上的文件中不是更容易且压力更小吗?同样,我只是根据我在这里和那里读到的内容进行猜测。 不,您不想在文件中存储任何内容。如果页面加载时间是您主要关心的问题,那么不要在请求期间从 API(或您的缓存系统)获取数据,而是异步(通过 AJAX)获取数据。这也将允许您独立实现缓存系统。 【参考方案1】:

好吧,正如我在评论中提到的,我会使用 Memcached 和一个数据库,但我会起草一个仅数据库的解决方案(使用 PDO 用于 twitter)并将 Memcached 部分作为奖励练习留给你。 ;) 我会通过 AJAX 加载关注者信息,以减少页面加载时间,例如关注者数量需要更新。

我将使用以下数据库架构:

CREATE TABLE IF NOT EXISTS `Followers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `url` varchar(100) NOT NULL,
  `data` longtext NOT NULL,
  `followers` int(5) NOT NULL,
  `last_update` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

首先我要定义一个接口,这样你就不用依赖任何实现了:

interface SocialFollowers

    public function getFollowers();

然后,对于 twitter 共享 API,我将有一个实现类,它获取数据库句柄和用于初始化的目标 URL。类属性由检索到的数据(如果可用)填充。如果时间戳足够新,您将立即获得关注者数量,否则会查询 API、存储结果并检索关注者数量。

class TwitterFollowers implements SocialFollowers

    private $data = null;
    private $url = "";
    private $db = null;
    private $followers = null;

    protected $shareURL = "https://cdn.api.twitter.com/1/urls/count.json?url=";

    public function __construct($db, $url) 
        // initialize the database connection here
        // or use an existing handle
        $this->db = $db;

        // store the url
        $this->url = $url;

        // fetch the record from the database
        $stmt = $this->db->prepare('SELECT * FROM `Followers` WHERE url = :url ORDER BY last_update DESC LIMIT 1');
        $stmt->bindParam(":url", $url);
        $stmt->execute();

        $this->data = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!empty($this->data))
            $this->followers = $this->data["followers"];
    

    public function getFollowers()
    
        // create a timestamp that's 30 minutes ago
        // if it's newer than the value from the database -> call the api
        $old = new DateTime();
        $old->sub(new DateInterval("PT30M"));

        if (is_null($this->followers) || (new DateTime($this->data["last_update"]) < $old) ) 
            return $this->retrieveFromAPI();
        

        return $this->followers;
    

    private function retrieveFromAPI()
    
        // mostly untouched
        ob_start();
        $twittershare = $this->shareURL . $this->url;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $twittershare);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        $jsonstring = curl_exec($ch);
        curl_close($ch);
        $bufferstr = ob_get_contents();
        ob_end_clean();
        $json = json_decode($bufferstr);

        $this->followers = $json->count;

        // store the retrieved values in the database
        $stmt = $this->db->prepare('INSERT INTO Followers (url, data, followers)'
            .'VALUES (:url, :data, :followers)');
        $stmt->execute(array(
            ":url" => $this->url,
            ":data" => $bufferstr,
            ":followers" => $this->followers
        ));

        return $this->followers;
    

对于 Facebook、Google+、the-next-social-network,您只需添加另一个实现。

请注意,此代码未经测试。它错过了 PDO 查询的一些 try/catch 块,并且还有改进的空间(例如:缺少某种锁定机制来防止同时检索相同的 URL,是否有必要存储返回的 blob 等)。

希望对你有所帮助。

[编辑] 我稍微更新了代码(修复了一些拼写错误和转换问题)并对其进行了测试。您可以在github 找到工作版本。所缺少的只是像 ajax sn-p(假设是 jQuery)这样的

$.ajax(
    url: "http://example.com/twitter.php",
    type: "get",
    data: url: "http://***.com"
    success: function(data, textStatus, jqXHR) 
        // Update the corresponding counter like
        // $("#twitterfollowers").text(data);
        console.log(data);
    
);

【讨论】:

感谢@nietonfir 的回答,但不幸的是它不起作用,它破坏了页面。我不知道,我只是不喜欢乱搞数据库,它是存储我网站重要信息的主要核心。 @CristiSilaghi 我不知道您是如何得出“搞乱数据库”的结论,因为数据库是用于存储数据的。 ;-) 如果您不想将该信息保存在与您的网站相同的存储层中,只需使用另一个数据库/表。正如我所说,代码没有经过测试或完成(例如缺少 AJAX 调用),但应该给你一个想法。 你说得对,我没有考虑过使用单独的数据库。我真傻:) 我不知道这种 php 编码(在这个高级别),所以不完整的代码并不能真正帮助我。这就是为什么我发布这个问题,以获得实施方面的帮助。我在网上找了几个教程,但我是缓存部分的php新手。 @CristiSilaghi 我更新了答案并修复了代码示例。我希望工作代码为您提供足够的信息来帮助您继续前进。祝你好运。 @MaXi32 你可以,但这首先会破坏缓存的整个概念,因为会话绑定到具有相应会话密钥的用户代理。并且会话处理程序默认是文件,所以数据库连接/redis/memcached/...肯定会更快。

以上是关于如何在php中为json api实现缓存系统的主要内容,如果未能解决你的问题,请参考以下文章

缓存 Instagram API 请求

PHP 中的子资源完整性和缓存破坏技术

千万级并发!如何设计一个多级缓存系统?

PHP数组缓存:三种方式JSON序列化和var_export的比较

使用 Cloudflare 缓存 JSON

laravel5.5缓存系统