今天遇到了一个url后追加中文参数乱码的问题,后来用URLEncoder.encode这个方法处理了下解决了。不过感觉还有点迷糊。所以自己写了一个测试的demo.
下面是一个很简单的servlet的部分代码:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String test = request.getParameter("test");
System.out.println("dddddddddddddddddddddddddddd"+test);
System.out.println(new String(test.getBytes("iso8859-1")));
}
输入url :http://localhost:8080/web/TestServlet?test=aa
输出 :ddddddddddddddddddddddddddddaa
aa
输入:http://localhost:8080/web/TestServlet?test=中文
输出: dddddddddddddddddddddddddddd????
中文
输入:http://localhost:8080/web/TestServlet?test=%D6%D0%CE%C4 (注:test是经过encode"中文"的编码)
输出: dddddddddddddddddddddddddddd????
中文
输入了三次,似乎在这里中文参数经不经过URLEncoder.encode都可以运行,我就不明白了,encode有什么作用?还有我传递的参数只是经过了encode在接受参数的时候并不需要解码?有点迷糊!
问题补充:
zhanjia 写道
1、
URLEncoder.encode(String s, String enc)
使用指定的编码机制将字符串转换为 application/x-www-form-urlencoded 格式
URLDecoder.decode(String s, String enc)
使用指定的编码机制对 application/x-www-form-urlencoded 字符串解码。
发送的时候使用URLEncoder.encode编码,接收的时候使用URLDecoder.decode解码,都按指定的编码格式进行编码、解码,可以保证不会出现乱码
首先谢谢你的回答,刚提到的编码、解码。我刚传递的是编码后的参数,但在servlet我并没解码也可以得到正常的参数,这是我不明白之一。还有一点是为什么我中文传递的时候,编码和不编码的效果是一样的,这是我不明白之二。希望给予答案,谢谢!
问题补充:
lockwang 写道
还要看你的网站服务器用的什么编码,最好全部统一
服务器我用的是redhat,在/etc/sysconfig/i18n里设置的是GBK这样编码应该和windows是一致的
问题补充:
langshao 写道
URLEncoder.encode 之后浏览器就不会乱编码了,否则会有一些浏览器出现乱码的(如在IE的URL地址中直接输入中文试试)。
一般Tomcat、WebLogic等都会自动解码,不再需要你自己写程序解码。
Tomcat中指定URL用UTF-8编码server.xml:
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443" useBodyEncodingForURI="true" URIEncoding="UTF-8" />
解码工作是中间件容器自动完成的吗,URIEncoding="UTF-8"这段的意思是
URLDecoder.decode(str,"UTF-8")吗?
问题补充:
zhanjia 写道
网页提交字符串:
当页面中的表单提交字符串时,首先把字符串按照当前页面的编码,转化成字节串。然后再将每个字节转化成 "%XX" 的格式提交到 Web 服务器。比如,一个编码为 GB2312 的页面,提交 "中" 这个字符串时,提交给服务器的内容为 "%D6%D0"。
在服务器端,Web 服务器把收到的 "%D6%D0" 转化成 [0xD6, 0xD0] 两个字节,然后再根据 GB2312 编码规则得到 "中" 字。
在 Tomcat 服务器中,request.getParameter() 得到乱码时,常常是因为前面提到的“误解一”造成的。默认情况下,当提交 "%D6%D0" 给 Tomcat 服务器时,request.getParameter() 将返回 [0x00D6, 0x00D0] 两个 UNICODE 字符,而不是返回一个 "中" 字符。因此,我们需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字节串,再用 string = new String(bytes, "GB2312") 重新得到正确的字符串 "中
感谢回答说的很好,
在页面我做一个含有中文的参数的form提交过程是这样的:
提交form时候浏览器会默认将中文已页面编码方式做 application/x-www-form-urlencode,这时候“中”字被编码为%D6%D0,等效代码为URLEncoder.encode("中","GBK");
而后再servlet中通过做这样的代码处理:
String test = request.getParameter("test");
byte[] bytes = test.getBytes("iso8859-1");
for(int i=0;i
{
System.out.println(Integer.toHexString(bytes[i]&0xff));
}
打印的字节为D6,D0 得到字节正确,而后从新用GBK编码即可。
大概流程搞懂了,这里有点为什么先用iso8859-1解码呢,难道java系统默认有次iso8859-1的编码吗
问题补充:
langshao 写道
引用
而后再servlet中通过做这样的代码处理:
String test = request.getParameter("test");
byte[] bytes = test.getBytes("iso8859-1");
for(int i=0;i {
System.out.println(Integer.toHexString(bytes[i]&0xff));
}
打印的字节为D6,D0 得到字节正确,而后从新用GBK编码即可。
大概流程搞懂了,这里有点为什么先用iso8859-1解码呢,难道java系统默认有次iso8859-1的编码吗
- byte[] bytes = test.getBytes("iso8859-1");
改为
- byte[] bytes = test.getBytes();
看看。
- public byte[] getBytes()
- {
- return StringCoding.encode(value, offset, count);
- }
- static byte[] encode(char ac[], int i, int j)
- {
- String s = Charset.defaultCharset().name();
- try
- {
- return encode(s, ac, i, j);
- }
- catch(UnsupportedEncodingException unsupportedencodingexception)
- {
- warnUnsupportedCharset(s);
- }
- try
- {
- return encode("ISO-8859-1", ac, i, j);
- }
- catch(UnsupportedEncodingException unsupportedencodingexception1)
- {
- MessageUtils.err((new StringBuilder()).append("ISO-8859-1 charset not available: ").append(unsupportedencodingexception1.toString()).toString());
- }
- System.exit(1);
- return null;
- }
谢谢你的代码了,这里是如果 String s = Charset.defaultCharset().name();得不到编码名的时候会有异常进而传入"iso8859-1" 有什么方式可以给它设置上defaultCharset吗?也就是说让它在
String s = Charset.defaultCharset().name();得到值
另外我在servlet中执行了
System.out.println("默认编码"+Charset.defaultCharset());这样的代码得到是GBK,难道是有代码执行先后的问题吗?