今天来聊聊通过SCF实现COS更新后自动刷新CDN功能

腾讯云的COS和CDN产品是天生一对,搭配使用和大幅提高下载速度,降低成本,优化性能。但是其中也存在一个问题,当COS文件更新(重新上传或删除)CDN仍然保存缓存内容,造成与源站不一致,那能否在COS更新的时候自动刷新CDN 的缓存呢?答案是肯定的。我们可以使用腾讯云的另一个款产品SCF(无服务器云函数)来实现。

实现的方法为:

1.创建COS bucket并绑定CDN

COS控制台-创建bucket(北京)

CDN控制台-绑定CDN域名

2.创建SCF函数和COS操作触发器

我们进入SCF控制台,创建与COS同地域的函数。

SCF控制台-创建函数

↑↑↑创建一个“空白函数”,函数名和运行环境根据自己的业务需要,我们这里起名test_php 运行环境选择PHP 5.6

注:选择的运行环境和后面封装CDN使用的语言环境有关。

SCF控制台-触发方式-添加触发方式

↑↑↑创建两个COS触发器,分别是文件上传时触发,文件删除时触发,COS和SCF函数必须为同一地域。

3.实现上传事件解析和刷新CDN功能

添加函数代码:

<?php
$gl = 1;
function main_handler($event, $context) {
    $eve = json_decode(json_encode($event,JSON_FORCE_OBJECT),true);
    $usr_url=strval($eve["Records"][0]["cos"]["cosObject"]["url"]);
    
    //截取object部分
    $object=substr($usr_url,strpos($usr_url,"/",8));

    /*需要填写您的密钥,可从  https://console.cloud.tencent.com/capi 获取 SecretId 及 $secretKey*/
    $secretKey='这里替换您的secretKey';
    $secretId='这里替换您的secretId';
    $action='RefreshCdnUrl';

    $HttpUrl="cdn.api.qcloud.com";
    /*除非有特殊说明,如MultipartUploadVodFile,其它接口都支持GET及POST*/
    $HttpMethod="GET";
    /*是否https协议,大部分接口都必须为https,只有少部分接口除外(如MultipartUploadVodFile)*/
    $isHttps =true;
    $nurl="http://这里替换成您的CDN域名".$object; //   示例:$nurl="http://abc.com".$object;
    //print_r($nurl);

    /*下面这五个参数为所有接口的 公共参数;对于某些接口没有地域概念,则不用传递Region(如DescribeDeals)*/
    $COMMON_PARAMS = array(
                    'Nonce' => rand(),
                    'Timestamp' =>time(NULL),
                    'Action' =>$action,
                    'SecretId' => $secretId,
                    'SignatureMethod' => 'HmacSHA256',
                    'urls.0' => $nurl
                    );
    $PRIVATE_PARAMS = array();
    //**********执行CDN刷新URL操作**********/
    CreateRequest($HttpUrl,$HttpMethod,$COMMON_PARAMS,$secretKey, $PRIVATE_PARAMS, $isHttps);
   return "RefreshCdnUrl OK";
}
/***************CDN API调用方法***************/
function CreateRequest($HttpUrl,$HttpMethod,$COMMON_PARAMS,$secretKey, $PRIVATE_PARAMS, $isHttps)
{
        $FullHttpUrl = $HttpUrl."/v2/index.php";

        /***************对请求参数 按参数名 做字典序升序排列,注意此排序区分大小写*************/
        $ReqParaArray = array_merge($COMMON_PARAMS, $PRIVATE_PARAMS);
        ksort($ReqParaArray);

        /**********************************生成签名原文**********************************
         * 将 请求方法, URI地址,及排序好的请求参数  按照下面格式  拼接在一起, 生成签名原文,此请求中的原文为 
         * GETcvm.api.qcloud.com/v2/index.php?Action=DescribeInstances&Nonce=345122&Region=gz
         * &SecretId=AKIDz8krbsJ5yKBZQ    ·1pn74WFkmLPx3gnPhESA&Timestamp=1408704141
         * &instanceIds.0=qcvm12345&instanceIds.1=qcvm56789
         * ****************************************************************************/
        $SigTxt = $HttpMethod.$FullHttpUrl."?";
        $isFirst = true;
        foreach ($ReqParaArray as $key => $value)
        {
                if (!$isFirst) 
                {
                        $SigTxt = $SigTxt."&";
                }
                $isFirst= false;
                /*拼接签名原文时,如果参数名称中携带_,需要替换成.*/
                if(strpos($key, '_'))
                {
                        $key = str_replace('_', '.', $key);
                }
                $SigTxt=$SigTxt.$key."=".$value;
        }
        /*********************根据签名原文字符串 $SigTxt,生成签名 Signature******************/
        $Signature = base64_encode(hash_hmac('sha256', $SigTxt, $secretKey, true));

        /***************拼接请求串,对于请求参数及签名,需要进行urlencode编码********************/
        $Req = "Signature=".urlencode($Signature);
        foreach ($ReqParaArray as $key => $value)
        {
                $Req=$Req."&".$key."=".urlencode($value);
        }

        /*********************************发送请求********************************/
        if($HttpMethod === 'GET')
        {
                if($isHttps === true)
                {
                        $Req="https://".$FullHttpUrl."?".$Req;
                }
                else
                {
                        $Req="http://".$FullHttpUrl."?".$Req;
                }
                $Rsp = file_get_contents($Req);
        }
        else
        {
                if($isHttps === true)
                {
                        $Rsp= SendPost("https://".$FullHttpUrl,$Req,$isHttps);
                }
                else
                {
                        $Rsp= SendPost("http://".$FullHttpUrl,$Req,$isHttps);
                }
        }
        var_export(json_decode($Rsp,true));
}
function SendPost($FullHttpUrl, $Req, $isHttps)
{
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $Req);
        curl_setopt($ch, CURLOPT_URL, $FullHttpUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if ($isHttps === true) {
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,  false);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,  false);
        }
        $result = curl_exec($ch);
        return $result;
}
?>

↑↑↑上面内容为解析COS触发事件并刷新CDN URL的代码,注意代码中三个替换标识,需要更换成您自己的资源配置

4.验证效果

COS控制台-文件列表-上传文件
COS控制台-文件列表-删除

↑↑↑进入COS控制台上传一个文件对象并且删除一个已存在文件对象

SCF控制台-日志记录

↑↑↑SCF会触发并生成两个执行日志。注:如需调试,可在函数中增加输出语句。

CDN控制台-缓存刷新-操作记录

↑↑↑访问CDN控制台的缓存刷新–操作记录,可以看到我们上传和删除的资源均被刷新了,验证成功。

后记:在上面的实践中,我们实现了COS上传和删除文件对象时自动刷新CDN URL的功能,当然SCF产品功能并不止于此,您也可以通过代码来实现刷新后的预热功能,甚至调用CVM等其他业务服务器的功能,灵活组合,搭配使用,更多操作,等您来用。

正文完