前言上传图片是一个很常见的需求,方法也有很多种。这次用的是七牛云的对象存储,七牛云的oss还是比较不错的。七牛云的上传大致分为两种:向服务器请求七牛的文件上传令牌,然后上传文件到七牛(授权上传)直接上传文件到服务器,然后由七牛上传文件到七牛server牛授权上传其实有两种,一种是调用七牛SDK,一种是直接调用七牛的上传接口。本文将实现这两??种方法。实际开发使用的技术形式Data+axios+koa+koa-这种body授权上传的上传方式,后台只需要返回七牛的token,前端调用SDK或者上传接口SDK上传七牛云的sdk,即可通过script标签导入https://unpkg.com/qiniu-js@2.4.0/dist/qiniu.min.js通过sctipt标签导入这个文件,会在全局生成一个名为qiniu的对象。通过npm安装npminstallqiniu-js--saveimport*asqiniufrom'qiniu-js'qiniu-sdkMainapi,qiniu.upload(file,key,token,putExtra,config)file:Blobobjectkey:filenametoken:上传验证信息,前端通过接口请求后端获取config:上传配置参数putExtra:额外配置参数调用成功然后返回一个observable对象,调用它的subscribe方法得到响应结果observable.subscribe({complete(res){//上传完成的响应信息,res包含hash和key属性(默认)},next(res){//接收上传进度信息,res包含loaded、total、percent三个属性,提供上传进度信息.},error(err){//上传错误触发,err包含三个属性:code、message、isRequestError}});前端代码:使用axios发送请求constfileInput=document.getElementById('upload');fileInput.addEventListener('change',asyncfunction(e){constfile=e.target.files[0];//Blob,文件流对象//通过后端接口获取七牛云的tokenconstres=awaitaxios.get('/qiniuToken');const{token,key}=res.data;constputExtra={fname:'',//原始文档文件名params:{},//用于放置自定义变量mimeType:null//用于限制上传文件类型,为null表示不限制文件类型;eg:["image/png","image/jpeg"]};constconfig={useCdnDomain:true,//开启cdn加速域名region:null,//if为null,上传区域会自动解析};//调用qiniu.upload上传图片并生成observable实例constobservable=qiniu.upload(file,key,token,putExtra,config);//调用subscribe方法ofobservable获取响应结果observable.subscribe({complete(data){const{key}=data;//将返回的key与域名拼接,即图片地址consturl='配置的域名'+key;},?ext(res){//...},error(err){//...}});});API上传先获取token,然后调用上传的api,不同的空间区域对应不同的接口地址,我的空间是华南,接口地址:http://upload-z2.qiniu.comconstfileInput=document.getElementById('upload');fileInput.addEventListener('change',asyncfunction(e){constfile=e.target.files[0];//Blob,文件流对象//通过后端接口获取七牛云的tokenconstres=awaitaxios.get('/qiniuToken');const{token,key}=res.data;constformData=newFormData();formData.append('token',token);formData.append('key',key);//key:文件名,不用传,不传七牛会自动生成随机文件名hashformData.append('file',file);constresponse=awaitaxios.post('http://upload-z2.qiniu.com',formData);consturl='七牛云仓配置域名'+response.key;});以上两种上传方式,后端需要返回token后端代码:后端实现使用koa,因为只需要返回token,所以比较简单constqiniu=require('qiniu')router.get('/qiniuToken',async(ctx)=>{//accessKey,secretKey可以在个人中心查看constaccessKey='你的accesskey';constsecretKey='你的秘钥';//识别权限对象macconstmac=newqiniu.auth.digest.Mac(accessKey,secretKey);constoptions={scope:'yourbucket'//仓库名称};constputPolicy=newqiniu.rs.PutPolicy(options);consttoken=putPolicy.uploadToken(mac);constkey=+newDate()+Math.random().toString(16).slice(2);//key只需要是随机的,不重复即可ctx.body={status:1,data:{token,key}};});后端直传前端只需要传一个文件文件流对象fileInput.addEventListener('change',asyncfunction(e){constfile=e.target.files[0];//Blob,文件流对象constformData=newFormData();formData.append('file',formData);//file是后端接受的字段//axios识别到参数是formData类型后,会自动修改Content-Typeismultipart/form-dataconstres=awaitaxios.post('/qiniu',formData);const{url}=res.data;});后端需要调用qiniu-sdk下载koa-bodynpmi-Skoa-bodyconstkoaBody=require('koa-body');constkoaBodyOpts={multipart:true,//默认不接受formData参数,formLimitneedstobeenabled:'15mb'//default56kb,trytosetitlarge};//Usekoa-bodyapp.use(koaBody(koaBodyOpts))globally;//在路由中使用路由r.post('/qiniu',koaBody(koaBodyOpts),async(ctx)=>{const{file}=ctx.request.body.files;constext=path.extname(file.name);constfileName=+newDate()+ext;constlocalFile=file.path;try{constres=awaitqiniuPut(fileName,localFile);consturl=qiniuOpts.url+res.key;ctx.body={状态:1,数据:{url}};}catch(e){console.log(e);ctx.body={status:0,msg:'上传失败'};}});//获取七牛云tokenconstqiniuToken=()=>{constaccessKey='你的访问密钥';constsecretKey='你的密钥';constmac=newqiniu.auth.digest.Mac(accessKey,secretKey);constoptions={scope:'你的桶'};constputPolicy=newqiniu.rs.PutPolicy(options);constuploadToken=putPolicy.uploadToken(mac);returnuploadToken;};//七牛云文件上传constqiniuPut=(key,localFile)=>{constuploadToken=qiniuToken();constconfig=newqiniu.conf.Config();//空间对应的机房config.zone=qiniu.zone.Zone_z2;合作社nstformUploader=newqiniu.form_up.FormUploader(config);constputExtra=newqiniu.form_up.PutExtra();returnnewPromise((resolve,reject)=>{formUploader.putFile(uploadToken,key,localFile,putExtra,(respErr,respBody,respInfo)=>{if(respErr){reject(respErr);}else{resolve(respBody);}});});}七牛云有很多API,有兴趣的可以看看文档