阿里云OSS文件上传几种方法(主要是前端)

您所在的位置:网站首页 文件上传实现方式 阿里云OSS文件上传几种方法(主要是前端)

阿里云OSS文件上传几种方法(主要是前端)

2024-05-08 00:11| 来源: 网络整理| 查看: 265

目录零、准备一、服务端签名后直传1. 阿里云控制台配置2. 后端接口开发(PHP)3. 前端获取签名后上传二、使用STS临时凭证进行上传1. 后端接口开发(node)2. 前端获取临时token再通过sdk进行上传三、前端签名,使用PostObject直接上传(可配合使用STS)1.应用场景四、直接在前端使用sdk进行上传五、中转上传到应用服务器再上传到阿里云OSS六、错误七、小结

零、准备

要是实现将文件上传到阿里云OSS,首先就要开通了OSS服务,然后创建bucket之类的。这些就不多说了。 稍微看了下文档就能看见有accessKeyId,accessKeySecret,endpoint,bucket等之类的。这些要哪里来呢。

accessKeyId,accessKeySecret 在控制台找到RAM访问控制它大概长下面这样,在这里创建用户,就能得到accessKeyId,accessKeySecret了。注意:accessKeySecret只会显示一次,你创建的时候就要保存起来,要不然就要重创了。 image

然后就要给创建的用户权限,然后才能操作OSSAPI。 image

然后就是endpoint,bucket这些了,要在'对象存储 OSS'页面中拿。 Bucket列表能看到Bucket的名称,在每个bucket的概览里就能看到endpoint之类的了。 image

结合PHP(或者纯前端)主要介绍三种不同的向OSS上传文件的方式,都是用过或者踩过坑的😂。

一、服务端签名后直传

优点:官方文档

使用插件(如,element upload, web uploader等)上传,不用重写上传方法,通过地址提交,可以方便的使用插件提供的功能。 前端值传不进过应用服务器中传,效率更高,而且前端也能方便获取上传进度。 需要后端进行签名,前端获取签名后再去上传,也不会暴露accessKeySecret,accessKeyId等oss信息。 1. 阿里云控制台配置

创建跨越规则,否则web前端上传的时候会报CORS跨越错误。** 具体操作如下图: image

2. 后端接口开发(PHP)

可以参考下官方示例代码(PHP),然后我们按照自己需要进行修改就基本上能实现了。这里是修改后的代码,因为只需将视频上传到OSS中,而且上传后的地址也是知道的,所以就注释了上传回调相关的操作,代码如下:

