激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java在web頁面上的編碼解碼處理及中文URL亂碼解決

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

2020-04-06 11:22chenssy JAVA教程

這篇文章主要介紹了Java在web頁面上的編碼解碼處理及中文URL亂碼解決,文中所介紹的兩種使用過濾器解決中文鏈接亂碼的方法非常有效,需要的朋友可以參考下

編碼&解碼
 通過下圖我們可以了解在javaWeb中有哪些地方有轉碼:

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

用戶想服務器發送一個HTTP請求,需要編碼的地方有url、cookie、parameter,經過編碼后服務器接受HTTP請求,解析HTTP請求,然后對url、cookie、parameter進行解碼。在服務器進行業務邏輯處理過程中可能需要讀取數據庫、本地文件或者網絡中的其他文件等等,這些過程都需要進行編碼解碼。當處理完成后,服務器將數據進行編碼后發送給客戶端,瀏覽器經過解碼后顯示給用戶。在這個整個過程中涉及的編碼解碼的地方較多,其中最容易出現亂碼的位置就在于服務器與客戶端進行交互的過程。
 上面整個過程可以概括成這樣,頁面編碼數據傳遞給服務器,服務器對獲得的數據進行解碼操作,經過一番業務邏輯處理后將最終結果編碼處理后傳遞給客戶端,客戶端解碼展示給用戶。所以下面我就請求對javaweb的編碼&解碼進行闡述。
請求
 客戶端想服務器發送請求無非就通過四中情況:
 1、URL方式直接訪問。
 2、頁面鏈接。
 3、表單get提交
 4、表單post提交
URL方式
 對于URL,如果該URL中全部都是英文的那倒是沒有什么問題,如果有中文就要涉及到編碼了。如何編碼?根據什么規則來編碼?又如何來解碼呢?下面將一一解答!首先看URL的組成部分:

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

在這URL中瀏覽器將會對path和parameter進行編碼操作。為了更好地解釋編碼過程,使用如下URL
 http://127.0.0.1:8080/perbank/我是cm?name=我是cm
 將以上地址輸入到瀏覽器URL輸入框中,通過查看http 報文頭信息我們可以看到瀏覽器是如何進行編碼的。下面是IE、Firefox、Chrome三個瀏覽器的編碼情況:

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

 可以看到各大瀏覽器對“我是”的編碼情況如下:

 

path部分

Query String

Firefox

E6 88 91 E6 98 AF

E6 88 91 E6 98 AF

Chrome

E6 88 91 E6 98 AF

E6 88 91 E6 98 AF

IE

E6 88 91 E6 98 AF

CE D2 CA C7


查閱上篇博客的編碼可知對于path部分Firefox、chrome、IE都是采用UTF-8編碼格式,對于Query String部分Firefox、chrome采用UTF-8,IE采用GBK。至于為什么會加上%,這是因為URL的編碼規范規定瀏覽器將ASCII字符非 ASCII 字符按照某種編碼格式編碼成 16 進制數字然后將每個 16 進制表示的字節前加上“%”。
 當然對于不同的瀏覽器,相同瀏覽器不同版本,不同的操作系統等環境都會導致編碼結果不同,上表某一種情況,對于URL編碼規則下任何結論都是過早的。由于各大瀏覽器、各個操作系統對URL的URI、QueryString編碼都可能存在不同,這樣對服務器的解碼勢必會造成很大的困擾,下面我們將已tomcat,看tomcat是如何對URL進行解碼操作的。
 解析請求的 URL 是在 org.apache.coyote.HTTP11.InternalInputBuffer 的 parseRequestLine 方法中,這個方法把傳過來的 URL 的 byte[] 設置到 org.apache.coyote.Request 的相應的屬性中。這里的 URL 仍然是 byte 格式,轉成 char 是在 org.apache.catalina.connector.CoyoteAdapter 的 convertURI 方法中完成的:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected void convertURI(MessageBytes uri, Request request)
    throws Exception {
     ByteChunk bc = uri.getByteChunk();
     int length = bc.getLength();
     CharChunk cc = uri.getCharChunk();
     cc.allocate(length, -1);
     String enc = connector.getURIEncoding();  //獲取URI解碼集
     if (enc != null) {
      B2CConverter conv = request.getURIConverter();
      try {
       if (conv == null) {
        conv = new B2CConverter(enc);
        request.setURIConverter(conv);
       }
      } catch (IOException e) {...}
      if (conv != null) {
       try {
        conv.convert(bc, cc, cc.getBuffer().length - cc.getEnd());
        uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength());
        return;
       } catch (IOException e) {...}
      }
     }
     // Default encoding: fast conversion
     byte[] bbuf = bc.getBuffer();
     char[] cbuf = cc.getBuffer();
     int start = bc.getStart();
     for (int i = 0; i < length; i++) {
      cbuf[i] = (char) (bbuf[i + start] & 0xff);
     }
     uri.setChars(cbuf, 0, length);
 }

 從上面的代碼可知,對URI的解碼操作是首先獲取Connector的解碼集,該配置在server.xml中

