地址栏传参中文乱码详解
1.地址栏传参(包括<a>标签的href传参),浏览器会先将中文参数值按照某种编码方式(默认为utf-8,很多浏览器都可以进行设置更改默认编码)进行编码,然后再传到服务端。
服务端在第一次使用request.getParameter获取该参数值的时候,服务端会自动进行解码,这时解码的方式要么为默认的”iso8859-1",要么就是jsp页面中设置的contentType中charset的值,要使用jsp中contentType的charset设置的编码方式,必须在服务器中进行配置(如tomcat需要配置useBodyEncodingURI="true")。这种情况,只需保证jsp中contentType的charset设置的编码方式与浏览器的编码方式一致,并且配置useBodyEncodingURI="true"即可保证不乱码,或者不设置useBodyEncodingURI="true"的话,可通过new String(param.getBytes("iso8859-1","浏览器编码方式"))进行手动编码解码。
2.地址栏传参,还可以先用js或者java小脚本将参数值进行编码(如果事先不知道值的,可以通过js获取用户输入的值再使用escape,escapeURL等js方法进行编码;
如果事先就知道要传递的参数值,那么可以使用<%=URLEncoder.encode("参数值","编码方式") %>进行编码),然后再传递到服务端。这种方式实质上跟第一种方式(让浏览器自动编码)基本上是一样的,服务端在第一次使用request.getParameter()方法获取值的时候一定会自动进行解码,即是说,虽然可以在客户端手动编码,却无法在服务端通过URLDecoder.decode()进行手动解码(比如我在客户端将”中国“用gbk编码为”%D6%D0%B9%FA“,当我在服务端使用request.getParameter()时已经进行了解码,即获取不到”%D6%D0%B9%FA“)。所以只能通过保证”js或者java小脚本进行编码的编码方式和jsp中contentType的charset设置的编码方式一致并设置useBodyEncodingURI"来保证不乱码。这种方式比第一种方式要好些, 因为是自己程序控制的编码方式,而不是使用浏览器设置的编码方式,避免了用户修改浏览器默认编码设置而导致乱码。
3.表单提交,无论是get还是post提交,如果某个表单元素的值为编码后的值,如某个文本框输入值为“%D6%D0%B9%FA”,那么在服务端通过request.getParameter()可以获取到
“%D6%D0%B9%FA”这样的值,然后就可以使用URLDecoder.decode()进行解码。使用get方式提交可以观察到(get方式提交会将表单元素作为参数添加到地址栏,所以可以通过地址栏看到),如果某个表单元素值为“%D6%D0%B9%FA”,那么提交时可以看到浏览器地址栏该值会变为“%25%D6%25%D0%25%B9%25%FA”,在每个十六进制数的百分号之前会添加一个%25(16进制的25对应ascii符号为%),post提交方式也是一样的(通过HttpWatch看到请求内容)。所以猜想:%25是个特殊标志,用来保证客户端已经编码的中文传到服务端后服务端可以获取到客户端编码的值。