本文以Node.js语言为例,介绍如何通过Node.js代码在服务端先完成签名,并设置上传回调,然后通过表单直传数据到OSS。

前提条件

  • 应用服务器对应的域名可通过公网访问。
  • 应用服务器已经安装Node.js 8.0以上版本。您可以执行node -v命令验证Node.js版本。
  • 客户端运行需要浏览器支持HTML4、HTML5、Flash、Silverlight。

步骤一:配置应用服务器

  1. 下载应用服务器源码
  2. 本示例中以Ubuntu 16.04为例,将源码解压到/home/aliyun/aliyun-oss-appserver-node.js目录下。
  3. 在项目的根目录下执行npm install
  4. 在项目的根目录下找到源码文件app.js,修改以下代码片段:
    const config = {
      // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
      accessKeyId: 'yourAccessKeyId', 
      accessKeySecret: 'yourAccessKeySecret',
      // 填写Bucket名称。
      bucket: 'yourBucket',
      // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。例如callbackUrl填写为https://oss-demo.aliyuncs.com:23450。
      callbackUrl: 'yourCallBackUrl',
      // 当您需要设置上传到OSS文件的前缀时,请配置此项,否则置空即可。
      dir: 'yourPrefix'
    }

步骤2:配置客户端

  1. 下载客户端源码
  2. 解压文件。本例以解压到D:\aliyun\aliyun-oss-appserver-js目录为例。
  3. 在该目录下打开upload.js文件,找到以下代码语句:
    // serverUrl是用户用来获取签名直传和Policy等信息的应用服务器URL。请将下面的IP和Port配置为您自己的真实信息。
    serverUrl = 'http://88.88.88.88:8888'
  4. severUrl改为应用服务器的地址。例如,您可以将其修改为serverUrl = 'https://oss-demo.aliyuncs.com:23450',客户端可通过该地址获取签名直传和Policy等信息。

步骤三:配置跨域规则

客户端进行表单直传到OSS时,会从浏览器向OSS发送带有Origin的请求消息。OSS对带有Origin头的请求消息会进行跨域规则(CORS)的验证。因此需要为Bucket设置跨域规则以支持Post方法。

  1. 登录OSS管理控制台
  2. 单击Bucket列表,之后单击目标Bucket名称。
  3. 单击权限管理 > 跨域设置,在跨域设置区域单击设置
  4. 单击创建规则,配置如下图所示。
    说明 为了您的数据安全,请在实际使用时将来源填写实际允许访问的域名。各配置参数的更多信息,请参见设置跨域访问

步骤四:体验上传回调

  1. 在应用服务器根目录下,执行npm run server命令启动应用服务器。
  2. 在PC端的客户端源码目录中,打开index.html文件。
    注意 index.html文件不保证兼容IE 10以下版本浏览器。如果使用IE 10以下版本浏览器出现问题时,您需要自行调试。
  3. 单击选择文件,选择指定类型的文件,单击开始上传
    上传成功后,显示回调服务器返回的内容。

附录:应用服务器核心代码解析

应用服务器源码包含了签名直传服务以及上传回调服务的完整示例代码。以下仅提供核心代码片段,如需了解这两个功能的完整实现,请参见应用服务器源码(Node.js版本)

  • 签名直传服务
    获取应用服务器签名参数和回调服务器地址的代码片段如下:
    app.get("/", async (req, res) => {
      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": req.headers.origin || "*",
        "Access-Control-Allow-Methods": "PUT,POST,GET",
      });
    
      // 调用SDK获取签名。
      const formData = await client.calculatePostSignature(policy);
      // 填写Bucket外网域名。
      const host = `http://${config.bucket}.${
        (await client.getBucketLocation()).location
      }.aliyuncs.com`.toString();
      // 上传回调。
      const callback = {
        callbackUrl: config.callbackUrl,// 设置回调请求的服务器地址,例如http://oss-demo.aliyuncs.com:23450。
        callbackBody:// 设置回调的内容,例如文件ETag、资源类型mimeType等。
          "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。
        accessid: 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);
    });
  • 上传回调服务

    上传回调服务响应OSS发送给应用服务器的POST消息,代码片段如下:

    // 监听/result路径下的POST请求。
    app.post("/result", (req, res) => {
      // 通过Base64解码公钥地址。
      const pubKeyAddr = Buffer.from(
        req.headers["x-oss-pub-key-url"],
        "base64"
      ).toString("ascii");
      //  判断请求头中的x-oss-pub-key-url是否来源于OSS服务器。
      if (
        !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/") &&
        !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/")
      ) {
        System.out.println("pub key addr must be oss addrss");
        // 如果x-oss-pub-key-url不是来源于OSS服务器,则返回“verify not ok”,表明回调失败。
        res.json({ Status: "verify not ok" });
      }
      // 如果x-oss-pub-key-url来源于OSS服务器,则返回“Ok”,表明回调成功。
      res.json({ Status: "Ok" });
    });

    有关上传回调的更多信息,请参见Callback