腾讯云的 COS 和 CDN 产品是天生一对, 搭配使用和大幅提高下载速度, 降低成本, 优化性能. 但是其中也存在一个问题, 当 COS 文件更新 (重新上传或删除)CDN 仍然保存缓存内容, 造成与源站不一致, 那能否在 COS 更新的时候自动刷新 CDN 的缓存呢? 答案是肯定的. 我们可以使用腾讯云的另一个款产品 SCF(无服务器云函数) 来实现.
实现的方法为:
1. 创建 COS bucket 并绑定 CDN
COS 控制台 - 创建 bucket(北京)
CDN 控制台 - 绑定 CDN 域名
2. 创建 SCF 函数和 COS 操作触发器
我们进入 SCF 控制台, https://console.cloud.tencent.com/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 等其他业务服务器的功能, 灵活组合, 搭配使用, 更多操作, 等您来用.
来源: https://www.qcloud.com/developer/article/1354710