更新時(shí)間:2018年12月07日11時(shí)39分 來(lái)源:傳智播客 瀏覽次數(shù):
# WEB應(yīng)用中請(qǐng)求和響應(yīng)的字符集設(shè)置
在web應(yīng)用里,一切操作都是基于請(qǐng)求和響應(yīng)的。其中,請(qǐng)求表示客戶端向服務(wù)端發(fā)送的數(shù)據(jù),響應(yīng)表示服務(wù)端向客戶端返回的數(shù)據(jù)。客戶端和服務(wù)端之間的數(shù)據(jù)交互,如果沒(méi)有統(tǒng)一的字符集設(shè)置,就會(huì)導(dǎo)致數(shù)據(jù)亂碼。
本文就客戶端和服務(wù)端之間交互時(shí)的亂碼問(wèn)題進(jìn)行探討和解決。
> 注:本文使用的是Tomcat7.0版本
## 一、一次請(qǐng)求和響應(yīng)的執(zhí)行流程
在客戶端和服務(wù)端的交互過(guò)程中,數(shù)據(jù)需要通過(guò)網(wǎng)絡(luò)進(jìn)行傳輸,如果數(shù)據(jù)編碼和解碼方式設(shè)置不當(dāng),就會(huì)亂碼。其實(shí)亂碼的原因很簡(jiǎn)單:編碼解碼方式不一致,就必定會(huì)亂碼。那么亂碼的解決方案就很簡(jiǎn)單了:編碼和解碼使用相同的字符集。
? 我們有必要先了解一下一次請(qǐng)求和響應(yīng)的執(zhí)行過(guò)程,之后再說(shuō)如何解決亂碼問(wèn)題。
![請(qǐng)求和響應(yīng)流程](.\請(qǐng)求和響應(yīng)流程.jpg)
如上圖所示,請(qǐng)求流程如下:
```
頁(yè)面提交數(shù)據(jù)--->瀏覽器編碼--->服務(wù)器把數(shù)據(jù)封裝到request對(duì)象里--->我們的Servlet從request獲取數(shù)據(jù)并解碼
這個(gè)過(guò)程經(jīng)過(guò)了:瀏覽器編碼 和 request解碼。只要它們使用的字符集是相同的,那么客戶端傳遞給服務(wù)端的數(shù)據(jù)就不會(huì)亂碼。
```
響應(yīng)流程如下:
```
Servlet里使用response編碼并設(shè)置數(shù)據(jù)--->服務(wù)器把response轉(zhuǎn)換成HTTP響應(yīng)--->瀏覽器解碼并顯示數(shù)據(jù)
這個(gè)過(guò)程經(jīng)過(guò)了:response編碼數(shù)據(jù) 和 瀏覽器解碼數(shù)據(jù)。只要它們使用的字符集是相同的,那么服務(wù)端傳遞給客戶端的數(shù)據(jù)就不會(huì)亂碼。
```
## 二、請(qǐng)求參數(shù)的字符集設(shè)置
### 1. 瀏覽器的編碼方式設(shè)置
瀏覽器在提交數(shù)據(jù)時(shí),使用的編碼方式是由` `標(biāo)簽指定的,如下:
```html
```
### 2. request的解碼方式設(shè)置
? 服務(wù)端使用request對(duì)象來(lái)接收客戶端傳遞的參數(shù)。但是request默認(rèn)使用iso-8859-1進(jìn)行解碼,所以參數(shù)里的中文會(huì)亂碼。
? 如果想要得到正常的中文,必須讓request也采用瀏覽器編碼相同的字符集進(jìn)行解碼,才可以獲取正常的中文。我們頁(yè)面上設(shè)置的字符集是utf-8,那么就設(shè)置request也使用utf-8進(jìn)行解碼。實(shí)現(xiàn)代碼如下:
```java
//指定request使用utf-8進(jìn)行解碼請(qǐng)求體里的數(shù)據(jù)
request.setCharacterEncoding("utf-8");
//得到的是正常的中文
String name = request.getParameter("name");
```
? 但是以上方法僅適用于POST提交的參數(shù),不適用于GET提交的參數(shù)。因?yàn)镚ET提交的參數(shù)是在請(qǐng)求行里提交的,而請(qǐng)求行只支持iso-8859-1字符集,不支持其它字符集,所以方法無(wú)效了。
? 那么GET提交的參數(shù)應(yīng)該怎么辦呢?不能指定解碼的字符集,但我們可以進(jìn)行手動(dòng)轉(zhuǎn)碼,把亂碼值還原:怎么亂碼的,逆回去就會(huì)還原:
```
亂碼過(guò)程:頁(yè)面utf-8編碼“張三”--->request對(duì)象iso-8859-1解碼--->???亂碼值
還原過(guò)程:???亂碼值--->iso-8859-1編碼--->utf-8解碼--->張三
```
? 使用Java代碼實(shí)現(xiàn)還原過(guò)程就是:
```java
//先得到亂碼值
String value = request.getParameter("name");
//使用iso-8859-1編碼
byte[] bytes = value.getBytes("iso-8859-1");
//使用utf-8解碼,得到正常的中文
value = new String(bytes, "utf-8");
```
## 三、響應(yīng)數(shù)據(jù)的字符集設(shè)置
### 1. response的編碼方式設(shè)置
response默認(rèn)使用的是iso-8859-1字符集進(jìn)行編碼,是不支持中文的。所以如果想要傳輸中文數(shù)據(jù)到客戶端,首先就需要指定response的字符集,然后再向response中設(shè)置數(shù)據(jù)。設(shè)置方法如下:
```java
response.setCharacterEncoding("utf-8");
response.getWriter().print("李四");
```
設(shè)置完成,就可以向response里輸中文數(shù)據(jù)了。但是如果想要這些數(shù)據(jù)在瀏覽器上能夠正常顯示,就需要指定瀏覽器也采用utf-8進(jìn)行解碼才可以。
### 2. 瀏覽器的解碼方式設(shè)置
基本上各大瀏覽器都可以人為指定字符集,來(lái)解碼頁(yè)面,例如:firefox。可以在菜單-->查看-->文字編碼-->選擇字符集。這個(gè)字符集必須要和服務(wù)端設(shè)置的response字符集相同,我們這里也需要設(shè)置為utf-8。
但是給瀏覽器手動(dòng)指定解碼字符集,是需要一定的編程基礎(chǔ)的,而普通用戶基本無(wú)法完成這一操作。所以我們需要使用其它方案來(lái)解決響應(yīng)數(shù)據(jù)的亂碼問(wèn)題。
### 3. 響應(yīng)數(shù)據(jù)的字符集最終設(shè)置方案
response提供了一個(gè)最終的解決方法,既可以設(shè)置response編碼的字符集,也可以指定瀏覽器解碼的字符集。一步到位,解決響應(yīng)數(shù)據(jù)亂碼問(wèn)題。具體方法如下:
```java
//同時(shí)指定response編碼的字符集,和瀏覽器解碼的字符集,都使用utf-8
response.setContentType("text/html;charset=utf-8");
//再設(shè)置的中文,瀏覽器就正常顯示了。不需要再進(jìn)行其它任何額外的操作
response.getWriter().print("李四");
```
北京校區(qū)