C# 阿里云CDN缓存预热刷新功能测试

前言

      前段时间,公司的一个前端项目中需要展示3D模型和材质,其中模型是固定的,但材质所用到的贴图是渲染段动态生成的。实测前端加载模型+材质,总耗时将近20s,产品当然不满意。然后需要程序这边给出优化方案,首先想到的是方案一:减少资源大小,提高加载效率。另外一方面,由于图片由渲染端上传到OSS上,并通过了CDN加速,那有没有可能因为前端第一次下载时,资源没有被加速的问题呢?所以提出了方案二:图片上传后,主动调用CDN资源预热API,然后再通知前端加载被加速过的资源。
      通过两个方案的实施,发现方案一已经解决了问题,前端基本上可以秒加载,但为了以后考虑,还是决定将方案二的实施过程在此记录一下。

正文

一、阿里云新版API

      在官网新版的API页面找到对应功能的位置
C# 阿里云CDN缓存预热刷新功能测试_第1张图片

二、运行示例

      在对象存储里找到你想预热的文件,勾选后,导出URL。
C# 阿里云CDN缓存预热刷新功能测试_第2张图片

      在中间一栏的 [ ObjectPath ] 处填写需要预热的文件URL,如果有多个,使用 [ \r ] 或 [ \r\n ] 间隔。切换到C#,点击运行示例,等待片刻。
C# 阿里云CDN缓存预热刷新功能测试_第3张图片
      当底部控制台出现以下提示时,敲下回车即可继续

Type 'dotnet run' to make an api request with Aliyun C# SDK

shell@Alicloud:~/alibabacloud_sdk_demo/cdn/GfTCX95Fu/csharp/core$ dotnet run

      若出现如下提示,即说明调试成功

ASP.NET Core
------------
Successfully installed the ASP.NET Core HTTPS Development Certificate.
To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For establishing trust on other platforms refer to the platform specific documentation.
For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.

Unhandled Exception: Tea.TeaException: code: 404, The domain [hologarment-update.oss-cn-shanghai.aliyuncs.com] does not belong to you. request id: 28D96D69-4C39-5412-9CBB-37A5214928AB
   at AlibabaCloud.OpenApiClient.Client.DoRPCRequest(String action, String version, String protocol, String method, String authType, String bodyType, OpenApiRequest request, RuntimeOptions runtime)
   at AlibabaCloud.SDK.Cdn20180510.Client.PushObjectCacheWithOptions(PushObjectCacheRequest request, RuntimeOptions runtime)
   at AlibabaCloud.SDK.Sample.Sample.Main(String[] args) in /home/shell/alibabacloud_sdk_demo/cdn/GfTCX95Fu/csharp/core/Sample.cs:line 46

三、下载示例工程

      细心的你可能已经发现,刚才调试时并没有填写AccessKeyId、AccessKeySecret(即AK),而且示例工程的代码也发生了变化(刚才填写的ObjectPath已经在代码中赋值),这都要归功于Aliyun,已经帮我们自动获取了当前登录账户的AK。
C# 阿里云CDN缓存预热刷新功能测试_第4张图片

四、调试工程

      1. 打开压缩包,使用记事本打开 Sample.csproj ,将 netcoreapp2.1 修改为 net45 ,保存后,使用 vs201x 打开,
C# 阿里云CDN缓存预热刷新功能测试_第5张图片
      2. 这里要填写自己的账户AK

AlibabaCloud.SDK.Cdn20180510.Client client = CreateClient("accessKeyId", "accessKeySecret");

      3. 修改ObjectPath中URL的域名,为CDN加速域名
C# 阿里云CDN缓存预热刷新功能测试_第6张图片
例如:https://hologarment-update.oss-cn-shanghai.aliyuncs.com/1111111111111.jpg
改为:https://update.hologarment.tech/1111111111111.jpg

ps. 请提前在CDN-域名管理配置好需要加速的域名。然后在域名列表里将刚才配置好的加速域名绑定到二级域名,像这样
C# 阿里云CDN缓存预热刷新功能测试_第7张图片

      4. 启动调试,如果控制台出现如下提示,说明初步调试成功。
C# 阿里云CDN缓存预热刷新功能测试_第8张图片

五、根据API,完成测试代码的编写

参考API:
【 获取缓存刷新预热信息 DescribeRefreshQuota 】主要用于获取当前缓存刷新预热的余量
【 预热源站内容到缓存节点 PushObjectCache 】将URL预热到缓存节点
【 通过任务编号查询刷新预热任务信息 DescribeRefreshTaskById 】根据任务id查询预热状态

为了调试方便,我将URL放入到了一个txt文档中,这样就可以一键预热多个URL了。

