当前位置:   article > 正文

前端大文件上传 -- 上传文件到S3或本地服务器_前端分片上传s3

前端分片上传s3

特别提醒

大文件上传的文件切片逻辑, 包括如何将分片文件上传到本地服务器, 请查看之前的文章: 前端大文件上传 - 总结(Vue3 + hook + Web Worker实现,通过多个Worker线程大大提高Hash计算的速度), 本篇仅实现如何将大文件分块上传到S3.
后面写一篇文章实现选中多个文件,显示上传列表可取消上传,以及整合这两篇文件到一篇里,因为涉及的逻辑比较多

流程图

请添加图片描述

实现逻辑

上节的代码实现中的 uploadFile 函数,我们只需要在对应的代码中添加 加粗样式就行

// 例如下面
async function uploadFile() {
	const data = await checkFile()
	if (!data) return

	const { chunk_upload, upload_id } = data
	uploadId.value = upload_id

	if (chunk_upload.length === 0) {
		// 上传整个文件
		// 上传到S3
		if (isS3) return await handleUploadS3Request()
	}
	
	if (chunk_upload.length !== chunkTotal.value) {
		// 上传未上传的分片 - 断点续传
		if (isS3) return await handleUploadS3Request(chunk_upload)
	}

	// 无论是上传到S3还是本地服务器可能存在合并失败的问题
	// 这里应该处理未合并的情况,值需要发送合并请求
	code...
	
	// 上传完成 - 秒传(可能需要发起合并请求)
	code...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
handleUploadS3Request函数

提醒: 获取ETag需要配置对应的桶策略,ExposeHeaders数组里配置ETag

// 记录上传到S3的分块
	const s3UploadedChunks = ref([])

// 上传到S3
	async function handleUploadS3Request(uploadedChunks = []) {
		s3UploadedChunks.value = JSON.parse(JSON.stringify(uploadedChunks))

		for (let i = 0; i < fileChunkList.value.length; i++) {
			if (uploadedChunks.indexOf(i + 1) === -1) {
				// 申请上传S3的url
				const { code, data, msg } = await applyS3UrlFn({
					part_no: i + 1,
					upload_id: uploadId.value,
				})

				if (code === 0) {
					try {
						await uploadS3Chunk(data.signed_url, i)
					} catch (error) {
						// 上传失败
						...
						return false
					}
				} else {
					// 申请失败
					...
					return false
				}
			}
		}
	}

	// 上传S3文件某个分块
	async function uploadS3Chunk(url, i) {
		const etag = await createXhr(url, i)

		// 记录已上传的分块
		s3UploadedChunks.value.push(i + 1)
		// 上传S3文件某个分块完成
		await s3ChunkDoneFn({
			part_no: i + 1,
			upload_id: uploadId.value,
			etag,
		})

		if (s3UploadedChunks.value.length === chunkTotal.value) {
			// 上传S3文件所有分块完成
			await s3AllChunkDoneFn({ upload_id: uploadId.value })
			// 上传成功
			callback && callback()
		}
	}

	let xhr = null
	// 使用XMLHttpRequest上传Chunk
	async function createXhr(url, i) {
		return new Promise((resolve, reject) => {
			xhr = new XMLHttpRequest()
			xhr.open('PUT', url)

			xhr.upload.onprogress = (e) => {
				getFileProgress(e, i)
			}

			xhr.onload = () => {
				if (xhr.status === 200) {
					// 返回ETag
					resolve(xhr.getResponseHeader('ETag'))
				} else {
					reject(new Error('File upload failed'))
				}
			}

			xhr.onerror = () => {
				reject(new Error('File upload failed'))
			}

			xhr.onabort = () => {
				cancelFn({ upload_id: uploadId.value })
				reject(new Error('File upload aborted'))
			}

			xhr.send(fileChunkList.value[i])
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/707158
推荐阅读
相关标签
  

闽ICP备14008679号