目录

一.描述

二.OSS相关


一.描述

目前公司在做项目,应用的业务场景有上传,下载,预览;要求上传的文件的类型也比较多,有word,pdf,image,video,ai,psd等等这些类型,应用的是阿里云的OSS,本文就简单介绍一下前端(JS)相关的代码,用的框架是react,脚手架是antd pro4,重点介绍下阿里云相关的上传,下载,预览吧;

二.OSS相关

如果是项目的包管理工具用的是npm,应该先安装ali-oss这个包,然后通过import导入进来。

import OSS from 'ali-oss'

//如此就初始化了一个OSS的客户端,通过这个客户端可以实现上传,下载,预览等等相关的需求
const client = new OSS({
        region,//这些都是你们公司在购买阿里云的时候设定的
        accessKeyId: creds.AccessKeyId,//这些都是你们公司在购买阿里云的时候设定的
        accessKeySecret: creds.AccessKeySecret,//这些都是你们公司在购买阿里云的时候设定的
        bucket,
        secure:true,//在 OSSClient 初始化时加上 secure:true 就是 https 传输了
      });
  • 普通上传

OSS的上传可以分为普通上传和分片上传,如果文件的体积比较小,用普通上传就可以解决了,阿里云官方建议,如果文件的体积超过100M可以采用分片上传,先来分享一下普通上传,以上传图片为例子(用的client就是上文的代码实例出来的client,此后所有的client都是这个,不再赘述)。在使用antd或者element-ui提供的Upload插件的时候,会有一个方法来覆盖插件的默认上传行为,就是覆盖默认上传行为的方法里面去调用OSS的客户端进行上传就行了;

/*
vue的UI框架element-ui的上传插件,那个:http-request里面的方法就是用来覆盖默认上传行为的,以
uploadHttp为例子来展示OSS相关的上传
*/
            <el-upload
              action=""
              accept=".jpg,.jpeg,.png,.JPG,.JPEG,.bmp"
              list-type="picture-card"
              :http-request="uploadHttp"
              :show-file-list="false"
              :before-upload="beforeAvatarUpload">
              <div class="adv-pic-box" v-if="siteForm.siteIconUrl">
                <img :src="siteForm.siteIconUrl" width="150" height="150">
              </div>
              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
              <div slot="tip" class="el-upload__tip">图片格式:jpg,jpeg,png,bmp;文件大小:不大于1M</div>
            </el-upload>

OSS相关的上传代码放在了uploadHttp里面,详情如下:

uploadHttp ({ file }) {
      const fileName = `/${+new Date()}/${file.name}` // 定义唯一的文件名,规则可以根据需要去自定义的
      client.put(fileName, file, {
        'ContentType': 'image/jpeg'
      }).then(({ res, url, name }) => {
        if (res && res.status === 200) {
            //url 就表示文件上传成功以后服务器返回的一个可访问的链接
          this.siteForm.siteIconUrl = url
        }
      }).catch((err) => {
        this.$message.error('图片上传失败!')
        console.log(`阿里云OSS上传图片失败回调`, err)
      })
    },
  • 分片上传

分片上传是以antd的上传插件Upload为例子来展示代码的,因为分片上传要实时显示上传进度,产品方就要求加入一个进度条来显示上传 进度,监测进度这个OSS有专门的回调来处理,实在是太强大了!具体看代码吧!

/*

此处是react的UI插件antd的上传组件,这里的customRequest就是用来自定义上传行为的,在这个方法里面涉及到了OSS上传

*/
        <Upload
          {...uploadProps}
          accept={accept}
          className='ht-upload'
          fileList={fileList}
          listType={listType}
          beforeUpload={this.handleBeforeUpload}
          customRequest={this.handleCustomUpload}
          onChange={this.handChange}
          onRemove={this.onRemove}
        >
          <Button type='primary' icon={<UploadOutlined />}>{btnText}</Button>
        </Upload>
        //此处的progress就是实时显示上传进度的
        <div className='wrap-upload' style={{ width: '100%' }}>
          {
            percent !== 0 && <Progress {...progressProps} percent={percent} />
          }
            //提示文本
          <p className="ht-upload-hint">{hintText}</p>
        </div>

