表单(form) post 方式提交时的编码与乱码(上)

news2024/9/26 1:24:22

在上一篇章中谈论了表单以 get 提交时的编码与乱码问题, 这一章中将讨论以 post 方式提交时的编码与乱码问题.

在前面也同时提到, 表单有一个叫 enctype 的属性, 它有两个值, application/x-www-form-urlencodedmultipart/form-data.

这一属性实际只对 post 方式起作用, 因为 get 方式实际只支持前一种类型, 也就是 application/x-www-form-urlencoded, 这是缺省的类型.

在使用 post 方式提交时, 缺省的编码类型也依然是这个 application/x-www-form-urlencoded. 在这一篇章中, 先讨论这一类型;在下篇中, 再讨论 multipart/form-data 类型.

post 方式, application/x-www-form-urlencoded 类型的编码

对于 application/x-www-form-urlencoded 类型, 前面讨论 get 的方式已经详细讨论过了, post 方式用它, 底层原理依旧是相同的, 只不过它的数据此时不是放在 uri 中, 而是在 消息体 中发送过去.

简单地讲, 就是地址栏中是看不出来的.

发送形式有差别, 但在这里关心的编码方式上, 却与 get 是一样的. 比如, 非字母数字的字符要用转义表示, 键值对用等号隔开, 多个键值对用 “&” 符号拼接.

对于要转义的字符, 在编码的使用上, 也是一样的:

  1. 没有用 accept-charset 指定, 就用文档本身的编码;
  2. 设置了 accept-charset 的值, 就用它设置的值.

稍微要注意的反而是后台的接收方面.

一个具体的例子

依旧是构建一个简单的 post 方式提交的表单:

<!DOCTYPE html><html><head>
<meta charset="UTF-8">
<title>表单 post 提交页(页面编码 utf8)</title>
</head><body>
<h2>post 提交, 页面编码: UTF-8</h2><hr>
<form action="form_post_target_default.jsp" method="post">
	<input name="english" value="hi">
	<input name="chinese" value="你好">
	<input type="submit" value="submit"></form>
</body></html>

然后提交到一个后台的 jsp 上, 依旧是简单地取出显示:

<%@ page pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>表单 post 接受页(缺省)</title>
</head>
<body>
<h3>request keep default</h3>
${param.english} ${param.chinese}
</body>
</html>

提交后会发现这样的方式地址栏将不会再有 “查询字符串(query component)” 了:

表单 post 地址栏 乱码

但能注意到接收页面的显示是乱码的. 此时查看请求头的信息:

表单 post 请求头 Form data

表单数据是正常的, 点击 view source, 发现确实是 utf-8 的转义编码:

表单 post 请求头 Form data view source

整体上也是 urlencoded 的方式, 跟上篇说到的 get 一样, 因为还是缺省的 application/x-www-form-urlencoded 方式的编码.

后台用 setCharacterEncoding 设置解码字符集

所以, 整个发送环节是没有问题的, 问题出在后台接收处理上. 因为数据不是在 uri 中, 自然之前的所谓设置 URIEncoding 是没有用了, 这时需要不同的策略.

post 情况下, 在取出数据前, 就 java servlet 平台而言, 需要用 request.setCharacterEncoding("utf-8") 先设置一下, 编码的具体值与浏览器所用的一致即可, 因为表单用的是 utf-8, 这里也就设置为 utf-8, 像这样:

<%@ page pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>表单 post 接受页(utf-8)</title>
</head>
<body>
<h3>request.setCharacterEncoding("utf-8")</h3>
<%request.setCharacterEncoding("utf-8"); %>
${param.english} ${param.chinese}
</body>
</html>

调整之后, 再测试就正常了:

表单 post 浏览器 测试 正常

假如没有作这一步骤的设置, 那么 servlet 中将使用缺省的 iso-8859-1 来解码.

在某些情况下, 如果你无法在这一层面进行调整, 也可以保持按 iso-8859-1 的方式来接收, 然后使用一种 hack 的方式来倒腾出正确的 string 的值, 具体见 文本在内存中的编码(3) 中的介绍, 这里不再详述.

