移动端表单乱码主因是浏览器默认编码不统一:ios safari缺失meta时fallback至iso-8859-1,android webview可能继承gbk;accept-charset无效,必须在head最前声明,且服务端需在getparameter前调用request.setcharacterencoding("utf-8")。

移动端表单提交为什么总乱码?先看浏览器默认编码逻辑
不是所有移动端浏览器都默认用 UTF-8 编码表单数据。iOS Safari 在缺失 <meta charset="UTF-8"> 时会 fallback 到 ISO-8859-1,Android WebView 可能继承系统编码(比如某些国产 ROM 强制 GBK)。这意味着你写的 你好 在 iOS 上可能被编码成 %C4%E3(ISO-8859-1),而服务端按 UTF-8 解就会变成 。
关键点在于:accept-charset="UTF-8" 在 iOS Safari 上基本无效,不能靠它兜底;enctype="application/x-www-form-urlencoded" 下的 GET/POST 请求,编码源头是页面本身的字符集声明,不是表单属性。
-
<meta charset="UTF-8">必须写在最前面,且早于任何<script></script> - 不要依赖
accept-charset做跨平台兼容——它在 Android WebView 和旧版 iOS 中支持极差 - 如果页面本身是 GBK 编码(比如老系统遗留页),那必须全链路保持 GBK,不能只改 meta
POST 请求里 request.setCharacterEncoding() 为什么没用?
Java Web 中常见错误:把 request.setCharacterEncoding("UTF-8") 写在 getParameter() 之后,或写在读取 getInputStream() 之后。一旦请求体被读过一次(哪怕只是调用 getParameter()),再设编码就完全失效。
更隐蔽的问题是:Tomcat 默认对 URL 查询参数(GET)用 ISO-8859-1 解码,但对 POST 请求体的编码由 request.setCharacterEncoding() 控制——两者不统一,就会出现 GET 正常、POST 乱码。
- 必须在第一次调用
getParameter()或getInputStream()前执行request.setCharacterEncoding("UTF-8") - 推荐用 Filter 统一处理,且仅对
POST方法生效(GET 参数走URIEncoding配置) - Spring Boot 用户确认
CharacterEncodingFilter的forceEncoding为true,否则只对 request 生效,response 不强制
fetch + FormData 提交文件时后端收不到 $_FILES?边界解析失败
移动端 fetch 提交 FormData 时,Android WebView 7.x 及更早版本不支持自动设置 boundary,导致请求头是 Content-Type: multipart/form-data;(缺 boundary 值),PHP 的 $_FILES 直接为空,php://input 也读不到完整原始体。
Node.js 的 multer 报 Unexpected end of multipart data 也是同源问题:服务端找不到合法的 ------WebKitFormBoundaryxxx 开头,或结尾缺 --boundary--。
- 避免在低版本 WebView 中混用
fetch和FormData上传文件,降级用XMLHttpRequest并手动设Content-Type头 - Chrome 57+、iOS 12.2+ 才真正支持 fetch 自动 boundary,上线前务必查目标 WebView 版本
- 调试时用抓包工具(如 Charles)看实际请求体是否含完整 boundary 分隔符,而不是只信 Network 面板的 parsed view
HTML 字符串通过 URL 传参时为什么总截断?双重编码不是可选项
直接 encodeURIComponent('<div id="a">&</div>') 得到 %3Cdiv%20id%3D%22a%22%3E%26%3C%2Fdiv%3E,但拼进 URL 后变成 ?html=%3Cdiv%20id%3D%22a%22%3E%26%3C%2Fdiv%3E,其中 %26(即 &)会被 URL 解析器当作参数分隔符,导致后面内容被丢弃。
这就是为什么 URLSearchParams.get('html') 只拿到 <div id="a"> ——<code>& 已经被当成新参数起点。
- 发送端必须双重编码:
encodeURIComponent(encodeURIComponent(htmlString)) - 接收端严格逆序解码:
decodeURIComponent(decodeURIComponent(urlParam)) - 检查是否双重编码成功:结果应以
%25开头(如%253Cdiv...),%25是%的编码,说明外层编码生效 - 别用
encodeURI()替代 —— 它放过&、=、/等保留字符,对 HTML 字符串完全不可靠