完整代码如下:

// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

using AlibabaCloud.SDK.Cdn20180510.Models;
using Tea;
using Newtonsoft.Json;
using TaskInfo = AlibabaCloud.SDK.Cdn20180510.Models.DescribeRefreshTaskByIdResponseBody.DescribeRefreshTaskByIdResponseBodyTasks;
using System.IO;
using System.Text;

namespace AlibabaCloud.SDK.Sample
{
    public class Sample
    {
        public class Config
        {
            //此处填写为自己的账号AK
            public const string AccessKeyId = "AccessKeyId";
            public const string AccessKeySecret = "AccessKeySecret";
        }


        public static void Main(string[] args)
        {
            Cdn20180510.Client client = CreateClient(Config.AccessKeyId, Config.AccessKeySecret);
            string objectPath = GetObjectPathFromAsset();
            int objectPathCount = GetSubStrCountInStr(objectPath, "http", 0);
            //获取缓存预热余量
            int refreshRemain = GetRefreshRemain(client);
            //余量不足,不再发送预热请求
            if (refreshRemain < objectPathCount)
            {
                return;
            }

            PushObjectCacheRequest request = new PushObjectCacheRequest
            {
                // 预热区域。取值: domestic、overseas。  如果不传该参数,默认的预热区域为您的域名所配置的CDN加速区域
                //Area = "";
                // 需要预热的URL,多个URL之间需要用换行符\n或\r\n分隔。
                //
                // 注意:需要将OSS返回路径的前缀域名地址  hologarment-virtualloom.oss-cn-shanghai.aliyuncs.com
                //       设置为CDN加速域名地址            hologarment-virtualloom.hologarment.tech
                // 
                ObjectPath = objectPath,
                // 安全验证
                //SecurityToken="", // 默认不需要填写。除非为App用户设置了临时Token
            };

            string pushTaskId = PushObjectCache(client, request);

            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); // 当地时区
            long start = (long)(DateTime.Now - startTime).TotalMilliseconds; // 相差毫秒数

            if (!pushTaskId.Equals("-1"))
            {
                TeaConsole.Client.Log("--------------------检查预热请求状态--------------------");
                CheckCacheStatusById(client, pushTaskId, objectPathCount);//此处为 objectPathCount 是因为上边 ObjectPath 总共有objectPathCount个url
            }

            long end = (long)(DateTime.Now - startTime).TotalMilliseconds; // 相差毫秒数
            TeaConsole.Client.Log($"预热 {objectPathCount} 个URL,共用时:{end - start}");
        }

        /**
         * 使用AK&SK初始化账号Client
         * @param accessKeyId
         * @param accessKeySecret
         * @return Client
         * @throws Exception
         */
        public static Cdn20180510.Client CreateClient(string accessKeyId, string accessKeySecret)
        {
            OpenApiClient.Models.Config config = new OpenApiClient.Models.Config
            {
                // 您的AccessKey ID
                AccessKeyId = accessKeyId,
                // 您的AccessKey Secret
                AccessKeySecret = accessKeySecret,
            };
            // 访问的域名
            config.Endpoint = "cdn.aliyuncs.com";
            return new Cdn20180510.Client(config);
        }

        /// 
        /// PushObjectCache  预热源站内容到缓存节点
        /// https://next.api.aliyun.com/document/Cdn/2018-05-10/PushObjectCache
        /// 
        /// 
        /// 
        public static string PushObjectCache(Cdn20180510.Client client, PushObjectCacheRequest request)
        {
            try
            {
                PushObjectCacheResponse resp = client.PushObjectCache(request);

                TeaConsole.Client.Log("--------------------预热源站内容成功--------------------");
                TeaConsole.Client.Log(TeaUtil.Common.ToJSONString(resp.Body.ToMap()));

                return resp.Body.PushTaskId;
            }
            catch (TeaException error)
            {
                TeaConsole.Client.Log(error.Message);
            }
            catch (Exception _error)
            {
                TeaException error = new TeaException(new Dictionary<string, object>
                {
                    { "message", _error.Message }
                });
                TeaConsole.Client.Log(error.Message);
            }

            return "-1";
        }

        /**
        * PushObjectCache  预热源站内容
        */
        public static async Task PushObjectCacheAsync(Cdn20180510.Client client, PushObjectCacheRequest request)
        {
            try
            {
                PushObjectCacheResponse resp = await client.PushObjectCacheAsync(request);
                TeaConsole.Client.Log("--------------------预热源站内容成功--------------------");
                TeaConsole.Client.Log(TeaUtil.Common.ToJSONString(resp.Body.ToMap()));
            }
            catch (TeaException error)
            {
                TeaConsole.Client.Log(error.Message);
            }
            catch (Exception _error)
            {
                TeaException error = new TeaException(new Dictionary<string, object>
                {
                    { "message", _error.Message }
                });
                TeaConsole.Client.Log(error.Message);
            }
        }

