尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
大文件分片上传实战:Blob切片、秒传与断点续传五层追问
1. 大文件分片上传到底在解决什么问题1.1 从一个真实场景说起去年帮一个做在线教育的朋友处理课件上传的问题他们平台允许老师上传录播视频单个文件动辄两三个G。最开始用的是最朴素的方式——一个FormData把整个文件塞进去axios发一个 POST 请求完事。小文件没问题但一到大文件就各种翻车浏览器内存直接飙到几个G页面卡死网络稍微抖一下传到 80% 断了用户得从头再来后端那边 Nginx 默认client_max_body_size只有 1M直接给你返回 413。后来我们把方案换成了分片上传问题基本都解决了。这篇文章就把这套方案从底层原理到落地细节完整拆一遍我把它总结成五层追问一层一层往下挖每一层都对应一个实际开发中绕不开的问题。如果你正在做文件上传相关的功能或者面试被问到大文件上传怎么实现这篇应该能帮你把思路理顺。核心关键词先摆出来Blob 切片、分片上传、秒传、断点续传、弱网容错。这几个词不是孤立的它们是一条链上的不同环节理解了它们之间的关系整个方案就通了。1.2 为什么不能直接传整个文件先说清楚为什么不然方案就是空中楼阁。浏览器上传文件本质是把文件读成二进制数据通过 HTTP 请求体发给服务端。一个 2G 的文件如果一次性读进内存FileReader或者FormData会尝试把它整个加载到内存里。现代浏览器单个标签页的内存上限大概在 1.5G 到 4G 之间取决于设备和浏览器一个 2G 的文件加上页面本身的开销很容易触发内存溢出页面直接崩溃。就算内存扛得住网络层面也扛不住。HTTP 请求一旦发出中途断网、切换 WiFi、服务端超时整个请求就废了没有续传的概念。而且大文件传输时间长用户等待体验极差进度条走到一半卡住是常态。分片上传的思路很直接把大文件切成一个个小块比如 5MB 一片逐片上传服务端收齐后合并。这样做的好处是单次请求体积小内存压力小某一片失败只重传那一片不用重头来配合并发上传还能提速。这就是整个方案的起点。1.3 五层追问的框架我把这套方案拆成五层每一层解决一个核心问题层级核心问题关键技术第一层怎么把文件切开Blob.slice / File 对象第二层怎么保证切得对、合得对分片策略、哈希校验、合并顺序第三层怎么避免重复上传秒传、文件指纹第四层断了怎么接着传断点续传、进度持久化第五层网络差怎么办弱网容错、重试、并发控制下面一层一层展开。2. 第一层追问Blob 切片到底是怎么切的2.1 Blob 和 File 的关系很多人分不清Blob和File。简单说File继承自Blob是Blob的一个特例。Blob表示一段不可变的二进制数据File在此基础上多了name、lastModified这些元信息。你在input typefile里拿到的file对象就是一个File它同时也是一个Blob。关键点在于Blob是不可变的你不能直接修改它但可以基于它切出新的Blob。这就是分片的基础。// 拿到文件对象 const file document.querySelector(#fileInput).files[0]; // 切第一片从 0 到 5MB const chunk file.slice(0, 5 * 1024 * 1024); console.log(chunk instanceof Blob); // true console.log(chunk.size); // 5242880slice方法接收两个参数起始字节和结束字节不含。返回一个新的Blob指向原文件的一段。注意这个操作是零拷贝的——它不会真的把数据复制一份到内存只是创建了一个指向原数据的引用。所以切 1000 片也不会额外占用 1000 份内存这一点很关键。2.2 切片大小的选择切片大小不是随便定的它直接影响上传效率和成功率。我踩过的坑是一开始设成 1MB结果一个 2G 的文件切出 2000 片请求数太多浏览器并发连接数有限HTTP/1.1 下同域名一般 6 个大量请求排队反而慢。后来改成 5MB效果好很多。但 5MB 也不是万能。如果用户网络很差5MB 一片传半天超时风险高。如果网络很好5MB 又偏小请求数还是多。我的经验是默认 5MB适合大多数场景兼顾请求数和单次传输时间。弱网环境降到 1MB 到 2MB减少单片超时概率。内网或高速环境可以到 10MB 到 20MB减少请求数。还有一个动态策略根据前几片的平均上传耗时动态调整后续分片大小。这个后面讲弱网容错时再展开。const DEFAULT_CHUNK_SIZE 5 * 1024 * 1024; // 5MB function createChunks(file, chunkSize DEFAULT_CHUNK_SIZE) { const chunks []; let start 0; while (start file.size) { const end Math.min(start chunkSize, file.size); chunks.push({ index: chunks.length, blob: file.slice(start, end), start, end, }); start end; } return chunks; }这段代码把文件切成若干片每片记录了索引和字节范围。索引很重要服务端合并时要靠它排序。2.3 为什么不用 ArrayBuffer 直接切有人会问为什么不把文件读成ArrayBuffer再切因为ArrayBuffer是真正把数据加载到内存里的一个 2G 文件读成ArrayBuffer直接爆内存。而Blob.slice是惰性的只有真正发送请求时浏览器才会去读对应那段数据。这是Blob相比ArrayBuffer的核心优势。ArrayBuffer适合的场景是你需要对二进制数据做处理比如加密、压缩、计算哈希。计算文件哈希时我们确实会用到ArrayBuffer但也是分片读取的不会一次性读整个文件。提示Blob.slice的零拷贝特性是分片上传能成立的前提。如果你用ArrayBuffer一次性读整个文件分片就失去意义了。3. 第二层追问分片怎么保证切得对、合得对3.1 分片元数据的设计光把文件切开还不够每一片都得带上足够的元信息服务端才知道这片属于哪个文件、排在第几位。我设计的分片请求体大概是这样const formData new FormData(); formData.append(file, chunk.blob); formData.append(fileHash, fileHash); // 整个文件的唯一标识 formData.append(chunkIndex, chunk.index); // 当前片索引 formData.append(totalChunks, chunks.length); // 总片数 formData.append(chunkSize, chunk.blob.size); // 当前片大小fileHash是整个文件的指纹用来区分不同文件也是秒传的基础。chunkIndex是排序依据。totalChunks让服务端知道收齐了没有。chunkSize用于校验防止传输过程中数据损坏。3.2 文件哈希怎么算才不卡计算文件哈希是分片上传里最容易被忽视的性能陷阱。如果你用crypto.subtle.digest一次性读整个文件算 SHA-2562G 的文件能把页面卡死好几秒甚至十几秒。用户点了上传页面直接无响应体验极差。正确做法是分片读取、增量计算。但浏览器原生的crypto.subtle.digest不支持增量它只能一次性算完。所以实际项目中我们通常用spark-md5这类库它支持分片增量计算。import SparkMD5 from spark-md5; function calculateHash(file, chunkSize 5 * 1024 * 1024) { return new Promise((resolve) { const spark new SparkMD5.ArrayBuffer(); const reader new FileReader(); const chunks Math.ceil(file.size / chunkSize); let currentChunk 0; reader.onload (e) { spark.append(e.target.result); currentChunk; if (currentChunk chunks) { loadNext(); } else { resolve(spark.end()); } }; function loadNext() { const start currentChunk * chunkSize; const end Math.min(start chunkSize, file.size); reader.readAsArrayBuffer(file.slice(start, end)); } loadNext(); }); }这段代码逐片读取文件把每片的ArrayBuffer喂给spark-md5最后得到一个完整的 MD5。整个过程是异步的不会阻塞主线程太久。即便如此2G 文件算下来也要几秒所以实际项目中我会加一个进度提示让用户知道正在计算文件指纹。3.3 采样哈希用部分数据换速度如果对哈希精度要求没那么高可以用采样哈希——只取文件头、中、尾各一段数据算哈希。这样速度快很多但碰撞概率会上升。我的做法是文件小于 100MB 用全量哈希大于 100MB 用采样哈希头 2MB 中间 2MB 尾 2MB。function sampleHash(file) { const sampleSize 2 * 1024 * 1024; const chunks []; chunks.push(file.slice(0, sampleSize)); chunks.push(file.slice(Math.floor(file.size / 2), Math.floor(file.size / 2) sampleSize)); chunks.push(file.slice(file.size - sampleSize)); // 把这三段拼起来算哈希 // ... }采样哈希的碰撞概率在实际业务中是可以接受的因为文件名、大小、修改时间这些元信息也可以一起参与判断。但如果你做的是网盘类产品对秒传准确性要求极高还是老老实实全量哈希。3.4 服务端合并的顺序问题服务端收到所有分片后要按chunkIndex顺序合并。这里有个坑如果并发上传分片到达服务端的顺序是乱的。所以服务端不能按到达顺序追加必须按索引排序后再合并。常见的做法是每个分片存成独立文件命名带上索引比如fileHash_0、fileHash_1合并时按索引排序读取。或者用流式合并维护一个有序的写入流。MinIO 这类对象存储提供了分片上传的原生支持uploadId加partNumber的机制服务端会自动按 partNumber 合并省去自己排序的麻烦。注意合并前一定要校验分片完整性。我遇到过因为网络问题导致某片数据损坏合并出来的文件打不开的情况。校验方式可以是比对分片大小或者对每片算一个 CRC32。4. 第三层追问秒传是怎么实现的4.1 秒传的本质是查重秒传听起来很神奇其实原理很简单上传前先拿文件哈希去服务端问一句这个文件你有了吗如果有直接返回文件地址不用传了。本质就是一次查重。async function checkFileExists(fileHash, fileName) { const res await fetch(/api/upload/check, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ fileHash, fileName }), }); return res.json(); // { exists: true, url: ... } }服务端维护一张表记录每个已上传文件的哈希和存储路径。收到 check 请求查表命中就返回已存在的地址。4.2 秒传的边界情况秒传不是万能的有几个边界情况必须处理第一哈希碰撞。不同文件算出相同哈希的概率极低但不是零。所以服务端命中后最好再比对一下文件大小双重确认。第二文件被删了但记录还在。如果用户删了文件但数据库记录没清秒传会返回一个失效的地址。所以删除文件时要同步清理记录或者秒传命中后校验一下实际文件是否存在。第三权限问题。A 用户上传的文件B 用户秒传命中但 B 没有权限访问 A 的文件。这种情况要么做文件去重但权限独立要么秒传只对同一用户生效。网盘类产品通常用引用计数的方式多个用户引用同一份物理文件各自有独立的逻辑记录。第四分片上传中途的秒传。用户传了一半断了重新上传时除了检查整个文件是否存在还要检查已上传了哪些分片。这就是断点续传要解决的问题下一层展开。4.3 秒传的收益与代价秒传的收益很直观热门文件比如公司内部共享的模板、课程视频第二次上传瞬间完成节省带宽和时间。但代价是每次上传前都要算哈希大文件算哈希本身就要几秒。所以秒传和哈希计算是一对矛盾不算哈希没法秒传算哈希又要等。我的优化策略是小文件小于 10MB直接算全量哈希反正快大文件先算采样哈希做初步判断如果采样哈希命中再算全量哈希确认。这样大部分秒传场景都能快速命中少数需要确认的才走全量。5. 第四层追问断点续传怎么记住传到哪里了5.1 断点续传的两个层面断点续传分两个层面服务端记住收了哪些片客户端记住传了哪些片。两者要配合。服务端层面每收到一片就记录一下比如在 Redis 里存一个 Setkey 是fileHashvalue 是已收到的chunkIndex集合。客户端重新上传前先问服务端哪些片你已经有了然后只传缺的那些。async function getUploadedChunks(fileHash) { const res await fetch(/api/upload/uploaded?fileHash${fileHash}); const data await res.json(); return new Set(data.uploadedIndexes); // [0, 1, 2, 5, 6] }客户端拿到已上传的索引集合过滤掉这些片只传剩下的。const uploaded await getUploadedChunks(fileHash); const pendingChunks chunks.filter(c !uploaded.has(c.index));5.2 客户端进度持久化服务端记录是权威的但客户端也可以做一层本地缓存减少查询。比如用localStorage存一下当前文件的已传片索引刷新页面后先读本地再和服务端对一下。// 存 localStorage.setItem(upload_${fileHash}, JSON.stringify([...uploadedIndexes])); // 读 const local JSON.parse(localStorage.getItem(upload_${fileHash}) || []);但本地缓存不可靠用户换设备、清缓存就没了。所以最终还是要以服务端为准。本地缓存只是加速不能作为唯一依据。5.3 分片上传的幂等性断点续传要求分片上传是幂等的同一片传多次结果应该一样。服务端收到重复的分片应该覆盖而不是追加。这样客户端重试时不用担心重复。实现上服务端存分片时用fileHash chunkIndex作为唯一键重复写入直接覆盖。合并时按索引读天然去重。5.4 一个容易忽略的坑文件变了但哈希没变如果用户上传到一半把文件改了比如用编辑器保存了一下文件内容变了但文件名没变。这时候如果还用原来的哈希续传合并出来的文件就是错的。解决办法是续传前重新算一次哈希和上次的比对。如果变了清空已传分片重新开始。这个逻辑听起来简单但实际项目中很容易漏掉导致用户拿到一个损坏的文件。提示断点续传的前提是文件内容不变。文件一旦变化哈希就变续传必须作废。这个校验不能省。6. 第五层追问弱网环境下怎么保证传得完6.1 弱网的典型表现弱网不是网速慢这么简单它有几个典型表现高延迟、高丢包、连接不稳定、带宽波动大。在这种环境下分片上传会遇到单片超时、请求失败、连接中断、上传速度忽快忽慢。我实测过在地铁里上传文件4G 信号时有时无5MB 的片经常传到一半断掉。后来把片降到 1MB成功率明显提升。这就是弱网容错的第一个策略动态调整分片大小。6.2 重试机制的设计重试不是简单地失败了再试一次要有策略第一重试次数限制。无限重试会卡死。一般设 3 次超过就标记该片失败让用户决定是否继续。第二退避策略。第一次失败后等 1 秒重试第二次等 2 秒第三次等 4 秒。指数退避避免瞬间大量重试压垮服务端。第三区分错误类型。网络错误超时、断连可以重试业务错误文件格式不对、权限不足重试没用直接报错。async function uploadChunkWithRetry(chunk, maxRetry 3) { for (let i 0; i maxRetry; i) { try { return await uploadChunk(chunk); } catch (err) { if (i maxRetry - 1) throw err; if (!isRetryable(err)) throw err; await sleep(Math.pow(2, i) * 1000); // 1s, 2s, 4s } } }6.3 并发控制与动态调速并发上传能提速但并发太高会适得其反。浏览器对同域名并发连接数有限制而且弱网下并发太高会导致每个请求都慢。我的做法是默认并发 3 到 4 个根据网络状况动态调整。如果连续几片都很快提高并发如果频繁超时降低并发。class UploadPool { constructor(concurrency 3) { this.concurrency concurrency; this.running 0; this.queue []; } async add(task) { if (this.running this.concurrency) { await new Promise(resolve this.queue.push(resolve)); } this.running; try { return await task(); } finally { this.running--; if (this.queue.length) this.queue.shift()(); } } }这个简单的并发池能控制同时进行的请求数。配合动态调整concurrency就能适应不同的网络环境。6.4 超时与心跳弱网下请求可能长时间没响应。设置合理的超时时间很重要。太短了正常请求也被砍太长了卡住不动。我的经验是单片超时设为分片大小 / 最低预期速度。比如 5MB 的片最低预期 100KB/s超时就是 50 秒。另外长连接可以加心跳定期发个空请求确认连接还活着。如果心跳失败主动断开重连而不是等超时。6.5 弱网容错的整体策略表问题策略参数建议单片超时减小分片弱网降到 1MB请求失败指数退避重试3 次1s/2s/4s并发过高动态降并发默认 3弱网降到 1连接中断心跳检测每 10s 一次速度波动动态调速根据历史耗时调整7. 完整实操从零搭一个分片上传7.1 前端整体流程把前面的东西串起来前端流程大概是用户选文件拿到File对象。计算文件哈希大文件用采样哈希。调 check 接口命中秒传直接结束。没命中调 uploaded 接口拿已传分片。切片过滤掉已传的剩下的进并发池上传。每片上传成功更新进度持久化已传索引。全部传完调 merge 接口合并。合并成功拿到文件地址。async function uploadFile(file) { const fileHash await calculateHash(file); // 秒传检查 const checkRes await checkFileExists(fileHash, file.name); if (checkRes.exists) { return checkRes.url; } // 断点续传检查 const uploaded await getUploadedChunks(fileHash); const chunks createChunks(file); const pending chunks.filter(c !uploaded.has(c.index)); // 并发上传 const pool new UploadPool(3); const uploadedIndexes new Set(uploaded); await Promise.all(pending.map(chunk pool.add(async () { await uploadChunkWithRetry(chunk, fileHash); uploadedIndexes.add(chunk.index); updateProgress(uploadedIndexes.size / chunks.length); localStorage.setItem(upload_${fileHash}, JSON.stringify([...uploadedIndexes])); }) )); // 合并 const mergeRes await mergeChunks(fileHash, chunks.length, file.name); localStorage.removeItem(upload_${fileHash}); return mergeRes.url; }7.2 服务端接口设计服务端需要四个接口接口方法作用/api/upload/checkPOST秒传检查/api/upload/uploadedGET查询已传分片/api/upload/chunkPOST上传单个分片/api/upload/mergePOST合并分片分片存储可以用本地磁盘也可以用 MinIO 这类对象存储。MinIO 原生支持分片上传uploadId机制能省不少事。如果用本地磁盘就按fileHash/chunkIndex存合并时按索引排序读取拼接。// 合并逻辑Node.js 示例 async function mergeChunks(fileHash, totalChunks, fileName) { const dir path.join(UPLOAD_DIR, fileHash); const targetPath path.join(FILE_DIR, fileName); const writeStream fs.createWriteStream(targetPath); for (let i 0; i totalChunks; i) { const chunkPath path.join(dir, String(i)); const data await fs.promises.readFile(chunkPath); writeStream.write(data); } writeStream.end(); // 清理分片目录 await fs.promises.rm(dir, { recursive: true }); return targetPath; }7.3 进度与状态管理上传过程中用户最关心的是进度。进度分两种已传片数 / 总片数和已传字节数 / 总字节数。前者更平滑后者更精确。我一般两个都显示主进度用字节数。状态管理上每个文件维护一个状态对象pending、uploading、paused、success、failed。用户暂停时把状态改成paused正在传的片传完就停不再发新请求。恢复时从paused回到uploading继续传剩下的。8. 常见问题与排查技巧实录8.1 上传到 99% 卡住不动这是最经典的问题。原因通常是最后一片传完了但 merge 接口没调成功或者 merge 本身很慢大文件合并要时间。排查思路先看网络面板merge 请求发出去了没有发出去了看响应时间如果很久是服务端合并慢如果没发出去是前端逻辑问题检查 merge 的触发条件。我的优化merge 改成异步任务接口立即返回合并中前端轮询合并状态。这样不会因为 merge 超时导致整个上传失败。8.2 分片顺序错乱导致文件损坏前面提过并发上传时到达顺序是乱的。如果服务端按到达顺序追加文件就废了。排查方法合并后比对文件哈希和上传前的哈希不一致就是顺序问题。解决就是按索引排序合并。8.3 内存泄漏分片上传如果处理不当会有内存泄漏。常见原因是FileReader的onload回调里持有大对象引用没释放或者并发池的任务队列无限增长。排查用 Chrome 的 Memory 面板看上传过程中内存是否持续上升不下降。解决就是及时释放引用控制队列长度。8.4 常见问题速查表现象可能原因排查方向解决99% 卡住merge 超时看 merge 请求改异步合并文件损坏分片顺序错比对哈希按索引排序内存飙升引用未释放Memory 面板释放引用秒传不生效哈希不一致比对前后哈希统一哈希算法弱网频繁失败分片太大看超时日志减小分片重复上传幂等没做看服务端日志唯一键覆盖8.5 几个独家避坑技巧技巧一哈希算法前后端要一致。前端用spark-md5后端也得用 MD5别一个 MD5 一个 SHA-256对不上。技巧二分片大小要能被文件大小整除吗不需要。最后一片可以小一点服务端合并时按实际大小读就行。技巧三上传前先探测网络。发一个小请求测一下延迟和带宽据此决定初始分片大小和并发数。比盲目用默认值强。技巧四进度条别用假动画。有些项目进度条是匀速动画实际进度对不上用户看着到 100% 了结果还在传。老老实实按真实进度走。技巧五失败的分片要能单独重试。不要整个文件重来只重试失败的那几片。这能省大量时间。9. 一些延伸思考分片上传这套方案往深了挖还有很多可以优化的点。比如多线程下载其实是分片上传的逆过程——服务端支持 Range 请求客户端并发下载不同片段再拼接。理解了上传的分片逻辑下载的分片逻辑也就通了。再比如把 Blob URL 转成 File这是另一个常见需求。URL.createObjectURL生成的 Blob URL 是个临时地址想把它转回 File 对象可以用fetch(blobUrl).then(res res.blob())再包一层 File 构造函数。这个技巧在处理图片预览、裁剪后上传时很有用。还有ArrayBuffer 和 Blob 的互转Blob转ArrayBuffer用blob.arrayBuffer()ArrayBuffer转Blob用new Blob([arrayBuffer])。这两个转换在加密、压缩场景下经常用到。我个人在实际项目中的体会是分片上传的难点不在切和传而在容错和状态管理。把断点续传、秒传、弱网重试这三块做扎实整个方案就稳了。至于分片大小、并发数这些参数没有银弹得根据实际网络环境和用户场景调。我一般会留一个配置面板方便线上动态调整比改代码重新发版灵活得多。最后分享一个小技巧上传日志一定要打全每片的开始时间、结束时间、耗时、重试次数都记下来。出了问题看日志比猜快得多。这套日志在优化分片策略时也是宝贵的数据来源。
RELATED

