鸿蒙环境服务端签名直传

本文介绍如何在鸿蒙环境下将文件上传到OSS。

背景信息

鸿蒙环境是当下比较流行的操作环境,与服务端签名直传的原理类似,鸿蒙环境上传文件到OSS是利用OSS提供的PutObject接口来实现文件上传到OSS。关于PutObject的详细介绍,请参见PutObject

说明

本文只展示关于鸿蒙环境下服务端签名直传的关键代码片段,如果您需要了解更多详细信息,请下载完整示例:oss-js-sdk-harmony-demo.zip

步骤一:获取签名URL

为了您的数据安全,建议使用签名方式上传文件。OSS提供服务端签名和客户端签名两种签名方式, 这里以服务端签名为例:

说明

使用代码前,您需要先安装OSS SDK。更多信息,请参见安装

使用服务端获取签名时,您需要先搭建一个签名服务,然后由客户端调用签名服务生成签名URL,具体步骤如下:

  1. 搭建服务端接口。

    const express = require("express");
    const mime = require("mime");
    const OSS = require("ali-oss");
    const app = express();
    const port = 3000; // 监听端口
    
    app.use(express.json());
    
    app.use(express.urlencoded({ extended: false }));
    
    app.post("/get_sign_url", async (req, res) => {
      const {
        fileName,
        method,
        headers = {},
        queries = {},
        additionalHeaders = [],
      } = req.body; // 从body中解析出数据
      const client = new OSS({
        region: "yourRegion",
        accessKeyId: "yourAccessKey",
        accessKeySecret: "yourAccessKeySecret",
        stsToken: "yourSTSToken",
        bucket: "yourBucket",
        authorizationV4: true,
      });
    
      const reqHeaders = {
        ...headers,
      };
    
      // 处理一下content-type
      if (fileName && method === "PUT") {
        const fileNameSplit = fileName.split(".");
    
        reqHeaders["content-type"] = mime.getType(
          fileNameSplit.length > 1 ? fileNameSplit[fileNameSplit.length - 1] : ""
        );
      }
    
      // 生成V4签名URL
      const url = await client.signatureUrlV4(
        method,
        300,
        {
          headers: reqHeaders,
          queries,
        },
        fileName,
        additionalHeaders
      );
    
      res.json({
        url,
        contentType: reqHeaders["content-type"],
      });
    });
    
    app.listen(port, () => {
      console.log(`Example app listening on port ${port}`);
    });
    
  2. 在客户端获取签名URL。

    import { http } from '@kit.NetworkKit';
    import fs from '@ohos.file.fs';
    import { request } from './request';
    
    const serverUrl = 'http://x.x.x.x:3000/get_sign_url'; // 获取签名URL的服务器URL
    
    /**
     * getSignUrl返回数据
     */
    export interface ISignUrlResult {
      /** 签名URL */
      url: string;
      /** content-type */
      contentType?: string;
    }
    
    /**
     * 获取签名URL
     * @param fileName 文件名称
     * @param req 用于生成V4签名URL的请求信息
     * @param req.method 请求方式
     * @param [req.headers] 请求头
     * @param [req.queries] 请求查询参数
     * @param [req.additionalHeaders] 加签的请求头
     */
    const getSignUrl = async (fileName: string, req: {
      method: 'GET' | 'POST' | 'PUT';
      headers?: Record<string, string | number>;
      queries?: Record<string, string>;
      additionalHeaders?: string[];
    }): Promise<ISignUrlResult> => {
      console.info('in getSignUrl');
    
      try {
        const response = await request(serverUrl, {
          method: http.RequestMethod.POST,
          header: {
            'Content-Type': 'application/json'
          },
          extraData: {
            fileName,
            method: req.method,
            headers: req.headers,
            queries: req.queries,
            additionalHeaders: req.additionalHeaders
          },
          expectDataType: http.HttpDataType.OBJECT
        }, 200);
        const result = response.result as ISignUrlResult;
    
        console.info('success getSignUrl');
    
        return result;
      } catch (err) {
        console.info('getSignUrl request error: ' + JSON.stringify(err));
    
        throw err;
      }
    };
    

步骤二:使用鸿蒙系统上传

使用签名URL上传文件,示例代码如下:

import { http } from '@kit.NetworkKit';
import fs from '@ohos.file.fs';
import { request } from './request';

const putObject = async (fileUri: string): Promise<void> => {
  console.info('in putObject');

  const fileInfo = await fs.open(fileUri, fs.OpenMode.READ_ONLY);
  const fileStat = await fs.stat(fileInfo.fd);
  let signUrlResult: ISignUrlResult;

  console.info('file name: ', fileInfo.name);

  try {
    // 获取PutObject的签名URL
    signUrlResult = await getSignUrl(fileInfo.name, {
      method: 'PUT',
      headers: {
        'Content-Length': fileStat.size
      },
      additionalHeaders: ['Content-Length']
    });
  } catch (e) {
    await fs.close(fileInfo.fd);

    throw e;
  }

  const data = new ArrayBuffer(fileStat.size);

  await fs.read(fileInfo.fd, data);
  await fs.close(fileInfo.fd);

  try {
    // 使用PutObject方法上传文件
    await request(signUrlResult.url, {
      method: http.RequestMethod.PUT,
      header: {
        'Content-Length': fileStat.size,
        'Content-Type': signUrlResult.contentType
      },
      extraData: data
    }, 200);

    console.info('success putObject');
  } catch (err) {
    console.info('putObject request error: ' + JSON.stringify(err));

    throw err;
  }
};

常见问题

上传成功后,如何获取文件URL?

具体操作,请参见使用文件URL分享文件