?
1
<Connector URIEncoding="utf-8" />

 如果沒有定義則會采用默認編碼ISO-8859-1來解析。
 對于Query String部分,我們知道無論我們是通過get方式還是POST方式提交,所有的參數都是保存在Parameters,然后我們通過request.getParameter,解碼工作就是在第一次調用getParameter方法時進行的。在getParameter方法內部它調用org.apache.catalina.connector.Request 的 parseParameters 方法,這個方法將會對傳遞的參數進行解碼。下面代碼只是parseParameters方法的一部分:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//獲取編碼
 String enc = getCharacterEncoding();
 //獲取ContentType 中定義的 Charset
 boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
 if (enc != null) { //如果設置編碼不為空,則設置編碼為enc
  parameters.setEncoding(enc);
  if (useBodyEncodingForURI) { //如果設置了Chartset,則設置queryString的解碼為ChartSet
   parameters.setQueryStringEncoding(enc); 
  }
 } else //設置默認解碼方式
  parameters.setEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
  if (useBodyEncodingForURI) {
   parameters.setQueryStringEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
  }
 }

 從上面代碼可以看出對query String的解碼格式要么采用設置的ChartSet要么采用默認的解碼格式ISO-8859-1。注意這個設置的ChartSet是在 http Header中定義的ContentType,同時如果我們需要改指定屬性生效,還需要進行如下配置:

?
1
<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true"/>

 上面部分詳細介紹了URL方式請求的編碼解碼過程。其實對于我們而言,我們更多的方式是通過表單的形式來提交。
表單GET
 我們知道通過URL方式提交數據是很容易產生亂碼問題的,所以我們更加傾向于通過表單形式。當用戶點擊submit提交表單時,瀏覽器會更加設定的編碼來編碼數據傳遞給服務器。通過GET方式提交的數據都是拼接在URL后面(可以當做query String??)來提交的,所以tomcat服務器在進行解碼過程中URIEncoding就起到作用了。tomcat服務器會根據設置的URIEncoding來進行解碼,如果沒有設置則會使用默認的ISO-8859-1來解碼。假如我們在頁面將編碼設置為UTF-8,而URIEncoding設置的不是或者沒有設置,那么服務器進行解碼時就會產生亂碼。這個時候我們一般可以通過new String(request.getParameter("name").getBytes("iso-8859-1"),"utf-8") 的形式來獲取正確數據。
表單POST
 對于POST方式,它采用的編碼也是由頁面來決定的即contentType。當我通過點擊頁面的submit按鈕來提交表單時,瀏覽器首先會根據ontentType的charset編碼格式來對POST表單的參數進行編碼然后提交給服務器,在服務器端同樣也是用contentType中設置的字符集來進行解碼(這里與get方式就不同了),這就是通過POST表單提交的參數一般而言都不會出現亂碼問題。當然這個字符集編碼我們是可以自己設定的:request.setCharacterEncoding(charset) 。


