踩坑记录
1、refreshSTSTokenInterval 不生效
官方初始化文档中没有此配置项,但是在某个例子中写了这个属性。
既然是间隔,那我就设置 15*60*60*1000
15分钟吧,
【bug描述】 还没有到token过期时间,但是每一个 put(上传)和 signatureUrl(下载)操作都会重新请求token。
2、refreshSTSToken 刷新了token,但是下载文件token失效
【bug描述】:调用refreshSTSToken 后,获取到token,在下次操作才生效。也就是: token到期之前的值是a,到期后重新发送请求获取到的token是b,但是signatureUrl返回的文件地址中的token仍然是a,下载文件的时候就会提示token失效。再一次点击下载文件,url中的token是b,又可以正常下载了。
解决了refreshSTSTokenInterval 刷新间隔问题后,这个诡异的bug改的我怀疑自己的码代码水平了。
根本bug原因:Browser.js代码
-
refreshSTSTokenInterval 不生效
【bug原因】: 用时间戳 和 时间间隔比大小 -
refreshSTSToken 刷新了token,但是下载文件token失效
【bug原因】:同步的方法里执行异步请求,然后就没然后了
signatureUrl 部分源代码如下
var proto = exports;
proto.signatureUrl = function signatureUrl(name, options) {
// 略....
if (this.options.stsToken && isFunction(this.options.refreshSTSToken)) {
// 当前时间
var now = new Date();
/**
1、refreshSTSTokenInterval 不生效 bug原因:
用时间戳 和 时间间隔比大小,写这个代码的人咋想到的???????
**/
if (this.stsTokenFreshTime >= this.options.refreshSTSTokenInterval) {
this.stsTokenFreshTime = now;
/*
这里假设 refreshSTSTokenInterval 是生效的,刷新间隔15分钟到了以后 refreshSTSToken
2、refreshSTSToken 刷新了token,但是下载文件token失效 bug原因:
逗我玩呢?这里调用了个异步方法请求token,然后同步代码去拼接url,异步请求回来啥也不干了????
这操作就相当于有人告诉你办公室的钥匙换了,于是你去跟物业说:“给我一把新钥匙”。
也不等物业给你钥匙,说完自己就走了,继续用旧钥匙开门。
*/
this.options.refreshSTSToken().then(function (r) {
var credentials = formatObjKey(r, 'firstLowerCase');
if (credentials.securityToken) {
credentials.stsToken = credentials.securityToken;
}
checkCredentials(credentials);
Object.assign(_this.options, credentials);
});
} else {
this.stsTokenFreshTime = now;
}
}
if (this.options.stsToken) {
options['security-token'] = this.options.stsToken;
}
var signRes = signHelper._signatureForURL(this.options.accessKeySecret, options, resource, expires);
var url = urlutil.parse(this._getReqUrl(params));
url.query = {
OSSAccessKeyId: this.options.accessKeyId,
Expires: expires,
Signature: signRes.Signature
};
copy(signRes.subResource).to(url.query);
return url.format();
};
解决方案
import OSS from "ali-oss";
import { getOssToken } from "@/api/fileTransmit";
class Client {
client = null;
_tokenExpiredTime = 0;
_token = null;
_promise = null;
get token() {
// 【解决bug】refreshSTSTokenInterval 不生效
// 【解决方案】根据请求返回的Expiration时间判断是否过期,没有token的时候调用getAccess方法获取getOssToken
if (Date.now() >= this._tokenExpiredTime || this._token === null) {
return null;
} else {
return { ...this._token };
}
}
set token(value) {
// 设置token
this._token = value;
// 设置token过期时间
this._tokenExpiredTime = new Date(value.Expiration).getTime();
//【解决bug】refreshSTSToken 刷新了token,但是下载文件token失效
//【解决方案】如果已经初始化了,强制修改ossClient中存储的token。
if (this.client) {
this.client.options.stsToken = value.stsToken;
this.client.options.accessKeyId = value.accessKeyId;
this.client.options.accessKeySecret = value.accessKeySecret;
}
}
/**
* 请求token
*/
async requestAccess() {
// 【解决bug】refreshSTSTokenInterval 不生效
// 【解决方案】根据请求返回的Expiration时间判断是否过期,过期调用getOssToken 重新获取token,没有过期就使用存储的token
// 此处代码时配置的oss自动定时刷新不生效,所以在这里自己手动定时刷新
if (!this.token) {
this.token = await getOssToken();
}
return this.token;
}
/**
* 获取token队列
*/
getAccess() {
// 如果已经正在请求token,就返回正在请求的方法
if (this._promise) {
return this._promise;
}
this._promise = new Promise(async (resolve) => {
const res = await this.requestAccess();
this._promise = null;
resolve(res);
});
return this._promise;
}
/**
* oss初始化
*/
async init() {
try {
const access = await this.getAccess(true);
this.client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: "yourRegion",
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: access.accessKeyId,
accessKeySecret: access.accessKeySecret,
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: access.stsToken,
refreshSTSToken: this.getAccess.bind(this),
// 刷新临时访问凭证的时间间隔,单位为毫秒。
// refreshSTSTokenInterval: 15 * 60 * 1000,
// 填写Bucket名称。
bucket: "填写Bucket名称。"
});
} catch (e) {
throw new Error("获取oss凭证失败");
}
}
/**
* 上传
* @param {string} filename 上传的文件
* @param {File} file 上传的文件
* @return { {name: string, url: string} }
*/
async upload(filename, file) {
if (!this.client) {
await this.init();
}
// 【解决bug】refreshSTSTokenInterval 不生效
// 【解决方案】每次上传文件之前读取token
await this.getAccess();
const headers = { "x-oss-forbid-overwrite": "false" };
try {
const res = await this.client.put(filename, file, { headers });
if (res.message) {
throw res;
}
return { name: res.name, url: res.url };
} catch (e) {
throw e;
}
}
/**
* 下载
* @param {string} filename 下载的文件名
* @return { string } 下载地址
*/
async getResourceUrl(filename) {
if (!this.client) {
await this.init();
}
// 【解决bug】refreshSTSTokenInterval 不生效
// 【解决方案】每次下载文件之前读取token
await this.getAccess();
const response = {
"content-disposition": `attachment;`
};
try {
const url = await this.client.signatureUrl(filename, { response });
if (typeof url === "string") {
return url;
} else {
throw url;
}
} catch (e) {
throw e;
}
}
}
其他功能暂未使用,要是后续使用过程中发现新bug,还会继续更新
希望能帮助到使用ali-oss( Browser.js SDK)的打工人