likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 61

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

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

上传の初体验

把官网提供的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服务了,去把这里优化一下!

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

上传の再优化

痛定思痛后,我重新认真去看了阿里云提供的相关文档,发现它有提供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代码,这次得到了表扬,自己美美地打了包,发到了线上测试环境。然后,反转来了,线上测试环境上传这里有问题,报了跨域问题。

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

问题の排查

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

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

问题の解决

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

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

// 构建上传请求的 URL
var uploadUrl = protocol + '//your-domain.com/upload';

总结&收获

这篇文章出自我毕业后的一个半月,自己也很快地从学生思维转变到了打工人思维模式上,未来之路还很长,自己要学的东西也还很多,希望自己能保持着对技术的热情走远些吧!

转载自:https://juejin.cn/post/7268909606049857555
评论
请登录