OSS分片上传的代码:

handleCustomUpload = (params: any) => {
    message.loading('正在上传......')
    const { onUploadSuccess = noop } = this.props
    const { file } = params
    // eslint-disable-next-line @typescript-eslint/naming-convention
    const this_Com: any = this
    const fileName = `/${+new Date()}/${file.name}` // 定义唯一的文件名

    // 此方法用来实现OSS的分片上传
    client.multipartUpload(fileName, file, {
        // 这个回调方法就是用来监测上传进度的,因为本人在写代码时用的是类组件,而这个方法中的this指向的不是此组件,因此就在外面声明了一个变量来缓存一下this,来达到更新上传进度的目的
      progress(pct: any, checkpoint: any) {
        const percent = Number(pct * 100).toFixed(0)
        this_Com.setState({ percent })
      }
    }).then((result: any) => {
      const { res } = result
      if (res && res.status === 200) {
        const url = res.requestUrls[0].split('?')[0]
        const imgItem = {
          uid: file.uid,
          name: file.name,
          status: 'done',
          url,
          imgUrl: url,
        }
        onUploadSuccess([ imgItem ])
        this.setState({ fileList: [ imgItem ] })
        message.destroy()
        message.success('上传成功!')
      }
    }).catch((err: any) => {
      message.destroy()
      message.error('上传失败!')
      console.log(`阿里云OSS上传图片失败回调`, err)
    })
  }
  • 下载

点击页面上的一个按钮,或者其他用户行为触发下载,在下载时,执行下列方法:

//点击下载,调用下列方法
  DownLoad = () => {
    const { downName = '', uploadUrl = '' } = this.state
    // 注意这个filename就是下载文件以后要显示的文件名,千万不要写错了,要不然下载下来的文件名会是乱码
    const response = {
      'content-disposition': `attachment; filename=${decodeURIComponent(downName)}`
    }
    const str = uploadUrl.indexOf('https') > -1 ? 'https' : 'http'

    // 注意一下这个filePath,是上传的时候返回来的链接的全路径,要包含文件名和文件后缀
    const url = client.signatureUrl(filePath, { response })
    // 此时这个url就是一个可以下载的链接,可以直接在浏览器打开下载,也可以通过前端的a标签实现下载
    downloadUseA(url, downName)

    // 直接在浏览器打开下载的话,可以执行下列代码:
    // window.open(url)
  }


// 采用a标签的方式实现下载
export function downloadUseA(url: string, name: string) {
  const a = document.createElement('a')
  a.download = decodeURIComponent(name)
  a.href = url
  a.style.display = 'none'
  document.body.appendChild(a)
  a.click()
  a.remove()
}
  • 预览

我试了一下pdf 的预览,没有问题,可以正常预览,但是word不能正常预览,仔细看一下阿里云官方的这篇文章:OSS在线预览word,下方有评论说目前暂不支持word预览。

实现预览的前端代码:

// object-key表示从OSS下载文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
const url = client.signatureUrl('object-key', { expires: 3600 });
// 此处以设置URL的有效时长为3600s为例,若不设置有效时长,则默认为1800s。

console.log(url);
/*
这个url就是一个可预览的在线链接,可以直接在浏览器打开这个链接来预览,也可以放在iframe标签中嵌入到网页里面,具体如何预览,看你们的个人需求就行了!

把ifram头部的工具栏给隐藏掉的话,就只需在src的后面加上‘#toolbar=0’,看如下例子:
<iframe id='ifm' src={`${fileUrl}#toolbar=0`} frameBorder="0" width='100%' height={height}/>
隐藏掉工具栏以后就不能打印和下载了
*/

至此就分享完毕