ant design 组件上传视频直传七牛云

更新日期: 2022-05-14 阅读次数: 1284 字数: 888 分类: ReactJS

由于视频文件太大,不适合通过自己服务器中转一层,还是在前端直接传到七牛云合理。

文档

  • 七牛云 Go SDK 文档,参考上传凭证的生成:https://developer.qiniu.com/kodo/sdk/go
  • 七牛云 JS SDK 文档,参考其自定义文件名:https://developer.qiniu.com/kodo/1283/javascript

关于 token

token 上传凭证。

  • 作用:客户端(移动端或者Web端)上传文件的时候,需要从客户自己的业务服务器获取上传凭证
  • 有效期:默认情况下,在不指定上传凭证的有效时间情况下,默认有效期为1个小时。也可以自行指定上传凭证的有效期
  • 是否有调用频率限制:无。因为最简单的上传凭证只需要AccessKey,SecretKey和Bucket就可以,不需要与七牛服务器进行交互。

拉取 token 的时机

CreateForm 初始化的时候拉取一次足够了,不太可能在这个页面停留 1 小时以上。

但是感觉还是封装成组件比较好,否则多个页面这些配置还要改 N 个地方。

TODO

  • [X] go gin 后台生成上传凭证接口
  • [X] 查看 ant design 官方组件的阿里云 OSS 直传示例代码,基于此梳理七牛云的逻辑
  • [X] 封装成 react 组件
  • [X] 编辑历史数据,报错:TypeError: items.map is not a function。fileList 参数,后台返回的是字符串,需要转换成 array
  • [X] 上传完成后,可以预览
  • [X] fileList 逻辑确认。删除等操作回调里
  • 自定义 preview 界面。否则默认是新窗口打开视频播放,倒是可以接收。

七牛云上传地址

ant design upload 组件,action 属性需要填写对应的上传地址。 而七牛云不同地区 Bucket 有不同的上传地址,参考这里:

https://developer.qiniu.com/kodo/1671/region-endpoint-fq

例如,华南地区是:

https://upload-z2.qiniup.com

七牛接口返回

{"hash":"FuxTlDmDSHGp1ijpBEOo9LNZJnti","key":"FuxTlDmDSHGp1ijpBEOo9LNZJnti"}

key 即文件名,默认是七牛后台自动生成的。还是替换成自己的规则比较好。 需要在上传的时候,通过 key 指定文件名。

视频上传组件

import React from 'react';
import { Form, Upload, message, Button } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { uploadToken } from '@/services/ant-design-pro/api';


const QINIU_SERVER = 'https://upload-z2.qiniup.com';    // 华南地区

/**
 * 视频上传组件
 *
 * props 值列表:
 * - value: form 中的值。多个视频链接以英文逗号分隔
 * - max: 最多可以上传几个视频。max = 1 可上传一张,不设置则可上传无限多。
 **/
class QiniuUploadVideo extends React.Component {
  constructor(props) {
    super(props);
    let _state = {
      token: '',
      filePrefix: '',
      urlPrefix: '',
      fileList: [],
      max: this.props.max,
    };

    if (this.props.value) {
      let urls = this.props.value.split(",");
      let i = -1;
      for (let url of urls) {
        _state.fileList.push({
          uid: i + "",
          name: '视频',
          status: 'done',
          url: url,
        })
      }
    }

    this.state = _state;
  }

  async componentDidMount() {
    await this.init();
  }

  init = async () => {
    try {
      const data = await uploadToken();
      console.log(data);

      this.setState({
        token: data.uploadToken,
        filePrefix: data.filePrefix,
        urlPrefix: data.urlPrefix,
      });
    } catch (error) {
      message.error(error);
    }
  };

  handleChange = ({ file, fileList, event }) => {
    const { status, response } = file
    if (status === 'done') {
      // 上传成功
      const { key, hash } = response
      if (key) {
        message.success("上传成功")
        let imgs = [];
        for (let file2 of fileList) {
          if (file2.url) {
            imgs.push(file2.url);
          } else {
            imgs.push(this.state.urlPrefix + "/" + file2.response.key);
          }
        }
        // 调用父组件 onChange 方法, 将新值传递回去
        this.props.onChange(imgs.join(","))
      } else {
        message.error("上传失败")
      }
    }
    this.setState({ fileList })
  };

  getExtraData = file => {
    const { token, filePrefix } = this.state;

    return {
      token: token,
      key: filePrefix + "_" + file.name,
    };
  };

  render() {
    const uploadButton = (
        <Button icon={<UploadOutlined />}>点击上传视频</Button>
    );
    const props = {
      action: QINIU_SERVER,
      name: 'file',
      fileList: this.state.fileList,
      //listType: "picture-card",
      onChange: this.handleChange,
      data: this.getExtraData,
    };
    return (
      <Upload {...props}>
          {(this.state.max && this.state.fileList.length >= this.state.max) ? null : uploadButton}
      </Upload>
    );
  }
}

export default QiniuUploadVideo;

爱评论不评论