slice.html 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>自定义的分片上传</title>
  6. <style>
  7. h1, h2 {
  8. font-weight: normal;
  9. }
  10. #msg {
  11. margin-top: 10px;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <h1>自定义的分片上传</h1>
  17. <input id="fileSelector" type="file">
  18. <input id="submitBtn" type="submit">
  19. <div id="msg"></div>
  20. <script src="../dist/cos-js-sdk-v5.js"></script>
  21. <script src="./common/async.js"></script>
  22. <script>
  23. (function () {
  24. // 请求用到的参数
  25. var Bucket = 'test-1250000000';
  26. var Region = 'ap-guangzhou';
  27. var ChunkSize = 1024 * 1024 * 8;
  28. // 初始化 SDK
  29. var cos = new COS({
  30. getAuthorization: function (options, callback) {
  31. var url = '/sts'; // 如果是 npm run sts.js 起的 nodejs server,使用这个
  32. var xhr = new XMLHttpRequest();
  33. xhr.open('GET', url, true);
  34. xhr.onload = function (e) {
  35. try {
  36. var data = JSON.parse(e.target.responseText);
  37. var credentials = data.credentials;
  38. } catch (e) {
  39. }
  40. if (!data || !credentials) return console.error('credentials invalid');
  41. callback({
  42. TmpSecretId: credentials.tmpSecretId,
  43. TmpSecretKey: credentials.tmpSecretKey,
  44. SecurityToken: credentials.sessionToken,
  45. StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
  46. ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
  47. });
  48. };
  49. xhr.send();
  50. },
  51. });
  52. // 上传文件
  53. var uploadFile = function (file, callback) {
  54. var fileSize = file.size;
  55. var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
  56. // 创建 UploadId
  57. cos.multipartInit({
  58. Bucket: Bucket,
  59. Region: Region,
  60. Key: Key,
  61. }, function (err, data) {
  62. if (err) return console.error('UploadId 创建出错:', err);
  63. var UploadId = data.UploadId;
  64. console.log('UploadId 已创建:', UploadId);
  65. var Parts = new Array(Math.ceil(fileSize / ChunkSize)).fill(0).map(function (item, index) {
  66. return {PartNumber: index + 1};
  67. });
  68. Async.eachLimit(Parts, 3, function (partItem, nextPart) {
  69. var PartNumber = partItem.PartNumber;
  70. var start = (PartNumber - 1) * ChunkSize;
  71. var end = Math.min(start + ChunkSize);
  72. var blob = file.slice(start, end);
  73. // 上传每个分片
  74. cos.multipartUpload({
  75. Bucket: Bucket,
  76. Region: Region,
  77. Key: Key,
  78. UploadId: UploadId,
  79. PartNumber: PartNumber,
  80. Body: blob,
  81. }, function (err, data) {
  82. if (err) return nextPart(err);
  83. if (!data.headers.etag) return nextPart('浏览器获取不到 ETag Header,需要存储桶配置 CORS ExposeHeaders 允许当前域名跨域读取 ETag 字段。');
  84. partItem.ETag = data.headers.etag || '';
  85. console.log('分片上传完成:', partItem.PartNumber, partItem.ETag);
  86. nextPart();
  87. });
  88. }, function (err) {
  89. if (err) return console.error('上传分片出错:', err);
  90. // 完成分片上传
  91. cos.multipartComplete({
  92. Bucket: Bucket,
  93. Region: Region,
  94. Key: Key,
  95. UploadId: UploadId,
  96. Parts: Parts,
  97. }, function (err, data) {
  98. if (err) return console.error('文件完成出错:', err);
  99. console.log('文件上传成功:', data.Location);
  100. callback(err, data);
  101. });
  102. });
  103. });
  104. };
  105. // 监听表单提交
  106. document.getElementById('submitBtn').onclick = function (e) {
  107. var file = document.getElementById('fileSelector').files[0];
  108. if (!file) {
  109. document.getElementById('msg').innerText = '未选择上传文件';
  110. return;
  111. }
  112. file && uploadFile(file, function (err, data) {
  113. console.log(err || data);
  114. document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
  115. });
  116. };
  117. })();
  118. </script>
  119. </body>
  120. </html>