html文件上传中服务器
用户选中一个2GB的文件务器视频文件,点击上传按钮。上传浏览器不会把整个文件读进内存再发出去——那样页面早就崩了。中服它把文件切成一个个小块,文件务器每块默认大小取决于浏览器实现,上传Chrome通常按64KB的中服块顺序读取,通过HTTP POST请求把二进制数据塞进请求体,文件务器Content-Type标成multipart/form-data。上传服务器那边收到的中服是什么?是一段带边界分隔符的原始字节流,夹杂着文件名、文件务器MIME类型和实际文件内容。上传
很多人以为上传就是中服"浏览器发给服务器"这么简单。实际上中间隔着一层HTTP协议,文件务器而HTTP本身不关心你传的上传是文本还是视频。服务器端拿到请求后,中服得自己解析这段multipart数据。拿Node.js举例,如果用Express框架配合multer中间件,multer会把上传的临时文件写到磁盘的/tmp目录下,然后你在路由回调里通过req.file拿到文件路径、大小、原始文件名。此时文件已经落在服务器硬盘上了,但还没进入你指定的存储目录——你得自己写代码把它挪过去。
这里有个容易踩的坑:multipart解析器默认有大小限制。multer的limits.fileSize如果不设,默认是Infinity,听起来很美好,但服务器内存和磁盘撑不住。我见过一个项目,前端没做分片,后端没设限制,用户传了个10GB的蓝光原盘,直接把服务器磁盘写满,整个服务挂了。后来改成前端用File.slice()分片,每片5MB,后端用busboy流式解析,边收边写,才稳住。
服务器接收上传文件的方式分两种:缓冲式和流式。缓冲式是把整个请求体读进内存再处理,小文件无所谓,大文件就是灾难。流式是边读边写,请求体像水管一样,数据流过来就写到磁盘或转发到对象存储。Nginx作为反向代理时,默认client_max_body_size是1MB,超过就返回413。你得改成client_max_body_size 500m;,否则请求根本到不了后端应用。
还有一个细节:上传进度条怎么来的?浏览器端用XMLHttpRequest.upload.onprogress事件能拿到已发送字节数。但注意,这只代表数据发出去了,不代表服务器写完了。服务器写磁盘可能很慢,尤其是机械硬盘随机写入。所以进度条到100%后,最好再发一个确认请求,让后端告诉你文件确实落盘了。
实际部署中,文件通常不直接存应用服务器本地。应用服务器把文件流转发给对象存储(比如S3、OSS、MinIO),拿到一个URL存进数据库。这样应用服务器无状态,扩容方便。但转发又多了一跳网络开销。小文件无所谓,大文件最好让前端直接传对象存储,后端只负责签发临时凭证。这又是另一个话题了。
服务器端处理上传,核心就三件事:解析multipart、控制大小和类型、决定存哪里。听起来简单,但每个环节都有坑。我自己的习惯是,任何上传接口先加limits,再校验MIME类型白名单,最后用流式写入临时目录,校验通过后再移动到最终位置。多写几行代码,少加几次班。
(责任编辑:焦点)














