小程序客户端文件上传阿里OSS直传实践(服务端获取签名)

客户端直传步骤, oss后台配置好相关设置,可参考:https://help.aliyun.com/document_detail/92883.html 流程,服务端以PHP为例,

1.引入库

composer require ramsey/uuid    //引入通用唯一识别ID

2.此处是服务端获取阿里签名代码

<?php


namespace app\service;

use Ramsey\Uuid\Uuid;

/**
 * Class AliOssService
 * @package app\service
 *
 * 微信小程序直传实践
 * @see https://help.aliyun.com/document_detail/92883.html
 */
class AliOssService
{
    // 配置oss参数
    private const AccessKeyId = '<AccessKeyId>';

    private const AccessKeySecret = '<AccessKeySecret>';

    private const Host = 'https://<region>.oss-cn-beijing.aliyuncs.com';

    // 签名有效期 单位: 秒
    private const Expire = 3 * 60;

    // 允许上传的文件最大和最小范围 单位:字节
    private const ContentLengthMin = 0;
    private const ContentLengthMax = 20 * 1024 * 1024;


    /**
     * 获取服务端签名方式上传参数
     * @param $params array
     *   ext string 扩展名 eg: jpg
     *   dirname string 上传目录 eg: image
     * @return array
     * @throws \Exception
     */
    public static function getUploadParams($params)
    {

        // 接收参数
        $ext     = $params['ext'];
        $dirname = $params['dirname'];

        // 文件路径和文件名
        $dir = self::getDirname($dirname);

        $key = $dir . self::getFilename($ext);

        // 过期时间
        $expiration = self::getExpireTime(self::Expire);

        // 参数设置
        // 附录:Post Policy
        // https://help.aliyun.com/document_detail/31988.htm#section-d5z-1ww-wdb
        $policyParams = [
            'expiration' => $expiration,
            'conditions' => [
                // 指定前缀
                ['starts-with', '$key', $dir],
                // 限制上传文件大小。单位:字节
                ['content-length-range', self::ContentLengthMin, self::ContentLengthMax]
            ]
        ];

        $policyBase64 = self::getPolicyBase64($policyParams);

        $signature = self::getSignature($policyBase64, self::AccessKeySecret);

        return [
            'accessKeyId' => self::AccessKeyId,
            'host'        => self::Host,
            'policy'      => $policyBase64,
            'signature'   => $signature,
            'expire'      => $expiration,
            'key'         => $key,
            'url'         => self::Host . '/' . $key
        ];
    }

    /**
     * 获取参数base64
     * @param $policyParams array
     * @return string
     */
    public static function getPolicyBase64($policyParams)
    {
        return base64_encode(json_encode($policyParams));
    }

    /**
     * 获取签名
     * @param $policyBase64 string
     * @param $accessKeySecret string
     * @return string
     */
    public static function getSignature($policyBase64, $accessKeySecret)
    {
        return base64_encode(hash_hmac('sha1', $policyBase64, $accessKeySecret, true));
    }

    /**
     * 获取过期时间
     * @param $time int 单位: 秒
     * @return mixed
     */
    public static function getExpireTime($time)
    {
        return str_replace('+00:00', '.000Z', gmdate('c', time() + $time));
    }

    /**
     * 获取按照月份分隔的文件夹路径
     * @param $dirname string eg: image/video
     * @return string eg: image/2022-10/
     */
    public static function getDirname($dirname)
    {
        return $dirname . '/' . date('Y-m') . '/';
    }

    /**
     * 获取一个随机的文件名
     * @param $ext string eg: jpg
     * @return string eg: a4030d9f-c4a2-4f1a-8e33-80e017e572d5.jpg
     * @throws \Exception
     */
    public static function getFilename($ext)
    {
        $uuid = Uuid::uuid4()->toString();
        return $uuid . '.' . $ext;
    }
}

3.提供给客户端获取签名的接口实现

<?php

namespace app\controller;


use app\BaseController;
use app\exception\AppException;
use app\service\AliOssService;

class AliOssController extends BaseController
{

    public function getUploadParams()
    { 
        $ext     = input('ext');
        $dirname = input('dirname', 'image');

        // 参数校验
        if (!$ext) {
            throw new AppException('ext is empty');
        }

        if (!in_array($dirname, ['image', 'video'], true)) {
            throw new AppException('dirname: only allow image or video');
        } 
        $result = AliOssService::getUploadParams([
            'ext'     => $ext,
            'dirname' => $dirname,
        ]); 
        return $result;

    }

}

4.客户端直传实战,以微信小程序侧代码示例,获取到服务端签名,然后直传阿里oss

// 获取文件扩展名
function getFilePathExtention(filePath) {
  return filePath.split('.').slice(-1)[0];
}

// 上传到阿里云oss
function uploadFileAsync(config, filePath) {
  console.log(config);

  return new Promise((resolve, reject) => {
    wx.uploadFile({
      url: config.host, // 开发者服务器的URL。
      filePath: filePath,
      name: 'file', // 必须填file。
      formData: {
        key: config.key,
        policy: config.policy,
        OSSAccessKeyId: config.accessKeyId,
        signature: config.signature,
        // 'x-oss-security-token': securityToken // 使用STS签名时必传。
      },

      success: (res) => {
        console.log(res);

        if (res.statusCode === 204) {
          resolve();
        } else {
          reject('上传失败');
        }
      },
      fail: (err) => {
        // console.log(err);
        reject(err);
      },
    });
  });
}

// 上传文件
export async function uploadFile(filePath, dirname = 'image') {
  console.log(filePath);

  let ext = getFilePathExtention(filePath);

   // 改方法通过接口获取服务端生成的上传签名    
   const resParams = await Http.AliOssGetUploadParams({
    ext,
    dirname,
  });

  //   console.log(resParams.data);
  //   let objectName = resParams.data.uuid + '.' + getFilePathExtention(filePath);
  await uploadFileAsync(resParams.data, filePath);

  //   console.log(res);
  return resParams;
}
 
© 版权声明
THE END
喜欢就支持一下吧
点赞7赞赏 分享
评论 抢沙发
头像
平等表达,友善交流,有爱评论~
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容