公司内部开发了一个文件相关的应用,由于服务器带宽限制导致多个用户同时上传或者下载文件时速度很慢,遂将文件迁移至阿里云OSS服务器。下面是迁移的过程中遇到的部分问题。
错误信息如下:
Access to XMLHttpRequest at 'http://xxx.oss-cn-hangzhou.aliyuncs.com/test/logo.jpg' from origin 'http://192.168.29.131:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
该问题按照以下步骤正确配置跨域规则。
*
。GET
、POST
、PUT
、DELETE
、HEAD
。*
。具体错误代码如下:
<Error>
<Code>AccessDeniedCode>
<Message>Access denied by authorizer's policy.Message>
<RequestId>655EED1451FCAD1916A298B4RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.comHostId>
<AccessDeniedDetail>
<PolicyType>SessionPolicyPolicyType>
<AuthPrincipalOwnerId>1883463381918383AuthPrincipalOwnerId>
<AuthPrincipalType>AssumedRoleUserAuthPrincipalType>
<AuthPrincipalDisplayName>devram:251264809289383873AuthPrincipalDisplayName>
<NoPermissionType>ImplicitDenyNoPermissionType>
<AuthAction>oss:PutObjectAuthAction>
AccessDeniedDetail>
<EC>0003-00000301EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000301RecommendDoc>
Error>
Web端上传文件至OSS服务器,为避免暴露阿里云账号访问密钥(AccessKey ID和AccessKey Secret),通常临时访问凭证的方式执行OSS相关操作。
临时访问凭证包括临时访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)。
在获取访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)时,需要制定策略(Policy),而策略中则指定了权限以及资源目录等内容。如下:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:PutObject" // 上传文件权限
],
"Resource": [
"acs:oss:*:*:examplebucket/xxx/*", // examplebucket为bucket名称,其中xxx为上传文件目录
]
}
]
}
注意:需要配置Action以及Resource,并且Resource中指定的目录需要与实际目录一致
详细解决方案见:https://api.aliyun.com/troubleshoot?q=0003-00000301
详细错误代码如下:
<Error>
<Code>SecurityTokenExpiredCode>
<Message>The security token you provided has expired.Message>
<RequestId>655EED5451FCAD1916A298B4RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.comHostId>
<SecurityToken>CAISowJ1q6Ft5B2yfSjIr5xxxxSecurityToken>
<EC>0002-00000007EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0002-00000007RecommendDoc>
Error>
获取访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)时需要指定一个有效时间,超时即失效,再次上传文件则会报如上信息。
WEB端aliyun-oss-sdk-6.18.0.min.js
创建OSS上传对象,可以指定刷新token方法,如下:
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。
region: "yourRegion",
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: "yourAccessKeyId",
accessKeySecret: "yourAccessKeySecret",
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: "yourSecurityToken",
// 填写Bucket名称。
bucket: "examplebucket",
retryMax: 3, // 需指定retryMax,否则refreshSTSToken无法执行
refreshSTSToken: async() => {
// 向您搭建的STS服务获取临时访问凭证。
const info = await fetch('xxx/xxxx/get-token')
return {
accessKeyId: info.accessKeyId,
accessKeySecret: info.accessKeySecret,
stsToken: info.securityToken
}
},
// 刷新临时访问凭证的时间间隔,单位为毫秒。
refreshSTSTokenInterval: 1000
})
指定refreshSTSToken
方法后,在执行文件上传时若token超时,则会自动刷新token并上传文件。值得注意的时单单指定refreshSTSToken
方法并不会达成预期效果,需要同时指定retryMax
参数才行(参考issue:https://github.com/ali-sdk/ali-oss/issues/1179)。
部分类型文件(如pdf)文件无法在浏览器中预览或下载,错误截图如下:
登录OSS服务器后台管理平台,在文件列表查看文件,发现文件类型不是预期的类型:
出现该问题大概率是由于上传文件时指定的Content-Type
错误造成的,上传文件不指定Content-Type
即可。
通过OSS.signatureUrl
方法转换的url,通过浏览器地址栏访问下载报AccessDenied
错误。详细错误如下:
<Error>
<Code>AccessDeniedCode>
<Message>Access denied by authorizer's policy.Message>
<RequestId>65600B6235EB2631229B98CBRequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.comHostId>
<AccessDeniedDetail>
<PolicyType>SessionPolicyPolicyType>
<AuthPrincipalOwnerId>1883463381918303AuthPrincipalOwnerId>
<AuthPrincipalType>AssumedRoleUserAuthPrincipalType>
<AuthPrincipalDisplayName>devram:251264809289383873AuthPrincipalDisplayName>
<NoPermissionType>ImplicitDenyNoPermissionType>
<AuthAction>oss:GetObjectAuthAction>
AccessDeniedDetail>
<EC>0003-00000301EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000301RecommendDoc>
Error>
由错误信息中的
可知获取访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)时未配置GetObject
权限。在获取密钥和安全令牌时指定GetObject
权限即可。如下:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:PutObject", // 上传文件权限
"oss:GetObject" // 下载文件权限
],
"Resource": [
"acs:oss:*:*:examplebucket/xxx/*", // examplebucket为bucket名称,其中xxx为上传文件目录
]
}
]
}
具体错误信息如下:
<Error>
<Code>SignatureDoesNotMatchCode>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.Message>
<RequestId>656155B635EB263982354AF5RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.comHostId>
<OSSAccessKeyId>STS.NXVCU7dhZXdzwmZjAVBDnFPB2OSSAccessKeyId>
<SignatureProvided>rJ7d1McbT/JvVV2QrenR9DwS+r4=SignatureProvided>
<StringToSign>PUT
image/jpeg
Sat, 25 Nov 2023 02:02:30 GMT
x-oss-security-token:CAISsQJ1q6...
/mybucket/dir/11/20231123152500353242.jpgStringToSign>
<StringToSignBytes>50 ...StringToSignBytes>
<EC>0002-00000040EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0002-00000040RecommendDoc>
Error>
出现以上错误,根据错误信息中的链接:https://api.aliyun.com/troubleshoot?q=0002-00000040 排查,可能原因是AccessKey ID
与AccessKey Secret
填写错误导致,可以使用AccessKey ID
与AccessKey Secret
登录ossbrowser来验证正确性。具体步骤,请参见安装并登录ossbrowser。
但是,在部分场合下AccessKey ID
与AccessKey Secret
设置正确,调用PutObject
接口依然会报如上错误,这就比较坑了,在官网文件中也找不到相关的解释。查询了网上部分开发者的解释,可能是如下原因:
AccessKey ID
与AccessKey Secret
前后包含了空格/
、\
以及.
开头问题现象如下:
大概率是CDN做了缓存导致的。
解决方法:cdn控制台,找到域名(xxx.xxxxxx.cn),性能优化这里,将忽略参数的配置删除即可。
而对于已经缓存的图片,需要将访问的文件/图片刷新。具体操作是在CDN管理>刷新预热里,输入对应的url进行刷新操作即可。
SecurityTokenExpired
错误前端通过client.client.signatureUrl(objectName)
生成下载链接,再浏览器通过该链接下载文件,可能会报SecurityTokenExpired
错误,具体错误信息如下:
<Error>
<Code>SecurityTokenExpiredCode>
<Message>The security token you provided has expired.Message>
<RequestId>652E74D33D19C03130C4CB62RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.comHostId>
<SecurityToken>CAISxAJ1q6Ft5B4dyfS...SecurityToken>
<EC>0002-00000007EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0002-00000007RecommendDoc>
Error>
错误信息很简单,SecurityTokenExpired
指的就是SecurityToken
已经过期,需要重新请求一个SecurityToken
即可。在实际情况下,当SecurityToken
过期再去通过调用client.signatureUrl()
生成的链接去下载文件,还可能会报AccessKey ID不存在
或者InvalidAccessKeyID
的错误,出现该错误,解决方案也是重新请求一个SecurityToken
即可。
在这里我比较疑惑的是,通过client.put()
上传文件,若SecurityToken
过期,则会自动调用refreshSTSToken
方法进行刷新token操作,而client.signatureUrl()
则不会自动刷新token。
有了疑问之后,就去翻signatureUrl
的源码:https://github.com/ali-sdk/ali-oss/blob/master/lib/common/object/signatureUrl.js ,发现曾经的某个版本,signatureUrl
方法是带有刷新token操作的,具体代码点击这里:https://github.com/ali-sdk/ali-oss/commit/374231c9c1dcc5ed1312a2d19915b0894e3b964a#diff-96d41084308d1bba6abbdff9229ab13d216ffa78f742337acd5afd25d35caaf5R26 ,但是在后续的版本中,signatureUrl
方法移除了刷新操作。
幸运的是在翻Git的过程中,发现与signatureUrl.js同目录的组件里,有另外一个名为asyncSignatureUrl.js的组件,点进去看里面代码的逻辑,正是之前signatureUrl.js
组件里类似,包含刷新token操作的代码。
遂将项目里调用client.signatureUrl()
的代码,替换成client.asyncSignatureUrl()
,实际效果是token过期后,会自动进行刷新操作。