前端·

阿里云OSS存储之服务端签名+客户端直传

详细介绍阿里云OSS服务端签名和客户端直传开发流程。

前期准备

  1. 进入阿里云OSS存储-Bucket列表,创建bucket

image.png

  1. 进入RAM控制台,添加访问权限
  • 创建用户 注:OpenAPI访问打钩

image.png

  • 下载CSV文件,获取AccessKeyId、AccessKeySecret

image.png

服务端签名

服务端签名直传

  • 根据步骤创建 配置跨域规则

创建项目

  1. express为例,创建任意文件夹打开终端,执行以下步骤
// 初始化 package.json
npm init

// 下载相关包
npm install express moment ali-oss -s
  1. 创建server.js文件,运行node server.js,启动node服务http://127.0.0.1:3000/signature。文件内容如下:
// server.js
const express = require('express');
const app = express();
const moment = require("moment");
const OSS = require("ali-oss");

const hostname = "127.0.0.1";
const port = 3000;


app.listen(port, function () {
    console.log(`http://${hostname}:${port}`)
})
  
// 应用服务器核心代码解析
// 可以不用回调callback
app.get("/signature", async (req, res) => {
  const config = {

    // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
    accessKeyId: "LTAI5tMdm5QTzsGZoTtLw1p4",
    accessKeySecret: "0uMZ4TNfAnvexZGJETIKReINP20Fiq",
    // 填写Bucket名称。
    bucket: "lg-blog-test",
    // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。例如callbackUrl填写为https://oss-demo.aliyuncs.com:23450。
    // callbackUrl: 'yourCallBackUrl',
    // 当您需要设置上传到OSS文件的前缀时,请配置此项,否则置空即可。
    // 此处采用时间划分
    dir: "blog/" + moment(new Date()).format("YYYYMMDD") + "/",
  };

  const client = new OSS(config);

  const date = new Date();
  date.setDate(date.getDate() + 1);

  const policy = {
    expiration: date.toISOString(), //设置Unix时间戳(自UTC时间1970年01月01号开始的秒数),用于标识该请求的超时时间。
    conditions: [
      ["content-length-range", 0, 1048576000], //设置上传文件的大小限制。
    ],
  };

  // 设置跨域资源共享规则CORS。
  res.set({
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "PUT,POST,GET",
  });

  // 调用SDK获取签名。
  const formData = await client.calculatePostSignature(policy);


  // 填写Bucket外网域名。
  const host = 'https://lg-blog-test.oss-cn-hangzhou.aliyuncs.com';

  // 上传回调。
  //   const callback = {
  //     callbackUrl: config.callbackUrl, // 设置回调请求的服务器地址,例如http://oss-demo.aliyuncs.com:23450。
  //     // 设置回调的内容,例如文件ETag、资源类型mimeType等。
  //     callbackBody:
  //       "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
  //     callbackBodyType: "application/x-www-form-urlencoded", //  设置回调的内容类型。
  //   };

  // 返回参数。
  const params = {
    expire: moment().add(1, "days").unix().toString(),
    policy: formData.policy, // 从OSS服务器获取到的Policy。
    signature: formData.Signature, // 从OSS服务器获取到的Signature。
    accessKeyId: formData.OSSAccessKeyId, // 从OSS服务器获取到的OSS AccessKeyId。
    host, // 格式为https://bucketname.endpoint,例如https://bucket-name.oss-cn-hangzhou.aliyuncs.com。
    // callback: Buffer.from(JSON.stringify(callback)).toString("base64"), // 通过Buffer.from对JSON进行Base64编码。
    dir: config.dir, // 获取到的文件前缀。
  };

  res.json(params);
});

启动后,如下:

image.png

客户端调用

  1. 创建index.html,并运行。文件内容如下:
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OSS web直传</title>
</head>
<body>
    <input id="file" type="file" name="" id="" >
    <img id="img" width='max-content' height = 'max-content' src="" alt="">
</body>
<script>
    const fileDom = document.getElementById('file')
    const imgDom = document.getElementById('img')
    fileDom.onchange = async (e) => {
        const file = e.target.files[0]
        // 获取签名信息
        const data = await fetch('http://localhost:3000/signature')
        const signatureInfo = await data.json()

        // web直传
        const formData = new FormData()
        const name = signatureInfo.dir + file.name
        formData.append('key', signatureInfo.dir + file.name)
        formData.append('policy', signatureInfo.policy)
        formData.append('OSSAccessKeyId', signatureInfo.accessKeyId)
        formData.append('success_action_status', '200') // 默认值
        formData.append('signature', signatureInfo.signature)
        formData.append('file', file)
        formData.append('x-oss-object-acl', 'public-read') // 只读访问权限
        const response = await fetch(signatureInfo.host, {
            method: 'POST',
            body: formData
        })
        if (response.ok) {
            const url = `${signatureInfo.host}/${name}`
            imgDom.setAttribute('src', url)
        }
    }
</script>
</html>

此处采用 vscode 插件运行: image.png

阿里云服务器查看,上传成功。如下:

image.png

遇到的问题

  1. 报错信息:You have no right to access this object because of bucket acl.

解决:读写权限设置为公共读,保存后即可访问。

如下:

image.png