1. 程式人生 > >為什麼get請求會出現亂碼?

為什麼get請求會出現亂碼?

一、有時候我們在處理get請求時,比如下面的一個url跳轉

window.location.href = "某個url"

當你的url裡存在某個引數為中文字元,那麼你就可能遇到亂碼問題,為什麼說可能呢,因為tomcat預設編碼其實是ISO-8859-1,如果你在tomcat伺服器配置了utf-8編碼的話(config目錄下的server.xml檔案),就不會出亂碼了,配置如下(注意在你的使用的端口裡配置,一般都是在8080埠下配置一下URIEncoding)

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8"/>
二、現在我們不在伺服器裡做上面配置,那麼就需要使用到js的編碼技術以及java.net包提供的解碼技術,首先比如說我們傳的url裡存在一個引數departName=“教育BG研發中心”,那麼我們呼叫js的方法進行編碼encodeURI(encodeURI(departName)),如下:
    var departName = encodeURI(encodeURI(departName));
    window.location.href = "http://a.b.c?departName="+departName;
為什麼做兩次編碼呢?
原因如下:

1、利用encodeURI()在javascript中對中文URL引數進行編碼時,你的中文引數會被轉換為類似於“%E6%B5%8B%E8%AF%95”這種字串
2、但是瀏覽器機制會認為“%”是一個轉義字元,瀏覽器會把位址列URL中的傳遞的已轉換引數“%”與“%”之間的已轉義字元進行處理傳遞到後臺Action(介面)中。這樣會造成與實際經過encodeURI()編碼後的URL不符,因為瀏覽器誤認為“%”是轉義字元字元了,它並未將“%”認為是個普通字元。
3、要使得通過encodeURI()轉換後的URL被瀏覽器正常處理,必須在外層再用encodeURI()處理一次已被encodeURI()編碼後的RUL。這此處理encodeURI()會將已編碼後的URL中被瀏覽器解析為轉義字元的“%”再次進行編碼,轉換為普通字元。

這個時候,在後臺接口裡使用java.net做一下轉換就可以了:

String depName = java.net.URLDecoder.decode(request.getParameter("departName"), "UTF-8");

截圖debug除錯結果:


上面的轉換方式是:js前端轉2次,後端轉1次;

網上還有一種方式是:js轉一次,後端轉2次,這個沒有嘗試,貼出來如下:

url=encodeURI(url)
String app_name = java.net.URLDecoder.decode(request.getParameter("name"), "utf-8");
app_name = new String(app_name.getBytes("ISO-8859-1"),"utf-8");

三、至於有些人疑惑post傳遞的引數裡也有中文,為什麼從前臺傳遞過來不亂碼呢?

原因是post是以資料包的形式將封裝好的引數傳遞給後臺,中間不會做編碼轉換相關的處理,所以後臺直接獲取也不會出現亂碼。

當然有時post是會亂碼的(比如使用HttpClient包下的工具,遠端呼叫其它伺服器的介面,偶爾會遇到這種亂碼的情況),此時可以在接收時設定一下編碼,如下幾種方式:

1.java程式碼裡設定

request.setCharacterEncoding("UTF-8");
2.從web配置檔案設定
     <filter>
        <description>字符集過濾器</description>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
          <description>字符集編碼</description>
          <param-name>encoding</param-name>
          <param-value>UTF-8</param-value>
        </init-param>
     </filter>
     <filter-mapping>
      <filter-name>encodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
     </filter-mapping>
3.使用HttpURLConnection遠端訪問:
HttpURLConnection connection = null;
connection.setRequestProperty("contentType", "utf-8");
4.使用InputStreamReader讀取流時:
InputStreamReader in = null;
in = new InputStreamReader(connection.getInputStream(),"utf-8");
BufferedReader bufferedReader = new BufferedReader(in);
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while ((line = bufferedReader.readLine()) != null) {
    stringBuffer.append(line);
}
result = stringBuffer.toString();
5.使用HttpClient的HttpGet時:
CloseableHttpClient httpclient = httpClientBuilder.build();
HttpGet httpget = new HttpGet("url");
CloseableHttpResponse response = httpclient.execute(httpget);
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
6.使用HttpClient的HttpPost時:
CloseableHttpClient httpclient = httpClientBuilder.build();
HttpPost httpPost = new HttpPost(url);
List<BasicNameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("userAccount",userAccount));
params.add(new BasicNameValuePair("token",token));
UrlEncodedFormEntity httpEntity= new UrlEncodedFormEntity(valuePairs, "UTF-8");
httpMethod.setEntity(httpEntity);
CloseableHttpResponse response = httpclient.execute(httpMethod);
String content = EntityUtils.toString(response.getEntity(), "UTF-8");

語法:encodeURI(URIstring)

引數URIstring描述:必需。一個字串,含有 URI 或其他要編碼的文字。

返回值:URIstring 的副本,其中的某些字元將被十六進位制的轉義序列進行替換。

說明:

    1.該方法不會對 ASCII 字母和數字進行編碼,也不會對這些 ASCII 標點符號進行編碼: - _ . ! ~ * ' ( ) 。

    2.該方法的目的是對 URI 進行完整的編碼,因此對以下在 URI 中具有特殊含義的 ASCII 標點符號,encodeURI() 函式是不會進行轉義的:;/?:@&=+$,#

提示和註釋:如果 URI 元件中含有分隔符,比如 ? 和 #,則應當使用 encodeURIComponent() 方法分別對各元件進行編碼。