近日,一则关于网页开发的技术问题在国内外开发者社区引发热议:当用户通过 HTML multipart/form-data 表单上传文件时,在绝大多数桌面浏览器和 Android 设备上一切正常,唯独在 iOS 设备(包括 iPhone 和 iPad)的 Safari 及部分内嵌浏览器中,服务器端接收到的 $_POST 数据与 $_FILES 文件数据竟然同时为空。这一诡异现象不仅困扰了众多独立开发者,也让不少依赖表单上传功能的企业级 Web 应用在移动端遭遇“滑铁卢”。

现象:只发生在“附加文件”时

据多位开发者反映,问题复现步骤极其简单:在 iOS 设备上打开一个包含 <input type="file"> 的网页表单,选择一张图片或任意文档,点击提交。随后服务器端却收到了“空空如也”的请求——不仅文件数组 $_FILES 为空,连原本应该通过 POST 发送的普通字段(如用户名、留言内容等)也全部丢失。更有趣的是,如果用户不选择任何文件,仅提交普通文本字段,则一切正常。这意味着“文件附件”成了触发故障的唯一开关。

这一现象并非个例。在 Stack Overflow、GitHub Issues 以及苹果开发者论坛中,类似帖子可追溯至数年前,且至今仍在 intermittently(间歇性)出现。有开发者尝试在 iOS 16、17、18 等不同版本上复现,发现部分系统版本稳定触发,部分版本时好时坏,表现出极强的“玄学”色彩。

根因猜测:不是 HTML 的错,而是请求头“起了内讧”

经过多轮抓包分析,有资深工程师指出,问题大概率出在 iOS 网络栈对 multipart/form-data 请求的边界标识(boundary)处理上。根据 RFC 7578 规范,浏览器在发送此类请求时,会在 Content-Type 头中附带一个随机生成的 boundary 字符串,请求体中的每个字段和文件数据都用 --boundary 分隔。正常情况下,服务器(如 PHP)会依据该 boundary 解析数据。

然而在 iOS 上,部分版本的 WebKit 引擎在构造请求时,可能出现 boundary 字符串与请求体实际使用的分隔符不一致,或者对文件二进制内容中的某些字节序列进行了错误转义,导致服务器端解析失败。更糟糕的是,iOS 的某些“优化”机制可能在文件较大时,将 POST 请求变异为分段传输(chunked transfer),而部分 PHP 配置未开启 always_populate_raw_post_data 或对流的兼容性不足,最终造成 $_POST$_FILES 双双复位。

另一部分开发者则怀疑是 iOS 的“隐私保护”功能在作祟。自 iOS 13 起,Safari 对跨域表单提交和第三方 Cookie 的限制愈发严格,若页面与提交地址存在跨域情况,系统可能直接剥离整个请求体。不过该猜测尚未得到苹果官方证实。

影响:移动办公场景首当其冲

这一 Bug 对真实业务的影响不容小觑。在移动办公、在线审批、医疗影像上传、电商用户反馈等场景中,用户经常需要在手机上拍照、上传附件并填写备注。一旦提交后所有数据丢失,用户看不到任何错误提示(页面通常显示成功或空白),但后台却查无记录,极易引发数据安全事故和用户投诉。

更棘手的是,由于问题仅在 iOS 真机上出现,桌面端模拟器无法复现,传统测试流程很难覆盖。许多小团队直到上线运营后才从用户的客诉中得知故障,修复成本陡增。

临时对策与最终出路

面对这一顽疾,社区目前给出的临时方案包括:

  1. 改用 AJAX/XHR 手动构造 FormData,绕开浏览器原生表单提交,并在发送前显式设置 Content-Type(或缺省让浏览器自动生成)。不少开发者反馈此法可有效规避问题。
  2. 将文件上传与业务字段分离:先通过 AJAX 单独上传文件,再将返回的文件 ID 随普通文本字段提交,避开单次 multipart 请求。
  3. 使用 fetch API 替代传统提交,并强制设置 enctype 和 boundary,已验证在多数 iOS 版本上可靠。
  4. 服务端兜底:检查原始请求体(php://input),配合第三方库(如 Guzzle)手动解析 multipart 流,但实现复杂度较高。

长期来看,最终出路仍然依赖苹果在 WebKit 中修复该底层缺陷。有开发者已向 WebKit Bugzilla 提交报告(Bug 编号待查证),但目前苹果官方尚未给出明确回应。在此期间,建议所有面向 iOS 用户的 Web 应用,务必在测试阶段加入“真实 iPhone + 附件提交”的专项用例,切莫因桌面端正常而掉以轻心。

结语

一个看似古老的 multipart/form-data 标准,竟在 iOS 上栽了跟头,再次印证了 Web 开发的“移动端陷阱”无处不在。对于开发者而言,及时拥抱现代 API、完善多端真机测试,或许才是应对平台碎片化最稳妥的姿势。我们将持续关注苹果官方的修复进展。