OSS简单上传下载整理

更新:OSS在私有云环境文件上传失败

代码在私有云执行时,总是出现以下错误

[ErrorCode]: NoSuchBucket
[RequestId]: 000000000000000000000000
[HostId]: oss***********.cn
[ResponseError]:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>NoSuchBucket</Code>
  <Message>The specified bucket does not exist.</Message>
  <RequestId>000000000000000000000000</RequestId>
  <HostId>oss***********.cn</HostId>
  <BucketName>abc</BucketName>
</Error>

但实际bucketName在配置信息中填写的是abc-oss,而abc是在存储空间下一个自定义的存放文件的路径,起初一直以为是配置信息读取错位的问题.....

查不出来原因,代码debug之后才有进一步发现...

错误信息如下:
errorMessage:SignatureDoesNotMatch

errorCode:The request signature we calculated does not match the signature you provided. Check your key and signing method.

这篇博客(传送门:解决私有云环境OSS报SignatureDoesNotMatch错误)挺有参考意义的,也成功解决了问题。

其实主要是CNAME的问题,关闭就好了

ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
// 私有云要关闭CNAME
conf.setSupportCname(false);
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret, conf);
//OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret,conf);

下载txt格式的文件时如果出现同样的问题,仍可以用以上方案解决问题


一、相关配置

传送门:对象存储OSS产品中的几个基本概念介绍

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OssConfig implements InitializingBean {

    @Value("${oss.end.point}")
    private String ossEndPoint;
    @Value("${oss.access.key.id}")
    private String ossAccessKeyId;
    @Value("${oss.access.key.secret}")
    private String ossAccessKeySecret;
    @Value("${oss.bucket.name}")
    private String ossBucketName;
    @Value("${oss.folder.name}")
    private String ossFolderName;
    @Value("${oss.visit.url}")
    private String ossVisitUrl;

    public static String OSS_END_POINT;
    public static String OSS_ACCESS_KEY_ID;
    public static String OSS_ACCESS_KEY_SECRET;
    public static String OSS_BUCKET_NAME;
    public static String OSS_FOLDER_NAME;
    public static String OSS_VISIT_URL;

    @Override
    public void afterPropertiesSet() throws Exception {
        OSS_END_POINT = ossEndPoint;
        OSS_ACCESS_KEY_ID = ossAccessKeyId;
        OSS_ACCESS_KEY_SECRET = ossAccessKeySecret;
        OSS_BUCKET_NAME = ossBucketName;
        OSS_FOLDER_NAME = ossFolderName;
        OSS_VISIT_URL = ossVisitUrl;
    }
}

1、OSS对外服务的访问域名(必要)OSS_END_POINT 

传送门:公共云下OSS Region和Endpoint对照表

2、访问秘钥(必要)OSS_ACCESS_KEY_ID & OSS_ACCESS_KEY_SECRET

传送门:创建AccessKey

3、存储空间名称(必要)OSS_BUCKET_NAME

自由创建,符合命名规范都可以

4、存储文件夹名称(非必要)OSS_FOLDER_NAME

可要可不要,有一个配置的文件夹名称,方便文件管理

5、获取文件访问地址前缀(非必要)OSS_VISIT_URL

满足 bucketName + endPoint 的一个http地址,比如:http://bucketname.oss-cn-hangzhou.aliyuncs.com/


二、相关依赖

        <!-- OSS -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>2.5.0</version>
        </dependency>

