1. 程式人生 > >87.ajax提交 後臺返回中文亂碼問題

87.ajax提交 後臺返回中文亂碼問題

介面返回資料相關

使用@ResponseBody後返回NUll

說明:剛把後臺執行起來,興高采烈的測試介面資料,結果無論如何都是返回null, 最終通過各種百度,發現原來是沒有引入關鍵的Jar包. 解決辦法: 需要引入jackson的jar包(jackson core和jackson mapper),引入後 圖:

使用@RequestMapping返回中文亂碼

原因分析:(網上基本都是一致的答案)

首先: 確定的是(經過多次測試的結果)只有當返回值是 String時才會出現中文亂碼,而當返回值是Map<String, Object>或者是其它型別時,並沒有中文亂碼的出現.

然後找原因: 原因是這可以說是spring mvc的一個bug,spring MVC有一系列HttpMessageConverter去處理用@ResponseBody註解的返回值,如返回list或其它則使用 MappingJacksonHttpMessageConverter,返回string,則使用 StringHttpMessageConverter,而這個convert使用的是字符集是iso-8859-1,而且是final的。所以在當返回json中有中文時會出現亂碼。
  1. public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");      


解決辦法(以及是否嘗試成功): 嘗試了很多種網上的辦法,有一些根本無用,有一些當客戶端的Accep是 application/json;時無用.最終也是結合客戶端的修改才成功解決問題的。 環境: SpringMvc 3.1 客戶端分為三種不同的請求: 1.瀏覽器中直接Get訪問,Accept是"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" 2.用Jquery的jsonp ajax請求,Accept是"*/*" 3.用h5+環境下的mui ajax請求,Accept是"application/json;charset=utf-8" (PS:h5+是最近做的跨平臺移動專案的開發環境,另外就是有試過預設的Accept"application/json"的話不管伺服器端用哪種方法,在呢麼配置,都會返回亂碼,所以最後只得手動加上charset=utf-8了) 注: 
如果什麼都不加,第一種和第二種都是返回的亂碼,第三種由於手動要求了返回格式,所以沒有亂碼,這裡之所以要第三組做對比是因為有一些方法會造成第三組不能正常訪問。

嘗試方法一: 在配置檔案中的mvc:annotation-driven中新增如下程式碼

  1. <mvc:annotation-driven >  
  2.     <!-- 訊息轉換器 -->  
  3.     <mvc:message-converters register-defaults="true">  
  4.       <bean class="org.springframework.http.converter.StringHttpMessageConverter">  
  5.         <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>  
  6.       </bean>  
  7.     </mvc:message-converters>  
  8.   </mvc:annotation-driven>  
原理: StringHttpMessageConverter的父類裡有個List<MediaType> supportedMediaTypes屬性,用來存放 StringHttpMessageConverter支援需特殊處理的 MediaType 型別,如果需處理的 MediaType 型別不在 supportedMediaTypes列表中,則採用預設字符集。 最終結果: 請求方法1中文亂碼 請求方法2返回正確的中文 請求方法3返回正確的中文

