前端直传图片到七牛云OSS

764 阅读2分钟

最近在用 vue3 + springboot 做项目,需要将图片存储到第三方OSS服务,我选择了熟悉的七牛云,并打算换一种上传方式,以前都是将文件发给业务服务器,由业务服务器上传文件给七牛云。这次我选择使用前端直传,就是前端发起上传请求,请求业务服务器并获取上传凭证,然后带着上传凭证等参数,直接上传文件到七牛云对象存储服务器

这样做的好处是减轻了服务器的压力,业务服务器不需要上传文件,只需要负责给客户端颁发上传凭据,获取文件链接并保存到数据库中。大致步骤如下:

一、前端选择要上传的文件,将要上传的文件的文件名发送给后端,后端收到文件名后生成上传凭证(前端代码略,这里主要展示后端代码)

在配置文件中配置密钥、bucket等信息

oss:  
    accessKey: yourAccessKey 
    secretKey: yourSecretKey
    bucket: yourBucket  
    domain: yourDomain

新建配置类,使用注解@ConfigurationProperties(value = "oss")读取配置文件

import lombok.Data;  
import org.springframework.boot.context.properties.ConfigurationProperties;  
import org.springframework.stereotype.Component;  
  
@Component  
@ConfigurationProperties(value = "oss")  
@Data  
public class OssProperties {  
    private String accessKey;  
    private String secretKey;  
    private String bucket;  
    private String domain;  
}

controller代码

@RestController  
@RequestMapping("/...")  
public class OssController {  

        private final OssProperties ossProperties;  
  
        public OssController(OssProperties ossProperties) {  
            this.ossProperties = ossProperties;  
        }  
  
/**  
* 获取上传凭证  
*/  
@PostMapping("/policy/{fileName}")  
public Result getPolicyByQiNiuYun(@PathVariable("fileName") String fileName){  
        String accessKey = ossProperties.getAccessKey();  
        String secretKey = ossProperties.getSecretKey();  
          
        LocalDate localdate = LocalDate.parse(LocalDate.now().toString());  
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");  
        String key = localdate.format(dtf) + "/" + fileName;  
        String bucket = ossProperties.getBucket();  
          
        Auth auth = Auth.create(accessKey, secretKey);  
        String upToken = auth.uploadToken(bucket, key);  
        MyPutRet put = new MyPutRet();  
        put.setKey(key);  
        put.setToken(upToken);  
        return Result.success(put);  
    }   
}

二、前端得到key和token后,开始上传文件,上传成功后七牛云会返回key和hash

由于这里是前端直传,所以没有涉及后端代码

/**
 * 上传文件
 */
export function uploadFileApi(
  file: File,
  token: string,
  key: string
): AxiosPromise<HashAndKey> {
  const formData = new FormData();
  formData.append("file", file);
  formData.append("token", token);
  formData.append("key", key);
  return request({
    url: "http://upload-z0.qiniup.com",
    method: "post",
    data: formData,
    headers: {
      "Content-Type": "multipart/form-data",
    },
  });
}

七牛云给我们返回的这个key其实和第一步中后端代码中的key是一样的,都是路径+文件名

image.png

三、前端带着第二步返回的key向后端业务服务器发送请求,后端生成文件的url地址返回给前端

前端

/**
 * 获取文件 url
 */
export function getDownloadUrl(key: KeyParam): AxiosPromise<string> {
  return request({
    url: "/third-party/oss/downloadUrl",
    method: "get",
    params: key,
  });
}

后端 controller

/**  
* 获取文件下载url  
*/  
@GetMapping("/downloadUrl")  
public Result getDownloadUrl(@RequestParam("key") String key){  
    // domain 用户 bucket 绑定的下载域名 eg: mock.qiniu.com【必须】  
    // useHttps 是否使用 https【必须】  
    // key 下载资源在七牛云存储的 key【必须】  
    DownloadUrl url = new DownloadUrl(ossProperties.getDomain(), false, key);  
    String urlString = null;  
    try {  
        urlString = url.buildURL();  
    } catch (QiniuException e) {  
        throw new RuntimeException("buildURL Error");  
    }  
    return Result.success(urlString);  
}

注意:只有七牛云的空间为公开才可以像我这样直接拼接生成url,如果是私有空间需要携带 token 请求七牛云获取文件下载链接,具体查看七牛云的开发文档

参考资料

七牛云JavaSDK文档

七牛云区域和访问域名列表