为什么我的“OSS”上传图片会失败?

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,内容安全 1000次 1年
对象存储 OSS,恶意文件检测 1000次 1年
简介: 在项目中添加上传头像功能时,起初通过阿里云OSS SDK快速实现并返回图片URL给前端。然而,mentor指出直接回传密钥存在安全风险,建议使用STS临时授权优化安全性。优化后,本地测试正常,但线上环境出现跨域问题。最终通过调整前端代码,使用`window.location.protocol`确保请求协议一致,解决了跨域问题。这一过程不仅提升了功能的健壮性,也让我深刻理解了安全性和兼容性的重要性。

引子

近日接到了一个需求,给项目的个人资料设置加上上传头像的功能。我心想这不是简简单单,项目里已经配置了阿里云的oss,我做毕设的时候用过七牛云的对象存储,这需求不是一模一样,直接去调用官方提供的sdk就好了,光速搞完就可以愉快地自我提升了(指换个方式摸鱼)。

1.png

上传の初体验

把官网提供的sdk封装成工具类,相关的参数写在配置文件里,接着写个接口,把参数配置注入进去,在接口里提供参数然后直接调用工具类,将上传后图片的路径返回给前端即可。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 调用ossClient.getObject返回一个OSSObject实例,该实例包含文件内容及文件元信息。
            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
            // 调用ossObject.getObjectContent获取文件输入流,可读取此输入流获取其内容。
            InputStream content = ossObject.getObjectContent();
            if (content != null) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(content));
                while (true) {
                    String line = reader.readLine();
                    if (line == null) break;
                    System.out.println("\n" + line);
                }
                // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
                content.close();
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

自己测试了一下,前端调用也正常返回图片url和正常显示了,于是开心地找到mentor去“报喜”。
我:简简单单,一个小时就搞定这个需求了,直接review吧!
mentor:可以呀,年轻人效率就是高,我来看看。
几分钟后,mentor:你小子快是快,可是没考虑好安全性啊,现在你把key直接回传前端也不做限制,别人拿到不就可以白嫖我们的oss服务了,去把这里优化一下!

2.png

上传の再优化

痛定思痛后,我重新认真去看了阿里云提供的相关文档,发现它有提供STS临时授权,最终我这样做图片上传,前端发起请求后,后端根据调用临时授权方法,返回给前端一个临时的token令牌,再在前端拿着令牌进行上传操作。

 // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        //String bucketName = "examplebucket";
        // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        //String objectName = "exampleobject.txt";
        //String pathName = "D:\localpath\examplefile.txt";

        // 从STS服务获取临时访问凭证后,您可以通过临时访问密钥和安全令牌生成OSSClient。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 执行OSS相关操作,例如上传、下载文件等。
            // 上传文件,此处以上传本地文件为例介绍。
            // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
            //PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(pathName));
            //ossClient.putObject(putObjectRequest);

            // 下载OSS文件到本地文件。如果指定的本地文件存在则覆盖,不存在则新建。
            // 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
            //ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(pathName));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

优化以后,自己也进行了本地测试没问题,于是再次找到mentor来review代码,这次得到了表扬,自己美美地打了包,发到了线上测试环境。然后,反转来了,线上测试环境上传这里有问题,报了跨域问题。
3.png

问题の排查

首先,跨域问题的出现我们都知道必然是域名、端口、协议这三者至少有一个出了问题,于是我光速定位报错的请求,把它和本地的url进行比对,并最终发现问题,我本地请求使用的是HTTP请求,而线上使用的是HTTPS请求,在前端代码里发这个请求我也是写死的HTTP请求。
4.png

问题の解决

由于我是在前端发起上传的,因此最终我决定使用window.location.protocol属性,这个属性可以获取当前页面的协议(例如 HTTP 或 HTTPS)。这样就可以确保上传请求的协议与当前页面的协议一致,避免跨域问题。

// 获取当前页面的协议
var protocol = window.location.protocol;

// 构建上传请求的 URL
var uploadUrl = protocol + '//your-domain.com/upload';
相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
对象存储 容器
Typora配置阿里云OSS作为图床上传图片
Typora配置阿里云OSS作为图床上传图片
841 0
|
对象存储
阿里云对象存储oss+picgo+typora实现步骤及无法上传图片解决方案
阿里云对象存储oss+picgo+typora实现步骤及无法上传图片解决方案
517 0
阿里云对象存储oss+picgo+typora实现步骤及无法上传图片解决方案
|
运维 API 对象存储
阿里云OSS上传图片不能打开的解决办法
  最近项目需要把附件部署到阿里云oss,集成过程中发现上传的图片不能直接打开预览,只能下载到本地保存。   解决办法:设置ContentType   var endpoint="阿里云OSS EndPoint";   // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
4035 0
|
域名解析 对象存储 数据安全/隐私保护
如何 Wordpress 使用 OSS 上传图片、文件
如何使用 OSS 上传 Wordpress 的图片文件
2179 2
|
对象存储
oss上传图片的图片名和url路径后缀不一致问题分析与说明
oss上传图片的图片名和url路径后缀不一致问题分析与说明
693 0
|
JavaScript 对象存储
阿里云 OSS 如何通过 Node.js 上传图片 #49
阿里云 OSS 如何通过 Node.js 上传图片 #49
388 0
|
存储 安全 对象存储
用Typora,PicGo和OSS实现自动上传图片
以前写博客要发布到好些个平台,我是将图片一张张上传到每个平台,后来发现是真的麻烦,上传图片花的时间太多,极大的降低了我写文章的积极性。后来改进为使用oss,把博客的图片都上传到oss上面。然后使用oss返回的图片url,这样我的文章里面的图片只上传了一次,最后把整篇文章的mardown复制到各个平台上,平台一般都会把markdown的文章中的img标签的图片上传到他们自己的服务器,然后把图片打上平台的水印,然后把原图片链接替换掉。
737 1
用Typora,PicGo和OSS实现自动上传图片
|
对象存储
【在线教育】课程封面上传图片到阿里云OSS(三)
【在线教育】课程封面上传图片到阿里云OSS
188 0
【在线教育】课程封面上传图片到阿里云OSS(三)
|
前端开发 开发工具 对象存储
【在线教育】课程封面上传图片到阿里云OSS(二)
【在线教育】课程封面上传图片到阿里云OSS
184 0
【在线教育】课程封面上传图片到阿里云OSS(二)
|
存储 对象存储 数据安全/隐私保护
【在线教育】课程封面上传图片到阿里云OSS(一)
【在线教育】课程封面上传图片到阿里云OSS
169 0
【在线教育】课程封面上传图片到阿里云OSS(一)