阿里云OSS无法使用图片URL访问,访问时提示下载【已解决】

实现图片上传到oss,解决阿里云OSS无法使用图片URL访问,访问时提示下载,不用申请域名。

创建 Bucket

  • 右上方选择创建 Bucket,可以看到下方有很多常用入口
    在这里插入图片描述
  • 创建 一般选择默认即可,注意命名规范,此时留意一下读写权限,后边有个坑
    在这里插入图片描述
  • 右上角点击 bucket列表 可以查看
    在这里插入图片描述

建立RAM账号 链接: 官方文档.

  • 官方提示 建立RAM账号,因为自己的账号权限太大一旦泄露,就会出现问题,所以需要建立RAM账号,相当于子账号,然后给子账号分配权限,比如本次是实现对象存储。
    • 创建用户。注意选择编程式访问,用于程序访问
      在这里插入图片描述
    • 返回用户列表,点击用户进入设置用户。
      • 创建 AccessKey,及时记录下来,如果忘记了,可以重新创建
        在这里插入图片描述

      • 添加权限(此处指OSS权限)
        在这里插入图片描述

根据官方文档 编写简单上传

用的是先保存到本地然后以文件流的形式上传到OSS,上传方式很多种,这是最简单的

controller

    @PostMapping("/fileUpload.json")
    public String fileUpload(@RequestParam("file") MultipartFile file) throws FileNotFoundException {
        if (file.isEmpty()) {
            return "上传文件内容为空,请重新选择";
        }
        String tempFilePath = this.getClass().getResource("/").getPath();
        String fileName = file.getOriginalFilename();
        File tempFile = new File(tempFilePath + fileName);
        try {
            file.transferTo(tempFile);
            //return "上传成功" + tempFilePath + fileName;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ossConfig.fileUpload(fileName, tempFilePath + fileName);
    }
package com.jgybzx.config;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author jgybzx
 * @date 2020/12/21 15:40
 * @description 用于连接阿里 OSS 对象存储的必要条件,放在配置文件中,以ConfigurationProperties方式读取
 */
@Component
@ConfigurationProperties(prefix = "oss")
public class OssConfig {
	/**
	* 使用自己真实的地址
	*/
    private String endpoint;
    /**
    * 之前复制的 accessKeyId
    */
    private String accessKeyId;
    /**
    * 之前复制的 accessKeySecret
    */
    private String accessKeySecret;
    /**
    * 自己新建的 bucketName
    */
    private String bucketName;

    /**
     * @param fileName     文件上传时的名字
     * @param tempFilePath 文件保存到本地时的临时目录,用于生产文件流
     * @return
     * @throws FileNotFoundException
     */
    public String fileUpload(String fileName, String tempFilePath) throws FileNotFoundException {
        // 用于在OSS上命名,建议格式 :年月日/文件名.后缀名,此时可以 以时间建立一个文件夹保存上传的图片
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String transformDate = simpleDateFormat.format(new Date());
        String objectName = transformDate + "/" + System.currentTimeMillis() + "_" + fileName;
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 上传文件流。
        InputStream inputStream = new FileInputStream(tempFilePath);
        
        ossClient.putObject(bucketName, objectName, inputStream);

		// 返回一个带有时间限制的 访问连接,(此处坑很大)
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        String url = ossClient.generatePresignedUrl(bucketName, objectName, expiration).toString();
        // 关闭OSSClient。
        ossClient.shutdown();
        return url.split("\\?")[0];
    }

   
    /*省略get set*/
}

结果展示
在这里插入图片描述

填坑环节

  1. 文件正常上传,但是返回的地址无法直接访问,一打开就是下载。
    经过百度,出现各种方法,比如映射自己的域名、添加Content-Disposition inline 关键字。标题所示,这个方法不用申请域名,并且不用设置 HTTP头。首先出现让直接下载的情况,怀疑是因为Content-Type = image/jpeg 如果换为 image/jpg 则可以直接预览。
    所以解决方法为 代码中设置 Content-Type 参考链接
    所以代码进行改动
/**
     * @param fileName     文件上传时的名字
     * @param tempFilePath 文件保存到本地时的临时目录,用于生产文件流
     * @return
     * @throws FileNotFoundException
     */
    public String fileUpload(String fileName, String tempFilePath) throws FileNotFoundException {
        // 用于在OSS上命名,建议格式 :年月日/文件名.后缀名,此时可以 以时间建立一个文件夹保存上传的图片
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String transformDate = simpleDateFormat.format(new Date());
        String objectName = transformDate + "/" + System.currentTimeMillis() + "_" + fileName;
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 设置设置 HTTP 头 里边的 Content-Type
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
        // 上传文件流。
        InputStream inputStream = new FileInputStream(tempFilePath);
        //ossClient.putObject(bucketName, objectName, inputStream);
        ossClient.putObject(bucketName, objectName, inputStream, objectMetadata);
        
        // 返回一个有时间的链接,
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        String url = ossClient.generatePresignedUrl(bucketName, objectName, expiration).toString();
        // 关闭OSSClient。
        ossClient.shutdown();
        return url.split("\\?")[0];
    }

    /**
     * 解决问题,直接访问上传的图片地址,会让下载而不是直接访问
     * 设置设置 HTTP 头 里边的 Content-Type
     * txt 格式经过测试,不需要转换 上传之后就是 text/plain。其他未测试
     * 已知  如果 Content-Type = .jpeg 访问地址会直接下载,本方法也是解决此问题
     * @param FilenameExtension
     * @return
     */
    public static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }

        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }
  1. 各种百度之后,访问还是不行,经过思索发现需要设置 Bucket 读写权限
    之前创建Bucket的时候 设置的读写权限为 私有,所以需要设置为 “公共读”,上传的图片默认继承Bucket的权限
    在这里插入图片描述
  2. 终极大坑。
    进过以上步骤发现还是不能访问,一直要权限,经过了各种搜索无果,思考了整个过程,发现有一步建立RAM账号很特殊。在设置权限的时候发现下边有一个
    Bucket 授权策略
    Bucket Policy 是阿里云 OSS 推出的针对 Bucket 的授权策略,您可以通过 Bucket Policy 授权您的 RAM 子账号,或其他用户的 RAM 子账号,访问您的 Bucket 的指定资源,并限制访问来源等。
    此时问题可能就找到原因了,此时的Bucket访问是用RAM,所以需要对RAM设置授权策略

在这里插入图片描述

二次修改

修改文件太大,spring报错的问题

Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (216185201) exceeds the configured maximum (104857600)

配置文件添加配置
properties写法

spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB

yml 写法

spring:  
  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB

三次修改

关于返回路径的问题

原来是 调用了ossClient.generatePresignedUrl返回了一个地址,后来发现阿里提供了访问的方法,如果文件的读写权限ACL为公共读,即该文件允许匿名访问,那么文件URL的格式为https://BucketName.Endpoint/ObjectName
所以只需要修改一下返回值即可
在这里插入图片描述

原文连接.

  • 11
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值