最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • el-upload 直连阿里云oss

    正文概述 掘金(Leo_哒哒)   2021-01-07   769

    步骤一:阿里OSS配置

    登录阿里云

    homenew.console.aliyun.com/home/scene/…

    el-upload 直连阿里云oss

    阿里云配置STS AssumeRole临时授权访问OSS资源

    1. 用户管理——>创建RAM子账号,并自动生成AccessKeyId和AccessKeySecret;
    2. 策略管理——>新建自定义策略,授权访问OSS的bucket;
    3. 角色管理——>创建角色,将步骤2的策略授权给该角色;
    4. 策略管理——>新建自定义策略,授权访问STS的AssumeRole,该策略使用步骤3的角色;
    5. 用户管理——>将步骤4的策略授权给步骤1 的子账号。
    6. 使用子账号的AccessKeyId、AccessKeySecret和角色的roleArn,roleSessionName可以自己随意起,申请STS临时授权访问OSS。

    步骤二:后端nest配置

    ossUpload.service.ts

    import { Injectable } from '@nestjs/common';
    import config from '../../../config';
    import * as STS from '@alicloud/sts-sdk';
    
    @Injectable()
    export class OssUploadService {
      /**
       * 获取 STS 认证
       * @param username 登录用户名
       */
      async getIdentityFromSTS(username: string) {
        const sts = new STS({
          endpoint: 'sts.aliyuncs.com',
          ...config,
        });
        
        const identity = await sts.getCallerIdentity();
        
        // 打*号是因为涉及安全问题,具体角色需要询问公司管理阿里云的同事
        const stsToken = await sts.assumeRole(`acs:ram::${identity.AccountId}:role/ram***oss`, `${username}`);
    
        return {
          code: 200,
          data: {
            stsToken,
          },
          msg: 'Success',
        };
      }
    }
    
    

    ossUpload.module.ts

    import { Module } from '@nestjs/common';
    import { OssUploadService } from './ossUpload.service';
    
    @Module({
      providers: [OssUploadService],
      exports: [OssUploadService],
    })
    export class OssUploadModule {}
    

    ossUpload.controller.ts

    import { Controller, Body, Post, Request, UseGuards } from '@nestjs/common';
    import { OssUploadService } from './ossUpload.service';
    
    @Controller()
    export class OssUploadController {
      constructor(private readonly ossUploadService: OssUploadService) {}
    
      @Post('oss-upload')
      async getIdentityFromSTS(@Body() Body: any) {
        return await this.ossUploadService.getIdentityFromSTS(Body.username);
      }
    }
    

    报错修复指南链接

    help.aliyun.com/knowledge_d…

    help.aliyun.com/document_de…

    help.aliyun.com/knowledge_d…

    步骤三:前端代码

    OSSFileUpload.vue

    <script lang="ts">
    import { Component, Vue, Prop, Emit } from 'vue-property-decorator';
    import { getTokenFormLocal } from '@/utils/Storage';
    import { API_FILE_UPLOAD } from '@/api';
    
    import oss from '@/utils/ossForUpload.ts';
    
    /**
     * 文件上传(aliOSS)
     *
     * @param {string} action - 上传的地址
     * @param {object} data - 上传时附带的额外参数
     * @param {string} name - 上传的文件字段名
     * @param {object} headers - 设置上传的请求头部
     * @param {number} maxSize - 文件上传的大小上限 单位kb
     * @param {number} limit - 最大允许上传个数
     * @param {string} fileTypes - 上传文件的类型
     * @param {array} fileList - 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
     *
     * @event on-success - 文件上传成功时的钩子 function(response, file, fileList)
     * @event on-remove - 文件列表移除文件时的钩子 function(file, fileList)
     * @event on-error - 文件上传错误 function(errorType, file) errorType: typeError 类型不匹配;overSize: 超出大小上线; exceed: 超出最大个数
     */
    
    @Component
    export default class OSSFileUpload extends Vue {
      @Prop({default() { return []; }}) public fileList!: any[]; // 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
    
      @Prop({default() {
        return `${process.env.VUE_APP_BASE_API_URL}${API_FILE_UPLOAD}`; // 上传接口
      }}) public action!: string; // 必选参数,上传的地址
      @Prop({default() {
        return {};
      }}) public data!: object; // 上传时附带的额外参数
      @Prop() public name!: string; // 上传的文件字段名
      @Prop({
        default() {
          return {
            identity: getTokenFormLocal() || '',
          };
        },
      }) public headers!: object; // 设置上传的请求头部
      @Prop(Number) public limit!: number; // 最大允许上传个数
      @Prop({default: 5 * 1024}) public maxSize!: number; // 文件上传的大小上线 单位kb
      @Prop() public fileTypes!: string;
    
      public httpRequest = oss;
      public alertMessage = ''; // 错误信息
    
      @Emit()
      public onSuccess(response: any, file: any, fileList: any) {
      }
    
      public beforeUpload(file: any) {
        file.percentage = 20;
        const enabledSize = file.size / 1024;
    
        if (enabledSize > this.maxSize) {
          this.$nextTick(function() {
            this.alertMessage = `文件大小不得超过${this.maxSize}kb`;
          });
          this.$emit('on-error-text', 'overSize', file);
          return false;
        }
    
        this.alertMessage = '';
      }
    
      /**
       * 文件超出个数限制时的钩子
       */
      public onExceed(files: any, fileList: any) {
        this.alertMessage = `超出最大上传数量${this.limit}`;
        this.$emit('on-error', this.alertMessage, files, fileList);
      }
    
      /**
       * 文件列表移除文件时的钩子
       */
      @Emit()
      public onRemove(file: any, fileList: any) {
        this.alertMessage = '';
      }
      public onError(err: any, file: any, fileList: any) {
        console.log('报错了');
        this.alertMessage = process.env.NODE_ENV === 'production' ? '网络异常,请稍后再试' : err;
        this.$emit('on-error', this.alertMessage, err, file, fileList);
      }
      public uploadProcess(event: any, file: any, fileList: any) {
        // console.log('文件上传中');
      }
    }
    </script>
    
    <template>
      <section>
        <el-alert
          :style="{
            marginBottom: '8px'
          }"
          v-show="!!alertMessage"
          :
          type="error"
          show-icon>
        </el-alert>
        <el-upload
          :limit="limit"
          :action="action"
          :data="data"
          :name="name"
          :accept="fileTypes"
          drag
          multiple
          :file-list="fileList"
          :headers="headers"
          :on-success="onSuccess"
          :before-upload="beforeUpload"
          :on-progress="uploadProcess"
          :on-exceed="onExceed"
          :on-remove="onRemove"
          :http-request="httpRequest"
          :on-error="onError">
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
          <div class="el-upload__tip" slot="tip"><slot name="tip"></slot></div>
        </el-upload>
      </section>
    </template>
    
    <style lang="less">
    </style>
    

    ossForUpload.ts

    // 记得npm i ali-oss一下
    import * as OSS from 'ali-oss';
    import { getPcBasicOss } from '@/model';
    import ImgZipper from 'imgzipper';
    
    function getError(action: any, option: any, xhr: any) {
      let msg;
      if (xhr.response) {
        msg = `${xhr.response.error || xhr.response}`;
      } else if (xhr.responseText) {
        msg = `${xhr.responseText}`;
      } else {
        msg = `fail to post ${action} ${xhr.status}`;
      }
    
      const err: any = new Error(msg);
      err.status = xhr.status;
      err.method = 'post';
      err.url = action;
      return err;
    }
    
    function getBody(xhr: any) {
      const text = xhr.responseText || xhr.response;
      if (!text) {
        return text;
      }
    
      try {
        return JSON.parse(text);
      } catch (e) {
        return text;
      }
    }
    
    function zipImg(file: any) {
      try {
        const imageType = file.type.includes('image');
    
        if ( imageType ) {
           return new Promise((res, rej) => {
            ImgZipper( file, (a: any, b: any) => {
              const zipfile = new File([a], file.name, {type: file.type, lastModified: Date.now()});
              res(zipfile);
            }, {
              scale: 0.78, // 生成图像缩放大小
              quality: 0.62, // 生成图像的质量
              disableBlob: null, // canvas.toBlob方法失败后调用函数
              type: 'image/jpeg', // 生成图像格式
              exif: true, // 是否使用调整相机旋转
            });
          });
        }
      } catch (err) {
        throw err;
      }
    }
    
    export default async function upload(option: any) {
      const {file = {}} = option;
      const newFile: any = await zipImg(file);
    
      try {
        // 这里改成我们node的请求
        const { credentials = {} } = await getPcBasicOss({ bucket: 'asal' });
    
        const client = new OSS({
          region: credentials.region,
          accessKeyId: credentials.AccessKeyId,
          accessKeySecret: credentials.AccessKeySecret ,
          stsToken: credentials.SecurityToken,
          bucket: 你的bucket,
        });
    
        const result = await client.put(`/l-web-pc/${newFile.name}`, newFile);
    
        return result;
    
      } catch (err) {
        option.onError(err);
        throw err;
      }
    }
    
    

    PS.如果是后端出接口,那就忽略node配置


    如果这篇文章有用,欢迎评论, 点赞, 加关注

    我是leo:祝大家早日升职加薪。


    起源地下载网 » el-upload 直连阿里云oss

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元