您现在的位置:首页 >> 前端 >> 内容

浅谈web开发中的乱码问题

时间:2017/9/16 9:07:27 点击:

  核心提示:String encode = URLEncoder.encode(request.getParameter(name),ISO-8859-1);String name = URLDecoder.de...

String encode = URLEncoder.encode(request.getParameter("name"),"ISO-8859-1");

String name = URLDecoder.decode(encode,"UTF-8");

@Test

publicvoidtest1()throwsException{

// 1,原始中文参数

String parameter ="中文";

System.out.println("原始中文参数:"+parameter);

// 2,浏览器通过UTF-8进行URLEncode

StringbrowerEncodeParameter = URLEncoder.encode(parameter,"UTF-8");

System.out.println("浏览器通过UTF-8进行URLEncode后的值:"+browerEncodeParameter);

// 3,通过ISO-8859-1进行URLDecode

StringserverDecodeParameter = URLDecoder.decode(browerEncodeParameter,"ISO-8859-1");

System.out.println("直接取出时通过ISO-8859-1进行URLDecode后得到的乱码:"+serverDecodeParameter);

// 4,手动通过ISO-8859-1对乱码进行URLEncode

StringcodeEncodeParameter = URLEncoder.encode(serverDecodeParameter,"ISO-8859-1");

System.out.println("手动对乱码通过ISO-8859-1进行URLEncode得到的浏览器原始提交的值:"+codeEncodeParameter);

// 5,手动通过UTF-8对步骤4得到的值进行URLDecode后得到正确中文参数

StringcodeDecodeParameter = URLDecoder.decode(codeEncodeParameter,"UTF-8");

System.out.println("手动通过UTF-8进行URLDecode后得到的正确中文参数:"+codeDecodeParameter);

}

原始中文参数:中文

浏览器通过UTF-8进行URLEncode后的值: %E4%B8%AD%E6%96%87

直接取出时通过ISO-8859-1进行URLDecode后得到的乱码: ??-?–‡

手动对乱码通过ISO-8859-1进行URLEncode得到的浏览器原始提交的值: %E4%B8%AD%E6%96%87

手动通过UTF-8进行URLDecode后得到的正确中文参数: 中文

String name = new String(request.getParameter("name").getBytes("IOS-8859-1"),"UTF-8");

request.setCharacterEncoding("UTF-8");

String value = requst.getParameter("name");

编码问题是很多开发者在Web开发过程中经常会遇到的问题,有的虽然能够机械的记住解决的代码,但是对乱码出现的原因以及解决的原理未作过了解。因此本文这部分内容作一个简单的总结和解释。

请求中文乱码

HTTP请求中,最常用的请求方式为GET和POST。请求参数会随着不同的请求方式出现在不同的位置,所以对于中文乱码的处理方式也不一样。

GET请求中文参数乱码解决

GET方式提交参数时,参数是直接出现在URL中的,对于GET请求,中文参数乱码问题解决方式有3种。

1.修改Tomcat编码。

Tomcat安装路径–> conf –>server.xml –> Connector标签–>增加URIEncoding属性

通常不建议使用这种方式,因为一个采用Tomcat8.0之前版本服务器的老项目,代码中可能已经处理了GET请求的乱码问题,采用这种方式反而会导致乱码的出现。Tomcat8以及以上版本已经将默认编码修改为UTF-8因此不用修改。

2.通过URLEncoder和URLDecoder进行编解码操作。

代码解释:

GET请求的参数是出现在URL中的QueryString部分的,URL中如果含有中文等非ASCII字符,则浏览器会对它们进行URLEncode,然后发送给服务器,在通过request.getParameter(“name”)取出时又会对该name对应的参数进行URLDecode。通常在进行URLEncode的时候采用的编码为UTF-8,而在URLDecode的时候会采用Tomcat服务器的默认编码ISO-8859-1,编码和解码所采用的编码方式不一致,所以出现乱码。既然通过request.getParameter(“name”)得到了一个采用ISO-8859-1进行URLDecode的乱码,那么我们可以对该乱码通过ISO-8859-1进行URLEncode,此时的值就是浏览器最初提交到后台的通过UTF-8 URLEncode后的数据。然后我们通过与浏览器一致的UTF-8编码对该数据进行解码。两端编码一致,乱码问题就得到了解决。

Talk is cheap,Show you the code.

我们通过下面的代码来解释乱码出现到解决的过程,

执行结果:

那么接下来继续对 GET 请求的剩下一种方式以及 POST 请求的中文乱码解决方式作一个总结。 3. 通过 String 的构造方法。