相关推荐

C# HttpClient跳过HTTPS证书验证的三种写法与踩坑指南

C# HttpClient跳过HTTPS证书验证的三种写法与踩坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/19 18:18:42
EG2153反激电源设计:自举供电与驱动电路调试技巧

EG2153反激电源设计:自举供电与驱动电路调试技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/19 18:18:42
Ollama本地部署:5分钟快速搭建大模型环境

Ollama本地部署:5分钟快速搭建大模型环境

1. 五分钟快速上手Ollama本地部署刚接触大模型时,很多人都会被复杂的部署流程劝退。今天分享一个实测有效的极简方案——用Ollama在本地快速搭建大模型运行环境。这个方案特别适合想快速体验大模型能力的新手,整个过程就像安装普通软件一样简单。Ollama是…

📅 2026/9/19 18:18:42
MORE NEWS

更多资讯

📰

ASTM A640标准文件识别与工程应用核验指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

FPGA新手入门:从点亮LED开始掌握Vivado与Verilog开发全流程

1. 为什么我建议每个FPGA新手都从点亮LED开始如果你刚拿到一块FPGA开发板,打开Vivado或者Quartus,面对满屏幕的选项和陌生的术语,大概率会有点懵。我见过太多人卡在第一步——软件装好了,板子插上了,然后呢&#xff1f…

