初试“七牛云”--零基础运用七牛云配合UEditor实现图片的上传和浏览(.NET篇)
(注册和建立存储空间就不介绍了,网上一把一把的资料,自己试着点点也能明白)
作为一个成熟的菜鸟,如果遇到一个新问题,第一步当然是先百度一下。。。
看了N个关于七牛云的使用的帖子,表示还是蒙圈的,看懂了一部分,但是不系统,理解的不连贯,作为一个凡是要弄个特别明白的死脑筋,于是开始从头看是研究文档。。。。(以下都是来自http://developer.qiniu.com/article/index.html#quickstart,经过个人精简,如有不明,详情请参阅文档)
先弄明白原理,才能更好的看懂代码。
1.三个结构
a.七牛云存储服务
b.业务服务器
c.客户端-------客户端通常同时是资源的生产方和消费方。客户端在展示内容时,通常需要先从业务服务器获取资源的元信息,并得到必要的[下载凭证][downloadtokenHref],然后使用下载凭证从七牛云存储服务获取待展示的资源内容,从而实现一个完整的内容展示过程。
2.业务流程
-
上传
客户端在上传资源到七牛云存储之前要先从业务服务器获取一个有效的上传凭证,因此需要先后和两个服务端打交道。
上传凭证保存在上传策略( RS文件夹-PutPolicy.cs)(上传策略具体参数设置 http://developer.qiniu.com/article/developer/security/put-policy.html)
如果有设置回调,则上传完成时七牛云存储会自动发起回调到指定的业务服务器。
-
下载
公开资源不需要对应的下载凭证,客户端可以直接从七牛云存储下载对应资源。私有资源需要对应的下载凭证,因此必须先和业务服务器打交道。
按照实际的使用场景,客户端对于内容的展示非常类似一个动态网页的生成过程,因此无论该页面内容是公开还是私有,均需要从业务服务器获取展示该页面的动态布局信息。所以通常显示过程也是需要先后和业务服务器及七牛云存储服务打交道。
于是乎,测试 官方的“简单上传”的代码(http://developer.qiniu.com/code/v6/sdk/csharp.html#io-put)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Qiniu.Auth; 7 using Qiniu.IO; 8 using Qiniu.IO.Resumable; 9 using Qiniu.RS; 10 11 namespace ConsoleDemo 12 { 13 class UploadDemo 14 { 15 16 private void upload() 17 { 18 //设置账号的AK和SK 19 Qiniu.Conf.Config.ACCESS_KEY = "Access_Key"; ① 20 Qiniu.Conf.Config.SECRET_KEY = "Secret_Key";② 21 IOClient target = new IOClient(); 22 PutExtra extra = new PutExtra(); 23 //设置上传的空间 24 String bucket = "bucket_name";③ 25 //设置上传的文件的key值 26 String key = "yourdefinekey";//上传成功后的文件名(可以和上传文件不是同一个名字) ④ 27 28 //普通上传,只需要设置上传的空间名就可以了,第二个参数可以设定token过期时间 29 PutPolicy put = new PutPolicy(bucket, 3600); 30 31 //调用Token()方法生成上传的Token 32 string upToken = put.Token(); 33 //上传文件的路径 34 String filePath = "/.../...";⑤ 35 36 //调用PutFile()方法上传 37 PutRet ret = target.PutFile(upToken, key, filePath, extra); 38 //打印出相应的信息 39 Console.WriteLine(ret.Response.ToString()); 40 Console.WriteLine(ret.key); 41 Console.ReadLine(); 42 } 43 44 static void Main(string[] args) 45 { 46 //实例化UploadDemo对象并调用设置的upload方法 47 UploadDemo Upload = new UploadDemo(); 48 Upload.upload(); 49 } 50 } 51 }
以上5处需要修改为自己的内容
看了半天都是蒙圈,最后感觉其实上传的过程就是两步、两步、两步!!!!
1.生成TOKEN(上传凭证upload-token,详情见http://developer.qiniu.com/article/developer/security/upload-token.html)
构造上传策略1json化=>2URL安全的Base64编码=>3使用SecretKey计算HMAC-SHA1签名=>4再进行一次URL安全的Base64编码=>
5最终拼接成uploadToken=>
总结,②是用于加密上传策略的,①③是构造上传策略,①②③一起生成token,④⑤和token一起作为PutFile()方法的上传参数。
具体到程序中,
Mac就是计算“七牛认证”的类(包括计算方法,让Token方法调用)
Mac的sign方法实现了上面第三步的“SecretKey计算HMAC-SHA1签名”&第四步
Mac的SignWithData调用了sign并实现上面第五步,拼接形成最后的上传凭证(token)
2.调用“ IOClient”的“PutFile()”方法上传
特别注意:如果注册空间的时候,选择了“华北”,那么需要增加一行代码,否则怎么上传都不成功。。。。
1 Qiniu.Conf.Config.UP_HOST = "http://up-z1.qiniu.com";
开个控制台,调用UploadDemo.upload
1 UploadDemo Upload = new UploadDemo(); 2 Upload.upload();
查看空间里有没有这个文件(空间-内容管理),如果有就说明“简单上传”测试成功了。
接下来,就是搞定ueditor中上传图片到七牛云。
由于ueditor使用的是流,所以只需要把PutFile方法改为使用Put方法,(IOClient中有个Put方法可以使用流,如下)
public PutRet Put(string upToken, string key, System.IO.Stream putStream, PutExtra extra) { if (!putStream.CanRead) { throw new Exception("read put Stream error"); } PutRet ret; NameValueCollection formData = getFormData(upToken, key, extra); try { CallRet callRet = MultiPart.MultiPost(Config.UP_HOST, formData, putStream); ret = new PutRet(callRet); onPutFinished(ret); return ret; } catch (Exception e) { ret = new PutRet(new CallRet(HttpStatusCode.BadRequest, e)); onPutFinished(ret); return ret; } }
代码改为:
using Qiniu.IO; using Qiniu.RS; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace qiniu { public class UploadDemo { public void upload() { Qiniu.Conf.Config.ACCESS_KEY = ""; Qiniu.Conf.Config.SECRET_KEY = ""; Qiniu.Conf.Config.UP_HOST = "http://up-z1.qiniu.com"; IOClient target = new IOClient(); PutExtra extra = new PutExtra(); //设置上传的空间 String bucket = ""; //设置上传的文件的key值 String key = "222.jpg"; //普通上传,只需要设置上传的空间名就可以了,第二个参数可以设定token过期时间 PutPolicy put = new PutPolicy(bucket, 3600);//调用Token()方法生成上传的Token string upToken = put.Token(); //上传文件的路径 String filePath = @"E:\chaye.jpg"; FileStream fs=new FileStream (filePath,FileMode.Open,FileAccess.Read); //调用PutFile()方法上传 // PutRet ret = target.PutFile(upToken, key, filePath, extra); PutRet ret=target.Put(upToken,key,fs,extra); //打印出相应的信息 Console.WriteLine(ret.Response.ToString()); Console.WriteLine(ret.key); Console.ReadLine(); } } }
既然方法试验成功,最后就是结合ueditor,改造代码
ueditor的IOClient.cs的Put方法添加
UploadHandler.cs中改造Process方法
1 public override void Process() 2 { 3 byte[] uploadFileBytes = null; 4 string uploadFileName = null; 5 6 if (UploadConfig.Base64) 7 { 8 uploadFileName = UploadConfig.Base64Filename; 9 uploadFileBytes = Convert.FromBase64String(Request[UploadConfig.UploadFieldName]); 10 } 11 else 12 { 13 var file = Request.Files[UploadConfig.UploadFieldName]; 14 uploadFileName = file.FileName; 15 if (!CheckFileType(uploadFileName)) 16 { 17 Result.State = UploadState.TypeNotAllow; 18 WriteResult(); 19 return; 20 } 21 if (!CheckFileSize(file.ContentLength)) 22 { 23 Result.State = UploadState.SizeLimitExceed; 24 WriteResult(); 25 return; 26 } 27 28 uploadFileBytes = new byte[file.ContentLength]; 29 try 30 { 31 file.InputStream.Read(uploadFileBytes, 0, file.ContentLength); 32 } 33 catch (Exception) 34 { 35 Result.State = UploadState.NetworkError; 36 WriteResult(); 37 } 38 } 39 40 Result.OriginFileName = uploadFileName; 41 42 //上传到七牛云 43 44 string qiNiuFileName=CommonHelper.CalcMD5(uploadFileBytes)+Path.GetExtension(uploadFileName);
//自己封装了一个MD5的方法,随意,可以不加,这里就是为了尽量避免重名 45 49 var savePath = PathFormatter.Format(uploadFileName, UploadConfig.PathFormat); 50 var localPath = Server.MapPath(savePath); 51 try 52 { 53 Qiniu.Conf.Config.ACCESS_KEY = ""; 54 Qiniu.Conf.Config.SECRET_KEY = ""; 55 Qiniu.Conf.Config.UP_HOST = ""; 56 IOClient target = new IOClient(); 57 PutExtra extra = new PutExtra(); 58 //设置上传的空间 59 String bucket = ""; 60 //设置上传的文件的key值 61 String key = qiNiuFileName;//1 62 63 //普通上传,只需要设置上传的空间名就可以了,第二个参数可以设定token过期时间 64 PutPolicy put = new PutPolicy(bucket, 3600); 65 66 67 //调用Token()方法生成上传的Token 68 string upToken = put.Token(); 69 //上传文件的路径 70 MemoryStream ms = new MemoryStream(uploadFileBytes); 71 72 //调用PutFile()方法上传 73 // PutRet ret = target.PutFile(upToken, key, filePath, extra); 74 PutRet ret = target.Put(upToken, key,ms, extra); 75 76 Result.Url = "外链默认域名" + qiNiuFileName; 77 78 Result.State = UploadState.Success; 79 80 //PutPolicy policy = new PutPolicy(bucket, 3600); 81 //string upToken = policy.Token(); 82 //Settings setting = new Settings(); 83 //ResumablePutExtra extra = new ResumablePutExtra(); 84 //ResumablePut client = new ResumablePut(setting, extra); 85 //CallRet callRet = client.PutFile(upToken, new byte[0] { }, ""); 86 //if (callRet.OK) 87 //{ 88 89 //} 90 91 } 92 catch (Exception e) 93 { 94 Result.State = UploadState.FileAccessError; 95 Result.ErrorMessage = e.Message; 96 } 97 finally 98 { 99 WriteResult(); 100 } 101 }
参考https://segmentfault.com/a/1190000002462516
注意:导致浏览器访问的时候(编译并不报错),显示 “文件访问出错,检查权限”,F12看上传后response报文,未找到newtonjson 4.5.0.0。
原因:因为之前手动添加过Newtonsoft.Json.dll(4.5.0.0),跟ueditor-net- Bin目录的newtonJson版本 不一致(9.0.0.0)。
解决方法:在web.config的<configuration>节点下添加,只需要添加一次,之后删除都可以。
<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> <bindingRedirect oldVersion="4.5.0.0-6.0.0.0" newVersion="9.0.0.0" /> </dependentAssembly> </assemblyBinding> </runtime>
猜想,关于newtonJSON版本的问题,都可以通过上面代码解决。
补充,如果需要两个版本的dll引用
<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" /> <codeBase version="6.0.0.0" href="D:\documents\visual studio 2012\Projects\NDT\NDTDecive\NDTDevice.Admin\ueditor\net\Bin\Newtonsoft.Json.dll" /> <codeBase version="9.0.0.0" href="D:\documents\visual studio 2012\Projects\NDT\NDTDecive\NDTDevice.Admin\qiniu\Newtonsoft.Json.dll" /> </dependentAssembly> </assemblyBinding> </runtime>