前段时间,在项目中遇到一个很奇怪的问题,服务器端接收中文参数为null,接收单字节字符能正常获取。一开始我以为是项目中某个过滤器做了一些多字节字符过滤,对系统接收参数的环节debug跟踪了好多遍,没发现有过滤多字节参数的地方。
我以前碰到过很多编码问题或者中文等多字节乱码问题,但是服务器得不到参数还是头一次情况,以前是不管编码怎样转换,总还有点东西吧,不至于为null,但是这个所谓的经验误导了我。跟踪服务端没有头绪,于是,我分析客户端提交请求的环节。客户端用ajax提交数据,提交前,UED同事对数据用js的escape函数encode了。
js的escape函数会将多字节数据转换为unicode格式,比如“阿里”会转换成” %u963F%u91CC”。转换就转换了吧,为什么服务端会认为它是null呢?服务器用的jboss,于是我就去查tomcat的源代码,发现tomcat在解析客户端提交的参数时,如果某个参数的值里有%,那么它会跳过两个字符往后寻找匹配的%。如果找不到就会抛出异常,并且该参数被忽略掉,通过request.getParameter得到的就是null。Tomcat接收请求后,会解析请求里的参数,具体类是org.apache.tomcat.util.http. Parameters,里面有一个方法public void processParameters( byte bytes[], int start, int len, String enc )。这个方法有这么一部分
try {
addParam( urlDecode(tmpName, enc), urlDecode(tmpValue, enc) );
} catch (IOException e) {
//此处省略异常处理部分
}
urlDecode函数调用了org.apache.tomcat.util.buf. UDecoder的public void convert( ByteChunk mb, boolean query )函数。遇到参数值有%时,有这么一段代码:
// read next 2 digits
if( j+2 >= end ) {
throw new CharConversionException("EOF");
}
byte b1= buff[j+1];
byte b2=buff[j+2];
if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
throw new CharConversionException( "isHexDigit");
j+=2;
int res=x2c( b1, b2 );
它认为如果一个参数值含有%,那么从这个%开始,后面应该是两个数字,如%aa%bb%%cc%,否则就会抛出异常,忽略此参数。
但是看看js的escape函数encode出来的值,以“阿里”为例,escape值是” %u963F%u91CC”,encodeURI的值是%E9%98%BF%E9%87%8C。显然escape的值是不合法的,服务器会丢弃这个参数,escape会将数据编码成unicode码,encodeURI将数据编码成utf-8编码,unicode码和utf-8编码存在着一个对应关系,并且utf-8编码是unicode的子集,是可变的多字节编码,服务器收到%E9%98%BF%E9%87%8C,会将它转成unicode码,然后从unicode码转成对应的编码,如果服务器没有设置编码则默认用ISO-8859-1。客户端数据编码的函数有escape,encodeURI,encodeUriComponent。这三个函数是有区别的,最后的解决是如此简单,在ajax提交时,将escape换成encodeURI就好了。
分享到:
相关推荐
这里的`maxPostSize="10240"`表示Tomcat允许的最大POST数据量为10240字节(即10KB)。如果需要解除这个限制,可以将`maxPostSize`的值设置为0,表示不限制POST请求的大小: ```xml ,text/xml" maxPostSize="0"/> ``...
Servlet通过`HttpServletRequest`对象接收请求参数,通过`HttpServletResponse`对象返回响应数据。 以下是一个简单的示例,演示如何使用Java的IO流和URL网络编程发送GET请求到Tomcat服务器: ```java import java....
- `bufferedAmount`:表示尚未发送到网络的字节数。 - `onopen`:连接成功时触发的事件处理函数。 - `onerror`:发生错误时触发的事件处理函数。 - `onclose`:连接关闭时触发的事件处理函数。 - `onmessage`:接收...
在本例中,提供了一个简单的静态方法`Chinese`,该方法接收一个字符串参数`value`,并将其从ISO-8859-1编码转换为UTF-8编码。 ##### 方法实现 ```java public static String Chinese(String value){ try { if ...
在Ajax请求中,前端浏览器与服务器之间的数据交换可能会经过多次编码转换,如果这些环节中的任何一处编码设置不正确,都可能导致乱码问题的发生。 1. **前端编码**:前端在发送请求时会将数据进行编码。 2. **传输...
Java提供了Serializable接口,可以将对象转换为字节流,然后在另一端反序列化回原来的对象。 4. **IO流**:在Java中,输入输出流(InputStream和OutputStream)用于读写数据。在聊天室中,我们可能需要使用...
- **GET请求乱码**:可通过修改Tomcat配置文件或手动对参数进行编码转换来解决。 修改Tomcat配置文件: ```xml ``` 或者对GET请求参数进行编码转换: ```java String userName = new String(request...
- **HashMap**: 基于哈希表实现的键值对存储容器,允许一个null键和多个null值。 - **遍历方式**: 使用`iterator`遍历keySet或entrySet。 ##### 4.4 Collection三种遍历方式总结 - **for循环**: 通用,适用于所有...
Java 类加载机制是Java虚拟机(JVM)的关键特性之一,它负责将类的字节码文件加载到内存中,并转换为对应的类对象。在Java中,类加载器(ClassLoader)扮演着至关重要的角色,它们负责查找和加载类。本文将深入探讨...
### Java面试必会知识点解析 #### 一、基本概念 1. **操作系统中heap和stack的... - **九种基本数据类型的大小**:byte(1字节)、short(2字节)、int(4字节)、long(8字节)、float(4字节)、double(8字节)、char(2字节)、...
- **方法重载**:同一类中方法名相同但参数列表不同的多个方法。 ##### StringBuffer、StringBuilder与String的区别 - **String**:不可变字符串,适用于频繁读取而很少修改的情况。 - **StringBuilder**:可变...
- **HashMap**:非线程安全,允许一个null键和多个null值。 ##### Forword(请求转发)与Redirect(重定向) - **请求转发**:服务器内部进行转发,客户端地址栏不变。 - **重定向**:服务器告诉客户端去另一个地址获取...