解決URL中文亂碼問題
我們主要通過兩種形式提交向服務器發送請求:URL、表單。而表單形式一般都不會出現亂碼問題,亂碼問題主要是在URL上面。通過前面幾篇博客的介紹我們知道URL向服務器發送請求編碼過程實在是實在太混亂了。不同的操作系統、不同的瀏覽器、不同的網頁字符集,將導致完全不同的編碼結果。如果程序員要把每一種結果都考慮進去,是不是太恐怖了?有沒有辦法,能夠保證客戶端只用一種編碼方法向服務器發出請求?
 有!這里我主要提供以下幾種方法
javascript
 使用javascript編碼不給瀏覽器插手的機會,編碼之后再向服務器發送請求,然后在服務器中解碼。在掌握該方法的時候,我們需要料及javascript編碼的三個方法:escape()、encodeURI()、encodeURIComponent()。
escape
 采用SIO Latin字符集對指定的字符串進行編碼。所有非ASCII字符都會被編碼為%xx格式的字符串,其中xx表示該字符在字符集中所對應的16進制數字。例如,格式對應的編碼為%20。它對應的解碼方法為unescape()。

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

事實上escape()不能直接用于URL編碼,它的真正作用是返回一個字符的Unicode編碼值。比如上面“我是cm”的結果為%u6211%u662Fcm,其中“我”對應的編碼為6211,“是”的編碼為662F,“cm”編碼為cm。
 注意,escape()不對"+"編碼。但是我們知道,網頁在提交表單的時候,如果有空格,則會被轉化為+字符。服務器處理數據的時候,會把+號處理成空格。所以,使用的時候要小心。 
encodeURI
 對整個URL進行編碼,它采用的是UTF-8格式輸出編碼后的字符串。不過encodeURI除了ASCII編碼外對于一些特殊的字符也不會進行編碼如:! @ # $& * ( ) = : / ; ? + '。

Java在web頁面上的編碼解碼處理及中文URL亂碼解決