三、上传功能

    @RequestMapping("/upload")
    @ApiOperation(value = "文件上传", notes = "上传文件")
    public Result upload(@RequestParam(value = "file") MultipartFile multipartFile) {
        String filename = System.currentTimeMillis() + "-" + multipartFile.getOriginalFilename();
        log.info("=========>OSS文件上传开始:" + filename);
        String endpoint = OssConfig.OSS_END_POINT;
        String accessKeyId = OssConfig.OSS_ACCESS_KEY_ID;
        String accessKeySecret = OssConfig.OSS_ACCESS_KEY_SECRET;
        String bucketName = OssConfig.OSS_BUCKET_NAME;

        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            //容器不存在,就创建
            //if (!ossClient.doesBucketExist(bucketName)) {
            //    ossClient.createBucket(bucketName);
            //    CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            //    createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
            //    ossClient.createBucket(createBucketRequest);
            //}
            //设置权限 这里是公开读
            //ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);


            //创建文件路径
            String fileUrl = OssConfig.OSS_FOLDER_NAME + "/" + filename;
            //上传文件
            PutObjectResult result = null;
            try {
                result = ossClient.putObject(new PutObjectRequest(bucketName, fileUrl, multipartFile.getInputStream()));
            } catch (IOException e) {
                log.error("IOException occurred: ", e);
            }
            if (null != result) {
                log.info("==========>OSS文件上传成功,OSS完整地址:" + fileUrl);
                return Result.success(OssConfig.OSS_VISIT_URL + fileUrl);
            }
        } catch (OSSException oe) {
            log.error("OSSException occurred: ", oe);
        } catch (ClientException ce) {
            log.error("ClientException occurred: ", ce);
        } finally {
            //关闭
            ossClient.shutdown();
        }
        return Result.fail("上传失败");
    }

其中注释掉的代码:

bucketName 对应的存储空间已经创建了,在校验是否存在时,如果运维没有给访问者配备权限,是会报错的。

如果需要保留注释部分代码且运行时不报错,就需要给 accessKey 的拥有者配备相应权限

报错情况如下(示范):

[ErrorCode]: AccessDenied
[RequestId]: FFFFFFFFFFFFFFFFFFFFFFFF
[HostId]: bucketName + endPoint
[ResponseError]:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>AccessDenied</Code>
  <Message>The bucket you access does not belong to you.</Message>
  <RequestId>FFFFFFFFFFFFFFFFFFFFFFFF</RequestId>
  <HostId>bucketName + endPoint</HostId>
</Error>

传送门:API错误中心

还有一个需要注意的地方是捕获异常对象 ClientException ,选择阿里云的jar包

import com.aliyun.oss.ClientException;

四、下载功能

    @RequestMapping(value = "download")
    @ApiOperation(value = "文件下载", notes = "下载文件")
    public void download(String ossUrl, HttpServletResponse response) {

        ossUrl = ossUrl.substring(OssConfig.OSS_VISIT_URL.length());
        InputStream in = null;
        try {
            OSSClient ossClient = new OSSClient(OssConfig.OSS_END_POINT, OssConfig.OSS_ACCESS_KEY_ID, OssConfig.OSS_ACCESS_KEY_SECRET);

            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = ossClient.getObject(OssConfig.OSS_BUCKET_NAME, ossUrl);
            in = ossObject.getObjectContent();
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(ossUrl.substring(ossUrl.lastIndexOf("-") + 1), "UTF-8"));
            OutputStream outputStream = response.getOutputStream();

            byte buf[] = new byte[2048];
            int length = 0;
            // 输出文件
            while ((length = in.read(buf)) > 0) {
                outputStream.write(buf, 0, length);
            }
            // 关闭输出流
            outputStream.close();
        } catch (Exception e) {
            log.error("获取文件错误:", e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e) {
                log.error("出错");
            }
        }

    }

五、更新:记录一次OSS上线问题

 刚申请下来的私有云上的OSS,在测试环境中配置用的公司的OSS是没有问题的,但是上到生产环境上时却一直报错,情况跟在GitHub上讨论区中的一位网友发言类似,但是并没有提到正确的解决方案。

传送门:分片上传的是否可以指定到目前,目前之前上传到bucketName的根目录 · Issue #211 · aliyun/aliyun-oss-java-sdk · GitHub

分析:

代码层面,跟其他用到OSS的项目使用的代码,抛却业务逻辑外,基本是一模一样的

配置层面,比对其他项目都是没有问题的

但是生产环境却一直报错

 解决:

①找了OSS售后,将版本从2.5.0更新到3.4.1版本,测试还是同样的报错

②对比他们给的demo,以及把相关配置发给送对方去测验,遂发现ent.point的不一致,对方提供测试截图中ent.point前缀拼接了bucket名称,形如:bucket.entpoint

③修改配置测试后一切正常

④严重怀疑2.5.0版本如果改成同样的配置,功能也能正常使用。但最根本的是,这个的配置,跟其他有OSS项目的配置完全不一样,就怀疑该OSS在申请的时候什么东西漏了。但问题已经解决了,这些猜测就没有去验证了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值