vue上传图片到七牛云的思路与实现

本文分为思路篇和代码篇,思路篇主要是思路和代码混合,主要重点是讲解思路;代码篇是注释和代码结合,主要展示代码.
[温馨提示,由于博客园编辑器问题,直接赋值我的编辑器的代码粘贴到这里的颜色格式非常乱,建议不要开启夜间模式观看]

一、思路篇

 

方法一:上传图片流程的思路(通过前台上传图片):

 

1.接收token前的操作

说明:前台点击上传图片的按钮前,需要先获取七牛云的token,需要的流程如下:

1.1前台打开本地图片的时候,需要获取本地图片的名称(用来赋值给下面的key,以便生成token),然后发给后台,

后台把文件名称(此时文件名建议进行操作,重命名)赋值给key

1.2后台根据:key以及你的七牛云命名空间的名称即:bucket 生成token 后发送给前台

 

2.接受到token后的操作

2.1前台接收到token,需要把文件转为字节流 然后把【token】以及【文件字节流】以及【文件名称:key】打包成一个对象,然后开始发送到七牛云

 

3.具体代码:后台操作


//需要填写你的 Access Key 和 Secret Key 这个在七牛云 个人中心>密钥管理 功能里面
qiniu.conf.ACCESS_KEY = '0kSEeVVtcqWFQ18z0TWlDe6eBC3lFchpHLBNe-_F';//公钥
qiniu.conf.SECRET_KEY = 'Y2P5am6LWW44yxo2YWwsiY4RteqyFeut58gCHBM_';//私钥
//要上传的空间
bucket = 'we-teach';//我的bucket名称,即文件的命名空间的名称
//上传到七牛后保存的文件名
key = 'my-nodejs-logo.png';//此处我直接在前台生成我需要保持的文件名,然后发到给后端。也可以把文件名直接发到后端,让后端处理,由于前端后端都是我一个人写的,所以我比较随意
//构建上传策略函数,生成token并设置回调的url以及需要回调给业务服务器的数据。此处的回调服务器地址需要你的公网服务器地址,但是我直接在本地操作的,没有公网地址,所以就没有改动七牛云的example了,直接
function uptoken(bucket, key) {
  var putPolicy = new qiniu.rs.PutPolicy(bucket+":"+key);
  putPolicy.callbackUrl = 'http://your.domain.com/callback';
  putPolicy.callbackBody = 'filename=$(fname)&filesize=$(fsize)';
  return putPolicy.token();
}
//生成上传 Token
token = uptoken(bucket, key);//此处的token需要发给前台,好让前台开始操作,实现图片上传
console.log("七牛云上传图片的token:",token);//后台代码结束

