添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

公司新分了一个项目,项目中使用OSS做文件存储;CTO考虑说:为了不浪费后端网络带宽,文件的上传下载由web端和app端直接对接OSS,并且要支持断点续传和断点下载,服务端来提供临时访问令牌。
Coder:没问题,保证完成任务!

Web端访问OSS,由于不在同域下,报出异常如下:

<Code>AccessForbidden</Code>
<Message>
CORSResponse: This CORS request is not allowed. This is usually because the evalution of Origin, 
request method Access-Control-Request-Method or Access-Control-Requet-Headers are not whitelisted by the resource's CORS spec.
</Message>

需要配置OSS跨越
这里是dev环境所对应的bucket设置的跨域配置
在这里插入图片描述
OSS详细跨域配置链接:
阿里云OSS跨域资源共享

随着时间的流逝,我们的项目经历了N轮的测试,终于要发布演示(stage)环境了。这个时候app端出现了问题:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access denied by authorizer's policy.</Message>
  <RequestId>62EB5D472C1E93303271BA2F</RequestId>
  <HostId>xxx-test.oss-cn-hangzhou.aliyuncs.com</HostId>
</Error>

这个问题大概意思是 授权人的策略拒绝访问,定睛一看,这是说STS的权限策略有问题呀!但是这个权限策略是我司资深运维配置的怎么会有问题呢?(不知道怎么配置的小伙伴点这个链接
先检查后端生成临时生成token的代码,发现没有问题。。。。。
就在这时,发现一个问题!为什么我们配置的bucket名称是xxx-stage,但是异常抛的却是xxx-test呢?

那么重点来了:刚才文章头部说了,需要支持断点下载。

那我们走OSS的下载方法就是这个:

private DownloadFileResult downloadFileWithCheckpoint(DownloadFileRequest downloadFileRequest) throws Throwable {
        DownloadFileResult downloadFileResult = new DownloadFileResult();
        DownloadCheckPoint downloadCheckPoint = new DownloadCheckPoint();
        // The checkpoint is enabled, downloads the parts download results from
        // checkpoint file.
        if (downloadFileRequest.isEnableCheckpoint()) {
            // read the last download result. If checkpoint file dosx not exist,
            // or the file is updated/corrupted,
            // re-download again.
            try {
                downloadCheckPoint.load(downloadFileRequest.getCheckpointFile());
            } catch (Exception e) {
                remove(downloadFileRequest.getCheckpointFile());
            // The download checkpoint is corrupted, download again.
            if (!downloadCheckPoint.isValid(objectOperation, downloadFileRequest)) {
                prepare(downloadCheckPoint, downloadFileRequest);
                remove(downloadFileRequest.getCheckpointFile());
        } else {
            // The checkpoint is not enabled, download the file again.
            prepare(downloadCheckPoint, downloadFileRequest);
        // Progress listen starts tracking the progress.
        ProgressListener listener = downloadFileRequest.getProgressListener();
        ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_STARTED_EVENT);
        // Concurrently download parts.
        DownloadResult downloadResult = download(downloadCheckPoint, downloadFileRequest);
        Long serverCRC = null;
        for (PartResult partResult : downloadResult.getPartResults()) {
            if (partResult.getServerCRC() != null) {
                serverCRC = partResult.getServerCRC();
            if (partResult.isFailed()) {
                ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_PART_FAILED_EVENT);
                throw partResult.getException();
        // check crc64
        if(objectOperation.getInnerClient().getClientConfiguration().isCrcCheckEnabled() &&
           !hasRangeInRequest(downloadFileRequest)) {
            Long clientCRC = calcObjectCRCFromParts(downloadResult.getPartResults());
            try {
                OSSUtils.checkChecksum(clientCRC, serverCRC, downloadResult.getObjectMetadata().getRequestId());
            } catch (Exception e) {
                ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_FAILED_EVENT);
                throw new InconsistentException(clientCRC, serverCRC, downloadResult.getObjectMetadata().getRequestId());
        // Publish the complete status.
        ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_COMPLETED_EVENT);
        // rename the temp file.
        renameTo(downloadFileRequest.getTempDownloadFile(), downloadFileRequest.getDownloadFile());
        // The checkpoint is enabled, delete the checkpoint file after a
        // successful download.
        if (downloadFileRequest.isEnableCheckpoint()) {
            remove(downloadFileRequest.getCheckpointFile());
        downloadFileResult.setObjectMetadata(downloadResult.getObjectMetadata());
        return downloadFileResult;

这都是什么玩意?看不懂!
仔细阅读一下我们发现这一行代码有点意思downloadCheckPoint.load(downloadFileRequest.getCheckpointFile())
这是说加载检查点,那我们点进去看一下发现:

public synchronized void load(String cpFile) throws IOException, ClassNotFoundException {
            FileInputStream fileIn = new FileInputStream(cpFile);
            ObjectInputStream in = new ObjectInputStream(fileIn);
            DownloadCheckPoint dcp = (DownloadCheckPoint) in.readObject();
            assign(dcp);
            in.close();
            fileIn.close();

有点意思,这是从本地加载文件继续下载的位置,但是你加载位置就加载位置你怎么把我的bucketName也给加载进来了,问题找到了:当我们使用断点续传下载时,OSS会在我们本地文件夹生成.dcp文件,OSS以文件流的方式将该文件读取出来,
在这里插入图片描述
然后将dcp文件传入assign(dcp)中,代码如下:
在这里插入图片描述
可以看到这里将dcp.buketName赋值给了变量bucketName,所以我们在下载文件时传进来的bucketName被覆盖了,问题解决!将本地下载路径中的同名dcp文件删除,下载成功!

总的来说,我们在test环境切stage环境时,App端的文件下载路径是同一个,恰巧在test环境时文件未下载完,本地的dcp文件未被删除,切换至stage环境后下载相同名称的文件时,发现指定路径下已经存在了该文件的dcp文件,就将该dcp文件加载进来了,然后将dcp中的bucketName赋值给了当前bucketName;这时拿着stage环境获取到的sts令牌就被拒绝了。

好了,感谢大家能看到这里,文章结束了,如果上述内容有问题的话,欢迎大家指正!

<Code>AccessDenied</Code> <Message>The bucket you access does not belong to you.</Message> <RequestId>5CEF38AEE94046FA268... 客户端直传是指客户端直接上传文件到对象存储OSS。相对于服务端代理上传,客户端直传避免了业务服务器中转文件,提高了上传速度,节省了服务器资源。 在典型的服务端和客户端架构下,常见的文件上传方式是服务端代理上传:客户端将文件上传到业务服务器,然后业务服务器将文件上传到OSS。在这个过程中,一份数据需要在网络上传输两次,会造成网络资源的浪费,增加服务端的资源开销。为了解决这一问题,可以在客户端直连OSS来完成文件上传,无需经过业务服务器中转。 然后跟着官方提示的代码直接copy 顺利上传成功 https://help.aliyun.com/document_detail/93939.html?spm=a2c4g.11186623.6.1199.29757f366K... This XML file does not appear to have any style information associated with it. The document tree is shown below.AccessDeniedAccess Denied000001841823139F98132450BB32A9E00GY0mqTB9Y4704vE <Error> <Code>AccessDenied</Code> <Message>S3 API Request made to Console port. S3 Requests should be sent to API port.</Message> <RequestId>0</RequestId> </Error> io.minio.errors.InvalidResponseExcept 使用STS临时授权OSS进行上传、下载等操作时,涉及到如下报错的排查方法。 ErrorCode: AccessDenied ErrorMessage: Access denied by authorizer’s policy. 问题原因 该报错是获取STS token代码中的policy参数的授权问题导致,如下Java获取token的Demo代码所示,其中的Policy设置代表token的policy权限设置,最终的token权限是用户角色的授权和代码中policy权限的交集。 <Code>AccessDenied</Code> <Message>Access denied by authorizer's policy.</Message> <RequestId>5DC4E1F94ABA213436C410D3</RequestId>...