encodeURIComponent
 把URI字符串采用UTF-8編碼格式轉化成escape格式的字符串。相對于encodeURI,encodeURIComponent會更加強大,它會對那些在encodeURI()中不被編碼的符號(; / ? : @ & = + $ , #)統統會被編碼。但是encodeURIComponent只會對URL的組成部分進行個別編碼,而不用于對整個URL進行編碼。對應解碼函數方法decodeURIComponent。
 當然我們一般都是使用encodeURI方來進行編碼操作。所謂的javascript兩次編碼后臺兩次解碼就是使用該方法。javascript解決該問題有一次轉碼、兩次轉碼兩種解決方法。
一次轉碼
 javascript轉碼:

?
1
2
var url = '<s:property value="webPath" />/ShowMoblieQRCode.servlet?name=我是cm';
window.location.href = encodeURI(url);

 轉碼后的URL:http://127.0.0.1:8080/perbank/ShowMoblieQRCode.servlet?name=%E6%88%91%E6%98%AFcm
 后臺處理:

?
1
2
3
4
String name = request.getParameter("name");
System.out.println("前臺傳入參數:" + name);
name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("經過解碼后參數:" + name);

 輸出結果:
 前臺傳入參數:??????cm
 經過解碼后參數:我是cm
二次轉碼
 javascript

?
1
2
var url = '<s:property value="webPath" />/ShowMoblieQRCode.servlet?name=我是cm';
window.location.href = encodeURI(encodeURI(url));

 轉碼后的url:http://127.0.0.1:8080/perbank/ShowMoblieQRCode.servlet?name=%25E6%2588%2591%25E6%2598%25AFcm
 后臺處理:

?
1
2
3
4
String name = request.getParameter("name");
System.out.println("前臺傳入參數:" + name);
name = URLDecoder.decode(name,"UTF-8");
System.out.println("經過解碼后參數:" + name);

 輸出結果:
 前臺傳入參數:E68891E698AFcm
 經過解碼后參數:我是cm

filter
 使用過濾器,過濾器提供兩種,第一種設置編碼,第二種直接在過濾器中進行解碼操作。
過濾器1
 該過濾器是直接設置request的編碼格式的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class CharacterEncoding implements Filter {
 
 private FilterConfig config ;
 String encoding = null;
  
 public void destroy() {
  config = null;
 }
 
 public void doFilter(ServletRequest request, ServletResponse response,
   FilterChain chain) throws IOException, ServletException {
  request.setCharacterEncoding(encoding);
  chain.doFilter(request, response);
 }
 
 public void init(FilterConfig config) throws ServletException {
  this.config = config;
  //獲取配置參數
  String str = config.getInitParameter("encoding");
  if(str!=null){
   encoding = str;
  }
 }
 
}

 配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 中文過濾器的配置 -->
 <filter>
  <filter-name>chineseEncoding</filter-name>
  <filter-class>com.test.filter.CharacterEncoding</filter-class>
   
  <init-param>
   <param-name>encoding</param-name>
   <param-value>utf-8</param-value>
  </init-param>
 </filter>
  
 <filter-mapping>
  <filter-name>chineseEncoding</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

過濾器2
 該過濾器在處理方法中將參數直接進行解碼操作,然后將解碼后的參數重新設置到request的attribute中。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class CharacterEncoding implements Filter {
 protected FilterConfig filterConfig ;
 String encoding = null;
  
 public void destroy() {
  this.filterConfig = null;
 }
 
 /**
  * 初始化
  */
 public void init(FilterConfig filterConfig) {
  this.filterConfig = filterConfig;
 }
 
 /**
  * 將 inStr 轉為 UTF-8 的編碼形式
  *
  * @param inStr 輸入字符串
  * @return UTF - 8 的編碼形式的字符串
  * @throws UnsupportedEncodingException
  */
 private String toUTF(String inStr) throws UnsupportedEncodingException {
  String outStr = "";
  if (inStr != null) {
   outStr = new String(inStr.getBytes("iso-8859-1"), "UTF-8");
  }
  return outStr;
 }
 
 /**
  * 中文亂碼過濾處理
  */
 public void doFilter(ServletRequest servletRequest,
   ServletResponse servletResponse, FilterChain chain) throws IOException,
   ServletException {
  HttpServletRequest request = (HttpServletRequest) servletRequest;
  HttpServletResponse response = (HttpServletResponse) servletResponse;
 
  // 獲得請求的方式 (1.post or 2.get), 根據不同請求方式進行不同處理
  String method = request.getMethod();
  // 1. 以 post 方式提交的請求 , 直接設置編碼為 UTF-8
  if (method.equalsIgnoreCase("post")) {
   try {
    request.setCharacterEncoding("UTF-8");
   } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
   }
  }
  // 2. 以 get 方式提交的請求
  else {
   // 取出客戶提交的參數集
   Enumeration<String> paramNames = request.getParameterNames();
   // 遍歷參數集取出每個參數的名稱及值
   while (paramNames.hasMoreElements()) {
    String name = paramNames.nextElement(); // 取出參數名稱
    String values[] = request.getParameterValues(name); // 根據參數名稱取出其值
    // 如果參數值集不為空
    if (values != null) {
     // 遍歷參數值集
     for (int i = 0; i < values.length; i++) {
      try {
       // 回圈依次將每個值調用 toUTF(values[i]) 方法轉換參數值的字元編碼
       String vlustr = toUTF(values[i]);
       values[i] = vlustr;
      } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
      }
     }
     // 將該值以屬性的形式藏在 request
     request.setAttribute(name, values);
    }
   }
 
  }
  // 設置響應方式和支持中文的字元集
  response.setContentType("text/html;charset=UTF-8");
 
  // 繼續執行下一個 filter, 無一下個 filter 則執行請求
  chain.doFilter(request, response);
 }
}

配置:

?
1
2
3
4
5
6
7
8
9
10
<!-- 中文過濾器的配置 -->
 <filter>
  <filter-name>chineseEncoding</filter-name>
  <filter-class>com.test.filter.CharacterEncoding</filter-class>
 </filter>
  
 <filter-mapping>
  <filter-name>chineseEncoding</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 

其他
 1、設置pageEncoding、contentType

