背景
最近搞一个商城类的项目,图片资源我采用的是第三方云储存服务。又拍云(UpYun)是国内知名的云存储服务商,还提供了10G的免费空间,还可以做图片预处理(如:缩略图),还提供了FTP的管理,配置和功能上完全胜任!
但是,又拍云的官方网站找了一圈,找不到C#相关的SDK,GitHub找到的第三方的SDK用的都不是最新版的API,跟官方的文档一点都不匹配。“拿来主义”宣告失败!无奈之下,只能参考官方的PHP-SDK“自己动手丰衣足食”。
说实话,又拍云的官方文档的很多地方语焉不详,所以显得坑还是比较多的。尤其在signature和policy的获取,作为老司机的我,不看官方的PHP-SDK代码,还被卡了很久。于是,项目的demo刚搞定,我就赶紧把填坑的过程记录下来~
上传文件
我们项目主要是用Web后台进行图片管理,文件size不大。所以,直接用Form API即可。
Form上传的流程:
1.首先创建有一个页面放置上传表单,例如:upload.html
Upyun表单上传例子
请选择上传文件
选择文件:
确定
删除文件:
删除
2.发个Ajax请求服务端,计算签名校验的参数,得到Policy & Authorization
前端JS请求签名信息:
var UPYUN = null;
function getUpYunAuth() {
$.post("/Ajax/GetUpYunAuth", "", function (res) {
UPYUN = res;
});
}
getUpYunAuth() ;
接着是服务端GetUpYunAuth的代码:
//MD5加密
public static string GetMD5(string inputStr)
{
using (var md5 = MD5.Create())
{
var bs = puteHash(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 = puteHash(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
{
{ "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();
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,如:UpYunSaveKey: 文件保存路径方案,如:/uploads/{year}{mon}/{random}_{filename}{.suffix}
UpYunDomain: 文件保存后访问的地址,如:UpYunUser和UpYunPassword,分别对应操作员的账号和密码
3.提交表单上传文件
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('');
}
console.log('upload success');
console.log(res);
},
fail: function (data) {
console.log(data);
}
});
}
删除文件
删除文件用的是Restful API,Authorization的生成的跟FormAPI差不多,不需要policy,只要把生成的Authorization放在RequestHeader里头就好了。这里有一点要注意的是生成Signature的uri必须加上操作文件的路径
例如://test/demo.jpg
如果FormAPI上传的话,只需要 /
前端js代码其实很简单
function delFile() {
var fileUrl = $("#delFileUrl").val();
if (confirm("是否确定删除文件:" + fileUrl)) {
$.post("/Ajax/DelUpYunFile", "fileUrl=" + fileUrl, function (res) {
console.log(res);
});
}
}
关键是后端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
{
{ "Authorization", auth },
{ "Date", date },
{ "User-Agent", "UpYunDotNetCoreSDK/Tony" },
{ "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 == .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);
}
缩略图
关于图片上传的处理,官方的文档已经描述得比较很详细,我这里就不赘述了。直接给传送连接完事:/knowledge-base/image/
结尾
其他的文件操作,比如:创建目录、获取目录文件列表、文件属性等等,这些都是RESTFul API的内容,套路跟删除文件是一样的。如果大家有需要,可以自己举一反三,我也不继续啰嗦了。