公司内部开发了一个文件相关的应用,由于服务器带宽限制导致多个用户同时上传或者下载文件时速度很慢,遂将文件迁移至阿里云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.
该问题按照以下步骤正确配置跨域规则。
- 登录OSS管理控制台。
- 单击Bucket 列表,然后单击目标Bucket名称。
- 在左侧导航栏,选择数据安全 > 跨域设置。
- 在跨域设置页面,单击创建规则。
- 在创建跨域规则面板,按以下说明配置各项参数,其他参数保留默认配置。
- 来源:设置为
*
。 - 允许Methods:选中
GET
、POST
、PUT
、DELETE
、HEAD
。 - 允许Headers:设置为
*
。 - 暴露Headers:设置为指定值或者不填。
- 单击确定。
具体错误代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code>
<Message>Access denied by authorizer's policy.</Message>
<RequestId>655EED1451FCAD1916A298B4</RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.com</HostId>
<AccessDeniedDetail>
<PolicyType>SessionPolicy</PolicyType>
<AuthPrincipalOwnerId>1883463381918383</AuthPrincipalOwnerId>
<AuthPrincipalType>AssumedRoleUser</AuthPrincipalType>
<AuthPrincipalDisplayName>devram:251264809289383873</AuthPrincipalDisplayName>
<NoPermissionType>ImplicitDeny</NoPermissionType>
<AuthAction>oss:PutObject</AuthAction>
</AccessDeniedDetail>
<EC>0003-00000301</EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000301</RecommendDoc>
</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/*",
注意:需要配置Action以及Resource,并且Resource中指定的目录需要与实际目录一致
详细解决方案见:https://api.aliyun.com/troubleshoot?q=0003-00000301
详细错误代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SecurityTokenExpired</Code>
<Message>The security token you provided has expired.</Message>
<RequestId>655EED5451FCAD1916A298B4</RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.com</HostId>
<SecurityToken>CAISowJ1q6Ft5B2yfSjIr5xxxx</SecurityToken>
<EC>0002-00000007</EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0002-00000007</RecommendDoc>
</Error>
获取访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)时需要指定一个有效时间,超时即失效,再次上传文件则会报如上信息。
WEB端aliyun-oss-sdk-6.18.0.min.js
创建OSS上传对象,可以指定刷新token方法,如下:
const client = new OSS({
region: "yourRegion",
accessKeyId: "yourAccessKeyId",
accessKeySecret: "yourAccessKeySecret",
stsToken: "yourSecurityToken",
bucket: "examplebucket",
retryMax: 3,
refreshSTSToken: async() => {
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>AccessDenied</Code>
<Message>Access denied by authorizer's policy.</Message>
<RequestId>65600B6235EB2631229B98CB</RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.com</HostId>
<AccessDeniedDetail>
<PolicyType>SessionPolicy</PolicyType>
<AuthPrincipalOwnerId>1883463381918303</AuthPrincipalOwnerId>
<AuthPrincipalType>AssumedRoleUser</AuthPrincipalType>
<AuthPrincipalDisplayName>devram:251264809289383873</AuthPrincipalDisplayName>
<NoPermissionType>ImplicitDeny</NoPermissionType>
<AuthAction>oss:GetObject</AuthAction>
</AccessDeniedDetail>
<EC>0003-00000301</EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000301</RecommendDoc>
</Error>
由错误信息中的<AuthAction>oss:GetObject</AuthAction>
可知获取访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)时未配置GetObject
权限。在获取密钥和安全令牌时指定GetObject
权限即可。如下:
"Version": "1",
"Statement": [
"Effect": "Allow",
"Action": [
"oss:PutObject",
"oss:GetObject"
"Resource": [
"acs:oss:*:*:examplebucket/xxx/*",
具体错误信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<RequestId>656155B635EB263982354AF5</RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.com</HostId>
<OSSAccessKeyId>STS.NXVCU7dhZXdzwmZjAVBDnFPB2</OSSAccessKeyId>
<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.jpg</StringToSign>
<StringToSignBytes>50 ...</StringToSignBytes>
<EC>0002-00000040</EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0002-00000040</RecommendDoc>
</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
前后包含了空格- endpoint配置错误(如:endpoint中混入多余的空格、斜杠),正确的格式应该是:https://oss-cn-hangzhou.aliyuncs.com ,具体可以在https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints#concept-zt4-cvy-5db 中查找对应的endpoint。
- objectName不规范,如objectName长度超过1023个字节,且不能以
/
、\
以及.
开头
问题现象如下:



大概率是CDN做了缓存导致的。
解决方法:cdn控制台,找到域名(xxx.xxxxxx.cn),性能优化这里,将忽略参数的配置删除即可。
而对于已经缓存的图片,需要将访问的文件/图片刷新。具体操作是在CDN管理>刷新预热里,输入对应的url进行刷新操作即可。

前端通过client.client.signatureUrl(objectName)
生成下载链接,再浏览器通过该链接下载文件,可能会报SecurityTokenExpired
错误,具体错误信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SecurityTokenExpired</Code>
<Message>The security token you provided has expired.</Message>
<RequestId>652E74D33D19C03130C4CB62</RequestId>
<HostId>xxx.oss-cn-hangzhou.aliyuncs.com</HostId>
<SecurityToken>CAISxAJ1q6Ft5B4dyfS...</SecurityToken>
<EC>0002-00000007</EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0002-00000007</RecommendDoc>
</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过期后,会自动进行刷新操作。😄
使用STS临时授权OSS进行上传、下载等操作时,涉及到如下报错的排查方法。
ErrorCode: AccessDenied
ErrorMessage: Access denied by authorizer’s policy.
问题原因
该报错是获取STS token代码中的policy参数的授权问题导致,如下Java获取token的Demo代码所示,其中的Policy设置代表token的policy权限设置,最终的token权限是用户角色的授权和代码中policy权限的交集。
由后端返回一个过期时间,前端在每次请求时,判断token的过期时间,如果快到过期时间了,就去调用刷新token的接口(不推荐 --- 如果本地时间被篡改,特别是本地时间比服务器时间慢时,拦截会失败,不建议采用)服务端把用户信息放入 token 里,设置一个过期时间,客户端请求的时候通过 authorization 的 header 携带 token,服务端验证通过,就可以从中取到用户信息。token无感刷新,是为了解决频繁登录造成的用户体验问题,需要前端定时去刷新token,以帮助用户静默登录。
的步骤一中下载“浏览器客户端代码”,下载后解压出来,有一堆文件,需要用到的有四个,分别是 base64.js,crypto.js,hmac.js,sha1.js。,之前是使用的客户端签名,也就是在小程序内签名后直接使用,但是因为使用小程序签名还需要引入一些文件,并且现在是自己写后端,所以试着学习写一下。这块本来不想写的,因为我们用的小程序,如果使用这个的话,需要小程序先上传到后端服务器,然后后端拿到文件再上传到 oss,没有直传来得方便。第四步骤的第二小步完成后将创建的权限策略授予了刚才创建的角色。
<Code>AccessDenied</Code>
<Message>Access denied by authorizer's policy.</Message>
<RequestId>5DC4E1F94ABA213436C410D3</RequestId>...
Access to XMLHttpRequest at 'https://xxxxx.oss-cn-beijing.aliyuncs.com/websiteInfo/newsicon_1646794266000.jpg' from origin 'http://xxxxxx:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'A
如果是自定义Header参数的话,前端发起ajax请求后,浏览器首先会发起一个预检请求(OPTIONS),然后才是业务请求,所以在预检请求的时候浏览器就已经输出跨域报错了,因此针对自定义Header需要把这个预检请求排除掉;/*** 过滤器//... /*** 拦截所有请求,校验url和token//加上校验放行 if(request . getMethod() . equals("OPTIONS")) {} else {} //... }...
再使用阿里云的oss获取临时访问凭证的时候,报错信息bucket不存在,后来找阿里云的售后,他说用他给我的代码,我一看这个代码没有使用到policy,那岂不是自定义权限策略没用,但是却不报错了,可以正常上传了,......
背景:迁移项目上传图片到阿里云的oss存储报跨域错误和超时错误
报错信息一:Access to XMLHttpRequest at 'xxxxx' from origin 'xxxxxxxxx' 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 re