当前位置: 首页 > news >正文

雅安建设局网站重庆专业做网站公司

雅安建设局网站,重庆专业做网站公司,做网站都去哪申请网址,个人简历html代码目录 中等文件代理服务器放行#xff1a;10MB为单位 proxy nginx 大文件切片#xff1a;100MB为单位 断点#xff1a;存储切片hash 前端方案A localstorage 后端方案B 服务端 上传 前端 后端 下载 前端 后端 多个大文件传输#xff1a;spark-md5 哈希碰撞…目录 中等文件代理服务器放行10MB为单位 proxy nginx 大文件切片100MB为单位 断点存储切片hash 前端方案A localstorage 后端方案B 服务端 上传 前端 后端 下载 前端 后端 多个大文件传输spark-md5 哈希碰撞 总结 Blob.prototype.slice 切片 web-worker 在 worker 线程中用spark-md5 根据文件内容算hash promise.allSettled()并发请求 中等文件代理服务器放行10MB为单位 proxy proxy_buffering来控制是否启用代理缓冲 proxy_buffer_size和proxy_buffers来调整缓冲区的大小 nginx 在nginx.conf配置文件中找到或添加一个 http、server 或 location 块具体位置取决于希望修改的范围。在该块中添加或修改 client_max_body_size 指令 http {     ...     server {         ...         location /upload {             client_max_body_size 100M;             ...         }         ...     }     ... } 检查配置文件是否有语法错误 sudo nginx -t 如果没有报告错误重新加载Nginx以使配置更改生效 sudo systemctl reload nginx React版本见前端文件流、切片下载和上传优化文件传输效率与用户体验 - 掘金 pre 标签可定义预格式化的文本。 pre 标签的一个常见应用就是用来表示计算机的源代码 BlobBinary Large Object对象存储二进制数据 ArrayBuffer 对象类型缓存二进制数据 大文件切片100MB为单位 每个片段大小通常在几百KB到几MB之间 断点存储切片hash 前端方案A localstorage 容量限制 不同浏览器可能有不同的限制但通常容量限制在 5MB 到 10MB 之间。用于存储断点下标够用 遵循同源策略 持久性 关闭后也存在只有用户主动清除浏览器缓存或使用代码删除数据 访问同步在读取或写入大量数据时可能阻塞 数据类型 string 适用场景容量小非敏感持久性数据。如果需要处理更大容量的数据或者需要在不同域之间共享数据可以考虑 IndexedDB 或服务器端存储。 这样下次上传就可以跳过之前已上传的部分有两种方案实现记忆的功能 后端方案B 服务端 前端方案有一个缺陷如果换了个浏览器就localstorage就失效了所以推荐后者 上传 前端 templatedivinput typefile changehandleFileChange /button clickstartUploadStart Upload/button/div /templatescript export default {data() {return {file: null,chunkSize: 1024 * 1024, // 1MBtotalChunks: 0,uploadedChunks: [],};},methods: {handleFileChange(event) {this.file event.target.files[0];},startUpload() {if (this.file) {this.totalChunks this.getTotalChunks();this.uploadedChunks JSON.parse(localStorage.getItem(uploadedChunks)) || [];this.uploadChunks(0);}},uploadChunks(startChunk) {if (startChunk this.totalChunks) {console.log(Upload complete);localStorage.removeItem(uploadedChunks); return;}//模拟每次至多发起5个并发请求实际开发中根据请求资源的限定决定const endChunk Math.min(startChunk 5, this.totalChunks);const uploadPromises [];for (let chunkIndex startChunk; chunkIndex endChunk; chunkIndex) {if (!this.uploadedChunks.includes(chunkIndex)) {const startByte chunkIndex * this.chunkSize;const endByte Math.min((chunkIndex 1) * this.chunkSize, this.file.size);const chunkData this.file.slice(startByte, endByte);const formData new FormData();formData.append(chunkIndex, chunkIndex);formData.append(file, chunkData);uploadPromises.push(fetch(/upload, {method: POST,body: formData,}));}}Promise.allSettled(uploadPromises).then(() {const newUploadedChunks Array.from(new Set([...this.uploadedChunks, ...Array.from({ length: endChunk - startChunk }, (_, i) i startChunk)]));this.uploadedChunks newUploadedChunks;localStorage.setItem(uploadedChunks, JSON.stringify(this.uploadedChunks));this.uploadChunks(endChunk);}).catch(error {console.error(Error uploading chunks:, error);});},getTotalChunks() {return Math.ceil(this.file.size / this.chunkSize);},}, }; /script 后端 const express require(express); const path require(path); const fs require(fs); const multer require(multer); const app express(); const chunkDirectory path.join(__dirname, chunks);app.use(express.json()); app.use(express.static(chunkDirectory));const storage multer.diskStorage({destination: chunkDirectory,filename: (req, file, callback) {callback(null, chunk_${req.body.chunkIndex});}, });const upload multer({ storage });app.post(/upload, upload.single(file), (req, res) {const { chunkIndex } req.body;console.log(Uploaded chunk ${chunkIndex});res.sendStatus(200); });app.listen(3000, () {console.log(Server started on port 3000); }); 下载 前端 templatedivbutton clickstartDownloadStart Download/button/div /templatescript import { saveAs } from file-saver;export default {data() {return {totalChunks: 0,chunkSize: 1024 * 1024, // 默认1MfileNm: file.txt,downloadedChunks: [],chunks: [], // 存储切片数据concurrentDownloads: 5, // 并发下载数量};},methods: {startDownload() {this.fetchMetadata();},fetchMetadata() {fetch(/metadata).then(response response.json()).then(data {this.totalChunks data.totalChunks;this.chunkSize data.chunkSize;this.fileNm data.fileNm;this.continueDownload();}).catch(error {console.error(Error fetching metadata:, error);});},async continueDownload() {const storedChunks JSON.parse(localStorage.getItem(downloadedChunks)) || [];this.downloadedChunks storedChunks;const downloadPromises [];let chunkIndex 0;while (chunkIndex this.totalChunks) {const chunkPromises [];for (let i 0; i this.concurrentDownloads; i) {if (chunkIndex this.totalChunks !this.downloadedChunks.includes(chunkIndex)) {chunkPromises.push(this.downloadChunk(chunkIndex));}chunkIndex;}await Promise.allSettled(chunkPromises);} // 当所有切片都下载完成时 合并切片this.mergeChunks();},downloadChunk(chunkIndex) {return new Promise((resolve, reject) {const startByte chunkIndex * this.chunkSize;const endByte Math.min((chunkIndex 1) * this.chunkSize, this.totalChunks * this.chunkSize);//我不太清楚实际开发中切片是靠idx还是startByte、endByte还是两者都用....fetch(/download/${chunkIndex}?start${startByte}end${endByte}).then(response response.blob()).then(chunkBlob {this.downloadedChunks.push(chunkIndex);localStorage.setItem(downloadedChunks, JSON.stringify(this.downloadedChunks));this.chunks[chunkIndex] chunkBlob; // 存储切片数据resolve();}).catch(error {console.error(Error downloading chunk:, error);reject();});});},mergeChunks() {const mergedBlob new Blob(this.chunks);// 保存合并后的 Blob 数据到本地文件saveAs(mergedBlob, this.fileNm);// 清空切片数据和已下载切片的 localStoragethis.chunks [];localStorage.removeItem(downloadedChunks);},}, }; /script后端 const express require(express); const path require(path); const fs require(fs); const app express(); const chunkDirectory path.join(__dirname, chunks);app.use(express.json());app.get(/metadata, (req, res) {const filePath path.join(__dirname, file.txt); const chunkSize 1024 * 1024; // 1MBconst fileNmfile.txt;const fileStats fs.statSync(filePath);const totalChunks Math.ceil(fileStats.size / chunkSize);res.json({ totalChunks, chunkSize, fileNm }); });app.get(/download/:chunkIndex, (req, res) {const chunkIndex parseInt(req.params.chunkIndex);const chunkSize 1024 * 1024; // 1MBconst startByte chunkIndex * chunkSize;const endByte (chunkIndex 1) * chunkSize;const filePath path.join(__dirname, file.txt); fs.readFile(filePath, (err, data) {if (err) {res.status(500).send(Error reading file.);} else {const chunkData data.slice(startByte, endByte);res.send(chunkData);}}); });app.listen(3000, () {console.log(Server started on port 3000); });多个大文件传输spark-md5 MD5Message Digest Algorithm 5哈希函数 若使用 文件名 切片下标 作为切片 hash这样做文件名一旦修改就失去了效果 所以应该用spark-md5根据文件内容生成 hash webpack 的contenthash 也是基于这个思路实现的 另外考虑到如果上传一个超大文件读取文件内容计算 hash 是非常耗费时间的并且会引起 UI 的阻塞导致页面假死状态所以我们使用 web-worker 在 worker 线程计算 hash这样用户仍可以在主界面正常的交互 // /public/hash.js// 导入脚本 self.importScripts(/spark-md5.min.js);// 生成文件 hash self.onmessage e {const { fileChunkList } e.data;const spark new self.SparkMD5.ArrayBuffer();let percentage 0;let count 0;// 递归加载下一个文件块const loadNext index {const reader new FileReader();reader.readAsArrayBuffer(fileChunkList[index].file);reader.onload e {count;spark.append(e.target.result);// 检查是否处理完所有文件块if (count fileChunkList.length) {self.postMessage({percentage: 100,hash: spark.end()});self.close();} else {// 更新进度百分比并发送消息percentage 100 / fileChunkList.length;self.postMessage({percentage});// 递归调用以加载下一个文件块loadNext(count);}};};// 开始加载第一个文件块loadNext(0); };切片hash/传输等目的都是为了 内存效率 对于大文件一次性将整个文件加载到内存中可能会导致内存占用过高甚至造成浏览器崩溃。通过将文件切成小块在处理过程中只需要操作单个块减小了内存的压力。 性能优化 如果直接将整个文件传递给哈希函数可能会导致计算时间较长尤其是对于大文件。分成小块逐个计算哈希值可以并行处理多个块提高计算效率。 错误恢复 在上传或下载过程中网络中断或其他错误可能会导致部分文件块没有传输成功。通过分块计算哈希你可以轻松检测到哪些块没有正确传输从而有机会恢复或重新传输这些块。 // 生成文件 hashweb-worker calculateHash(fileChunkList) {return new Promise(resolve {// 创建一个新的 Web Worker并加载指向 hash.js 的脚本this.container.worker new Worker(/hash.js);// 向 Web Worker 发送文件块列表this.container.worker.postMessage({ fileChunkList });// 当 Web Worker 发送消息回来时触发的事件处理程序this.container.worker.onmessage e {const { percentage, hash } e.data;// 更新 hash 计算进度this.hashPercentage percentage;if (hash) {// 如果计算完成解析最终的 hash 值resolve(hash);}};}); },// 处理文件上传的函数 async handleUpload() {if (!this.container.file) return;// 将文件划分为文件块列表const fileChunkList this.createFileChunk(this.container.file);// 计算文件 hash并将结果存储在容器中this.container.hash await this.calculateHash(fileChunkList);// 根据文件块列表创建上传数据对象this.data fileChunkList.map(({ file, index }) ({fileHash: this.container.hash,chunk: file,hash: this.container.file.name - index,percentage: 0}));// 上传文件块await this.uploadChunks(); }哈希碰撞 输入空间通常大于输出空间无法完全避免碰撞 哈希(A) 21 % 10 1 哈希(B) 31 % 10 1 所以spark-md5 文档中要求传入所有切片并算出 hash 值不能直接将整个文件放入计算否则即使不同文件也会有相同的 hash 总结 Blob.prototype.slice 切片 web-worker 在 worker 线程中用spark-md5 根据文件内容算hash promise.allSettled()并发请求 面试官桀桀一笑你没做过大文件上传功能那你回去等通知吧 - 掘金
http://www.zqtcl.cn/news/666000/