📰

SPSS多元线性回归实例:从截图到语法复现与结果解读

简介:这份PDF面向备考统计类考试、需要掌握多元线性回归实操的读者,以SPSS软件为工具,通过完整实例演示从数据输入到结果解释的全流程。资源共1个PDF文件,压缩包约7.91MB,内容以操作截图为主,直观呈现SPSS界…

📰

OneUptime Runbook 代理(Agent)完全指南:在自建基础设施内安全执行 Bash 与 JavaScript 步骤

OneUptime Runbook 代理(Agent)完全指南:在自建基础设施内安全执行 Bash 与 JavaScript 步骤 【免费下载链接】oneuptime Complete open-source monitoring and observability platform. 项目地址: https://gitcode.com/GitHub_Trending/on…

📰

Glances MPP 插件详解:监控 Rockchip 平台硬件视频编解码引擎(RKVENC / RKVDEC / RKJPEGD)

指标监控监控大盘CLI告警MCP 服务 【免费下载链接】glances Glances an Eye on your system. A top/htop alternative for GNU/Linux, BSD, macOS and Windows operating systems. 项目地址: https://gitcode.com/gh_mirrors/gl/glances 点击查看 免费下载 导读 本…

📰

Taro H5 端路由系统解析:从 `@tarojs/router` 看小程序路由规范在 Web 端的落地

Taro H5 端路由系统解析:从 tarojs/router 看小程序路由规范在 Web 端的落地 【免费下载链接】taro 开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