?
1
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>

 2、設置tomcat的URIEncoding
 在默認情況下,tomcat服務器使用的是ISO-8859-1編碼格式來編碼的,URIEncoding參數對get請求的URL進行編碼,所以我們只需要在tomcat的server.xml文件的<Connector>標簽中加上URIEncoding="utf-8"即可。

延伸 · 閱讀

精彩推薦
  • JAVA教程實例講解java的純數字加密解密

    實例講解java的純數字加密解密

    本文給大家分享的是一個java純數字加密解密技術,加密和解密本身就是一對共生體,缺一不可,需要的朋友可以參考下 ...

    奔跑吧呂子4422019-12-29
  • JAVA教程JDBC基礎教程

    JDBC基礎教程

    這篇文章主要介紹了JDBC基礎知識與操作技巧,講述原理與基本技巧的基礎上分析了安全問題與操作注意事項,非常具有實用價值,需要的朋友可以參考下 ...

    shichen20142422019-12-07
  • JAVA教程Java實現Socket的TCP傳輸實例

    Java實現Socket的TCP傳輸實例

    這篇文章主要介紹了Java實現Socket的TCP傳輸,實例分析了java通過socket實現TCP傳輸的相關技巧,需要的朋友可以參考下 ...

    wo_soul4192019-12-19
  • JAVA教程java自帶的MessageDigest實現文本的md5加密算法

    java自帶的MessageDigest實現文本的md5加密算法

    這篇文章主要介紹了java自帶的MessageDigest實現文本的md5加密算法,需要的朋友可以參考下 ...

    lijiao2612020-03-19
  • JAVA教程區分Java的方法覆蓋與變量覆蓋

    區分Java的方法覆蓋與變量覆蓋

    作為初學者2個比較容易出錯的定義,方法覆蓋和變量覆蓋。下面我們一起來看看作者如何去探討Java的方法覆蓋和變量覆蓋。 ...

    lijiao2162020-01-05
  • JAVA教程Java掩碼的幾種使用例舉

    Java掩碼的幾種使用例舉

    今天小編就為大家分享一篇關于Java掩碼的使用,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    Alan_阿蘭2032019-06-23
  • JAVA教程Java中調用SQL Server存儲過程詳解

    Java中調用SQL Server存儲過程詳解

    這篇文章主要介紹了Java中調用SQL Server存儲過程詳解,本文講解了使用不帶參數的存儲過程、使用帶有輸入參數的存儲過程、使用帶有輸出參數的存儲過程、...

    junjie1252019-12-08
  • JAVA教程java使用poi讀取excel內容方法實例

    java使用poi讀取excel內容方法實例

    本文介紹java使用poi讀取excel內容的實例,大家參考使用吧 ...

    java教程網5192019-10-29
主站蜘蛛池模板: 国产三级a三级三级 | caoporn国产一区二区 | av在线免费看片 | 一级黄色国产视频 | 手机在线看片国产 | 欧美精品一区二区三区四区 | 午夜久久久精品一区二区三区 | 4p嗯啊巨肉寝室调教男男视频 | 日本一区免费看 | 91av原创| 国产精品视频一区二区三区四区国 | 成人精品一区二区三区中文字幕 | a视频在线免费观看 | 久久国产精品网 | 在线免费小视频 | 国产精品久久久久影院老司 | 国产欧美日韩二区 | 在线看小早川怜子av | 牛牛碰在线视频 | 欧美性成人| 毛片在哪看 | 国产免费看片 | 日本在线视频免费观看 | 懂色av懂色aⅴ精彩av | 婷婷一区二区三区四区 | 国产精品视频免费在线观看 | 黄色大片在线观看 | 最新欧美精品一区二区三区 | 色999国产 | 蜜桃网站在线观看 | 一级毛片播放 | 视频一区 日韩 | 羞羞的动漫在线观看 | 亚洲成人在线视频网 | 欧美精品一区二区久久 | 一区二区三区精品国产 | 夜夜夜精品视频 | 日本一道aⅴ不卡免费播放 视屏一区 | 国产精品视频六区 | 精品国产乱码久久久久久丨区2区 | 日韩视频在线观看免费 |