一般来说, 除非不得已, 不太建议使用 hack 的方式.

使用 accept-charset 属性指定 post 时的编码

假如表单页面增加 accept-charset 字段, 值设为与文档本身编码 utf-8 不一样的 GBK:

<!DOCTYPE html><html><head>
<meta charset="UTF-8">
<title>表单 post 提交页(页面编码 utf8)</title>
</head><body>
<h2>post 提交, 页面编码: UTF-8</h2><hr>
<form action="form_post_target_utf8.jsp" method="post" accept-charset="gbk">
	<input name="english" value="hi">
	<input name="chinese" value="你好">
	<input type="submit" value="submit"></form>
</body></html>

那么这样之后, 提交的数据就是 GBK 编码了, 不是 utf-8 编码的情况下调试工具中无法正常为字符:

表单 post accept-charset gbk 请求头

不过点击 view source, 还是可以看到原始的值:

表单 post accept-charset gbk 请求头 view source

四个字节确实为 gbk 编码.

而后台的解码此时也会再一次出现问题:

表单 post accept-charset 与 setCharacterEncoding 不一致 乱码

因为提交数据的实际编码是 gbk, 而后台代码却还是按 utf-8 来解码, 所以就出错了. 而调整方式也很简单, 就是把 request.setCharacterEncoding("utf-8") 改为 request.setCharacterEncoding("gbk") 即可, 改完后的代码及具体测试这里就不再列出了, 读者可以自行实验.

总之, 一句话, 编码与解码两端要在使用的字符集编码上保持一致即可.

配置 filter 统一解码时所用的字符集

如果不想在每次接收前都来调用 request.setCharacterEncoding 这么设置一下, 可以统一配置一个过滤器, 以 tomcat8 为例, 可以这样在 web.xml 中去增加一个 filter, 并在初始化参数 init-param 下设置参数名 param-name 为 encoding, 设置参数值 param-value 为 UTF-8:

<filter>  
  <filter-name>Character Encoding Filter</filter-name>  
  <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>  
  <init-param>  
    <param-name>encoding</param-name>  
    <param-value>UTF-8</param-value>  
  </init-param>  
