文章目录

  • 1. 创建用户配置权限
  • 2.创建存储空间
  • 3. 后端项目整合
  • 3.1 ruoyi-common/pom.xml添加依赖
  • 3.2 application.yml添加配置
  • 3.3 com.ruoyi.common.utils.oss添加工具类
  • 3.4 com.ruoyi.aliyun.oss.controller添加OssController
  • 3.5 callback接口配置权限
  • 4. 前端项目整合
  • 4.1 安装依赖
  • 4.2 vuex添加用户id
  • 4.3 添加src\api\oss\oss.js
  • 4.4 全局挂载oss.js
  • *注意事项

1. 创建用户配置权限

参考:什么是STS 阿里云创建用户及授权参考:使用STS临时访问凭证访问OSS

创建完成后我们会获得:

  1. 用户AccessKey ID
  2. 用户AccessKey Secret
  3. 角色ARN

2.创建存储空间

参考:创建存储空间 创建完成后我们会获得:

  1. BucketName
  2. Region
  3. Endpoint

注意:

4. 预览时如果想在浏览器中预览,在Bucket中->传输管理->域名管理中绑定域名即可

5. Bucket读写权限设置为私有即可

6. 跨域设置

2.1. 来源:*

2.2. 允许Methods全勾选

2.3. 允许Headers:*

2.4. 暴露Headers可以不写

*参考

若依是bs架构吗 若依saas_若依是bs架构吗

3. 后端项目整合

3.1 ruoyi-common/pom.xml添加依赖
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>
3.2 application.yml添加配置
oss:
   sts:
       accesskey:
         id: 第一步用户AccessKey ID
         secret: 第一步用户AccessKey Secret
       bucket: 第二步BucketName
       region: 第二步Region
       endpoint: 第二步Endpoint
       role:
         arn: 第一步角色ARN
  • 之前的文章整合cas时有拆分了开发、测试、生产库的配置文件,那么在其中添加,如果没有,那么直接添加进application.yml中
oss:
   sts:
       callbackUrl: 该应用对外的域名[端口],如:https://dky12.xxx.com
3.3 com.ruoyi.common.utils.oss添加工具类
package com.ruoyi.common.utils.oss;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * ali oss临时授权访问
 */
public class AliyunStsOssUtil {

    public static Logger logger = LoggerFactory.getLogger(AliyunStsOssUtil.class);
    public static final String ACCESS_KEY_ID = "ACCESS_KEY_ID";
    public static final String ACCESS_KEY_SECRET = "ACCESS_KEY_SECRET";
    public static final String SECURITY_TOKEN = "SECURITY_TOKEN";
    public static final String EXPIRATION = "EXPIRATION";
    //这里使用cn-hangzhou区域,具体根据实际情况而定
    private static final String REGION = "cn-beijing";
    private static final String STS_API_VERSION = "2015-04-01";
    // 自有域名 通过这个域名在浏览器中可以直接预览而不是下载
    private static final String OWN_DOMAIN_NAME = "bucket中绑定的域名";

