123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- <!doctype html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>自定义的分片上传</title>
- <style>
- h1, h2 {
- font-weight: normal;
- }
- #msg {
- margin-top: 10px;
- }
- </style>
- </head>
- <body>
- <h1>自定义的分片上传</h1>
- <input id="fileSelector" type="file">
- <input id="submitBtn" type="button" value="上传文件">
- <input id="cancelBtn" type="button" value="取消最后一个上传文件">
- <div id="msg"></div>
- <script src="../dist/cos-js-sdk-v5.js"></script>
- <script src="./common/async.js"></script>
- <script>
- (function () {
- // 请求用到的参数
- var Bucket = 'test-1250000000';
- var Region = 'ap-guangzhou';
- var ChunkSize = 1024 * 1024 * 8;
- // 初始化 SDK
- var cos = new COS({
- getAuthorization: function (options, callback) {
- var url = '/sts'; // 如果是 npm run sts.js 起的 nodejs server,使用这个
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
- xhr.onload = function (e) {
- try {
- var data = JSON.parse(e.target.responseText);
- var credentials = data.credentials;
- } catch (e) {
- }
- if (!data || !credentials) return console.error('credentials invalid');
- callback({
- TmpSecretId: credentials.tmpSecretId,
- TmpSecretKey: credentials.tmpSecretKey,
- SecurityToken: credentials.sessionToken,
- StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
- ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
- });
- };
- xhr.send();
- },
- });
- var uuid = function () {
- var S4 = function () {
- return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
- };
- return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
- };
- // 外部维护上传任务状态
- var lastTaskId;
- var taskStateMap = {};
- cos._isRunningTask = function (tid) {
- return taskStateMap[tid] === 'uploading';
- };
- // 上传文件
- var uploadFile = function (file, callback) {
- var TaskId = lastTaskId = uuid();
- taskStateMap[TaskId] = 'uploading';
- var fileSize = file.size;
- var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
- console.log('上传任务已开始:' + lastTaskId, TaskId, Key);
- // 创建 UploadId
- cos.multipartInit({
- Bucket: Bucket,
- Region: Region,
- Key: Key,
- }, function (err, data) {
- if (!cos._isRunningTask(TaskId)) return;
- if (err) {
- taskStateMap[TaskId] = 'error';
- return console.error('UploadId 创建出错:', err);
- }
- var UploadId = data.UploadId;
- console.log('UploadId 已创建:', UploadId);
- var Parts = new Array(Math.ceil(fileSize / ChunkSize)).fill(0).map(function (item, index) {
- return {PartNumber: index + 1};
- });
- Async.eachLimit(Parts, 3, function (partItem, nextPart) {
- if (!cos._isRunningTask(TaskId)) return;
- var PartNumber = partItem.PartNumber;
- var start = (PartNumber - 1) * ChunkSize;
- var end = Math.min(start + ChunkSize);
- var blob = file.slice(start, end);
- // 上传每个分片
- cos.multipartUpload({
- Task: lastTaskId,
- Bucket: Bucket,
- Region: Region,
- Key: Key,
- UploadId: UploadId,
- PartNumber: PartNumber,
- Body: blob,
- }, function (err, data) {
- if (!cos._isRunningTask(TaskId)) return;
- if (err) return nextPart(err);
- if (!data.headers.etag) return nextPart('浏览器获取不到 ETag Header,需要存储桶配置 CORS ExposeHeaders 允许当前域名跨域读取 ETag 字段。');
- partItem.ETag = data.headers.etag || '';
- console.log('分片上传完成:', partItem.PartNumber, partItem.ETag);
- nextPart();
- });
- }, function (err) {
- if (!cos._isRunningTask(TaskId)) return;
- if (err) {
- taskStateMap[TaskId] = 'error';
- return console.error('上传分片出错:', err);
- }
- // 完成分片上传
- cos.multipartComplete({
- Bucket: Bucket,
- Region: Region,
- Key: Key,
- UploadId: UploadId,
- Parts: Parts,
- }, function (err, data) {
- if (err) {
- taskStateMap[TaskId] = 'error';
- return console.error('文件完成出错:', err);
- }
- console.log('文件上传成功:', data.Location);
- taskStateMap[TaskId] = 'success';
- callback(err, data);
- });
- });
- });
- };
- // 监听表单提交
- document.getElementById('submitBtn').onclick = function (e) {
- var file = document.getElementById('fileSelector').files[0];
- if (!file) {
- document.getElementById('msg').innerText = '未选择上传文件';
- return;
- }
- file && uploadFile(file, function (err, data) {
- console.log(err || data);
- document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
- });
- };
- // 监听取消上传
- document.getElementById('cancelBtn').onclick = function (e) {
- // 标记任务取消,让 SDK 外部的上传流程停止
- taskStateMap[lastTaskId] = 'canceled';
- // 取消 SDK 正在执行的 xhr 上传请求,触发 xhr.abort()
- cos.cancelTask(lastTaskId);
- console.log('上传任务已取消:' + lastTaskId);
- };
- })();
- </script>
- </body>
- </html>
|