嘗試方法二: 在配置檔案中的mvc:annotation-driven中新增如下程式碼

  1. <mvc:annotation-driven>  
  2.       <mvc:message-converters>  
  3.           <bean class="org.springframework.http.converter.StringHttpMessageConverter">  
  4.               <property name="supportedMediaTypes">  
  5.                   <list>  
  6.                    <span style="white-space:pre">   </span>  <value>text/html;charset=UTF-8</value>  
  7.                       <value>application/json;charset=UTF-8</value>  
  8.                       <value>*/*;charset=UTF-8</value>  
  9.                   </list>  
  10.               </property>  
  11.           </bean>  
  12.       </mvc:message-converters>  
  13.   </mvc:annotation-driven>  
原理: 原理同上,但是這裡多加了幾個value。 最終結果: 請求方法1中文亂碼 請求方法2返回正確的中文 請求方法3返回正確的中文 關於這種型別的方法為什麼不能正確解決,原因網上都是各不相同,這裡也不敢輕易做出結論.總之,目前來看這種方法不能解決問題

嘗試方法三: 在@RequestMapping裡的配置produces="text/html;charset=UTF-8;"

  1. @RequestMapping(value = "***",produces="text/html;charset=UTF-8;")  

原理: 手動給對應的Accept返回制定格式編碼資料。 最終結果: 請求方法1返回正確的中文 請求方法2返回正確的中文 請求方法3無法請求,出了錯,因為produces沒有新增application/json;對應的頭部.

嘗試方法四: 在@RequestMapping裡的併發配置produces={"application/json;","text/html;charset=UTF-8;"}

  1. @RequestMapping(value = "***",produces={"application/json;","text/html;charset=UTF-8;"})  

原理: 手動給對應的Accept返回制定格式編碼資料。 最終結果: 請求方法1返回中文亂碼 請求方法2返回中文亂碼 請求方法3返回正確的中文

嘗試方法五: 在@RequestMapping裡的併發配置produces={"text/html;charset=UTF-8;","application/json;"}

  1. @RequestMapping(value = "***",produces={"text/html;charset=UTF-8;","application/json;"})  

注意: 這裡和上個方法的區別是,produces裡面的順序對調了 原理: 手動給對應的Accept返回制定格式編碼資料。 最終結果: 請求方法1返回正確的中文 請求方法2返回正確的中文 請求方法3返回正確的中文 方法四和方法五對比分析: 發現produces設定多個Accept只有第一個的charset是有用的, 後面的Accept設定有效(因為不設定就無法接收對應的Accept請求),但是charset設定是無效的.需要客戶端手動制定charset才行. 具體原因並不清楚(原諒我並不精通) 所以得出的結論是:

produces={"text/html;charset=UTF-8;","application/json;"}

這樣設定,這樣普通瀏覽器的請求就能正常顯示中文,而客戶端的模擬請求(可以是ajax或http)則手動指定Accept的charset,即可正常接收中文。

客戶端使用Ajax請求跨域問題

說明:剛剛搭建的Java web後臺程式,用Http請求很正常,但是用普通的ajax請求時,出現了一個跨域問題,被拒絕訪問. 解決辦法: 在.net後臺佈置在IIS伺服器上的,直接可以在IIS的應用池中配置Access-Control-Allow-Origin: *就行了. PhP後臺也只需要手動配置 header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept'); Java Web後臺可以再對應的tomcat伺服器上通過CORS配置跨域訪問(詳情見另一篇),這裡暫時只探討Java Web的JSONP實現 於是:  這裡的Java Web後臺採用了JSONP傳輸方式來支援跨域. (缺點就是隻支援Get,而且需要伺服器端有JSONP的判斷,因為返回引數和普通的不一樣) JSONP前端程式碼:(這裡是用了JQ的jsonp請求)
  1. <span style="white-space:pre">                    </span>$.ajax(url, {  
  2.                         data: data,  
  3.                         dataType: "jsonp",  
  4.                         jsonpCallback: 'testGetData',  
  5.                         timeout: "15000", //超時時間設定為3秒;  
  6.                         type: "POST",  
  7.                         success: function(response) {  
  8.                             var result = 'success:' + JSON.stringify(response);  
  9.                             //返回的是utf8編碼,需要手動轉為utf16  
  10.                             console.log(result);  
  11.                             //alert(result);  
  12.                         },  
  13.                         error: function(error) {  
  14.                             var result = 'error:' + JSON.stringify(error);  
  15.                             console.log(result);  
  16.                             //alert(result);  
  17.                         }  
  18.                     });  

JSONP傳遞Java Web後臺程式碼片段: 1.在方法的最開頭獲取是否是JSONP請求-通過獲取callback引數
  1. //判斷是否是jsonp請求  
  2. String jsoncallback = request.getParameter("callback");  
2.判斷如果是JSONP的請求則用JSONP的返回引數,否則用正常的(示例裡面使用了Jackson來輔助)
  1. public static String getJsonPData(String callbackName,Map<String, Object> data) throws JsonGenerationException, JsonMappingException, IOException{  
  2.         ObjectMapper mapper = new ObjectMapper();  
  3.         String json = mapper.writeValueAsString(data);  
  4.         System.out.println("jsonp回撥:"+callbackName);  
  5.         System.out.println("jackson解析的字串:"+json);  
  6.         String result = "";  
  7.         if(callbackName==null||callbackName==""){  
  8.             //普通請求  
  9.             result = json;  
  10.         }else{  
  11.             //jsonp請求,返回的格式是類似於一個函式的字串形式(前端再執行這個回撥來獲取資料)  
  12.             result = callbackName+"("+json+")";  
  13.         }  
  14.         System.out.println("最終結果:"+result);  
  15.         return result;    
  16.     }