网站index.php被修改,网站建设的大公司好,做新得网站可以换到原来得域名嘛,免费正版高清素材库切片上传的原理是#xff1a;
1.因为file对象的基类是blob#xff0c;所以可以使用slice分割
2.将从input中获取的file对象使用slice进行分割#xff0c;每5M一片
3.分别上传各个切片#xff0c;等待切片上传完通知服务端合并#xff08;或者传每一片时把切片总数量也传…切片上传的原理是
1.因为file对象的基类是blob所以可以使用slice分割
2.将从input中获取的file对象使用slice进行分割每5M一片
3.分别上传各个切片等待切片上传完通知服务端合并或者传每一片时把切片总数量也传递过去让服务端自行合并
断点续传原理
切片上传完成之后将上传完的索引放到localStrage上再次上传时判断是否上传如果已经上传了则跳过这一片 实现代码
这里是主进程
import { getFileId } from ./utils/FileUtils
import { getLocalStrage, setLocalStrage, removeLocalStrage } from ./utils/localStrage
const worker new Worker(new URL(./uploadWorker.js, import.meta.url))// 监听WebWorker的消息
worker.onmessage (e) {const { type, data, filename, fileId, uploadInfo } e.dataif (type progress) {document.getElementById(progress).innerHTML 当前上传进度${data}%// 更新切片上传日志setLocalStrage(fileId, JSON.stringify(uploadInfo))} else if (type complete) {document.getElementById(progress).innerHTML 上传完毕worker.postMessage({type: merge,filename: filename,})// 移除切片上传日志removeLocalStrage(fileId)}
}// 监控用户上传数据
const upload document.getElementById(fileInput)upload?.addEventListener(change, async (e) {const file e?.target?.files?.[0]const fileId await getFileId(file)const infoLocal getLocalStrage(fileId)const uploadInfo infoLocal ? JSON.parse(infoLocal) : {fileId: fileId,fileName: file.name,uploadedChunks: [],}worker.postMessage({type: upload,file,fileId: fileId,uploadInfo: uploadInfo})
})这里是工作进程
const CHUNK_SIZE 1024 * 1024 * 5 // 5MBlet uploadInfo null;// 建通主线程的消息
self.onmessage (e) {console.log(收到主线程的消息)const { type, file, filename, fileId, uploadInfo: uploadInfoLocal } e.dataif (type upload) {// 初始化上传信息uploadInfo uploadInfoLocal// 开始上传文件uploadFile(file, fileId)} else if (type merge) {mergeFile(filename)}
}// 切片上传文件
function uploadFile(file, fileId) {const fileName file.name// 获取thunk的数量const chunksCount Math.ceil(file.size / CHUNK_SIZE)// 获取切片数据const chunks getChunks(file)uploadQueueChunks(chunks, fileName, chunksCount, fileId)
}/*** 获取切片数据* param file * returns */
function getChunks(file) {const chunks []for(let i 0; i file.size; i CHUNK_SIZE) {chunks.push(file.slice(i, i CHUNK_SIZE))}return chunks
}/*** 上传队列* param chunks 切片数据* param fileName 文件名* param chunksCount 总切片数* param maxConcurrency 最大并发数*/
async function uploadQueueChunks(chunks, fileName, chunksCount, fileId, maxConcurrency 5) {// 正在上传的队列const queue []// 正在上传的文件数量let activeUploads 0// 遍历上传切片for(let i 0; i chunks.length; i) {// 如果上传过了就直接跳过if(uploadInfo.uploadedChunks.indexOf(i) -1) {console.log(第${i}片已经上传过了)continue}const chunk chunks[i]// 判断当前上传队列是否达到最大并发if(activeUploads maxConcurrency) {// 等待队列中上传完成await Promise.race(queue)}// 上传切片const uploadPromise uploadedChunk(chunk, i, fileName, chunksCount).then(res {// 上传完成从队列中移除queue.splice(queue.indexOf(uploadPromise), 1)// 更新上传信息uploadInfo.uploadedChunks.push(i)// 减少正在上传的数量activeUploads--// 发送上传进度self.postMessage({type: progress,data: Math.round((uploadInfo.uploadedChunks.length / chunksCount) * 100),filename: fileName,uploadInfo: uploadInfo,fileId});})queue.push(uploadPromise)activeUploads}await Promise.all(queue)// 发送完成通知self.postMessage({type: complete,filename: fileName,fileId});
}/*** 上传切片数据* param thunk 切片数据* param index 切片索引* param name 文件名* param total 总切片数*/
function uploadedChunk(thunk, index, name, total) {console.log(上传第${index}片)const formData new FormData()formData.append(file, thunk)formData.append(index, index.toString())formData.append(filename, name)formData.append(totalChunks, total)return fetch(http://localhost:3000/upload, {method: POST,body: formData})
}function mergeFile(filename) {console.log(开始合并文件${filename})return fetch(http://localhost:3000/merge, {method: POST,headers: {Content-Type: application/json},body: JSON.stringify({ filename })})
}
这里是工具类
/*** 获取文件唯一ID* param {*} file * returns */
export async function getFileId(file) {const buffer await file.arrayBuffer();const hashBuffer await crypto.subtle.digest(SHA-256, buffer);const hashArray Array.from(new Uint8Array(hashBuffer));return hashArray.map(byte byte.toString(16).padStart(2, 0)).join();}export function getLocalStrage(fileId) {return localStorage.getItem(fileId);
}export function setLocalStrage(fileId, data) {return localStorage.setItem(fileId, data);
}export function removeLocalStrage(fileId) {return localStorage.removeItem(fileId);
}文件目录是这样的 就能实现下面的效果: