起因
在編寫servlet
代碼的時候,練習重定向和請求轉發(fā),發(fā)現重定向至html
頁面時,頁面顯示中文正常,使用請求轉發(fā)至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");
}
}
}
請求轉發(fā)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
訪問請求轉發(fā)頁面
http://127.0.0.1:8080/repForward?username=admin&password=123456
可以看出請求轉發(fā)出現了亂碼
我們再故意輸錯密碼,測試一下請求轉發(fā)失敗的頁面fail.html
http://127.0.0.1:8080/repForward?username=admin&password=1234
同樣亂碼
解決方法(1)
網上已經有人給出了解決方法,即將請求轉發(fā)跳轉的html
編碼設置為GBK
,如下
重新訪問請求轉發(fā)頁面
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
,而為什么請求轉發(fā)和重定向都設置了UTF-8
但只有請求轉發(fā)的頁面顯示亂碼了
在這篇博文中提到
因此,我認為一個HTML文件在集成開發(fā)創(chuàng)建時是UTF-8的格式,這個格式在IDE上應該可以設置,但在打開時是更具默認編碼格式打開的(即ANSI),因此會產生亂碼
而在我們的討論+猜測下,請求轉發(fā)的過程類似于
圖中的GBK
指的是servlet默認讀取文件的編碼方式,不同地區(qū)的電腦可能默認不一樣
在另一篇博文對請求轉發(fā)詳細流程的介紹中也提到:
forward() 方法的處理流程:
● 清空用于存放響應正文(響應體)數據的緩沖區(qū)。
● 如果目標組件為Servlet 或JSP,就調用它們的service() 方法,把該方法產生的響應結果發(fā)送到客戶端,如果目標組件為文件系統(tǒng)中的靜態(tài) html 文檔,就讀去文檔中的數據并把它發(fā)送到客戶端。
也就是說,請求轉發(fā)是有一個讀文檔數據的過程,側面論證了圖示
讀文檔數據涉及到了文檔原來的編碼和讀取文件的編碼方式,分析可得,出現亂碼的原因是,文檔本身的編碼是UTF-8
,但servlet讀取時是使用默認編碼方式GBK
讀取的。
而我們在servlet中設置編碼的過程,也就是圖中的第二部分,所以不管我們用什么樣的方式設置UTF-8
,都只會讓只能使用GBK
解析的頁面亂碼
當然這一部分還是猜測,所以我們用另外兩種方法來驗證我們的觀點
論證1
不管編碼解碼的結果如何,我們想要傳遞的數據字節(jié)流是不變的,它不會因為亂碼字符就從登陸成功變成登陸失敗,換一句話說,不管用中文還是英文表達同一件事情,其內核都是表達的這件事,并不會因為使用的語言而改變
既然文檔本身的編碼是UTF-8
,servlet讀取方式為GBK
,我們把文檔本身編碼修改為GBK
,如果上面的推斷是正確的,這樣做應該就能夠讓亂碼正常
流程為:
GBK -> GBK -> 字符流 -> UTF-8 ->UTF-8頁面顯示
打開VScode
,方便轉換編碼
可以看到文件此時保存的編碼為UTF-8
我們修改其為GBK
,點擊通過編碼保存
設置成GBK
可以見到此時文件保存編碼修改為了 GBK
這個時候再啟動servlet
請求轉發(fā)
訪問 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
重啟服務,訪問請求轉發(fā)頁面
http://127.0.0.1:8080/repForward?username=admin&password=123456
此時訪問的頁面編碼依舊沒有亂碼,說明jsp-config
起了作用,同時確實是因為servlrt
默認讀取html
文件的編碼方式為GBK
為了驗證真的是jsp-config
的作用,將其刪除再試一次
刪除后訪問亂碼
證明確實servlet
默認讀取html
文件編碼方式為GBK
,這個默認方式不同的地區(qū)應該是不同的,例如美國應該是ASCII
總結
兩個論證中的方法也都能解決請求轉發(fā)至html
頁面亂碼的問題
亂碼出現的原因是文件本身編碼和servlet
默認讀取文件編碼方式不一樣而導致的
至于為什么重定向的頁面顯示中文是正常的,我們認為是請求轉發(fā)和重定向這兩個功能的實現在servlet
中不一樣,比如請求轉發(fā)是需要讀取轉發(fā)的html
文件,重定向是讓用戶自己重新去訪問html
頁面,缺少了默認讀取的部分,具體的實現區(qū)別需要看servlet
的源代碼才能知道
參考鏈接
- https://blog.csdn.net/qq_27368993/article/details/83616090
- https://blog.csdn.net/qq_26164609/article/details/102826376
END
建了一個微信的安全交流群,歡迎添加我微信備注進群
,一起來聊天吹水哇,以及一個會發(fā)布安全相關內容的公眾號,歡迎關注 ??
本文摘自 :https://www.cnblogs.com/