代码解释:

无论从浏览器提交时中文参数是什么编码格式,到达服务器时因为 Tomcat 编码方式的原因,采用 ISO-8859-1 的方式给解析成了乱码

request.getParameter(“name”) 获取到的就是一个通过 ISO-8859-1 方式解析之后的乱码,那么我们通过 getBytes(“ISO-8859-1”) 将它反解成原有编码的字符数组,相当于打回原形,这是一个正确的字符数组,然后通过 String 的构造方法将这个正确的字符数组转成 UTF-8 编码的字符串。因为代码相对简单,因此通常采用这种方式。

POST请求中文参数乱码解决

对于 POST 方式,表单中的参数值对是通过 request body 发送给服务器,此时浏览器会根据网页的 ContentType(“text/html; charset=编码”) 中指定的编码进行对表单中的数据进行编码,然后发给服务器。POST 的参数是在请求体中,直接到达后台,数据在 Servlet 中的 request 中。request 有一个缓冲区,request 的缓冲区采用的是 ISO-8859-1 编码,因为 requeset 是 Tomcat 负责创建的,所以用的是 Tomcat 的编码。解决方式是设置 request 缓冲区编码。在服务器端的程序中我们可以通过 request 对象 的 setCharacterEncoding 方法设置编码,然后通过 request 对象的 getParameter 获得正确的数据。

响应中文乱码 通常情况我们都是通过 HttpServletResponse 对象向页面进行响应,HttpServletResponse 有两种响应方式,一种是 OutputStream 字节流,另一种是 PrintWriter 字符流。是否会出现中文乱码,以及乱码解决方式跟采用的流的类型有关。 字节流

使用字节流不一定会出现中文乱码,取决于操作系统,工作空间以及浏览器打开页面时采用的编码。如果两端编码一致,则不会出现中文乱码,不一致则出现乱码。

解决方式:

设置字符数组取出时的编码

设置浏览器打开时的编码

response.getOutPutStream.write("中文".getBytes("UTF-8"));

response.setHeader("Content-Type","text/html;charset=UTF-8");

总之是设置输出时的字节数组编码和浏览器解析时的编码一致。中文转成字节数组的时候,如果 IDE 工作空间的编码正好和浏览器一致,可以不用设置字符数组取出时的编码,但是为了保险起见,建议还是设置。

字符流

使用字符流一定会出现中文乱码,HttpServletResponse 使用的字符流是有缓冲区的,缓冲区使用的默认编码是 IOS-8859-1,压根儿就不支持中文。

解决方式:

设置字符流缓冲区的编码

设置浏览器打开时的编码

response.setCharacterEncoding("UTF-8");

response.setHeader("Content-Type","text/html;charset=UTF-8");

response.getWriter().println("中文");

简化写法

response.setContentType("text/html;charset=UTF-8");

response.getWriter().println("中文");

文件下载时的中文文件名乱码处理 文件下载前,文件名一般是以 GET 请求方式的参数直接出现在浏览器的地址栏也就是 URL 中的,所以需要先通过解决 GET 请求中文乱码的方式将中文文件名接收成正常的中文。 在下载开始时,需要设置文件保存时采用的文件名,不同浏览器因为特性的不同需要分别设置,如 IE 等内核的浏览器要求 Content-Disposition 响应头中的中文文件名需要通过 URLEncoder 进行编码,而火狐浏览器要求 Content-Disposition 响应头中的中文文件名需要通过 Base64 进行编码。所以要通过请求头中的 User-Agent 头信息获取到浏览器类型后分别处理。

解决方式

// 1.接收参数,解决 GET 请求参数中文乱码,目的是将中文文件名转成正常中文

String filename = new String(request.getParameter("filename").getBytes("ISO-8859-1"),"UTF-8");

// 根据浏览器的类型处理保存的中文文件名的乱码问题:

String agent = request.getHeader("User-Agent");

if(agent.contains("Firefox")){

filename = base64EncodeFileName(filename);

}else{

filename = URLEncoder.encode(filename,"UTF-8");

}

// 2.2设置Content-Disposition头

response.setHeader("Content-Disposition", "attachment;filename="+filename);

通过 Base64 编码中文文件名的方法代码如下:

// 参数为中文文件名

public static String base64EncodeFileName(String fileName) {

BASE64Encoder base64Encoder = new BASE64Encoder();

try {

return "=?UTF-8?B?"

+ new String(base64Encoder.encode(fileName

.getBytes("UTF-8"))) + "?=";

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

Tags:浅谈 谈W WE EB 
作者:网络 来源:itcasthuan