oss直传
this.file = new Map() //此处是用来存储数据
function upLoad(options, props) {
const { file, onSuccess, onError, onProgress } = options
const { fileSizeLimit, useInMonitor, onCallback } = props || {}
const abort = () => {} //终止请求
//第一步:查看文件是否限制,使用new window.file生成带size的文件
if (fileSizeLimit && file.size > fileSizeLimit) {
onError({
success: false,
message: `请上传${fileSizeLimit / (1024 * 1024)}M以下文件`,
})
return { abort }
}
//第二步:获取为未token时的文件信息
const fileInfo = addFile(
file,
{
status: 'pending',
onError,
onSuccess,
onProgress,
onCallback,
retry: () => {
this.setStatus(fileInfo.key, 'pending', {
precent: 0,
error: null,
})
this.simpleUpload(fileInfo, option)
},
},
useInMonitor
)
//第三步:取到带token的地址
simpleUpload(fileInfo, options)
}
function addFile(file, payload, indie) {
let uuid = 0
let noop = () => {}
const fileInfo = {
key: uuid++,
file,
...payload,
onerror: payload.onError || noop,
onSuccess: payload.onSuccess || noop,
onProgress: payload.onProgress || noop,
onCallback: payload.onCallback || noop,
cancel: () => {
const info = this.getfile(key) //取消的时候找到对应的文件
if (typeof info.xhr.abort === 'function') {
info.xhr.abort()
}
this.reject(key, new Error('已取消上传'))
},
abort: () => {
const info = this.getFile(key)
if (!indie && typeof info.xhr.abort === 'function') {
info.xhr.abort()
}
info.aborted = true
},
}
this.file.set(key, fileInfo) //存储数据
if (indie) {
//此处为监听者的数据处理
this.list.unshift(key)
this.emiter.emit('addFile', fileInfo)
}
return fileInfo
}
function getOssToken() {
const url = 'https://pre-dmt.alibaba-inc.com/portal/osstoken' //此处为oss直传url,视情况而定
//此时为获取token参数的流程,详情见oss返回参数
return GET(url, { method: 'GET' })
.then((res) => {
res.json()
})
.then((res) => {
return res.data
})
}
function simpleUpload(info, option) {
const { file, headers, data } = option
const id = info.key
return getOssToken()
.then((token) => {
//token.dir为新地址的前缀,
const pathName = [token.dir, getFileName(file)].join('')
const xhr = entireUpload(token, {
file,
pathName,
data,
headers,
onProgress: (ev) => {
this.progress(id, ev)
},
//将成功返回的结果里添加自己想要的数据,做成功时的回调
onSuccess: () => {
const payload = {
url: pathName,
downloadUrl: `${token.host}/${pathName}`,
}
this.resolve(id, payload)
},
onError: (ex) => {
this.reject(id, ex)
},
})
info.xhr = xhr
return info
})
.catch((ex) => reject(id, ex))
}
//带文件信息,带token上传
function entireUpload(
token,
{ file, pathName, data, headers, onProgress, onSuccess, onError }
) {
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onerror = ex => {
onError(ex);
};
if (xhr.upload) {
xhr.upload.onprogress = function progress(ev) {
if (ev.total > 0) {
(ev).percent = (ev.loaded / ev.total) * 100;
}
onProgress(ev);
};
}
xhr.onload = () => {
// allow success when 2xx status
// see https://github.com/react-component/upload/issues/34
if (xhr.status < 200 || xhr.status >= 300) {
return onError(new Error(xhr.statusText));
}
let result;
try {
result = JSON.parse(xhr.responseText || xhr.response);
} catch {}
onSuccess(result);
};
xhr.open('post', token.host, true);
const formData = new FormData();
if (data) {
Object.entries(data).forEach(([key, value]) => {
formData.append(key, String(value));
});
}
formData.append('OSSAccessKeyId', token.accessid);
formData.append('policy', token.policy);
formData.append('Signature', token.signature);
formData.append('key', pathName);
// 成功后的状态码,默认是 204
formData.append('success_action_status', '200');
formData.append('file', file);
// when set headers['X-Requested-With'] = null , can close default XHR header
// see https://github.com/react-component/upload/issues/33
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// if (headers['X-Requested-With'] !== null) {
// }
if (headers) {
Object.entries(headers).forEach(([key, value]) => {
xhr.setRequestHeader(key, String(value));
});
}
xhr.send(formData);
return xhr;
}
//以下关于处理的pathName仅为参考,可使用可不适用
function extname(fileName) {
const pointIndex = fileName.lastIndexOf('.') //查找点最后一次出现的位置
return [fileName.substr(0, pointIndex), fileName.substr(pointIndex)]
}
function getFileName(file) {
const [fileName, ext] = extname(file.name)
const name = encodeURIComponent(fileName)
.replace(/[%\s]+/g, '')
.substr(0, 16)
return `${name}${Date.now().toString(32)}${ext}` //新拼接而成的地址
}
SDK=放着你想要的软件功能的软件包
API=SDK上唯一的接口