美文网首页
又拍云存储(UpYun)的.NET Core填坑

又拍云存储(UpYun)的.NET Core填坑

作者: ChenReal | 来源:发表于2019-02-19 12:22 被阅读0次

    背景

            最近搞一个商城类的项目,图片资源我采用的是第三方云储存服务。又拍云(UpYun)是国内知名的云存储服务商,还提供了10G的免费空间,还可以做图片预处理(如:缩略图),还提供了FTP的管理,配置和功能上完全胜任!
            但是,又拍云的官方网站找了一圈,找不到C#相关的SDK,GitHub找到的第三方的SDK用的都不是最新版的API,跟官方的文档一点都不匹配。“拿来主义”宣告失败!无奈之下,只能参考官方的PHP-SDK“自己动手丰衣足食”。
            说实话,又拍云的官方文档的很多地方语焉不详,所以显得坑还是比较多的。尤其在signature和policy的获取,作为老司机的我,不看官方的PHP-SDK代码,还被卡了很久。于是,项目的demo刚搞定,我就赶紧把填坑的过程记录下来~

    上传文件

            我们项目主要是用Web后台进行图片管理,文件size不大。所以,直接用Form API即可。

    Form上传的流程:

    1.首先创建有一个页面放置上传表单,例如:upload.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Upyun表单上传例子</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script type="text/javascript" src="//g.alicdn.com/sj/lib/jquery/dist/jquery.min.js"></script>
    </head>
    <body>
        <h4>请选择上传文件</h4>
        <p id="formInfo"></p>
        <form method="post" enctype="multipart/form-data">
            <div>
                选择文件:
                <input name="file" id="file" type="file" />
            </div>
            <div>
                <button type="button" onclick="doUpload()">确定</button>
            </div>
            <div>
                删除文件:
                <input id="delFileUrl" type="text" value="/test/demo.jpg" />
            </div>
            <div>
                <button type="button" onclick="delFile()">删除</button>
            </div>
        </form>
        <div id="imgShow"></div>
    </body>
    </html>
    

    2.发个Ajax请求服务端,计算签名校验的参数,得到Policy & Authorization

    • 前端JS请求签名信息:
    <script>
    var UPYUN = null;
    function getUpYunAuth() {
        $.post("/Ajax/GetUpYunAuth", "", function (res) {
            UPYUN = res;
        });
    }
    getUpYunAuth() ;
    </script>
    
    • 接着是服务端GetUpYunAuth的代码:
    //MD5加密
    public static string GetMD5(string inputStr)
    {
        using (var md5 = MD5.Create())
        {
            var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(inputStr));
            var result = BitConverter.ToString(bs);
            result = result.Replace("-", "");
            return strResult;
        }
    }
    //HMAC-SHA1加密
    public static byte[] GetHMACSHA1Byte(string inputStr, string key)
    {
        byte[] secrectKey = Encoding.UTF8.GetBytes(key);
        using (var hmac = new HMACSHA1(secrectKey))
        {
            hmac.Initialize();
            var result = hmac.ComputeHash(Encoding.UTF8.GetBytes(inputStr));
            return result;
        }
    }
    //获取Policy
    public static string GetPolicy(string bucket, string saveKey, string date)
    {
        var ts = Helper.StringUtil.GetTimeStamp() + 30 * 60; //时间戳 30分钟过期
        var policyDict = new Dictionary<string, string>
        {
            { "bucket", bucket },
            { "expiration", ts.ToString() },
            { "save-key", saveKey },
            { "date", date }
        };
        var policy = JsonConvert.SerializeObject(policyDict);
        policy = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy));
        return policy;
    }
    //获取签名
    public static string GetSignature(string user, string pass, string method, string uri, string date = null, string policy = null)
    {
        var paramList = new List<string>();
        paramList.Add(method);
        paramList.Add(uri);
        if (date != null) paramList.Add(date);
        if (policy != null) paramList.Add(policy);
        var bt =GetHMACSHA1Byte(string.Join("&", paramList.ToArray()), pass);
        var result = Convert.ToBase64String(bt);
        result = "UPYUN " + user + ":" + result;
        return result;
    }
    //Ajax请求的Action方法
    [HttpPost]
    public IActionResult GetUpYunAuth()
    {
        //获取又拍云的配置
        var host = ConfigLoader.GetAppConfigValue("UpYunHost"); 
        var saveKey = ConfigLoader.GetAppConfigValue("UpYunSaveKey");
        var bucket = ConfigLoader.GetAppConfigValue("UpYunBucket");
        var domain = ConfigLoader.GetAppConfigValue("UpYunDomain"); 
        var user = ConfigLoader.GetAppConfigValue("UpYunUser");
        var pass = ConfigLoader.GetAppConfigValue("UpYunPassword");
        pass = GetMD5(pass).ToLower();
        string date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'", new CultureInfo("en-US"));
    
        var policy = GetPolicy(bucket, saveKey, date); //计算policy
        var auth = GetBodySignature(user, pass, "POST", "/" + bucket, date, policy); //计算签名
    
        var result = new { host, saveKey, bucket, domain, policy, auth };
        return Json(result);
    }
    

    关于配置项,做个简要的说明:

    UpYunHost: API调用地址+bucket,如:https://v0.api.upyun.com/<bucket>
    UpYunSaveKey: 文件保存路径方案,如:/uploads/{year}{mon}/{random}_{filename}{.suffix}
    UpYunDomain: 文件保存后访问的地址,如:http://image.chenreal.com,这是我CNAME过去的域名
    UpYunUserUpYunPassword,分别对应操作员的账号密码

    3.提交表单上传文件

    <script>
    function doUpload() {
        var form = document.querySelector("form");
        var uploadData = new FormData(form);
        uploadData.append('policy', UPYUN["policy"]);
        uploadData.append('authorization', UPYUN["auth"]);
        var yunUrl = UPYUN["host"];
        $.ajax({
            url: yunUrl,
            type: 'POST',
            data: uploadData,
            cache: false,
            processData: false,
            contentType: false,
            success: function (data) {
                var res = JSON.parse(data);
                if (res.code == 200) {
                    $("#formInfo").html("上传成功");
                    var imgUrl = UPYUN["domain"] + res.url;
                    $("#imgShow").html('<img src="' + imgUrl + '" />');
                }
                console.log('upload success');
                console.log(res);
            },
            fail: function (data) {
                console.log(data);
            }
        });
    }
    </script>
    

    删除文件

            删除文件用的是Restful API,Authorization的生成的跟FormAPI差不多,不需要policy,只要把生成的Authorization放在RequestHeader里头就好了。这里有一点要注意的是生成Signature的uri必须加上操作文件的路径

    例如:/<bucket>/test/demo.jpg

    如果FormAPI上传的话,只需要 /<bucket>

    • 前端js代码其实很简单
    <script>
    function delFile() {
        var fileUrl = $("#delFileUrl").val();
        if (confirm("是否确定删除文件:" + fileUrl)) {
            $.post("/Ajax/DelUpYunFile", "fileUrl=" + fileUrl, function (res) {
                console.log(res);
            });
        }
    }
    </script>
    
    • 关键是后端Action的处理
    [HttpPost]
    public IActionResult DelUpYunFile()
    {
        var fileUrl = Request.Form["fileUrl"];
    
        var host = ConfigLoader.GetAppConfigValue("UpYunHost");
        var bucket = ConfigLoader.GetAppConfigValue("UpYunBucket");
        var user = ConfigLoader.GetAppConfigValue("UpYunUser");
        var pass = ConfigLoader.GetAppConfigValue("UpYunPassword");
        pass = BizLib.Helper.Security.GetMD5(pass, false).ToLower();
        string date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'", new CultureInfo("en-US"));
        //计算签名
        var auth = GetBodySignature(user, pass, "DELETE", "/" + bucket + fileUrl, date);
        var url = host + fileUrl;
        //拼装RequestHeader
        var headers = new Dictionary<string, string>
        {
          { "Authorization", auth },
          { "Date", date },
          { "User-Agent", "UpYunDotNetCoreSDK/Tony2019" },
          { "x-upyun-async", "true" }
        };
        //HTTP Request
        var result = new SMessage();
        using (var httpClient = new HttpClient())
        {
            if(headers != null)
            {
                foreach(var kv in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(kv.Key, kv.Value);
                }
            }
            try
            {
                var resp = resp = httpClient.DeleteAsync(url).Result;
                if (resp.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    result.data = resp.Content.ReadAsStringAsync().Result;
                    result.succ = true;
                }
                else
                {
                    result.ret = (int)resp.StatusCode;
                    result.data = "Request Error";
                }
            }
            catch (Exception ex)
            {
                result.SetCustomErr(ex.Message);
            }
        }
    
        return Json(result);
    }
    

    缩略图

            关于图片上传的处理,官方的文档已经描述得比较很详细,我这里就不赘述了。直接给传送连接完事:https://help.upyun.com/knowledge-base/image/

    结尾

            其他的文件操作,比如:创建目录、获取目录文件列表、文件属性等等,这些都是RESTFul API的内容,套路跟删除文件是一样的。如果大家有需要,可以自己举一反三,我也不继续啰嗦了。

    相关文章

      网友评论

          本文标题:又拍云存储(UpYun)的.NET Core填坑

          本文链接:https://www.haomeiwen.com/subject/idlzeqtx.html