Fusion Upload组件 对接 阿里云OSS/七牛/又拍

1,172 阅读4分钟

BeforeUpload 方法

Upload组件的BeforeUpload方法,是一个十分强大的方法,可以在上传请求发起之前做一系列的操作行为。从而达到改变请求参数的目的。

beforeUpload 的 Function Signature (实在不知道怎么翻译了) 为 Function(file: Object, options: Object) => Boolean/Object/Promise。 说明这个方法接收两个参数

  1. file,即将上传的原生File对象
  2. options,上传的各个参数, 包括
{
    action: "http://xxxxx.xxxx"
    data: {}
    headers: {}
    method: "post"
    name: "file"
    timeout: undefined
    withCredentials: true
}

返回值也支持多种(Boolean/Object/Promise):

返回值 行为
false 阻止上传
true 继续上传
Object 结构同入参 options 继续上传并且把 返回值 merge到 上传参数中
Promise.reject() 阻断上传
Promise.resolve(false) 阻断上传
Promise.resolve(true) 继续上传
Promise.resolve(data) 结构同入参 options 继续上传并且把 Promise返回值 merge到上传参数中

看起来挺复杂,但是其实内在逻辑就是一个: 返回false就阻止上传, 返回Object都merge上传参数,其他返回值直接继续上传。返回既可以是直接return,也可以是通过Promise返回值。

有了beforeUpload的能力,就可以用来做很多事情了。

formatter方法

Upload对返回值是有要求的。 只有HTTP状态码为2xx,且返回体为

{
     "success": true, //必需
      "message": "上传成功",  // (非必须)
      "url": "https://img.alicdn.com/tps/TB19O79MVXXXXcZXVXXXXXXXXXX-1024-1024.jpg"             // 返回结果
      "imgURL": "https://img.alicdn.com/tps/TB19O79MVXXXXcZXVXXXXXXXXXX-1024-1024.jpg",         // 图片预览地址 (非必须)
      "downloadURL": "https://img.alicdn.com/tps/TB19O79MVXXXXcZXVXXXXXXXXXX-1024-1024.jpg",    // 文件下载地址 (非必须)
}

则代表成功。

由于各大云厂商,对于成功请求成功的定义是不一样的。所以需要用到Upload组件Upload组件的formatter方法。formatter接收原始的 response,用户自行把原始response转化为Uplaod要求的标准response并返回即可。

阿里云OSS

OSS 是阿里云提供的文件存储服务, 在集团内也是十分常用的一个存储服务。 目前阿里云推荐的方式是,Web端签名直传OSS。

首先看看文档样例,对接OSS主要分为三个步骤:

  1. 获取文件信息
  2. 请求上传参数
  3. 上传文件

这样就又要用到beforeUpload方法了,三个步骤都可以在beforeUpload中完成。假设我们的后端实现和官方Demo一致。官方样例的上传参数返回是这样的:

{
    "accessid": "xxxxxxx",
    "host": "http://post-test.oss-cn-hangzhou.aliyuncs.com",
    "policy": "xxxxxxxxxxxxxxxx",
    "signature": "xxxxxxxxxxxxx",
    "expire": 1546944707,
    "dir": "xxx/xxxx/xx/xx"
}

前端通过ajaxGetOSSToken函数上面这个数据,那么beforeUpload就可以这样写:

function beforeUpload(file, uploadOptions) {
    // file 原生的File对象,即将被上传的文件
    // uploadOptions 是 上传参数
    let promise = ajaxGetOSSToken(); // 函数自行实现,保证返回一个promise来就可以
    promise = promise.then((data) => {
    	uploadOptions.data = {
    		name: file.filename,
			key: `${data.dir}${file.name}`,
			policy: data.policy,
			OSSAccessKeyId: data.accessid,
			success_action_status: 200
			signature: data.signature
    	};
    	uploadOptions.headers = {'X-Requested-With': null};// 需要跨域上传的话加这一段
    	uploadOptions.action = data.host;
    	return uploadOptions;
    });

    return promise;
}
 <Upload
        action="" // 先不填 有服务端返回
        beforeUpload={beforeUpload}
        onChange={onChange}
        onSuccess={onSuccess}
        withCredentials={false} // 这个很重要
    >
        <Button>Upload File</Button>
    </Upload>

可以上传文件到OSS的Upload组件就完成了。

七牛云存储

七牛提供了Form上传接口与后端生成Token的Java SDK NodeJS SDK。 假设后端返回的数据是这样的:

{
    "token": "xxxxxxx",
    "key": "xxx/yyyy/zzz/aaa.jpg",
    "host": "http://upload.qiniup.com/"
}

前端通过ajaxGetOSSToken函数上面这个数据,那么beforeUpload就可以这样写:

function beforeUpload(file, uploadOptions) {
    // file 原生的File对象,即将被上传的文件
    // uploadOptions 是 上传参数
    
    let promise = ajaxGetOSSToken(); // 函数自行实现,保证返回一个promise来就可以
    promise = promise.then((data) => {
    	uploadOptions.data = {
    		token: data.token,
			key: data.key,
    	};
    	uploadOptions.headers = {'X-Requested-With': null};// 需要跨域上传的话加这一段
    	uploadOptions.action = data.host;
    	return uploadOptions;
    });
    
    return promise;
}
 <Upload
        action="" // 先不填 有服务端返回
        beforeUpload={beforeUpload}
        onChange={onChange}
        onSuccess={onSuccess}
        withCredentials={false} // 这个很重要
    >
        <Button>Upload File</Button>
    </Upload>

可以上传文件到七牛的Upload组件就完成了。

又拍云

又拍云提供Form API,支持大文件和小文件上传,本处以小文件上传为例。也给后端生成Token的各种语言的SDK。 假设后端返回的数据是这样的:

{
    saveKey: "xxxxx",
    policy: "xxxxxx==",
    authorization: "xxxxxxxx",
    bucket: "xxxx",
}

前端通过ajaxGetOSSToken函数上面这个数据,那么beforeUpload就可以这样写:

function beforeUpload(file, uploadOptions) {
    // file 原生的File对象,即将被上传的文件
    // uploadOptions 是 上传参数
    
    let promise = ajaxGetOSSToken(); // 函数自行实现,保证返回一个promise来就可以
    promise = promise.then((data) => {
    	uploadOptions.data = {
    		'save-key': data.saveKey,
			policy: data.policy,
			authorization: data.authorization,
        expiration: 30,
    	};
    	uploadOptions.headers = {'X-Requested-With': null};// 需要跨域上传的话加这一段
    	uploadOptions.action = " http://v0.api.upyun.com/" + data.bucket;
    	return uploadOptions;
    });
    return promise;
}
 <Upload
        action="" // 先不填 有服务端返回
        beforeUpload={beforeUpload}
        onChange={onChange}
        onSuccess={onSuccess}
        withCredentials={false} // 这个很重要
    >
        <Button>Upload File</Button>
    </Upload>

可以上传文件到又拍云的Upload组件就完成了。