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

img

访问请求转发页面

http://127.0.0.1:8080/repForward?username=admin&password=123456

img

可以看出请求转发出现了乱码

我们再故意输错密码,测试一下请求转发失败的页面fail.html

http://127.0.0.1:8080/repForward?username=admin&password=1234

img

同样乱码

解决方法(1)

网上已经有人给出了解决方法,即将请求转发跳转的html编码设置为GBK,如下

img

重新访问请求转发页面

http://127.0.0.1:8080/repForward?username=admin&password=123456

img

此时乱码恢复正常

fail.html页面并没有修改为GBK,我们访问它试试,进行对照比较

http://127.0.0.1:8080/repForward?username=admin&password=1234

img

依旧乱码,可以看出是设置GBK生效

原因分析

虽然这样设置能够让页面的乱码正常,但是我们实际上是在servlet里面设置了UTF-8编码,为什么页面上还需要改为GBK,而为什么请求转发和重定向都设置了UTF-8但只有请求转发的页面显示乱码了

在这篇博文中提到

因此,我认为一个HTML文件在集成开发创建时是UTF-8的格式,这个格式在IDE上应该可以设置,但在打开时是更具默认编码格式打开的(即ANSI),因此会产生乱码

而在我们的讨论+猜测下,请求转发的过程类似于

img

图中的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,方便转换编码

img

可以看到文件此时保存的编码为UTF-8

我们修改其为GBK,点击通过编码保存

img

设置成GBK

img

可以见到此时文件保存编码修改为了 GBK

img

这个时候再启动servlet请求转发

访问 http://127.0.0.1:8080/repForward?username=admin&password=123456

显示正常

img

侧面反映了我们思考的过程是正确的

论证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

img

img

重启服务,访问请求转发页面

http://127.0.0.1:8080/repForward?username=admin&password=123456

此时访问的页面编码依旧没有乱码,说明jsp-config起了作用,同时确实是因为servlrt默认读取html文件的编码方式为GBK

img

为了验证真的是jsp-config的作用,将其删除再试一次

删除后访问乱码

img

证明确实servlet默认读取html文件编码方式为GBK,这个默认方式不同的地区应该是不同的,例如美国应该是ASCII

总结

两个论证中的方法也都能解决请求转发至html页面乱码的问题

乱码出现的原因是文件本身编码和servlet默认读取文件编码方式不一样而导致的

至于为什么重定向的页面显示中文是正常的,我们认为是请求转发和重定向这两个功能的实现在servlet中不一样,比如请求转发是需要读取转发的html文件,重定向是让用户自己重新去访问html页面,缺少了默认读取的部分,具体的实现区别需要看servlet的源代码才能知道

参考链接

END

建了一个微信的安全交流群,欢迎添加我微信备注进群,一起来聊天吹水哇,以及一个会发布安全相关内容的公众号,欢迎关注 😃

GIF GIF

__EOF__

本文作者春告鳥
本文链接https://www.cnblogs.com/Cl0ud/p/15322455.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   春告鳥  阅读(3010)  评论(3编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示