阿里云OSS代码集成部分问题分析

公司内部开发了一个文件相关的应用,由于服务器带宽限制导致多个用户同时上传或者下载文件时速度很慢,遂将文件迁移至阿里云OSS服务器。下面是迁移的过程中遇到的部分问题。

问题1. 跨域错误

错误信息如下:

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.

该问题按照以下步骤正确配置跨域规则。

  1. 登录OSS管理控制台。
  2. 单击Bucket 列表,然后单击目标Bucket名称。
  3. 在左侧导航栏,选择数据安全 > 跨域设置
  4. 跨域设置页面,单击创建规则
  5. 创建跨域规则面板,按以下说明配置各项参数,其他参数保留默认配置。
    • 来源:设置为*
    • 允许Methods:选中GETPOSTPUTDELETEHEAD
    • 允许Headers:设置为*
    • 暴露Headers:设置为指定值或者不填。
  6. 单击确定

问题2. Access denied by authorizer’s policy.

具体错误代码如下:


<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

问题3. The security token you provided has expired.

详细错误代码如下:


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

问题4. 部分文件无法预览、下载

部分类型文件(如pdf)文件无法在浏览器中预览或下载,错误截图如下:阿里云OSS代码集成部分问题分析_第1张图片
登录OSS服务器后台管理平台,在文件列表查看文件,发现文件类型不是预期的类型:
阿里云OSS代码集成部分问题分析_第2张图片
出现该问题大概率是由于上传文件时指定的Content-Type错误造成的,上传文件不指定Content-Type即可。

问题5. 浏览器下载文件错误

通过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>

由错误信息中的oss:GetObject可知获取访问密钥(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为上传文件目录
           ]
     }
    ]
}

问题6. 上传文件(PutObject)错误:SignatureDoesNotMatch

具体错误信息如下:


<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 IDAccessKey Secret填写错误导致,可以使用AccessKey IDAccessKey Secret登录ossbrowser来验证正确性。具体步骤,请参见安装并登录ossbrowser。
但是,在部分场合下AccessKey IDAccessKey Secret设置正确,调用PutObject接口依然会报如上错误,这就比较坑了,在官网文件中也找不到相关的解释。查询了网上部分开发者的解释,可能是如下原因:

  1. AccessKey IDAccessKey Secret前后包含了空格
  2. endpoint配置错误(如:endpoint中混入多余的空格、斜杠),正确的格式应该是:https://oss-cn-hangzhou.aliyuncs.com ,具体可以在https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints#concept-zt4-cvy-5db 中查找对应的endpoint。
  3. objectName不规范,如objectName长度超过1023个字节,且不能以/\以及.开头

问题7. 图片上传后,访问缩略图再访问原图,显示的还是缩略图

问题现象如下:
阿里云OSS代码集成部分问题分析_第3张图片
阿里云OSS代码集成部分问题分析_第4张图片
阿里云OSS代码集成部分问题分析_第5张图片
大概率是CDN做了缓存导致的。
解决方法:cdn控制台,找到域名(xxx.xxxxxx.cn),性能优化这里,将忽略参数的配置删除即可。
而对于已经缓存的图片,需要将访问的文件/图片刷新。具体操作是在CDN管理>刷新预热里,输入对应的url进行刷新操作即可。
阿里云OSS代码集成部分问题分析_第6张图片

问题8. 下载文件报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过期后,会自动进行刷新操作。

你可能感兴趣的:(阿里云,数据库,云计算)