Servlet3:從根源瞭解並解決編碼問題

Chinese 苦力發表於2020-12-07

系列文章目錄

前言

你是否遇到無論使用什麼方法請求和響應總是亂碼的問題,這篇文章將帶你瞭解一切

URL編碼

在我們使用URL進行傳值時我們使用的格式為

?key1=value1&key2=value2

當我們要傳一些特殊字元以及中文時就必須使用百分號加傳入字元編碼的十六進位制表示形式,

舉個例子,寫一個jsp頁面編碼方式為GB2312,

<%@ page contentType="text/html;charset=GB2312" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="download" method="post">
        檔名稱<input type="text" name="filename">
        <input type="submit" value="提交" >
    </form>
</body>
</html>

傳入"你好"點選提交
在這裡插入圖片描述
我們開啟除錯工具檢視http傳輸的真是編碼為%C4%E3%BA%C3
在這裡插入圖片描述

然後我們寫一個測試程式測試一下該字串解碼後是否是"你好"

public class test {
    public static void main(String[] args) throws UnsupportedEncodingException {
        System.out.println(URLDecoder.decode("%C4%E3%BA%C3", "Gb2312"));
    }
}

檢視一下輸出,完全正確
在這裡插入圖片描述
如果我們將方法中的字符集改為utt8會怎麼樣

System.out.println(URLDecoder.decode("%C4%E3%BA%C3", "utf8"));

輸出一下,熟悉的字元來了
在這裡插入圖片描述
由於我們頁面通常使用utf8編碼格式,所以我把我的主頁編碼方式改回來再看一下"你好"的編碼,毫無疑問它變化了
在這裡插入圖片描述

編碼方式和字符集的區別

字符集和編碼方式區別很明顯,顧名思義,字符集就是字元的集合,如ASCII,GBK,BIG5,Unicode等,編碼方式是即可理解為定義在字符集上的對映規則對於unicode字符集,有utf8,utf16,utf32等多種編碼方式,但對於其他字符集比如,ASCII,GBK,GB2312等,不僅僅代表字符集,同時也代表了(預設的)的編碼方式

如何改變編碼方式

如果我們想改變一個資料的編碼方式,我們就必須先用原資料的編碼方式將源資料解碼為位元組資料,然後再使用我們需要的編碼方式進行編碼

Tomcat做了什麼

當使用者的請求到達伺服器時第一經手的是tomcat,它將資料自己預設的編碼方式處理請求和響應資料,傳給我們的自己定義的Servlet

POST請求亂碼

之所以要分POST請求和GET請求是因為post請求有響應體而get請求沒有響應體所以解決post請求亂碼有兩種方式

方式一

使用request.setCharacterEncoding()方法,注意此方法的官方說明,

Overrides the name of the character encoding used in the body of this request.

翻譯過來就是"重寫此請求主體中使用的字元編碼的名稱",由於get請求沒有請求體,所以它自然不會對get請求有作用

此方法必須在獲取所有請求引數前呼叫才有效

來看一個小例子
在這裡插入圖片描述

我在後代獲取username的值並傳入資料庫,(注意資料庫的編碼方式設定為utf8),
我們先不使用這個方法看看結果

列印結果
在這裡插入圖片描述
資料庫結果
在這裡插入圖片描述
毫無疑問都是亂碼,接著使用這各方法設定為utf8看看結果

列印結果,為什麼亂碼?
在這裡插入圖片描述
資料庫結果,意料之中
在這裡插入圖片描述
那麼在這裡為什麼列印還是亂碼呢,因為當輸出到螢幕時,也需要轉換為我們系統的編碼方式才能不亂碼,那麼加上這句程式碼再試試

System.out.println(new String(username.getBytes(StandardCharsets.UTF_8),"GBK"));

在這裡插入圖片描述
列印結果不亂了,所以說不能因為列印結果亂碼就認定這個方法不行

方式二

方式二就是通過通過編碼解碼的方法來改變編碼方式,tomcat預設的編碼方式為
ISO-8859-1,我們只需要用這個編碼解碼再用utf8編碼即可

request.getParameter("username").getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8)

GET請求亂碼

由於get請求沒有請求體所以只能用上述第二種方式

響應亂碼

解決響應亂碼也有兩步
第一步:設定響應體的編碼方式

response.setCharacterEncoding("UTF-8")

第二步:設定返回檔案的編碼方式

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

這樣就能完全瞭解並解決編碼問題了

相關文章