程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java在web頁面上的編碼解碼處置及中文URL亂碼處理

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

編輯:關於JAVA

Java在web頁面上的編碼解碼處置及中文URL亂碼處理。本站提示廣大學習愛好者:(Java在web頁面上的編碼解碼處置及中文URL亂碼處理)文章只能為提供參考,不一定能成為您想要的結果。以下是Java在web頁面上的編碼解碼處置及中文URL亂碼處理正文


編碼&解碼
 經由過程下圖我們可以懂得在javaWeb中有哪些處所有轉碼:

用戶想辦事器發送一個HTTP要求,須要編碼的處所有url、cookie、parameter,經由編碼後辦事器接收HTTP要求,解析HTTP要求,然後對url、cookie、parameter停止解碼。在辦事器停止營業邏輯處置進程中能夠須要讀取數據庫、當地文件或許收集中的其他文件等等,這些進程都須要停止編碼解碼。當處置完成後,辦事器將數據停止編碼後發送給客戶端,閱讀器經由解碼後顯示給用戶。在這個全部進程中觸及的編碼解碼的處所較多,個中最輕易湧現亂碼的地位就在於辦事器與客戶端停止交互的進程。
 下面全部進程可以歸納綜合成如許,頁面編碼數據傳遞給辦事器,辦事器對取得的數據停止解碼操作,經由一番營業邏輯處置後將終究成果編碼處置後傳遞給客戶端,客戶端解碼展現給用戶。所以上面我就要求對javaweb的編碼&解碼停止論述。
要求
 客戶端想辦事器發送要求不過就經由過程四中情形:
 1、URL方法直接拜訪。
 2、頁面鏈接。
 3、表單get提交
 4、表單post提交
URL方法
 關於URL,假如該URL中全體都是英文的那卻是沒有甚麼成績,假如有中文就要觸及到編碼了。若何編碼?依據甚麼規矩來編碼?又若何來解碼呢?上面將逐個解答!起首看URL的構成部門:

在這URL中閱讀器將會對path和parameter停止編碼操作。為了更好地說明編碼進程,應用以下URL
 http://127.0.0.1:8080/perbank/我是cm?name=我是cm
 將以上地址輸出到閱讀器URL輸出框中,經由過程檢查http 報文頭信息我們可以看到閱讀器是若何停止編碼的。上面是IE、Firefox、Chrome三個閱讀器的編碼情形:

 可以看到各年夜閱讀器對“我是”的編碼情形以下:

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 辦法中完成的:

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中

<Connector URIEncoding="utf-8" /> 

 假如沒有界說則會采取默許編碼ISO-8859-1來解析。
 關於Query String部門,我們曉得不管我們是經由過程get方法照樣POST方法提交,一切的參數都是保留在Parameters,然後我們經由過程request.getParameter,解碼任務就是在第一次挪用getParameter辦法時停止的。在getParameter辦法外部它挪用org.apache.catalina.connector.Request 的 parseParameters 辦法,這個辦法將會對傳遞的參數停止解碼。上面代碼只是parseParameters辦法的一部門:

//獲得編碼 
 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,同時假如我們須要改指定屬性失效,還須要停止以下設置裝備擺設:

<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()。

現實上escape()不克不及直接用於URL編碼,它的真正感化是前往一個字符的Unicode編碼值。好比下面“我是cm”的成果為%u6211%u662Fcm,個中“我”對應的編碼為6211,“是”的編碼為662F,“cm”編碼為cm。
 留意,escape()纰謬"+"編碼。然則我們曉得,網頁在提交表單的時刻,假如有空格,則會被轉化為+字符。辦事器處置數據的時刻,會把+號處置成空格。所以,應用的時刻要當心。 
encodeURI
 對全部URL停止編碼,它采取的是UTF-8格局輸入編碼後的字符串。不外encodeURI除ASCII編碼外關於一些特別的字符也不會停止編碼如:! @ # $& * ( ) = : / ; ? + '。

encodeURIComponent
 把URI字符串采取UTF-8編碼格局轉化成escape格局的字符串。絕對於encodeURI,encodeURIComponent會加倍壯大,它會對那些在encodeURI()中不被編碼的符號(; / ? : @ & = + $ , #)一切會被編碼。然則encodeURIComponent只會對URL的構成部門停止個體編碼,而不消於對全部URL停止編碼。對應解碼函數辦法decodeURIComponent。
 固然我們普通都是應用encodeURI方來停止編碼操作。所謂的javascript兩次編碼後台兩次解碼就是應用該辦法。javascript處理該成績有一次轉碼、兩次轉碼兩種處理辦法。
一次轉碼
 javascript轉碼:

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
 後台處置:

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

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
 後台處置:

String name = request.getParameter("name"); 
System.out.println("前台傳入參數:" + name); 
name = URLDecoder.decode(name,"UTF-8"); 
System.out.println("經由解碼後參數:" + name); 

 輸入成果:
 前台傳入參數:E68891E698AFcm
 經由解碼後參數:我是cm

filter
 應用過濾器,過濾器供給兩種,第一種設置編碼,第二種直接在過濾器中停止解碼操作。
過濾器1
 該過濾器是直接設置request的編碼格局的。

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; 
  } 
 } 
 
} 

 設置裝備擺設:

<!-- 中文過濾器的設置裝備擺設 --> 
 <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中。

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); 
 } 
} 
 

設置裝備擺設:

<!-- 中文過濾器的設置裝備擺設 --> 
 <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

<%@ 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"便可。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved