Servlet请求转发至html页面中文乱码问题与分析
起因
在编写servlet
代码的时候,练习重定向和请求转发,发现重定向至html
页面时,页面显示中文正常,使用请求转发至html
页面时,显示中文乱码,两个servlet
都在doGet()
方法内首先使用了resp.setCharacterEncoding("UTF-8");
设置编码为UTF-8
。
核心代码
各部分核心代码如下:
重定向repRedirect
代码:
@WebServlet("/repTest")
public class repRedirect extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
String username=req.getParameter("username");
String password=req.getParameter("password");
if(username.equals("admin")&&password.equals("123456")){
resp.sendRedirect("/Unit7/welcome.html");
}else{
resp.sendRedirect("/Unit7/fail.html");
}
}
}
请求转发repForward.java
代码:
@WebServlet("/repForward")
public class repForward extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
resp.setHeader("Content-Type","text/html;charset=UTF-8");
String username=req.getParameter("username");
String password=req.getParameter("password");
// if(username.isEmpty()&&password.isEmpty()){
// resp.sendRedirect("/Unit/welcome.html");
// }
if(username.equals("admin")&&password.equals("123456")){
req.getRequestDispatcher("/Unit7/welcome.html").forward(req,resp);
}else{
req.getRequestDispatcher("/Unit7/fail.html").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
跳转的html页面代码
welcome.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>欢迎登陆</h3>
</body>
</html>
fail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>登陆失败</h3>
</body>
</html>
访问效果
访问重定向页面
http://127.0.0.1:8080/repTest?username=admin&password=123456
访问请求转发页面
http://127.0.0.1:8080/repForward?username=admin&password=123456
可以看出请求转发出现了乱码
我们再故意输错密码,测试一下请求转发失败的页面fail.html
http://127.0.0.1:8080/repForward?username=admin&password=1234
同样乱码
解决方法(1)
网上已经有人给出了解决方法,即将请求转发跳转的html
编码设置为GBK
,如下
重新访问请求转发页面
http://127.0.0.1:8080/repForward?username=admin&password=123456
此时乱码恢复正常
fail.html
页面并没有修改为GBK
,我们访问它试试,进行对照比较
http://127.0.0.1:8080/repForward?username=admin&password=1234
依旧乱码,可以看出是设置GBK
生效
原因分析
虽然这样设置能够让页面的乱码正常,但是我们实际上是在servlet
里面设置了UTF-8
编码,为什么页面上还需要改为GBK
,而为什么请求转发和重定向都设置了UTF-8
但只有请求转发的页面显示乱码了
在这篇博文中提到
因此,我认为一个HTML文件在集成开发创建时是UTF-8的格式,这个格式在IDE上应该可以设置,但在打开时是更具默认编码格式打开的(即ANSI),因此会产生乱码
而在我们的讨论+猜测下,请求转发的过程类似于
图中的GBK
指的是servlet默认读取文件的编码方式,不同地区的电脑可能默认不一样
在另一篇博文对请求转发详细流程的介绍中也提到:
forward() 方法的处理流程:
● 清空用于存放响应正文(响应体)数据的缓冲区。
● 如果目标组件为Servlet 或JSP,就调用它们的service() 方法,把该方法产生的响应结果发送到客户端,如果目标组件为文件系统中的静态 html 文档,就读去文档中的数据并把它发送到客户端。
也就是说,请求转发是有一个读文档数据的过程,侧面论证了图示
读文档数据涉及到了文档原来的编码和读取文件的编码方式,分析可得,出现乱码的原因是,文档本身的编码是UTF-8
,但servlet读取时是使用默认编码方式GBK
读取的。
而我们在servlet中设置编码的过程,也就是图中的第二部分,所以不管我们用什么样的方式设置UTF-8
,都只会让只能使用GBK
解析的页面乱码
当然这一部分还是猜测,所以我们用另外两种方法来验证我们的观点
论证1
不管编码解码的结果如何,我们想要传递的数据字节流是不变的,它不会因为乱码字符就从登陆成功变成登陆失败,换一句话说,不管用中文还是英文表达同一件事情,其内核都是表达的这件事,并不会因为使用的语言而改变
既然文档本身的编码是UTF-8
,servlet读取方式为GBK
,我们把文档本身编码修改为GBK
,如果上面的推断是正确的,这样做应该就能够让乱码正常
流程为:
GBK -> GBK -> 字符流 -> UTF-8 ->UTF-8页面显示
打开VScode
,方便转换编码
可以看到文件此时保存的编码为UTF-8
我们修改其为GBK
,点击通过编码保存
设置成GBK
可以见到此时文件保存编码修改为了 GBK
这个时候再启动servlet
请求转发
访问 http://127.0.0.1:8080/repForward?username=admin&password=123456
显示正常
侧面反映了我们思考的过程是正确的
论证2
配置XML
文件
<jsp-config>
<jsp-property-group>
<url-pattern>*.html</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
意思是,任何以html
结尾的URL请求的资源,都以UTF-8
格式打开,这里也就是修改servlet
的读取文件编码方式,此时将welcome.html
文件的编码修改回UTF-8
重启服务,访问请求转发页面
http://127.0.0.1:8080/repForward?username=admin&password=123456
此时访问的页面编码依旧没有乱码,说明jsp-config
起了作用,同时确实是因为servlrt
默认读取html
文件的编码方式为GBK
为了验证真的是jsp-config
的作用,将其删除再试一次
删除后访问乱码
证明确实servlet
默认读取html
文件编码方式为GBK
,这个默认方式不同的地区应该是不同的,例如美国应该是ASCII
总结
两个论证中的方法也都能解决请求转发至html
页面乱码的问题
乱码出现的原因是文件本身编码和servlet
默认读取文件编码方式不一样而导致的
至于为什么重定向的页面显示中文是正常的,我们认为是请求转发和重定向这两个功能的实现在servlet
中不一样,比如请求转发是需要读取转发的html
文件,重定向是让用户自己重新去访问html
页面,缺少了默认读取的部分,具体的实现区别需要看servlet
的源代码才能知道
参考链接
- https://blog.csdn.net/qq_27368993/article/details/83616090
- https://blog.csdn.net/qq_26164609/article/details/102826376
END
建了一个微信的安全交流群,欢迎添加我微信备注进群
,一起来聊天吹水哇,以及一个会发布安全相关内容的公众号,欢迎关注 😃