        /// 
        /// 通过任务编号查询刷新预热任务信息
        /// https://next.api.aliyun.com/document/Cdn/2018-05-10/DescribeRefreshTaskById
        /// 
        /// 
        /// 
        public static void CheckCacheStatusById(Cdn20180510.Client client, string pushTaskId, int pushObjCount)
        {
            DescribeRefreshTaskByIdRequest request = new DescribeRefreshTaskByIdRequest()
            {
                TaskId = pushTaskId
            };
            while (true)
            {
                try
                {
                    DescribeRefreshTaskByIdResponse response = client.DescribeRefreshTaskById(request);
                    DescribeRefreshTaskByIdResponseBody responseBody = response.Body;
                    Dictionary<string, object> keyValuePairs = responseBody.ToMap();
                    TeaConsole.Client.Log(TeaUtil.Common.ToJSONString(keyValuePairs));

                    if (Convert.ToInt32(keyValuePairs["TotalCount"]) == pushObjCount)
                    {
                        if (isAllCompleted(keyValuePairs["Tasks"]))
                        {
                            TeaConsole.Client.Log("---------------------预热请求已完成---------------------");
                            TeaConsole.Client.Log("--------------------------------------------------------");
                            break;
                        }
                    }
                }
                catch (TeaException error)
                {
                    TeaConsole.Client.Log(error.Message);
                }
                catch (Exception _error)
                {
                    TeaException error = new TeaException(new Dictionary<string, object>
                    {
                        { "message", _error.Message }
                    });
                    TeaConsole.Client.Log(error.Message);
                }
                Thread.Sleep(100);
            }
        }

        /// 
        /// 缓存预热是否全部完成
        /// 
        ///  
        /// 
        public static bool isAllCompleted(object tasks)
        {
            List<object> taskInfos = (List<object>)tasks;
            for (int i = 0; i < taskInfos.Count; i++)
            {
                string json = TeaUtil.Common.ToJSONString(taskInfos[i]);
                TaskInfo taskInfo = JsonConvert.DeserializeObject<TaskInfo>(json);
                if (!taskInfo.Status.Equals("Complete"))
                {
                    return false;
                }
            }

            return true;
        }
        /// 
        /// 获取缓存刷新预热信息
        /// https://next.api.aliyun.com/document/Cdn/2018-05-10/DescribeRefreshQuota
        /// 
        /// 
        /// 缓存预热余量
        public static int GetRefreshRemain(Cdn20180510.Client client)
        {
            try
            {
                DescribeRefreshQuotaRequest request = new DescribeRefreshQuotaRequest();
                DescribeRefreshQuotaResponse response = client.DescribeRefreshQuota(request);

                TeaConsole.Client.Log("--------------------缓存刷新预热余量--------------------");
                Dictionary<string, object> keyValuePairs = response.Body.ToMap();
                TeaConsole.Client.Log(TeaUtil.Common.ToJSONString(keyValuePairs));
                TeaConsole.Client.Log($"当前剩余预热余量:{keyValuePairs["PreloadRemain"]}");

                return Convert.ToInt32(keyValuePairs["PreloadRemain"]);
            }
            catch (TeaException error)
            {
                TeaConsole.Client.Log(error.Message);
            }
            catch (Exception _error)
            {
                TeaException error = new TeaException(new Dictionary<string, object>
                {
                    { "message", _error.Message }
                });
                TeaConsole.Client.Log(error.Message);
            }
            return 0;
        }

        /// 
        /// 读取需要预热的URL地址列表
        /// 
        static string GetObjectPathFromAsset()
        {
            string objectPath = "";
            using (FileStream fs = new FileStream("ObjectPath.txt", FileMode.Open, FileAccess.Read))
            {
                StreamReader reader = new StreamReader(fs, Encoding.Default);
                objectPath = reader.ReadToEnd();
                reader.Close();
                fs.Close();
            }
            return objectPath;
        }
        public static int GetSubStrCountInStr(string str, string substr, int StartPos)
        {
            int foundPos = -1;
            int count = 0;

            do
            {
                foundPos = str.IndexOf(substr, StartPos);

                if (foundPos > -1)
                {
                    StartPos = foundPos + 1;
                    count++;
                }
            } while (foundPos > -1 && StartPos < str.Length);

            return (count);
        }
    }
}

最后

附上完整工程

看完记得【点赞、评论、收藏】三连哦~

你可能感兴趣的:(笔记,c#,阿里云,缓存)