相关文章:

  • 哪个餐饮店微网站做的有特色3d动画制作收费标准
  • h5旅游网站开发wordpress的站点地址如何配置
  • 网站正在维护中 模板招远网站建设
  • 福田欧曼银河报价seo文章是什么
  • 古云网站建设模具培训网站建设
  • 帮助企业做网站的销售卫浴洁具公司网站模板
  • 解释seo网站推广网站域名和空间费用
  • 深圳市珠宝网站建设手机网站框架
  • 晋城推广型网站开发dw做网站模板
  • 万网一个ip建立多个网站网页设计注册页面代码
  • 网站建设6000元地方门户网站有哪些
  • 十大SEO网站外链建设误区排版设计教程入门初学者
  • 网站基本维护网站设计软件下载
  • 网站开发的需求文档大型网站外链是怎么建设的
  • 网站建设实训心得与建议网站建设一般需要多少费用
  • 国内怎么打开WordPress网站wordpress制作api文件路径
  • 义乌网站开发公司wordpress段子模板
  • 国外有没有专门做靶材的网站做网站用哪个电脑
  • 郑州网站制作郑州网站制作上海网站建设免费推荐
  • php电子商务网站开发建设企业网站都需要啥
  • 从零学做网站如何让客户做网站
  • 关于销售网站建设的短文菜单宣传网站怎么做
  • 学网站开发有前途吗淮南服装网站建设费用
  • 网站外包附近临时工500元一天
  • 国外做logo的网站深圳有哪些软件外包公司
  • 网站加载流量一键生成app软件下载
  • 如何建设网站知乎襄阳做网站公司哪家好
  • 用ai怎么做网站专门做短视频的公司
  • 陶瓷类网站建设免费会员管理软件
  • 网站建设 用户管理一个服务器多个网站好吗