</filter>  
<filter-mapping>  
  <filter-name>Character Encoding Filter</filter-name>  
  <url-pattern>/*</url-pattern>  
</filter-mapping>

这样就统一设置为使用 utf-8 来解码了.

如果你不是使用 tomcat, 或者 tomcat 的版本太旧不包含上述 filter, 那么也可以自行定义一个类似的 filter, 原理上简单讲就是在 doFilter 方法里设置一下编码:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    request.setCharacterEncoding("utf-8");
    chain.doFilter(request, response);
}

更复杂完善一点的可以先看看 request 中是否已经设置过了 charset.

许多的 MVC 框架中关于编码的设置其实就是着力在这里.

关于 Filter 方面不了解的读者可以自行阅读 servlet 相关规范以了解.

当然了, 这样之后, 表单就不能用 gbk 编码方式来提交了. 如果你有一些遗留的 gbk 页面, 那么就要在其表单上设置 accept-charset="utf-8", 指示它用 utf-8 来编码提交的数据.

注意: 如果你不太确定这种统一的调整会造成哪些冲击, 那么就要慎重地去处理, 特别是在运行已久的遗留系统上, 可能还存在前面提到的各种混乱的 hack 的处理方式, 统一的调整可能会使得这样的代码失效.

这也是不提倡使用 hack 的原因, 它代表了一种不太正确的处理方式, 并给后续的调整带来了挑战, 后来者往往只能"将错就错", 继续地 hack 下去.

那么, 关于 post 方式以 application/x-www-form-urlencoded 的类型来提交时的编码与乱码问题, 因为与之前的 get 方式提交还是很相似的, 这里就简单介绍到这里.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/709829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

@Configuration 和 @Component 的区别 ,别再瞎用了!

一句话概括就是 Configuration 中所有带 Bean 注解的方法都会被动态代理&#xff0c;因此调用该方法返回的都是同一个实例。 理解&#xff1a;调用Configuration类中的Bean注解的方法&#xff0c;返回的是同一个示例&#xff1b;而调用Component类中的Bean注解的方法&#xff…

List, Set, Ordered-SetHash

前言 本文小结Redis中List&#xff0c;Set&#xff0c;ZSet和Hash四种数据类型的&#xff0c;基本特点&#xff0c;使用场景和实现方式。 一、List 1. 基本特点 a. 作为数组&#xff0c;基于下标索引操作, 但支持正向索引和反向索引; b. 作为链表, 支持高效插入&#xff1b…

信息安全-应用安全-定制化白盒检测 | 越权漏洞治理分享

目录 一、背景 二、面临的挑战 三、治理目标 四、解决方案 4.1 系统架构 4.2 鉴权函数 4.3 告警识别 4.4 鉴权分 五、未来的白盒检测方向 六、越权治理 七、小结 一、背景 在漏洞扫描领域&#xff0c;主流的扫描方式分为黑盒扫描和白盒扫描&#xff0c;其中源代码安…

MYSQL-主键外键约束

主键语法: 在创建表指定列数据类型时在后面加(可以结合AUTO_INCREMENT) PRIMARY KEY 主键要短&#xff0c;可唯一标识记录&#xff0c;且永不改变。 外键语法: 第一个column_name是被指定外键的本表列名 table_name是主键的表名 第二个column_name是主键列名 FOREIGN KE…

使用DataX同步数据(小白步骤,一看就懂)

详细文档说明,及图文讲解 ​​​​​​datax的异构数据同步资源-CSDN文库 Datax简介 下载datax软件,从开源镜像下载

python接口自动化(七)--状态码详解对照表(详解)

简介 我们为啥要了解状态码&#xff0c;从它的作用&#xff0c;就不言而喻了。如果不了解&#xff0c;我们就会像个无头苍蝇&#xff0c;横冲直撞。遇到问题也不知道从何处入手&#xff0c;就是想找别人帮忙&#xff0c;也不知道是找前端还是后端的工程师。 状态码的作用是&…

串口接收不定长数据的实现

使用串口进行数据的收发在嵌入式产品中是很常用的一种通信方式&#xff0c;因为串口的简单使用&#xff0c;很容易就被选为产品中数据交互的通信手段。 基于串口进行开发的功能有很多&#xff0c;比如同类/不同类产品之间的通信&#xff0c;RS485通信&#xff0c;RS232通信方式…

(二)线程的六种状态及上下文切换

&#xff08;二&#xff09;线程的六种状态及上下文切换 2.1 操作系统中线程的状态及切换2.2 Java 中线程的六种状态01、NEW&#xff08;线程尚未启动&#xff09;02、RUNNABLE&#xff08;运行中&#xff09;03、BLOCKED&#xff08;阻塞状态&#xff09;04、WAITING&#xff…

移动端微信小程序学习

目录 小程序和web端的不同 小程序的宿主环境 通信 组件 视图容器​编辑 text组件 button image ​编辑 API api三大分类 模板语法 事件绑定 ​编辑 事件传参​编辑 bindinput 条件渲染 列表渲染 ​编辑 全局配置 window 页面配置 网络数据请求 ​编辑 GET请求 POST…

近轴成像的相关性质

本文介绍薄透镜近轴成像的一些性质&#xff0c;所谓近轴成像&#xff0c;就是入射光线非常靠近光轴&#xff0c;意味着入射角很小。在介绍这些性质之前&#xff0c;我们先来看看三角函数的泰勒展开&#xff1a; sin ⁡ θ θ − θ 3 3 ! θ 5 5 ! − θ 7 7 ! . . . \sin{\…

#10047. 「一本通 2.2 练习 3」似乎在梦中见过的样子(内附封面)

题目描述 原题来自&#xff1a;2014 年湖北省队互测 Week2 「Madoka&#xff0c;不要相信 QB&#xff01;」伴随着 Homura 的失望地喊叫&#xff0c;Madoka 与 QB 签订了契约。 这是 Modoka 的一个噩梦&#xff0c;也同时是上个轮回中所发生的事。为了使这一次 Madoka 不再与…

JVM类加载机制-JVM(一)

我们运行一个.class文件&#xff0c;windows下的java.exe调用底层jvm.dll文件创建java虚拟机&#xff08;c实现&#xff09;。创建一个引导类加载器实例&#xff08;c实现&#xff09;C调用java代码Launcher&#xff0c;该类创建其他java类加载器。Launcher.getClassLoader()调…

【算法】最长公共子序列编辑距离(两个序列之间的DP)

文章目录 最长公共子序列&#xff08;LCS&#xff09;编辑距离&#xff08;Edit Distance&#xff09;总结相关题目练习583. 两个字符串的删除操作 https://leetcode.cn/problems/delete-operation-for-two-strings/712. 两个字符串的最小ASCII删除和 https://leetcode.cn/prob…

BWA序列比对方法丨针对较大基因组的并行计算和性能优化方式,利用多线程和负载均衡策略提高效率

BWA 序列比对 高通量测序技术日新月异发展迅猛&#xff0c;产生了数亿级大数据&#xff0c;生命的世界由DNA序列ATCG组成&#xff0c;正如计算机的世界由二进制01组成。 高通量测序的工作实质是把一本生命字典撕成碎片&#xff0c;然后每人手里拿一片&#xff0c;招募成千上万…

【洛谷】B3644 【模板】拓扑排序 / 家谱树(用邻接表存储和其他题解不一样哦)

本薅蒻通过这次学到的知识点&#xff08;本人认为好用的东西&#xff09;&#xff1a; 1&#xff1a; &#xff08;情况适用于输入的x为0时结束输入&#xff09; 2&#xff1a; 先输出“t”(就是因为这里wa了好几发&#xff0c;555555) 原本是在 if里面输出的&#xff0c;这…

mysql通过存储过程解决ERROR 1060 (42S21): Duplicate column的问题

问题描述 实际的日常开发工作中&#xff0c;经常需要对现有表的结构作出变更&#xff0c;涉及到sql相关的操作&#xff0c;基本都通过初始化脚本来完成&#xff0c;如果初始化脚本运行失败或者遇到其他问题&#xff0c;可能导致sql部分执行&#xff0c;不分失败的问题&#xf…

ModaHub ——向量数据库Milvus特征向量和预写式日志教程

目录 特征向量 什么是特征向量 特征向量的优势 应用领域 预写式日志 数据可靠性 缓冲区设置 旧日志删除 特征向量 什么是特征向量 向量是具有一定大小和方向的量&#xff0c;可以简单理解为一串数字的集合&#xff0c;就像一行多列的矩阵&#xff0c;比如&#xff1a…

领域事件驱动(三)子域

上一章对领域层的相关概念做了阐述 应用服务 应用层作为展现层与领域层的桥梁&#xff0c;是用来表达用例和用户故事的主要手段。 应用层通过应用服务接口来暴露系统的全部功能。在应用服务的实现中&#xff0c;它负责编排和转发&#xff0c;它将要实现的功能委托给一个或多…

蓝桥杯刷题-1

文章目录 1.蓝桥杯官网2.蓝桥杯题目进入界面 及 题目详情3.题目解答过程及思路4.运行结果图5.解答代码展示6.ASCII表图例 大家好&#xff0c;我是晓星航。今天为大家带来的是 蓝桥杯刷题 - 1 -单词分析 相关的讲解&#xff01;&#x1f600; 1.蓝桥杯官网 题库 - 蓝桥云课 (l…

source insight小键盘在vim中不能使用数字(数字按键变英文)

文章目录 问题描述解决办法注意&#xff1a; 问题描述 在使用source insight登录远程服务器并使用vim编辑模式时&#xff0c;出现数字键盘的0-9变成了yxwvutsrqp情况。 解决办法 注意&#xff1a; 如果你点了save as…的话&#xff0c;会让你保存untitled.key文件到你指定的路…