前台代码
//1.选中图片时发送key,即文件名称给后台,以便后台生成token
this.axios.get('/filename','my-nodejs-logo.png')
//2.选中图片后,开始上传前:获取token
//filePath_or_stream是要上传文件的本地路径或者字节流,虽然七牛云官方文档有说最简单//的上传就是本地上传时给一个本地的路径就好了
//但是我觉得直接指定本地的图片路径只适合后台上传,不适合前台,具体原因见下面的后话
//所以本文演示的都是传全部文件数据,而非文件地址
//
filePath_or_stream = './nodejs-logo.png'||filePath_or_stream=readableStream【readableStream是前台传过来的全部文件的数据流】 filePath_or_stream = readableStream;//图片的字节流数据 this.axios.get('/up/token').then(res => { console.log(res) const formdata = new FormData()//FormData是浏览器的方法,用于html追加表单键值对,详细使用可以看看MDN文档,简单介绍看看下面后话我的介绍 formdata.append('file', req.file)//往表单上传的数据域追加file属性,它的value是req.file。 reqreq.file是我们本地的文件地址,elementui的el-upload里的http-request像我们本地计算机发起请求数据,会把我们选择的文件地址赋值给req.file(原生的html的表单上传属性也可以获取文件的地址) formdata.append('token', res.data)//往表单上传的数据域追加token属性,它的value是res.data,res.data是后台在我们请求token时发送过来的数据 formdata.append('key', keyname)//往表单上传的数据域追加key属性, keyname是我们自定义需要保存的文件名称 // 3.点击上传时:获取到凭证之后再将文件上传到七牛云空间
//this.domain是你要上传的七牛云的空间所绑定的域名,formdata包含上传的所有数据,config用来设置请求头
this.axios.post(this.domain, formdata, config).then(res => { this.imageUrl = 'http://' + this.qiniuaddr + '/' + res.data.key // console.log(this.imageUrl) }) })


方法二:上传图片流程的思路(通过后台上传图片):
1.接收token前的操作
说明:前台点击上传图片的按钮时,【需要先把本地图片的名称以及图片字节流数据发给后台】,【或者把修改好后的需要重命名的图片名称以及图片字节流数据发给后台】,需要的流程如下:
1.1前台上传本地图片的时候,需要获取本地图片的名称(用来赋值给下面的key,以便生成token),然后同时把图片字节流一并发给后台,后台把文件名(此时文件名建议进行操作,重命名)称赋值给key
1.2后台根据:key以及你的七牛云命名空间的名称即:bucket 生成token 

2.接受到token后的操作
2.1后台生成token后, 把【token】以及【文件字节流】以及【文件名称:key】打包成一个对象,然后开始发送到七牛云

3.具体代码:后台操作
//需要填写你的 Access Key 和 Secret Key 这个在七牛云 个人中心>密钥管理 功能里面
qiniu.conf.ACCESS_KEY = '0kSEeVVtcqWFQ18z0TWlDe6eBC3lFchpHLBNe-_F';//公钥
qiniu.conf.SECRET_KEY = 'Y2P5am6LWW44yxo2YWwsiY4RteqyFeut58gCHBM_';//私钥

//要上传的空间
bucket = 'we-teach';//我的bucket名称,即文件的命名空间的名称

//上传到七牛后保存的文件名
key = 'my-nodejs-logo.png';//此处我直接在前台生成我需要保持的文件名,然后发到给后端。也可以把文件名直接发到后端,让后端处理,由于前端后端都是我一个人写的,所以我比较随意

//构建上传策略函数,生成token并设置回调的url以及需要回调给业务服务器的数据。此处的回调服务器地址需要你的公网服务器地址,
//但是我直接在本地操作的,没有公网地址,所以就没有改动七牛云的example了,直接copy没改

function uptoken(bucket, key) {
var putPolicy = new qiniu.rs.PutPolicy(bucket+":"+key); putPolicy.callbackUrl = 'http://your.domain.com/callback'; putPolicy.callbackBody = 'filename=$(fname)&filesize=$(fsize)'; return putPolicy.token(); } //生成上传 Token token = uptoken(bucket, key);//此处的token需要根据【前台发送来的图片名称】即:【key】加上【bucket】生成 console.log("七牛云上传图片的token:",token);
//filePath_or_stream是要上传文件的本地路径或者字节流,虽然七牛云官方文档有说最简单//的上传就是本地上传时给一个本地的路径就好了
//但是我觉得直接指定本地的图片路径只适合后台上传,不适合前台,具体原因见下面的后话
//所以本文演示的都是传全部文件数据,而非文件地址
// filePath_or_stream = './nodejs-logo.png'||filePath_or_stream=readableStream【readableStream是前台传过来的全部文件的数据流】 filePath_or_stream = readableStream;//使用前台传过来的字节流数据进行赋值 //构造上传函数 uptoken:上传凭证,由bucket与我们传过来的【key即需要保存的文件的名称】生成。 key【key即需要保存的文件的名称】,
//localFile【本地文件,可以是数据流或者地址,本文都是采用数据流】
function uploadFile(uptoken, key, localFile) { var extra = new qiniu.io.PutExtra(); qiniu.io.putFile(uptoken, key, localFile, extra, function(err, ret) { if(!err) { // 上传成功, 处理返回值 console.log(ret.hash, ret.key, ret.persistentId); } else { // 上传失败, 处理返回代码 console.log(err); } }); } //调用uploadFile上传 uploadFile(token, key, filePath_or_stream);

二、代码篇

由于代码有点多,所以直接上传gitee了,你可以直接到我的gitee上面下载这个源码,并且可以直接跑起来:我的:[gitee]
写了三个小demo,分布使用:
1.使用elementUI的upload组件实现上传图片;
2、使用原生的h5的input元素的file属性上传图片;
3.使用到了vue-cropper,实现上传图片前的剪切。

三、后话

1.关于filePath_or_stream

虽然七牛云允许我们在上传的时候直接在上传本地图片的地址就好了,但是我觉得此种场景只适合后台上传,并且后台上传还仍然有所限制,为什么呢?

下面解释: 由于我们上传数据的时候并不是平白无故就可以上传的,需要点对点的传数据。

1.1情景模拟:(A发送数据给B,只发送了数据的地址,就相当于我们只发送了图片地址) 假设A发送数据给B,那么A就一定要把数据拿到手,才能发送给B,虽然这里有讲废话的嫌疑,但是的确有道理。

假设我们上传图片时前台直接发送我们图片的地址给七牛云,那么七牛云只接收到我们本地计算机的地址,如:localhost://we-teach/1.png 那么七牛云虽然知道我们需要上传的图片的地址,但是却无能为力,首先我们的本地计算机的ip地址不是公网地址,七牛云即使知道我们本地的文件存储地址,也无法从我们的计算机获取数据 那么如果是后台发送的话,需要后台部署在一个公网IP的服务器上面,此时发送地址给七牛云,那么他接收到请求后就可以从我们的服务器拉取数据。 当然这些只是我猜测的,因为具体技术我也不太清楚,还是小菜鸡一个。

1.2情景模拟:(A发送数据给B,发送了数据的全部信息,就相当于我们把图片全部发送过去了) 所以我觉得既然只传地址的原理我搞不太懂,那么把数据全部发过去就可以了,这个原理简单且易懂,A拿着数据全部送到B门口,那么B就肯定能拿到了。所以本文传过去的数据都是图片的全部信息,而非本地地址而已。

1.3前台只传本地地址的情况下,能不能让七牛云也知道我们发送图片的具体信息,这个可以用FormData对象,这个是浏览器的接口,原生js没有,就是说这个方法只能用于html网页 formData,就像他的名字一样,表单数据,它可以用来给表单数据追加键值对。

具体用法可以看看MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData

FormData 是一个构造函数,使用它需要new一个实例const formdata = new FormData(),然后把我们本地的图片地址传入进去:formdata.append('file', req.file),那么表单数据对象就多了一个file的属性,他的值就是req.file 。无论是elementUi的上传组件,或者原生的html的上传的元素,道理都一样,都可以使用formData。

其实formData并不是只传地址就可以实现图片上传,当它append追加的是一个表单对象是,它会自动注入该表单对象的全部数据。比如formdata.append('file', req.file),它会把req.file的全部数据,即图片数据全部注入给属性名为file的值。所以formData本质就是注入某个表单对象的全部数据,这个说到底也不是传本地文件地址,而是把本地文件的全部数据流注入到表单里面。

小demo:

 <template>
  <!-- upload -->
  <div class="upload">
    <el-upload
      class="avatar-uploader"
      :action= domain
      :http-request = upqiniu
      :show-file-list="false"
      :before-upload="beforeUpload">
      <img v-if="imageUrl" :src="imageUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
  </div>
</template>
<script>
export default {
  data () {
    return {
      imageUrl: '',
      token: {},
      // 七牛云的上传地址,根据自己所在地区选择,我这里是华南区
      domain: 'https://upload-z2.qiniup.com',
      // 这是七牛云空间的外链默认域名
      qiniuaddr: 'p3z6q1uw1.bkt.clouddn.com'
    }
  },
  methods: {
    // 上传文件到七牛云
    upqiniu (req) {
      console.log(req)
      const config = {
        headers: {'Content-Type': 'multipart/form-data'}
      }
      let filetype = ''
      if (req.file.type === 'image/png') {
        filetype = 'png'
      } else {
        filetype = 'jpg'
      }
      // 重命名要上传的文件
      const keyname = 'lytton' + new Date() + Math.floor(Math.random() * 100) + '.' + filetype
      // 从后端获取上传凭证token
      this.axios.get('/up/token').then(res => {
        console.log(res)
        const formdata = new FormData()
        formdata.append('file', req.file)//追加file数据,req.file是我们本地的文件地址,elementui的el-upload里的http-request像我们本地计算机发起请求数据,会把我们选择的文件地址赋值给req.file
        formdata.append('token', res.data)
        formdata.append('key', keyname)
        // 获取到凭证之后再将文件上传到七牛云空间
        this.axios.post(this.domain, formdata, config).then(res => {
          this.imageUrl = 'http://' + this.qiniuaddr + '/' + res.data.key
          // console.log(this.imageUrl)
        })
      })
    },
    // 验证文件合法性
    beforeUpload (file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
      }
      return isJPG && isLt2M
    }
  }
}
</script>
<style scoped>
.upload {
  600px;
  margin: 0 auto;
}
.avatar-uploader .el-upload {
  border: 5px dashed #ca1717 !important;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409EFF;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  178px;
  height: 178px;
  display: block;
}
</style>

2.关于qiniu.io.PutExtra()

var extra = new qiniu.io.PutExtra();//extra官方文档虽然没有明确说明,

但是有一个example,我估计它是用来设置参数的可选值 例子:

个人觉得设置了扩展参数,然后执行回调操作时,它会在七牛云原本返回的原始json数据响应上面加上我们自定义的参数。

var putExtra = new qiniu.resume_up.PutExtra(); // 扩展参数

putExtra.params = { "x:name": "", "x:age": 27, }

putExtra.fname = 'testfile.mp4';

穷则独善其身,达则兼济天下……
原文地址:https://www.cnblogs.com/hmy-666/p/14650952.html