post方法提交的数据我们通过request.setCharacterEncoding(String enc)//enc编码设置和客户端提交的编码一致即可,一般需要解析中文设置为UTF-8
get方法提交的数据我们通过上面方法无法解析成功,必须手动解析:name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
原因分析:
先了解request中参数的解析与获取过程:
第一次调用request.getParameter(String name)时
1.先解析出该次请求中的所有参数
2.将参数存放到存入org.apache.tomcat.util.http.Parameters中的Hashtable paramHashStringArray中
3.从Hashtable paramHashStringArray取出对应的值
4.后续调用request.getParameter(String name)直接从Hashtable paramHashStringArray拿去对应值即可
解析过程(第一步):
源码分析---------------------------------
private void mergeParameters(){
if ((queryParamString == null) || (queryParamString.length() < 1))
return;
HashMap queryParameters = new HashMap();
String encoding = getCharacterEncoding();//获取到request.setCharacterEncoding(String enc)我们设置的编码值
if (encoding == null)
encoding = "ISO-8859-1";
try{
RequestUtil.parseParameters(queryParameters, queryParamString, encoding);
}catch (Exception e){
;
}
Iterator keys = parameters.keySet().iterator();
while (keys.hasNext()){
String key = (String) keys.next();
Object value = queryParameters.get(key);
if (value == null){
queryParameters.put(key, parameters.get(key));
continue;
}
queryParameters.put(key, mergeValues(value, parameters.get(key)));
}
parameters = queryParameters;
}
从源码得出结论:
存入之前先会获取我们设置的编码值,并按照该编码值解析存入map集合中,如果没有设置,默认ISO-8859-1
解决疑惑
先使用request.getParameter(String name)后再设置request.setCharacterEncoding(String enc)无效的原因
----第一次使用getParameter(String name)方法,已经在该请求所有数据存入map集合中,并进行获取编码判断if (encoding == null)encoding = "ISO-8859-1"
后面再设置就无效了,后面使用getParameter(String name)只是从存储好的map集合中拿,已不再进行判断编码了
为什么使用get提交数据时request.setCharacterEncoding(String enc)无效
----GET请求时,在URL中会解析参数 public String getParameter(String name){ if (!parametersParsed) {获取解析码并解析存储}},如果参数已经被解析过,if条件为false
不再获取enc解析
除了手动去设置name = new String(name.getBytes("ISO-8859-1"),"UTF-8")解决get乱码问题以外,还可以设置一下两个参数解决get乱码问题
1.useBodyEncodingForURI参数表示是否用request.setCharacterEncoding参数对URL提交的数据和表单中GET方式提交的数据进行重新编码,在默认情况下,该参数为false
2.URIEncoding参数指定对所有GET方式请求进行统一的重新编码(解码)的编码
总结:其实上面分析的解决乱码的核心原理,和我们使用过滤器解决web数据乱码问题原理是大同小异的,这就是为什么过滤器中需要加入开关标记flag来阻止第二次调用
getParameter(String name)时再次进行编码的原因,因为已经全部解码了,下次调用只是从map中获取值