    public static JSONObject getCredit(String userName, String roleArn, String accessKeyId, String accessKeySecret, String bucketName) throws ClientException {
        // 用于阿里云后台审计使用的临时名称,可根据实际业务传输,具体内容不影响服务使用
        String roleSessionName = userName;

        //执行角色授权
        IClientProfile profile = DefaultProfile.getProfile(REGION, accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        final AssumeRoleRequest request = new AssumeRoleRequest();
        request.setVersion(STS_API_VERSION);
        request.setRoleArn(roleArn);
        request.setRoleSessionName(roleSessionName);
        //request.setPolicy(policyObject.toJSONString());
        //临时授权有效时间,从900到3600
        request.setDurationSeconds(900L);
        final AssumeRoleResponse response = client.getAcsResponse(request);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(ACCESS_KEY_ID, response.getCredentials().getAccessKeyId());
        jsonObject.put(ACCESS_KEY_SECRET, response.getCredentials().getAccessKeySecret());
        //jsonObject.put(SECURITY_TOKEN, response.getCredentials().getBizSecurityToken());
        jsonObject.put(SECURITY_TOKEN, response.getCredentials().getSecurityToken());
        jsonObject.put(EXPIRATION, response.getCredentials().getExpiration());
        return jsonObject;
    }

    /**
     * STS方式获取图片地址
     * @param userName
     * @param roleArn
     * @param accessKeyId
     * @param accessKeySecret
     * @param bucketName
     * @param endpoint
     * @return
     * @throws ClientException
     */
    public static String getStsUrl(String userName, String roleArn, String accessKeyId, String accessKeySecret, String bucketName, String endpoint, String objectName)throws ClientException {
        OSS ossClient = getSTSOssClient(userName, roleArn, accessKeyId, accessKeySecret, bucketName, endpoint);

        // 填写签名URL的过期时间。
        Date expiration = null;
        expiration = getExpiration(expiration);
        // 生成签名URL。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
        // 设置过期时间。
        request.setExpiration(expiration);
        // 通过HTTP GET请求生成签名URL。
        URL signedUrl = ossClient.generatePresignedUrl(request);

        // 关闭OSSClient。
        ossClient.shutdown();
        // **如果没有绑定域名那么replaceFirst方法删除即可
        return signedUrl.toString().replaceFirst( bucketName+ "." +endpoint,OWN_DOMAIN_NAME);
    }

    /**
     * STS方式获取多张图片地址
     * @param userName
     * @param roleArn
     * @param accessKeyId
     * @param accessKeySecret
     * @param bucketName
     * @param endpoint
     * @return
     * @throws ClientException
     */
    public static List<String> getStsUrl(String userName, String roleArn, String accessKeyId, String accessKeySecret, String bucketName, String endpoint, List<String> objectNames)throws ClientException {
        List<String> urls = new ArrayList<>();

        if(!CollectionUtils.isEmpty(objectNames)){
            OSS ossClient = getSTSOssClient(userName, roleArn, accessKeyId, accessKeySecret, bucketName, endpoint);

            objectNames.forEach(objectName -> {
                // 填写签名URL的过期时间。
                Date expiration = null;
                expiration = getExpiration(expiration);
                // 生成签名URL。
                GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
                // 设置过期时间。
                request.setExpiration(expiration);
                // 通过HTTP GET请求生成签名URL。
                URL signedUrl = ossClient.generatePresignedUrl(request);
                urls.add(signedUrl.toString().replaceFirst( bucketName+ "." +endpoint,OWN_DOMAIN_NAME));
            });

            ossClient.shutdown();
        }

        return urls;
    }

    /**
     * 获取签名过期时间
     * @param expiration
     * @return
     */
    private static Date getExpiration(Date expiration) {
        try {
            long nowTimeMillis = System.currentTimeMillis();
            nowTimeMillis = nowTimeMillis + ( 600 * 1000); // 当前时间600秒后
            expiration = new Date(nowTimeMillis);
            //expiration = DateUtil.parseRfc822Date("Wed, 18 Mar 2022 14:20:00 GMT");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return expiration;
    }

    /**
         * STS方式获取客户端
         * @param userName
         * @param roleArn
         * @param accessKeyId
         * @param accessKeySecret
         * @param bucketName
         * @param endpoint
         * @return
         * @throws ClientException
         */
    private static OSS getSTSOssClient(String userName, String roleArn, String accessKeyId, String accessKeySecret, String bucketName, String endpoint) throws ClientException {
        JSONObject credit = getCredit(userName, roleArn, accessKeyId, accessKeySecret, bucketName);
        // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
        String stsAccessKeyId = credit.getString(ACCESS_KEY_ID);
        String stsAccessKeySecret = credit.getString(ACCESS_KEY_SECRET);
        String securityToken = credit.getString(SECURITY_TOKEN);
        // 创建OSSClient实例。
        return new OSSClientBuilder().build(endpoint, stsAccessKeyId, stsAccessKeySecret, securityToken);
    }
}
3.4 com.ruoyi.aliyun.oss.controller添加OssController
package com.ruoyi.aliyun.oss.controller;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyuncs.exceptions.ClientException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.oss.AliyunStsOssUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URI;
import java.net.URLDecoder;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/oss")
public class OssController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${oss.sts.endpoint}")
    private String endpoint;

    @Value("${oss.sts.region}")
    private String ossRegion;

    @Value("${oss.sts.bucket}")
    private String ossBucket;

    @Value("${oss.sts.accesskey.id}")
    private String ossAccessKeyId;

    @Value("${oss.sts.accesskey.secret}")
    private String ossAccessKeySecret;

    @Value("${oss.sts.role.arn}")
    private String ossRoleArn;

    @Value("${oss.sts.callbackUrl}")
    private String callbackUrl;

    /**
     * 获取授权信息
     *
     * @param type 授权类型,图片类型或普通文件类型
     * @return
     * @throws ClientException
     */
    @RequestMapping("/getCredit")
    public JSONObject getCredit(String type) throws ClientException {
        JSONObject jsonObject = new JSONObject();
        JSONObject creditInfo;
        creditInfo = AliyunStsOssUtil.getCredit("xxx", ossRoleArn, ossAccessKeyId, ossAccessKeySecret, ossBucket);
        //文件存放地域
        jsonObject.put("region", ossRegion);
        //临时访问accessKey
        jsonObject.put("AccessKeyId", creditInfo.getString(AliyunStsOssUtil.ACCESS_KEY_ID));
        //临时访问accessKeySecret
        jsonObject.put("AccessKeySecret", creditInfo.getString(AliyunStsOssUtil.ACCESS_KEY_SECRET));
        //临时访问
        jsonObject.put("SecurityToken", creditInfo.getString(AliyunStsOssUtil.SECURITY_TOKEN));
        //临时访问过期时间
        jsonObject.put("Expiration", creditInfo.getString(AliyunStsOssUtil.EXPIRATION));
        //bucket名称
        jsonObject.put("bucket", this.ossBucket);
        //文件的存放基目录
        //jsonObject.put("basePath", String.format("oss/%s", basePath));
        jsonObject.put("StatusCode", 200);

        // 回调
        String callbackUrl = this.callbackUrl + "/oss/callback";

        JSONObject jasonCallback = new JSONObject();
        jasonCallback.put("url", callbackUrl);
        jasonCallback.put("body",
                "filename=${object}" +
                        "&size=${size}" +
                        "&mimeType=${mimeType}" +
                        "&height=${imageInfo.height}" +
                        "&width=${imageInfo.width}" +
                        "&fileOriginalName=${x:fileOriginalName}" +
                        "&uploadUserId=${x:uploadUserId}" +
                        "&funCode=${x:funCode}" +
                        "&dataId=${x:dataId}" +
                        "&newFileName=${x:newFileName}" +
                        "&suffixName=${x:suffixName}");
        jsonObject.put("callback", jasonCallback);
        return jsonObject;
    }

    @PostMapping("/callback")
    public void callback(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String ossCallbackBody = GetPostBody(request.getInputStream(),
                Integer.parseInt(request.getHeader("content-length")));
        boolean ret = VerifyOSSCallbackRequest(request, ossCallbackBody);
        logger.debug("ossCallbackBody :" + ossCallbackBody);
        logger.debug("verify result : " + ret);
        if (ret) {
            // TODO 插入数据图片关联表
            if(i == 1){
                response(request, response, "{\"Status\":\"OK\"}", HttpServletResponse.SC_OK);
            }else {
                response(request, response, "{\"Status\":\"verdify not ok\"}", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        } else {
            response(request, response, "{\"Status\":\"verdify not ok\"}", HttpServletResponse.SC_BAD_REQUEST);
        }
    }

    /**
     * 服务器响应结果
     *
     * @param request
     * @param response
     * @param results
     * @param status
     * @throws IOException
     */
    private void response(HttpServletRequest request, HttpServletResponse response, String results, int status)
            throws IOException {
        String callbackFunName = request.getParameter("callback");
        response.addHeader("Content-Length", String.valueOf(results.length()));
        if (callbackFunName == null || callbackFunName.equalsIgnoreCase(""))
            response.getWriter().println(results);
        else
            response.getWriter().println(callbackFunName + "( " + results + " )");
        response.setStatus(status);
        response.flushBuffer();
    }

    /**
     * 获取Post消息体
     *
     * @param is
     * @param contentLen
     * @return
     */
    private String GetPostBody(InputStream is, int contentLen) {
        if (contentLen > 0) {
            int readLen = 0;
            int readLengthThisTime = 0;
            byte[] message = new byte[contentLen];
            try {
                while (readLen != contentLen) {
                    readLengthThisTime = is.read(message, readLen, contentLen - readLen);
                    if (readLengthThisTime == -1) {// Should not happen.
                        break;
                    }
                    readLen += readLengthThisTime;
                }
                return new String(message);
            } catch (IOException e) {
            }
        }
        return "";
    }

    /**
     * 验证上传回调的Request
     *
     * @param request
     * @param ossCallbackBody
     * @return
     * @throws NumberFormatException
     * @throws IOException
     */
    protected boolean VerifyOSSCallbackRequest(HttpServletRequest request, String ossCallbackBody)
            throws NumberFormatException, IOException {
        boolean ret = false;
        String autorizationInput = new String(request.getHeader("Authorization"));
        String pubKeyInput = request.getHeader("x-oss-pub-key-url");
        byte[] authorization = BinaryUtil.fromBase64String(autorizationInput);
        byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput);
        String pubKeyAddr = new String(pubKey);
        if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/")
                && !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/")) {
            System.out.println("pub key addr must be oss addrss");
            return false;
        }
        String retString = executeGet(pubKeyAddr);
        retString = retString.replace("-----BEGIN PUBLIC KEY-----", "");
        retString = retString.replace("-----END PUBLIC KEY-----", "");
        String queryString = request.getQueryString();
        String uri = request.getRequestURI();
        String decodeUri = java.net.URLDecoder.decode(uri, "UTF-8");
        String authStr = decodeUri;
        if (queryString != null && !queryString.equals("")) {
            authStr += "?" + queryString;
        }
        authStr += "\n" + ossCallbackBody;
        ret = doCheck(authStr, authorization, retString);
        logger.info("------authStr:" + authStr);
        logger.info("------pubKeyAddr:" + pubKeyAddr);
        logger.info("------authorization:" + authorization);
        logger.info("------retString:" + retString);
        return ret;
    }

    /**
     * 获取public key
     *
     * @param url
     * @return
     */
    @SuppressWarnings({"finally"})
    private String executeGet(String url) {
        BufferedReader in = null;

        String content = null;
        try {
            // 定义HttpClient
            CloseableHttpClient client = HttpClientBuilder.create().build();
            //@SuppressWarnings("resource")
            //DefaultHttpClient client = new DefaultHttpClient();
            // 实例化HTTP方法
            HttpGet request = new HttpGet();
            request.setURI(new URI(url));
            HttpResponse response = client.execute(request);

            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            content = sb.toString();
        } catch (Exception e) {
        } finally {
            if (in != null) {
                try {
                    in.close();// 最后要关闭BufferedReader
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return content;
        }
    }

    /**
     * 验证RSA
     *
     * @param content
     * @param sign
     * @param publicKey
     * @return
     */
    private static boolean doCheck(String content, byte[] sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = BinaryUtil.fromBase64String(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA");
            signature.initVerify(pubKey);
            signature.update(content.getBytes());
            boolean bverify = signature.verify(sign);
            return bverify;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private Map<String, String> getUrlParams(String ossCallbackBody) throws UnsupportedEncodingException {
        Map<String, String> params = new HashMap<>();
        String[] split = ossCallbackBody.replaceAll("\"","").split("&");
        for (String s : split) {
            String[] split1 = s.split("=");
            if (split1.length == 2) {
                params.put(split1[0], URLDecoder.decode(split1[1], "utf-8"));
            }else {
                params.put(split1[0],"");
            }
        }
        return params;
    }
}
3.5 callback接口配置权限

com.ruoyi.framework.config.CasSecurityConfig类中configure方法添加:

// permitAll | 用户可以任意访问
.antMatchers("/oss/callback").permitAll()

4. 前端项目整合

4.1 安装依赖
npm install ali-oss -s
4.2 vuex添加用户id

src\store\modules\user.js中state属性添加

userId: '',

mutations属性添加

SET_ID: (state, userId) => {
  state.userId = userId
},

actions属性的GetInfo函数修改

// 获取用户信息
GetInfo({ commit, state }) {
  return new Promise((resolve, reject) => {
    getInfo(state.token).then(res => {
      const user = res.user
      const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
      if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
        commit('SET_ROLES', res.roles)
        commit('SET_PERMISSIONS', res.permissions)
      } else {
        commit('SET_ROLES', ['ROLE_DEFAULT'])
      }
      commit('SET_NAME', user.userName)
      // 其实就是加了这一行
      commit('SET_ID', user.userId)
      commit('SET_AVATAR', avatar)
      resolve(res)
    }).catch(error => {
      reject(error)
    })
  })
},

src\store\getters.js中getters属性添加

userId: state => state.user.userId,
4.3 添加src\api\oss\oss.js
import request from '@/utils/request'
import OSS from 'ali-oss';
import store from '@/store'

/**
 * 获取ossClient
 * @param {} option 
 * @returns 
 */
 const getClient = async option => {
	let credit = await request({
		url:'/oss/getCredit',
		method: 'get'
	});
	console.log(option)
	//从后台拿到的临时授权信息
	return {
		client : new OSS({
			region: credit.region,
			accessKeyId: credit.AccessKeyId,
			accessKeySecret: credit.AccessKeySecret,
			stsToken: credit.SecurityToken,
			bucket: credit.bucket,
			secure: true,
		}),
		callback : credit.callback,
	};
}

/**
/ * 上传一个文件
*/
const uploadAction = async option => {
	let {client, callback} = await getClient();
	console.log(option)
	let filePath = '/' + option.fileName;
	//将多个/替换为1个/,防止oss文件路径中多个/造成空目录
	filePath = filePath.replace(/[\/]+/g, '\/');
	// 自定义变量传值
	console.log("uploadUserId=>",store.getters.userId)
	// 自定义函数,对应后端/oss/getCredit接口jasonCallback对象的body
	callback.customValue = {
		uploadUserId: store.getters.userId + '',
		funCode: option.funCode,
		dataId: option.dataId,
		fileOriginalName: option.file.name,
		newFileName: option.newFileName,
		suffixName: option.suffixName,
	};
	callback.contentType = "application/json";
	return client.put(
		filePath,
		option.file, {
			callback: callback,
		}
	)
}

/**
 * 上传多个文件
 * @param {*} files 文件集合
 * @param {*} fileDir oss中文件夹路径
 * @param {*} funCode 自定义参数,功能编号,后端保存时用于区分业务
 * @param {*} dataId 自定义参数,业务主键,后端保存时用于区分工单
 * @param {*} progress 
 * @returns oss object路径集合
 */
const uploadFiles = async (files, fileDir, funCode, dataId, progress = console.log) => {
	console.log("files=>",files)
	let urls = [];
	let date = new Date();
	let year = date.getFullYear();
	let month = date.getMonth() + 1;
	let day = date.getDate();

	for (let index = 0; index < files.length; index++) {
		let file = files[index];
		let suffixNameIndex = file.name.lastIndexOf('.');
		let suffixName = suffixNameIndex == -1 ? '' : file.name.substring(suffixNameIndex);
		let newFileName =  uuid().replaceAll("-","").toLocaleLowerCase() + suffixName
		let res = await uploadAction({
			//待上传文件信息
			file: files[index],
			//临时访问授权信息
			// token: credit.data,
			// 上传文件名称,为防止文件被覆盖(oss上传重复文件会覆盖同名文件),使用fileDir/年/月/日/uuid.文件后缀,具体可根据实际业务而定
			
			fileName: `${fileDir}/${year}/${month}/${day}/` + newFileName,
			//可选参数,图片上传过程中触发的操作
			progress: progress,
			funCode: funCode,
			dataId: dataId + '',
			newFileName,
			suffixName: suffixName.length < 1 ? '': suffixName.substr(1),
		});
		if (res.name) {
			urls.push(`${res.name}`);
		}
	}
	//返回多个文件上传结果,为多个oss文件路径地址(不包含host路径)
	return urls;
}

/**
 * 下载文件
 * @param {*} filePath oss object路径
 * @param {*} filename 下载后的文件名
 */
const downloadFile = async (filePath, filename)=>{
	let {client, callback} = await getClient();
	// 配置响应头实现通过URL访问时自动下载文件,并设置下载后的文件名。
	const response = {
		'content-disposition': `attachment; filename=${encodeURIComponent(filename)}`
	}
	// 填写Object完整路径。Object完整路径中不能包含Bucket名称。
	const url = client.signatureUrl(filePath, { response });
	console.log(url);
	return url;
}

function uuid(len, radix) {
	var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
	var uuid = [], i;
	radix = radix || chars.length;

	if (len) {
		// Compact form
		for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
	} else {
		// rfc4122, version 4 form
		var r;

		// rfc4122 requires these characters
		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
		uuid[14] = '4';

		// Fill in random data.  At i==19 set the high bits of clock sequence as
		// per rfc4122, sec. 4.1.5
		for (i = 0; i < 36; i++) {
			if (!uuid[i]) {
				r = 0 | Math.random()*16;
				uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
			}
		}
	}

	return uuid.join('');
}

export default {
	upload: uploadFiles,
	getClient: getClient,
	download: downloadFile,
}
4.4 全局挂载oss.js

src\main.js中添加

import oss from './api/oss/oss'
// js中通过this.$oss.函数名称调用
Vue.prototype.$oss = oss;

*注意事项

  1. 前端上传回调签名校验失败