
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了。
