
IBM Storage 提供了预签名URL的功能,该功能会创建一个临时链接,可用于共享公共的文件。该URL,还可以设定有效期。创建预签名 URL 的最简单方法是使用 AWS CLI ,还可以编程实现,比如Python,java,Nodejs。
官方文档:
https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-presign-url#presign-url-get

Nodejs 代码:
https://github.com/gustavares/cos-tutorial

下面以Nodejs为例子,介绍一下步骤。
- 在IBM CLoud上创建Storage服务,以及创建相应的Bucket,并且往Bucket中上传一个测试文件。(下面例子中上传了一个IOS.Mp4文件。)

- 创建服务凭证,添加HMAC认证。创建完,以后可以看到相应的认证信息。


- 创建一个Nodejs工程。
package.json { "name": "presigned", "version": "1.0.0", "description": "presigned", "main": "server.js", "scripts": { "start": "node server.js" }, "dependencies": { "express": "^4.16.4", "express-handlebars": "^3.1.0", "request": "^2.88.2", "ibm-cos-sdk": "^1.9.0" } }
Server.js "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var express = require("express"); var bodyParser = require('body-parser'); var path = require("path"); var request = require('request'); var app = express(); const AWS = require('ibm-cos-sdk'); const config = { endpoint: 'https://s3.au-syd.cloud-object-storage.appdomain.cloud/', apiKeyId: '11sG2RjQgHFDP1kBXkQ2ndfJ2jmLxA4753oHyxohl4bO', ibmAuthEndpoint: 'https://iam.cloud.ibm.com/identity/token', serviceInstanceId: 'crn:v1:bluemix:public:cloud-object-storage:global:a/a5b79a1c10354a3e8286560d97b7a989:f88885c9-95f0-40f5-b1ef-e9c87062d3ee::', credentials: new AWS.Credentials( "9d433db78aec4b6e90514a11274961fa", "08c85bc1b6a000d2f32ab8b5a05f664e9142102164ad61a6", null ), signatureVersion: 'v4' }; const cos = new AWS.S3(config); app.use(bodyParser.json()); app.use(express.static(path.resolve(__dirname, './'))); app.post('/getPresignedUrl', async function (req, res) { const url = await getPresignedUrl('jretest', 'iOS.MP4', 'getObject') return res.status(200).json({ url }); }); async function getPresignedUrl(bucket, fileName, operation) { console.log("begin"); const url = await cos.getSignedUrl(operation, { Bucket: bucket, Key: fileName, Expires:9000 }); return url; } var router = express.Router(); var serverPort = process.env.PORT || 8000; var server = app.listen(serverPort, function () { console.log("Server Start"); }); server.setTimeout(1200000)
Server.js "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var express = require("express"); var bodyParser = require('body-parser'); var path = require("path"); var request = require('request'); var app = express(); const AWS = require('ibm-cos-sdk'); const config = { endpoint: 'https://s3.au-syd.cloud-object-storage.appdomain.cloud/', apiKeyId: 'xxxx11sG2xxxxDP1kBXkQxxxxxxxxxxxxx', ibmAuthEndpoint: 'https://iam.cloud.ibm.com/identity/token', serviceInstanceId: 'crn:v1:bluemix:public:cloud-object-storage:global:a/xxxxx:f8xxxxx-95f0-xxxxxxxe::', credentials: new AWS.Credentials( "xxx43xxxx78axxxxxxx", "xxxxxxxxxxxx66xxxxxxxx", null ), signatureVersion: 'v4' }; const cos = new AWS.S3(config); app.use(bodyParser.json()); app.use(express.static(path.resolve(__dirname, './'))); app.post('/getPresignedUrl', async function (req, res) { const url = await getPresignedUrl('testbucket', 'iOS.MP4', 'getObject') return res.status(200).json({ url }); }); // bucket:Storage的bucket名字 // fileName:bucket中的文件名 // operation:操作 putObject 和 getObject // Expires 有效期间 单位是秒 async function getPresignedUrl(bucket, fileName, operation) { console.log("begin"); const url = await cos.getSignedUrl(operation, { Bucket: bucket, Key: fileName, Expires:9000 }); return url; } var router = express.Router(); var serverPort = process.env.PORT || 8000; var server = app.listen(serverPort, function () { console.log("Server Start"); }); server.setTimeout(1200000)
getSignedUrl更多的参数信息可以参照下面的链接:https://ibm.github.io/ibm-cos-sdk-js/AWS/S3.html#getSignedUrl-property

