前端Vue+axios实现阿里云oss文件上传(服务端签名直传)

前端Vue+axios实现阿里云oss文件上传(服务端签名直传)

问题描述

项目需要上传图片至服务器,但因为上传带宽慢,所以需要使用阿里云对象存储OSS用于上传文件,然后将上传后的文件链接处理上传到自己项目的服务器

  • 问题一

上传文件到服务器端规定请求头中的Content-type使用multipart/form-data形式,由于缺少经验自己并不清楚使用multipart/form-data要如何发送请求

  • 问题二

服务器端签名直传,首先是后端会提供一个接口,前端请求该接口后会返回一些字段数据,在依据返回的数据处理后再发送请求上传文件

在这里插入图片描述

其中callback字段我请求的接口数据没有,查看官网服务端签名直传还是没有弄明白,该怎么将返回的数据整合在一个FromDate对象中,然后发送post请求将FromDate对象传递给阿里云端的服务器

  • 问题三

将问题二中的数据整合后,使用axios发送post请求。由于发送请求的url是问题二中返回数据的host,出于浏览器的同源策略会出现跨域报错。登陆阿里云后台配置阿里云服务器的CORS允许跨域请求后,请求依然会出现跨域报错

在这里插入图片描述

问题解决

  • 问题一

使用multipart/form-data形式上传文件,需要使用到FormData对象

  1. 创建一个空对象
let fromData = new FormData();
  1. API添加查看数据
/*
*append() 追加数据,当字段已经存在时,使用append()添加相同字段,相当于对一个数组使用push()
*/
fromData.append("name","oss");

在这里插入图片描述

/*
*set()方法,不管相同字段多次set,前面的值会被后面的值给覆盖掉
*/
fromData.set("name","oss");
fromData.set("name","lihai");

在这里插入图片描述

/*
*getAll() 返回一个数组,数组中包括传入字段的值
*get() 返回一个字符串类型的数据,如果某个字段多次append()数据,get方法永远都是获取第一次append的数据
*/
formData.getAll("age");// ["10", "11"]
formData.get("age");//"10"

注意点:

FormData对象添加任何数据类型的值都会被自动转化成字符串类型

在这里插入图片描述

使用axios发送

axios应该需要二次封装,为了方便我用原生发送

import Axios from "axios";
Axios.post(url,formData,{
    headers:{
        "Content-Type":"multipart/form-data"
    }
})
  • 问题二

请求服务器接口会返回一些数据

在这里插入图片描述

获取数据后,前端部分只需要使用FromData对象添加字段数据

上传文件使用vant组件uploader

<uploader :after-read="onChange" v-if="index === 3">
    <div class="items-title">
        <p :class="{ font: index === 0 || index === 3 }">
            <img src="../../assets/images/icon/mandatory.png" alt="" />
        </p>
        <h3>{{ val.title }}</h3>
    </div>
</uploader>

Vue核心代码

onChange: async function (e) {
    let data = await this.getOss();//服务接口返回数据 
    const files = e,
          file = files.file,
          maxLen = 9;
    if (!/^image\/.+$/.test(file.type)) {
        Toast("请选择图片");
        return;
    }

    /**
       * 服务器签名直连
       */
    let fileName = `${Date.now()}.${file.type.split("/")[1]}`,//使用时间来定义文件名
        pathName = `${data.dir}${fileName}`;//相对路径   
    this.Files.set("key", pathName);//key 唯一值  即相对路径
    this.Files.set("policy", data.policy);//服务器返回的policy
    this.Files.set("OSSAccessKeyId", data.accessId);//服务器返回的accessId
    this.Files.set("success_action_status", "200");//定义成功为200
    this.Files.set("signature", data.signature);//服务器返回的signature
    this.Files.set("name", fileName);//文件名
    this.Files.set("file", file, fileName);//文件对象
    
    this.fileUpdata(data.host, pathName);
},
    
fileUpdata: async function (url, fileName) {
    let res = await _http.post(url, this.Files, {//发送请求的url就是服务器返回的host
      "Content-Type": "multipart/form-data",
    });
},
  • 问题三

终于将请求发出去了,但没想到它报跨域错误。还是在阿里云后台已经把CORS修改成*的前提下。

参考文档:https://help.aliyun.com/document_detail/31870.html?spm=a2c4g.11186623.2.9.1aba5d49k0Z2dG

在这里插入图片描述

xhr.withCredentials=false;表示跨域请求时,不发送cookit资源

我想到Axios二次封装,我把这个字段设置成了true,

axios.defaults.withCredentials = true;

axios.defaults.withCredentials设置回false后,成功了!!!!

在这里插入图片描述

https://ywja-public-bucket.oss-cn-hangzhou.aliyuncs.com/加上前面自己拼接上传的文件的相对路径就可以在浏览器上访问该图片了

在这里插入图片描述

在这里插入图片描述

图片压缩

本来没有东西写了,但我又遇到了个问题。在移动端上传图片文件大小会很大,占流量,而且上传后,再加载浏览会加载很慢,所有在上传图片文件时,要将图片进行压缩一次