use DateTime; class ContentsController extends Controller { // 阿里云oss配置 private $accessKeyId = 'xxxxxxxx'; // 请填写您的AccessKeyId private $accessKeySecret = 'xxxxxx'; // 请填写您的AccessKeySecret private $bucket= "your-bucketName"; private $endpoint = "oss-cn-hangzhou.aliyuncs.com"; public function gmt_iso8601($time) { $dtStr = date("c", $time); $mydatetime = new DateTime($dtStr); $expiration = $mydatetime->format(DateTime::ISO8601); $pos = strpos($expiration, '+'); $expiration = substr($expiration, 0, $pos); return $expiration . "Z"; } // 阿里云签名接口 // 调用该接口可传入要上传到的文件夹dir public function signature() { { $id = $this -> accessKeyId; // 请填写您的AccessKeyId。 $key = $this -> accessKeySecret; // 请填写您的AccessKeySecret。 $host = 'https://'.$this -> bucket.'.'.$this -> endpoint; // $host = 'https://xxxx.oss-cn-hangzhou.aliyuncs.com'; // $host的格式为 bucketname.endpoint, $dir = trim(I('dir', '', 'string')); // 用户上传文件时指定的前缀。 // 若需要配置回调服务器URL 则此配置 // private $callbackUrl = 'http://你的域名/callback.php';//上传回调的地址 还记得上图中callback.php文件吗,把这文件放在你的项目中,配个路由保证能访问到这个文件就行,这个值就是访问callback.php此文件的URL 例如:我放在项目根目录 那值就为 http://liutong.pro/callback.php // $callbackUrl = $this->callbackUrl; // $callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实URL信息。 // $callback_param = array('callbackUrl' => $callbackUrl, // 'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}', // 'callbackBodyType' => "application/x-www-form-urlencoded"); // $callback_string = json_encode($callback_param); // $base64_callback_body = base64_encode($callback_string); $now = time(); $expire = 30; //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问。 $end = $now + $expire; $expiration = $this->gmt_iso8601($end); //最大文件大小.用户可以自己设置 $condition = array(0 => 'content-length-range', 1 => 0, 2 => 2147483648); $conditions[] = $condition; // 表示用户上传的数据,必须是以$dir开始,不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录。 $start = array(0 => 'starts-with', 1 => '$key', 2 => $dir); $conditions[] = $start; $arr = array('expiration' => $expiration, 'conditions' => $conditions); $policy = json_encode($arr); $base64_policy = base64_encode($policy); $string_to_sign = $base64_policy; $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true)); $response = array(); $response['accessid'] = $id; $response['host'] = $host; $response['policy'] = $base64_policy; $response['signature'] = $signature; $response['expire'] = $end; $response['callback'] = $base64_callback_body; $response['dir'] = $dir; // 这个参数是设置用户上传文件时指定的前缀。 echo json_encode($response); } } }

Java签名方法:https://www.cnblogs.com/applesnt/p/14863057.html

3. 前端获取签名后上传

前端先调用签名接口(如上是'/syscenter/contents/signature'),返回签名信息:

{ "accessid": "xxxxxtAq4LFttzpLZqvn2N5Y", "callback": null, "dir": "upload/", "expire": 1666918519, "host": "https://zzxxx.oss-cn-hangzhou.aliyuncs.com", "policy": "eyJxxxx0aW9uIjoiMjAyMi0xMC0yOFQwODo1NToxOVoiLCJjb25kaXRpb25zIjpbWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsMCwyMTQ3NDgzNjQ4XSxbInN0YXJ0cy13aXRoIiwixxxxxxxxxx", "signature": "Q4xxWOjB3kjGaNRF097LyG0SQ=" }

然后就可以使用签名信息进行上传了,提交到host,其他参数也一起带上,主要代码如下:

上传 const uploadUrl = ref(); const uploadData = reactive() const getSignature = async () => { const data = await axios.get('/syscenter/contents/signature', param: {dir:'/upload'}) uploadUrl.value = data.host uploadData.policy = data.policy uploadData.OSSAccessKeyId = data.accessid uploadData['success_action_status'] = 200 uploadData.signature = data.signature } 二、使用STS临时凭证进行上传

优点:官方文档

前端使用的是临时凭证访问的OSS,无需暴露长期密钥,更安全。 配合ali-oss能方便进行大文件的分片上传。 1. 后端接口开发(node) const { STS } = require('ali-oss'); import express from "express"; const router = express.Router(); router.get("/getToken", function (req, res) { let sts = new STS({ accessKeyId: "xxxxxxx", accessKeySecret: "xxxx", }); // assumeRole配置RAM用户的ARN。 // policy填写自定义权限策略,用于进一步限制STS临时访问凭证的权限。如果不指定Policy,则返回的STS临时访问凭证默认拥有指定角色的所有权限。 // expiration用于设置临时访问凭证有效时间单位为秒,最小值为900,最大值以当前角色设定的最大会话时间为准。本示例指定有效时间为3000秒。 // sessionName用于自定义角色会话名称,用来区分不同的令牌,例如填写为sessiontest。 sts .assumeRole("acs:ram::175708322470****:role/ramtest", ``, "3000", "sessiontest") .then((result) => { console.log(result); res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-METHOD", "GET"); res.json({ AccessKeyId: result.credentials.AccessKeyId, AccessKeySecret: result.credentials.AccessKeySecret, SecurityToken: result.credentials.SecurityToken, Expiration: result.credentials.Expiration, }); }) .catch((err) => { console.log(err); res.status(400).json(err.message); }); }); export default router; 2. 前端获取临时token再通过sdk进行上传 { "accessKeyId": "STS.NSmigxxevTxbauZ5hMdM", "accessKeySecret": "5wLHcDpqjojqZaVXFgDnBej7WHrao5Xzy6eGXufWzkSC", "securityToken": "CAIS5QF1q6Ft5B2yfSjIr5DYIt3av7pX47i/Rx/homI0edUZh4jPrzz2IH5NfXhvBeAWtf83mmlY7/cdlqp0UIQd0O", "region": "cn-hangzhou", "bucket": "xxx-xx.oss-cn-hangzhou.aliyuncs.com", "endpoint": "sts.cn-hangzhou.aliyuncs.com" }

引用https://gosspublic.alicdn.com/aliyun-oss-sdk-6.17.0.min.js ,用了构建工具则npm i ali-oss使用其sdk,其仓库及文档地址,其中要注意的是,浏览器环境并不是所有的api都能使用的,很多方法调用后undefined就是用不了了:

bucket相关的方法(如:listBuckets, putBucketLogging等)是用不了的。 policy相关,calculatePostSignature等方法也用不了(6.17.0),所以想通过签名去上传也是行的。 是用sdk上传,其put(name, file[, options]),multipartUpload(name, file[, options])等方法都是通过put上传的,没有在控制台跨域配置勾选put则还是会报cors错误。 若使用multipartUpload上传,则一定条件下会自动分片,所以需在跨域配置中配置暴露header:ETag,否则也会报错。

使用element upload上传示例,可以同步显示上传进度:

点击上传 支持扩展名:.rar .zip .exe // 初始化OSS initOSS() { getOSSToken().then(async (res) => { const data = res.data const client = new OSS({ region: 'oss-cn-hangzhou', accessKeyId: data.accessKeyId, accessKeySecret: data.accessKeySecret, stsToken: data.securityToken, bucket: 'xxx', refreshSTSToken: async () => { const data = getOSSToken() return { accessKeyId: data.accessKeyId, accessKeySecret: data.accessKeySecret, stsToken: data.securityToken } }, refreshSTSTokenInterval: 300000 }) this.oss = client }) }, // 重新的上传方法 uploadFunction(item) { this.oss.multipartUpload('/xxxy/' + item.file.name, item.file, { // 同步上传进度 // http-request返回的参数中有用onProgress可以同步进度 progress: function (p, checkpoint) { item.onProgress({ percent: Math.floor(p * 100) }); } }).then((res) => { let url = res.res.requestUrls[0].split('?').pop(); this.uploadForm.filePath = url this.uploadForm.attachList.push(url) }).catch(() => { this.$message.error('上传出错') }) }, 三、前端签名,使用PostObject直接上传(可配合使用STS) 1.应用场景

适合使用第三方的上传插件,可通过URL直接传入到OSS,同时能使用插件的自带的功能,而不用重写其内部方法。

生成签名的方法:

import '@/utils/crypto1/crypto/crypto' import '@/utils/crypto1/hmac/hmac' import '@/utils/crypto1/sha1/sha1' import { Base64 } from 'js-base64' /** * 生成policy和签名 * 默认1小时后失效 * @param {*} accessKeySecret oss accessKeySecret * @param {*} expiration 过期时间 单位秒 * @returns */ export const genSignature = (accessKeySecret, expir = 600) => { const expiration = (new Date(Date.now() + expir * 1000)).toISOString() const policy = { expiration: expiration, // 失效时间 conditions: [ ['content-length-range', 0, 469824028] // 设置上传文件的大小限制 1G ] } const policyBase64 = Base64.encode(JSON.stringify(policy)) const bytes = Crypto.HMAC(Crypto.SHA1, policyBase64, accessKeySecret, { asBytes: true }); const signature = Crypto.util.bytesToBase64(bytes); return { policy:policyBase64, signature } }

使用该方法可以在前端生成policy,signature,然后作为参数传递给url

如在el-upload中使用:

... // 根据调用后端sts接口获取accessKeySecret,生成policy,signature getOSSPOSTData() { getOSSToken().then(async (res) => { const data = res.data const signatureInfo = genSignature(data.accessKeySecret) this.uploadData.OSSAccessKeyId = data.accessKeyId this.uploadData.accessKeySecret = data.accessKeySecret this.uploadData.policy = signatureInfo.policy this.uploadData.Signature = signatureInfo.signature this.uploadData['success_action_status'] = 200 this.uploadData['x-oss-security-token'] = data.securityToken }) },

PostObject文档: PostObject crypto1文件: crypto1 注:crypto1如用不是阿里云提供的可能会计算出来的hmac不一致导致,签名失败。

四、直接在前端使用sdk进行上传

当然我们还可以直接就在前端页面中,使用阿里云提供的js的sdk就能直接进行上传了,不过如此就会把OSS相关的AccessKeyId,AccessKeySecret之类的暴露出来就是。避免方法就是按照官方的建议搭建STS服务并使用其返回的临时访问凭证访问OSS。这里就没有进行尝试了,详细可参考官方文档。

下面是没有使用STS,直接在前端操作的相关代码(使用的VUE和element-UI):

点击查看代码 文件上传 Button 点击上传 想传啥就传啥 new Vue({ el: "#app", data: function () { return { visible: false, oss: "", fileList: [], }; }, created() { this.initOSS(); }, methods: { initOSS() { this.oss = new OSS({ // 阿里云oss相关信息 region: "ss-cn-hangzhou", accessKeyId: "LTAIxxxxxwxxn7SM", accessKeySecret: "zxxxxxxx6xxx8V", bucket: "zflxx", }); }, upload(item) { this.oss.multipartUpload(item.filename, item.file).then((res) => { console.log(res); }); }, }, }); 五、中转上传到应用服务器再上传到阿里云OSS

因为使用的是php,所以这里用的是OSS PHP SDK,可以参考官方文档安装好SDK后,然后就能可以调用其SDK开始操作了。

// 使用上传到OSS public function uploadoss() { $accessKeyId = "xxxcxvxve232"; ; $accessKeySecret = "xxxxxxx12121212"; $bucket= "xxx"; $endpoint = "oss-cn-beijing.aliyuncs.com"; $upname = trim(I('upname', '', 'string')); if (!$upname) { $upname = trim(I('get.upname', '', 'string')); } if (!empty($_FILES[$upname]['name'])) { try { // 开启OSSClient $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint); } catch (OssException $e) { print $e -> getMessage(); } $content = $_FILES[$upname]; $info = pathinfo($content["name"]); $ext = $info['extension']; $file_name = date("YmdHis").time().mt_rand(100000, 999999). ".{$ext}"; $object = "upload/".$file_name; try { $result = $ossClient -> uploadFile($bucket, $object, $content['tmp_name']); $ossUrl = $result['oss-request-url']; } catch (OssException $e) { echo $e; } echo json_encode(array('flag' => 1, 'msg' => 'OK', 'picUrl' => $picUrl)); } else { echo json_encode(array('flag' => -1, 'msg' => 'No', 'picUrl' => '')); } } 六、错误

Please set the etag of expose-headers in OSS:https://help.aliyun.com/document_detail/277773.html

CORS 错误:https://help.aliyun.com/document_detail/216832.html 注使用(ali-oss)包put文件使用的是put方法,光勾选post还会报错。

使用element upload 与 ali-oss sdk时进行度获取 https://github.com/ElemeFE/element/issues/9759

七、小结 使用php-sdk的话,流程是将文件上传到了服务器一次了,然后php在服务器中调用了阿里的sdk再将文件传到了OSS,小文件就无所谓了。要是上传大文件就很麻烦,服务器,php都得对大文件进行配置。过大的话还需要进行分片,可能才会有更好的上传体验。 使用后端签名,或者使用sts服务这种的,相当于是浏览器直接与阿里云进传输了,对大文件上传时比较友好的。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3