- 启动Server,我们用RESTClient做一下测试。可以看到确实生成了,一个临时的URL

因为我们的Bucket文件是个视频文件,现在我们试着在HTML中播放一下这个文件。
Html代码 <html> <head> <script> function jumpVideo() { var videoPlayer = document.getElementById("videoPlayer"); videoPlayer.currentTime = 50 videoPlayer.crossOrigin = 'anonymous'; } function copyImage() { var videoPlayer = document.getElementById("videoPlayer"); var image = document.getElementById("imagesrc"); var canvas = document.createElement("canvas"); canvas.width = videoPlayer.videoWidth * 1; canvas.height = videoPlayer.videoHeight * 1; canvas.getContext('2d') .drawImage(videoPlayer, 0, 0, canvas.width, canvas.height); image.src = canvas.toDataURL('image/png'); } </script> </head> <body> <div> <video id="videoPlayer" width="586px" height="341px" controls="true" src="https://xxxx.s3.au-syd.cloud-object-storage.appdomain.cloud/iOS.MP4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=9d433db78aec4b6e90514a11274961fa%2F20210622%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210622T130122Z&X-Amz-Expires=9000&X-Amz-Signature=0c82403ffbb962357c10d64471094fd1a99905a529fe2a303f60e5e29783136f&X-Amz-SignedHeaders=host" crossorigin="anonymous"></video> </div> <button onclick="jumpVideo()">click</button> <button onclick="copyImage()">copyImage</button> <img id="imagesrc" /> </body> </html>
这时会发现一个问题,我们这个Html有两个功能。1 播放视频 2 视频截图。
这个例子用原生的video标签播放视频,当video标签中不加【crossorigin=”anonymous”】时,视频是可以正常播放的,但是截图时【canvas.toDataURL(‘image/png’);】会报下面这个错误。

然后我们给视频的video标签中加上【crossorigin=”anonymous”】,会发现视频又播放不了了。
产生这个问题的原因是因为,IBM Storage Bucket中存储的对象默认时不支持跨域的,如果需要跨越,需要手动配置一下。
IBM Storage CORS跨域配置如下:
官方guide如下:
https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-compatibility-api-bucket-operations

可以看到操作存储区可以使用,IBM Cloud Cli,Curl, AWS CLI 等等。这里我们使用IBM Cloud Cli 做为例子。
- 通过sso 登录IBM Cloud。
ibmcloud login --sso

- 选择资源组
ibmcloud target -g xxxx(资源组的名字)

- 在本地准备CORS的配置文件
{ "CORSRules": [ { "AllowedOrigins": ["*"], "AllowedMethods": ["GET", "POST", "PUT", "DELETE", "HEAD"], "AllowedHeaders": ["*"], "ExposeHeaders": ["ETag", "x-cos-acl", "x-cos-version-id", "x-cos-delete-marker", "x-cos-server-side-encryption"] } ] }

- 切换到配置文件所在的路径,执行下面的命令。
cd /Users/xxxxx/Desktop/ ibmcloud cos put-bucket-cors --bucket xxx(bucket的名字) --cors-configuration file://presigned


- CORS配置成功以后,可以用下面的命令查询。
ibmcloud cos get-bucket-cors --bucket xxxx(bucket名字)

- 删除Bucket的CORS配置。删除的时候没有找到IBM Cloud CLI命令,这里面通过CURL命令来删除。具体命令可以参考guide:https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-curl

curl -X "DELETE" "https://s3.au-syd.cloud-object-storage.appdomain.cloud/xxxx?cors" -H "Authorization: bearer eyxxxxx"
- 这里面用到了 bearer token,下面的例子是通过Rest API获取Token。
// apiKey 可以在服务凭证里查询到 POST url:https://iam.cloud.ibm.com/identity/token?apikey=xxxxxxxxx&response_type=cloud_iam&grant_type=urn:ibm:params:oauth:grant-type:apikey Header Accept:application/jsonHeader Content-Type:application/x-www-form-urlencoded

最后,当Storage的跨域配置好以后,我们通过url访问Storage的文件时,会发现Response里面有下面的Header了。