前端压缩使用canvas进行操作,在原有代码上修改

  onChange: async function (e) {
      let data = await this.getOss();
      const files = e,
        file = files.file,
        maxLen = 9;
      if (!/^image\/.+$/.test(file.type)) {
        Toast("请选择图片");
        return;
      }
      if (this.htmlContext.length === maxLen) {
        return Toast("图片已超出数量");
      }
      this.showIconFn("上传中", "loading");

      /**
       * 服务器签名直连
       */
      let fileName = `${Date.now()}.${file.type.split("/")[1]}`,
        pathName = `${data.dir}${fileName}`;
      this.Files.set("key", pathName);
      this.Files.set("policy", data.policy);
      this.Files.set("OSSAccessKeyId", data.accessId);
      this.Files.set("success_action_status", "200");
      this.Files.set("signature", data.signature);
      this.Files.set("name", fileName);
      //图片压缩
      this.compression(file, data.host, pathName);
    },
    compression(file, host, pathName) {
      let image = document.createElement("img"),
        max = 600;//图片宽高
      self = this;
	 //图片加载后触发函数 
      image.onload = function () {
        let w = image.width,
          h = image.height,
          nw = w,
          nh = h;
        if (w > max) {
          nw = max;
          nh = h / (w / nw);
        }
        if (h > max) {
          nh = max;
          nw = w / (h / nh);
        }
       
        const canvas = document.createElement("canvas"); //新建一个画布,用来处理图像
        let ctx = canvas.getContext("2d") || canvas.getContext("2D"); //画布为2d
        canvas.width = nw;
        canvas.height = nh; //初始化画布的大小为之前的计算结果
        ctx.clearRect(0, 0, canvas.width, canvas.height); //清空画布
        ctx.drawImage(image, 0, 0, nw, nh); //绘制画布
		
		/*
		* 图片压缩关键在于canvas方法toBlob,第一个参数是回调函数,第二个参数为转化的图片格式,第三个参数是像素位数。将图片转化成image/jpg或image/webp大小可以变小
		*/
        canvas.toBlob(
          (blob) => {
          	//oss上传Blob文件会报错,所以再将Blob文件转化回File形式在上传阿里oss
            let files = new File([blob], file.name); //拿到的blod文件转化成文件
            self.Files.set("file", files, file.name); //将压缩后的图片二进制文件传入表单对象
            self.fileUpdata(host, pathName);
          },
          "image/webp",
          0.95
        ); 
      };
      image.src = URL.createObjectURL(file);
    },
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Vue + Axios + El-upload进行文件上传并跨域,需要按照以下步骤进行操作: 1. 在Vue项目中安装axios和element-ui。在命令行中输入以下命令即可安装: ``` npm install axios element-ui --save ``` 2. 在Vue项目中创建一个上传文件的组件,例如FileUpload.vue。在该组件中导入axios和element-ui,并且引入El-upload组件。示例代码如下: ```vue <template> <div> <el-upload class="upload-demo" :action="uploadUrl" :on-success="handleUploadSuccess" :before-upload="beforeUpload" :headers="headers" :data="formData" :file-list="fileList"> <el-button size="small" type="primary">点击上传</el-button> </el-upload> </div> </template> <script> import axios from 'axios' import { Message } from 'element-ui' export default { name: 'FileUpload', data () { return { fileList: [], uploadUrl: 'http://example.com/upload', formData: {}, headers: { 'Content-Type': 'multipart/form-data' } } }, methods: { handleUploadSuccess (response, file, fileList) { // 上传成功后的处理逻辑 console.log(response) }, beforeUpload (file) { // 文件上传前的处理逻辑 console.log(file) } } } </script> ``` 3. 在组件中实现文件上传的逻辑。在上传文件之前,需要设置请求头和请求数据,并且需要处理跨域请求。可以在组件的methods中定义一个upload方法,用来发送上传请求。示例代码如下: ```vue <script> import axios from 'axios' import { Message } from 'element-ui' export default { name: 'FileUpload', data () { return { fileList: [], uploadUrl: 'http://example.com/upload', formData: {}, headers: { 'Content-Type': 'multipart/form-data' } } }, methods: { handleUploadSuccess (response, file, fileList) { // 上传成功后的处理逻辑 console.log(response) }, beforeUpload (file) { // 文件上传前的处理逻辑 console.log(file) }, upload () { let config = { headers: this.headers, withCredentials: true // 跨域请求需要设置withCredentials为true } let data = new FormData() data.append('file', this.fileList[0].raw) // 向后端发送上传请求 axios.post(this.uploadUrl, data, config) .then(response => { this.handleUploadSuccess(response) }) .catch(error => { console.log(error) }) } } } </script> ``` 4. 最后,在Vue组件中使用El-upload组件,并且调用upload方法即可实现文件上传。示例代码如下: ```vue <template> <div> <el-upload class="upload-demo" :action="uploadUrl" :on-success="handleUploadSuccess" :before-upload="beforeUpload" :headers="headers" :data="formData" :file-list="fileList"> <el-button size="small" type="primary" @click="upload">点击上传</el-button> </el-upload> </div> </template> <script> import axios from 'axios' import { Message } from 'element-ui' export default { name: 'FileUpload', data () { return { fileList: [], uploadUrl: 'http://example.com/upload', formData: {}, headers: { 'Content-Type': 'multipart/form-data' } } }, methods: { handleUploadSuccess (response, file, fileList) { // 上传成功后的处理逻辑 console.log(response) }, beforeUpload (file) { // 文件上传前的处理逻辑 console.log(file) }, upload () { let config = { headers: this.headers, withCredentials: true // 跨域请求需要设置withCredentials为true } let data = new FormData() data.append('file', this.fileList[0].raw) // 向后端发送上传请求 axios.post(this.uploadUrl, data, config) .then(response => { this.handleUploadSuccess(response) }) .catch(error => { console.log(error) }) } } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值