PHP实现机械制造视频大文件分片上传与受控分享实战
1. 先说说机械制造行业里那些“传不动”的视频做机械制造的兄弟都清楚车间里最不缺的就是两个东西一个是铁疙瘩一个是视频。设备验收要录视频装配调试要录视频刀具磨损监测要录视频一条生产线从安装到跑通攒下来的视频素材按TB算都不夸张。我去年给一家做数控机床的企业做内部系统改造车间里的师傅用工业相机拍了一段机床空运行测试的视频4K分辨率H.264编码时长大概40分钟算下来将近9个GB。当时他们用的旧系统还是老式的网页上传项目经理跟我抱怨说这文件传了三次三次都是传到六七成的时候断掉断掉就得从头再来一来二去一个下午全搭进去了。这种场景在机械制造行业太常见了。监控视频、设备操作记录、质检过程录像、客户要求留存的生产过程影像随便一个文件就是几个GB。而常规的网页上传方案不管是用表单直接提交还是走Ajax上传本质上都是一次性把整个文件塞进请求体里。文件一大面临的问题就非常具体超时、内存溢出、连接被重置、服务器拒绝请求。所以当有人问“PHP在机械制造行业如何实现视频大文件的分片分享”这个问题的本质不是“怎么用PHP传大文件”而是在工业现场的弱网环境、老旧设备、不稳定连接条件下怎么把一个可能超过2GB的视频文件可靠地从前端送到后端并且让技术部门、质检部门甚至客户那边的人按需把视频取走。2. 整体方案设计分片上传是唯一靠谱的路线2.1 为什么不能直接传整个文件先说一个容易被忽略的事实PHP默认的upload_max_filesize往往只有2MB到8MBpost_max_size也就是8MB到32MB。就算你把这两个参数调到2GB实际传输过程中只要网络抖动一次、服务器处理超时一次整个请求就废了。有人会说那我把max_execution_time设成0不就行了。确实是能跑但代价是一个用户占着一个PHP-FPM进程好几个小时期间这台服务器对这个用户的所有请求都被占住其他工人调工艺文件、查图纸全都得排队。车间里同时视频上传的人一多整套系统直接瘫痪。再往深了说HTTP协议本身对大数据包并不友好。代理服务器、网关、负载均衡设备都有默认的超时设置常见的是60秒到300秒。你这边一个请求体塞了9GB还没传到一半中间某个环节先掐了连接前端拿到的就是一个中断的网络错误。这是再好的代码也绕不过去的物理限制。分片上传的思路就是把这个不可能完成的大请求拆成几百个几十秒就能完成的小请求。每个分片2MB、5MB或者8MB单独走一次HTTP请求传输时长控制在几秒到十几秒之间远低于各种超时阈值。这样即使某一个分片失败了重新传这一个分片就行已经传完的几百个分片不用动。2.2 分片之后还要有一个“分享”环节很多人做分片上传文件传完就结束了用户拿着服务器路径自己去下载。这在机械制造场景下根本不够用。车间里拍摄的视频经常要发给好几方看质量部要追溯问题、工艺部要分析流程、客户那边要确认验收结果。你不可能让每个人都跑到上传终端那里去拷贝文件更不可能每传一个视频就去开一个FTP账号。所以完整的方案必须分成两段第一段是上传阶段解决“怎么把大文件完整地交到服务器”的问题第二段是分享阶段解决“怎么让特定的人方便地把文件取走”的问题。这个分享不是简单的静态文件链接外发而是要有访问控制、有效期、日志记录的受控分享不然车间生产视频满天飞神仙也兜不住。2.3 三条技术路线的对比我先说结论纯PHP方案可行而且很多时候是最合适的。但在动手之前把几条路线摆在一起对比一下没坏处。第一条路线是传统的表单一次性上传。适合小文件简单直接但面对GB级别的视频基本就是拿头撞墙。第二条路线是用第三方云存储的直传SDK比如某云对象存储的分片接口。性能没问题但引入了一个外部依赖车间里的网络能不能稳定连到云端涉密的生产视频能不能放到第三方服务器这些疑问在很多制造企业里直接就把这条路堵死了。更现实的问题是很多厂区内部系统跑在纯内网环境压根没有出网权限。第三条路线就是自建分片上传接口用PHP做后端接收和合并。这条路的最大优势是可控数据留在内网、接口逻辑自己定、和现有的设备管理系统能无缝对接。缺点是PHP本身不是为高并发大IO设计的但机械制造行业的内部系统并发量通常也就几十个用户PHP完全扛得住。我最终走的方案就是第三条路下面把核心设计思路和完整代码实现一步步拆开讲。3. 核心细节解析分片上传的技术要点3.1 前端怎么切分文件前端分片用的是浏览器自带的File对象和slice()方法不需要引入任何第三方库。File对象是Blob的子类slice()方法可以直接按字节切出文件的一部分这部分数据可以独立作为一个Blob对象用来构造FormData发送请求。分片大小是第一个需要认真思考的参数。选太小的分片比如1MB一个9GB的文件就是9000多个分片每个分片都要走一次完整的HTTP请求请求数量太多反而增加了失败概率和服务器负担。选太大的分片比如50MB又回到了大请求的老路上一个分片传半天还不一定成功。我常用的分片大小是5MB到8MB具体根据网络状况调整。厂区局域网内带宽稳定可以选8MB如果是跨地域、走公网建议压到5MB甚至2MB。经验值是单分片传输时长控制在10秒以内超过这个时间就该考虑调小分片。前端还有一个关键点需要把每个分片的序号、分片总数、文件唯一标识一起发给后端。这样后端才知道哪些分片是属于同一个文件的以及合并的时候按什么顺序拼装。分片的唯一标识我用文件名文件大小最后修改时间做一个哈希这样即使不同用户上传了同名文件也不会互相覆盖。3.2 后端接收分片的目录设计后端这边分片接收接口的核心逻辑不复杂接收一个分片写入到临时目录。但目录设计如果一开始没想清楚后面全是坑。我采用的是两级目录结构第一级是当天日期方便按天清理第二级是这次上传任务的唯一ID也就是前端生成的那个哈希值。也就是说一个9GB的文件在合并之前会躺在类似这样的路径下/storage/upload_tmp/2025-06-10/8f3a2b9c1e7d4f6a/这个文件夹里放的是几百个分片文件命名规则是序号加上分片大小信息比如00001.part、00002.part。用序号做文件名并且统一用五位数字补零是为了合并的时候能按字典序直接读不会出现2.part排在10.part后面这种乱序问题。这里有一个容易忽略的细节分片接口不能用move_uploaded_file()直接存到目标位置而应该用move_uploaded_file()先把临时文件挪到当前分片目录下再重命名。原因是PHP处理上传文件时文件先到了系统临时目录如果你不显式挪走当前请求结束的时候这个临时文件就会被自动清理掉。3.3 合并文件时最核心的注意事项所有分片都传完之后前端发起一个“合并请求”后端把所有分片按顺序拼接成一个完整文件。拼接的方式有两种第一种是用PHP的文件操作函数逐个读、逐个写。这种方案不依赖系统命令PHP代码可控性强我采用的是这个方案。第二种是用系统命令cat直接拼接。速度快但PHP运行环境不一定有权限执行系统命令而且在共享主机上可能被禁用exec()函数。机械制造企业一般是自己部署服务器但有些IT运维策略比较保守所以我不建议依赖系统命令。用PHP实现合并的时候最容易被坑的一点是文件打开模式。很多人写文件习惯用w模式这个模式会把文件指针放到开头并截断文件每次打开都会把原来的内容清空。合并的时候必须用ab模式以追加二进制的方式写入文件指针自动在末尾不会覆盖之前写入的内容。另一个性能上的坑千万不要把整个分片内容一次性读入内存。PHP的file_get_contents()读一个8MB的分片在内存里会占用差不多两倍的空间虽然单次不大但合并过程中的中间数据如果处理不好9GB文件合并到一半就可能触发内存限制。正确做法是设置一个读取缓冲区比如每次读1MB写1MB循环操作。我写的合并核心代码如下public function mergeChunks(string $uploadId, string $fileName, int $totalChunks): bool { // 分片所在目录 $chunkDir $this-getChunkDir($uploadId); $targetPath $this-getSavePath($fileName); // 以追加二进制模式打开目标文件 $targetFile fopen($targetPath, ab); if (!$targetFile) { throw new RuntimeException(无法创建目标文件: . $fileName); } // 按顺序遍历所有分片 for ($i 1; $i $totalChunks; $i) { $chunkPath $chunkDir . / . str_pad($i, 5, 0, STR_PAD_LEFT) . .part; if (!file_exists($chunkPath)) { fclose($targetFile); throw new RuntimeException(缺少分片: . $i); } $chunkHandle fopen($chunkPath, rb); if (!$chunkHandle) { fclose($targetFile); throw new RuntimeException(无法打开分片: . $i); } // 逐块写入避免内存占用过高 while (!feof($chunkHandle)) { $buffer fread($chunkHandle, 1024 * 1024); // 每次读1MB fwrite($targetFile, $buffer); } fclose($chunkHandle); unlink($chunkPath); // 合并完就删除分片避免垃圾堆积 } fclose($targetFile); // 删除空的临时目录 rmdir($chunkDir); return true; }注意我在合并过程中顺手把已经合并完的分片文件删掉了。这个操作非常关键如果不删一个9GB的文件会同时占用原始分片空间9GB和合并后的完整文件空间9GB一共18GB。车间里视频多的时候磁盘很快就满了。3.4 分享链接的安全设计和访问控制文件合并完成之后下面进入分享环节。机械制造企业的视频文件不适合直接在Web目录下存放然后公开访问。比如你想把视频放到/var/www/html/videos/下面让用户直接用URL打开先不说权限问题光是路径泄露这一条就够喝一壶的。车间监控视频如果被无关人员顺着文件名猜出来下载了这在很多企业里属于严重事件。我采用的方案是“文件存储在Web根目录之外 Token授权访问”。具体做法是合并后的完整文件统一放到类似/data/media_files/的目录下这个目录在Web服务器的站点根目录外面用户没法通过URL直接访问。然后我在数据库里建一张分享记录表每次创建分享时生成一个随机的Token带有有效期、创建人、访问次数限制等信息。用户访问分享链接时PHP先校验Token是否有效、是否过期有效的则读取文件并输出给浏览器。这里有一个性能问题要提前说清如果视频文件是2GB你用PHP的readfile()一次性把整个文件输出给浏览器内存可能扛得住readfile()是流式读取不是读进内存再输出但会占用很长时间而且PHP进程会一直挂着。更严重的是如果用户只是点了链接但没看完视频就关闭页面服务器可能还在傻乎乎地往外送数据。解决这个问题有两个层面。第一个层面是在输出的过程中检查连接状态用connection_aborted()判断客户端是否还连着断开了就停止输出。第二个层面是启用HTTP的Range请求支持让播放器或下载工具可以按字节范围向服务器请求数据这样用户拖动视频进度条时服务器只需要输出对应的那一段字节而不是从头重新送一遍整个文件。Range请求的PHP实现不复杂核心是解析HTTP_RANGE头用fseek()定位到指定字节位置然后输出对应长度的数据。我强烈建议做视频分享功能的朋友把这一块做上否则你的Web服务器会在视频拖进度条时承受大量不必要的IO压力。3.5 上传接口的并发控制和断点续传上传过程中最常见的故障就是网络抖动导致某个分片失败。如果用户从头再传一次那分片就没有意义了。所以接口必须支持“断点续传”前端在传每个分片之前先发一个检查请求后端返回该分片是否已存在如果已经传过了就直接跳过。这个逻辑的实现非常直白。检查接口和后端接收分片逻辑共用同一个分片目录规则判断对应的分片文件是否存在。注意光看文件存在不够还要看文件大小是否和前端上报的分片大小一致避免出现传输了一半的残缺分片被误认为完整。并发控制上前端不要一次性把所有分片都并发发出去。我实测过并发数太高时Web服务器的连接数会被迅速打满其他正常的业务请求反而进不来。比较稳的做法是控制在前端同时最多3到5个分片请求这样既有一定的并行加速效果又不会把服务器压垮。4. 实操过程从环境配置到完整跑通4.1 调整PHP配置参数分片上传方案下单次请求体大小就是分片大小所以PHP配置反而不用把upload_max_filesize调得夸张。以下是我的一套基准配置upload_max_filesize 16M post_max_size 20M max_execution_time 60 max_input_time 60 memory_limit 256M解释一下为什么分片是5MB到8MB但upload_max_filesize要留出余量到16M。因为HTTP请求不只是文件内容还有FormData里的其他字段信息。而且用户浏览器发出的分片请求可能在传输过程中带有一些额外数据如果你把限制卡得刚刚好很容易出现“差一点点就超限”的情况。留一倍左右的余量是最稳妥的做法。memory_limit不需要调得特别高因为我们合并文件的时候用的是流式读写1MB的缓冲区256M完全够用。但如果你在代码里用了file_get_contents()去读整个分片再拼接那8MB的分片还好说但如果分片数量多、代码不规范导致数组里存了所有分片的内容引用256M一样会爆。4.2 Nginx和Apache的适配运行环境这块Nginx和Apache各有一些细节要处理。如果是Apache默认的请求体大小没有特殊限制主要受PHP的post_max_size控制所以配置相对省心。但Apache的mod_security模块可能干扰大文件上传如果你发现分片上传失败而且错误日志里有“ModSecurity: Request body exceeds”之类的记录需要在对应虚拟主机的配置里针对上传接口做一下排除。如果用的是Nginx事情就多一点。Nginx有两个参数和上传直接相关client_max_body_size默认只有1MBclient_body_timeout默认60秒。前者必须调大后者建议保持默认或者稍微放宽。分片方案下因为单个分片不大client_max_body_size调到20M就够了location /api/upload { client_max_body_size 20m; client_body_timeout 30s; proxy_request_buffering off; }这里特别说一下proxy_request_buffering off很多人容易忽略。Nginx作为反向代理时默认会把完整的请求体先缓冲到磁盘或者内存里然后再转发给后端PHP。如果开着这个缓冲分片上传时Nginx同样要等整个分片接收完才开始往PHP转发虽然单个分片不大没什么影响但关掉后可以降低内网环境下的传输延迟。不过要注意这个参数关了之后Nginx可能会把请求体流式转发给后端如果PHP和Nginx之间有代理超时设置需要同步调整。4.3 前端上传页面的实用实现前端我用的是比较常规的HTML5JavaScript实现。不引大型框架直接原生写方便集成到现有的设备管理后台里。核心流程分成四步第一步用户选择文件后计算文件哈希。这里注意对整个9GB文件做MD5是不现实的浏览器会卡顿很久。我采用的方式是取文件开头256KB、中间256KB、末尾256KB三段数据拼在一起计算一个快速哈希用来做上传任务的唯一标识。这个哈希碰撞概率虽然比完整哈希高但对于识别“是不是同一个上传任务”这个场景完全够用。第二步按分片大小切分文件生成分片列表。第三步用并发控制的异步请求依次上传分片每成功一个就更新进度条。这里要保存进度状态包括已经上传成功哪些分片这样用户刷新页面后还能从断点继续。第四步全部完成后发起合并请求。核心代码大致如下async function uploadVideo(file) { // 生成文件唯一标识 const fileId await computeFileId(file); const chunkSize 8 * 1024 * 1024; // 8MB const totalChunks Math.ceil(file.size / chunkSize); // 并发控制最多同时3个请求 const maxConcurrent 3; let currentIndex 0; async function runner() { while (currentIndex totalChunks) { const chunkIndex currentIndex; const start chunkIndex * chunkSize; const end Math.min(file.size, start chunkSize); const blob file.slice(start, end); // 如果这个分片已经传过就跳过 const exist await checkChunkExists(fileId, chunkIndex); if (exist) { updateProgress(totalChunks, chunkIndex 1); continue; } const formData new FormData(); formData.append(file_id, fileId); formData.append(chunk_index, chunkIndex); formData.append(total_chunks, totalChunks); formData.append(file_name, file.name); formData.append(file_size, file.size); formData.append(chunk, blob); const res await fetch(/api/upload/chunk, { method: POST, body: formData }); if (!res.ok) { // 单个分片失败不中断交给retry逻辑 currentIndex--; // 重试当前分片 await sleep(1000); continue; } updateProgress(totalChunks, chunkIndex 1); } } const workers Array.from({ length: maxConcurrent }, () runner()); await Promise.all(workers); // 所有分片传完后合并 const mergeRes await fetch(/api/upload/merge, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ file_id: fileId, file_name: file.name, total_chunks: totalChunks }) }); const data await mergeRes.json(); if (data.status ok) { // 拿到合并后的文件ID用于创建分享 createShareLink(data.file_id); } }有一个工程实践上的细节值得单独提一下分片失败时的重试逻辑。我上面的代码里用了一个笨办法currentIndex--把当前分片放回去重新取。很多前端框架自带的fetch没有内置重试机制所以这个“回退索引”的写法虽然简单却能确保每个分片在失败时至少能被重新尝试。当然更好的做法是维护一个失败分片的队列单独重试但那样代码复杂度高一些小型内部系统没必要。4.4 后台分享管理页面分享功能我用一张数据库表来管理字段大致包括字段类型说明idint 自增主键file_idvarchar(64)合并文件的唯一标识tokenvarchar(64)分享链接的随机Tokencreatorvarchar(32)创建人用户名expire_atdatetime过期时间max_downloadsint最大下载次数download_countint已下载次数created_atdatetime创建时间每次创建分享时用bin2hex(random_bytes(16))生成一个32位的十六进制Token。注意不要用md5(uniqid())这种按时间生成的“随机数”在并发请求下重复率高安全性差。访问分享链接时的校验流程是解析Token查询数据库检查是否过期、是否超过下载次数、文件是否还存在。全部通过后走文件输出逻辑。我这里没有给分享链接设置单独的访问密码但在一些严格管控的车间建议加一层简单的密码校验毕竟视频里可能有设备参数之类的内部信息。5. 机械制造场景下的性能调优与存储规划5.1 磁盘空间和临时目录清理策略车间视频项目跑了一段时间后最容易出的事故不是代码逻辑出错而是磁盘没空间了。一个车间一个月下来能录几十GB甚至上百GB的视频如果不做容量规划系统说挂就挂。我在项目里做了三层防护第一层是上传临时目录的自动清理。分片合并成功后分片文件会被删掉这是最理想的。但有些用户传了一半不传了或者浏览器崩了临时的分片目录就会残留下来。我用一个定时任务每天凌晨扫描上传临时目录删除超过48小时的残留分片目录。这个任务在Linux下用crontab执行一个PHP脚本就行不用上什么复杂的任务调度系统。第二层是分享文件的过期清理。分享记录里有有效期过期后定时任务把对应的物理文件也删掉。很多机械制造企业的视频都涉及客户信息或内部工艺不删掉一直堆着反而是风险。第三层是容量预警。我用脚本监控磁盘使用率超过80%就往管理员的微信或者短信发告警。预警阈值设在80%而不是90%是因为视频文件太大上传过程中磁盘占用是瞬时增长的等到了90%再告警可能已经来不及处理了。5.2 合并大文件时的IO优化前面提到了合并时用fread()按1MB为单位搬移数据。有的朋友可能会想缓冲区是不是设得越大越好比如一次读64MB合并速度是不是更快实测结果不是这样的。分片文件位于机械硬盘还是SSD上对合并且速度影响非常大。如果是机械硬盘大缓冲区读写反而会导致磁盘频繁在读写模式之间切换性能下降。而且PHP的fread()单次调用如果读取的字节数过大可能超过底层文件系统的单次IO限制导致实际读取字节数小于预期代码就可能出bug。1MB是一个很稳的值兼容性好机械硬盘和SSD都能跑得动。还有一个我没提但很重要的点合并操作不要在Web请求里同步执行。一个大文件合并可能耗时几十秒甚至几分钟如果用户在浏览器里等着合并请求返回期间页面一直转圈体验很差。而且如果用户在合并进行中关闭了页面PHP进程可能被中断合并到一半的文件就成了垃圾文件。我的做法是合并接口创建一条“合并任务”记录返回“任务已创建”给前端真正的合并逻辑交给后台的队列进程跑。前端定时轮询任务状态合并完成后通知用户。对于内部系统来说用简单的数据库表做任务队列就够了不需要引入消息中间件之类的重型组件。5.3 高并发场景下PHP-FPM的连接数估算机械制造行业内部系统正常不会遇到太高的并发但不排除车间里某个时刻有十几个人同时上传视频。这时PHP-FPM的进程数配置要提前算好。假设一个分片请求耗时2秒每个人上传时同时并发3个分片请求那么10个人就是30个并发请求。如果你用的PHP-FPM配置了pm.max_children20那剩余10个请求就要排队等待体验会明显变差。所以我把pm.max_children按“最大同时上传人数 × 每人的前端并发数 其他业务请求余量”来配置。比如预期最多15个人同时操作上传看视频每人的前端并发3个分片再加其他普通请求约20个那max_children至少设65。同时要注意pm.start_servers和pm.min_spare_servers也要相应调大否则连接上来时进程还没有创建好一样会排队。6. 常见问题与排查技巧实录6.1 分片上传时间长了PHP报“POST Content-Length exceeds the limit”这个错误信息非常容易出现在分片方案已经上线后。明明每个分片只有5MB但服务器还是报超出限制。原因是很多人改了upload_max_filesize和post_max_size但忘记重启PHP-FPM或Apache。注意改了php.ini之后只有重启服务才能生效。另外还有一种情况是用了.htaccess或者Nginx的fastcgi_param覆盖了PHP配置这在共享主机上尤其常见。排查方法很简单写一个临时PHP文件里面打印phpinfo()查看upload_max_filesize和post_max_size的实际值。看到的值和预期不一致就知道是配置没生效还是被覆盖了。6.2 合并后的视频播放卡顿或画面花屏合并出来的视频文件用播放器打开后播放几秒就停顿甚至出现花屏但单看分片文件都是正常的。这个问题的根源几乎都是合并顺序错乱。我见过某位同行的代码分片文件名没有补零直接用的原序号比如1.part、2.part、10.part、11.part。然后他用scandir()读取目录按文件名排序结果是1.part、10.part、11.part、2.part这样的顺序合并出来的文件自然就是乱的。另一种情况是前端上传时分片序号从0开始而后端合并时从1开始遍历导致第一个分片被跳过文件头部缺损。这类问题用眼看不出来一定要在接口层面统一约定前端用chunk_index标识从0开始后端用chunk_index 1作为文件名序号。6.3 上传小文件没问题传大文件就失败这个问题我排查过不止一次。小文件能传说明上传接口本身没问题大文件失败方向一般就两个超时和磁盘。超时方面不要再只看PHP的max_execution_time了要看整个请求链路。Nginx的proxy_read_timeout默认是60秒如果PHP接收分片后在程序里又做了一些额外的处理比如写日志、调外部接口整个请求耗时超过60秒Nginx就会先把连接断了PHP端根本感知不到。磁盘方面注意上传临时目录所在的磁盘分区空间。有时候你查看/根分区空间充足但上传临时目录挂载在/tmp或者/var的分区上那个分区可能早就满了。用df -h把每个挂载点都看一遍别只看默认位置。6.4 创建分享链接后点了没反应分享链接点击后页面空白或者直接404首先检查文件存储路径是否在Web根目录之外。如果路径在Web根目录之外静态服务器不会帮你处理必须走PHP入口。其次检查输出代码有没有在发送文件内容之前输出其他字符。比如在PHP文件头部有一个BOM头或者之前有个echo调试语句这些都会破坏响应头导致播放器或者浏览器无法正确识别视频流。我用了一个笨办法定位这类问题在浏览器开发者工具里看Network响应如果返回内容的最开始不是视频数据而是一堆字符那就是代码里混入了额外输出。6.5 上传到一半刷新页面后进度丢失前端的进度状态如果只存在内存变量里刷新当然就丢了。需要把“哪些分片已上传成功”的状态持久化。我一般用localStorage以fileId为键记录已完成的分片序号数组。每次分片成功后就更新这个数组。页面重新加载时先检查localStorage里有没有这个key如果有就直接从断点继续。这个方案数据存在浏览器本地不会增加服务器负担而且不涉及登录态的依赖实现成本很低。不过要注意localStorage有5MB左右的容量限制。对于大文件分片数量多时用chunkIndex的数组再加上JSON序列化几千个元素也不会超容量可以放心用。7. 实际操作中的几点体会项目从搭建到上线前后折腾了两周左右核心代码其实一天就能写完剩下的大部分时间都花在联调、边界情况处理和车间现场的网络适配上了。这里挑几个印象最深的点说一下。第一点是分片大小真的不能拍脑袋定。我最初在办公室的测试环境里用8MB分片跑得很顺但拿到车间现场一试有几个分片频繁超时。后来改成分片大小根据网络测速结果动态调整也就是上传之前先测一下当前的网络带宽根据带宽自适应选2MB、4MB还是8MB问题就解决了。这种动态调整的实现也不复杂前端在上传前发一个探针请求测一个往返延迟和一个小文件的传输耗时估算出大致带宽再决定分片大小。第二点是分享链接的有效期一定要设置。车间里很多人习惯性地把链接乱发如果不设过期时间视频文件在服务器上堆得越来越多磁盘空间和安全隐患都是问题。我们的做法是默认有效期7天特殊需要的可以申请延长到30天到期后定时任务自动清理。这个规则写进操作手册之后运维那边省心不少。第三点是日志要打全。上传接口的日志我记录了文件标识、分片序号、分片大小、客户端IP、耗时、结果。平时看着这些日志觉得没什么用一旦出问题排查起来就是救命稻草。有一次用户反馈上传特别慢我翻日志发现某个车间IP段的分片请求耗时比平均高出几十倍后来查出来是那个车间交换机的网线老化导致的开发层面完全想不到的问题但日志里一查就明白了。这套方案从上线至今跑了小半年陆续有十多个车间在用累计传输的视频文件大小超过1.5TB中途也遇到过几次分片丢失、磁盘占用告警但整体上没再出现“传一个9GB的视频传一下午”的情况。车间师傅们的反馈也很直接以前传视频都要找人帮忙现在自己点几下就能传上去还能生成链接发给客户省了不少事。如果你也在做机械制造行业相关系统的视频上传功能希望这篇实操记录能帮你少踩几个坑。分片上传本身不是一个新概念但把它和工业场景的实际约束结合起来还是有不少细节值得打磨的。