天突然想到之前的一個項目,是和另一個公司合作,我提供后臺,對方寫小程序調用我的接口,我本地測試好接口后,是沒有問題的,然后部署到對方服務器(windows系統),接著就是出先各種各樣的亂碼問題,在這里匯總記錄下,以便后面學習。
java亂碼出現的問題有很多,這里主要記錄下tomcat,log4j,mysql,jsp,html,http(get,post請求亂碼處理)。常見的問題可能是tomcat,http請求亂碼問題了,至于jsp和html的亂碼問題就很簡單了,相信大家也知道,我也就不多說了,首先來說下tomcat的亂碼問題,
一個是程序需要發送http GET請求到服務器,請求的參數中包含了中文字符。程序中參數為UTF-8格式,且經過了UTF-8 URL編碼再發送。使用的tomcat服務器,但服務器端后臺程序中取到的參數的中文是亂碼。
解決辦法:修改Tomcat的Server.xml,在Connector標簽中加上URLEncoding參數。
<Connector port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" debug="99" connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>
另一個是tomcat控制臺打印亂碼,程序中輸出到tomcat控制臺的中文信息亂碼了,
解決辦法:打開文件/tomcat/bin/catalina.bat,然后設置set JAVA_OPTS=的內容中添加選項-Dfile.encoding=UTF-8即可,當然,我不敢包證,但是我的就是這么處理然后就可以了。
然后是log4j的日志打印亂碼,這個亂碼也是打印在tomcat控制臺的時候亂碼,但是日志文件卻不會,而且我本地測試的時候打印也不會亂碼
而且我配置的也是utf-8,這個曾經讓我惱火好久,后面我偶然在一篇博客上發現,說有些服務器你配utf-8是不行的,他的是編碼就是GBK,我就權當試試,沒想到還真是這個問題,這也是讓我很無語,,,,
然后就是http請求的亂碼,我這個亂碼問題是我在shiro判斷是否登錄的時候,因為我是前后端分離,所以我shiro判斷未登錄的時候,是返回狀態碼和提示信息,而不是跳轉登錄頁面,我用response返回中文提示信息是,結果返回的是亂碼,可是我明明設置了
res.setCharacterEncoding("utf-8");
可是到前端頁面的時候還是亂碼了,這讓我很費解,后面我仔細想了下,我服務端是設置了返回utf-8的編碼,但是瀏覽器是用utf-8去解析的嗎?后面去查了下還要加一條配置,
res.setContentType("text/html;charset=utf-8");
之前知道有這個配置,但是一直不知道有什么區別,今天算是明白了一點,這個就是告訴瀏覽器,你要用什么編碼去解析這個數據。
最后一個是mysql 中文的亂碼了,這個著實讓我煩惱了好久,我去網上查了,說建表的時候要設置utf-8的編碼,可是我在新建數據庫的時候就設置了默認就是utf-8的編碼,然后我說要配置數據庫的默認編碼,修改mysql配置文件/etc/my.cnf。
[mysqld] character-set-server=utf8 [client] default-character-set=utf8 [mysql] default-character-set=utf8
我設置好這個以后,終于不會亂了,但是,,保存進去的中文居然全部變成了???號,于是又去奔波了,
通過這個命令,我們可以看到,我們服務端居然還不是utf-8???
這讓我很傷,終于,尋的良方,
只要在數據庫properties文件的連接信息里加兩個參數
?useUnicode=true&characterEncoding=utf-8
就可以了,唉,真是一波三折啊,
真是與服務器斗,其樂無窮;與數據庫斗,其樂無窮;與瀏覽器斗,其樂無窮啊
pache Derby 是一個開源的完全使用 Java 語言實現的嵌入式關系型數據庫。JDK歷史版本中曾經包含了 Derby 版本,叫做 Java DB,但目前 JDK 中已經不再默認包含了。
官網主頁:https://db.apache.org/derby/
在更新JDK到21/22版本后,同樣也是出現使用控制臺執行SQL腳本出現漢字亂碼。
D:\db-derby-10\bin>sysinfo
------------------ Java 信息 ------------------
Java 版本: 21.0.2
Java 供應商: Oracle Corporation
Java 主目錄: D:\JDK21
Java 類路徑: D:\db-derby-10/lib/derbyshared.jar;D:\db-derby-10/lib/derby.jar;D:\db-derby-10/lib/de
rbynet.jar;D:\db-derby-10/lib/derbyclient.jar;D:\db-derby-10/lib/derbytools.jar;D:\db-derby-10/lib/derby
optionaltools.jar
OS 名: Windows 10
OS 體系結構: amd64
OS 版本: 10.0
Java 用戶名: chenxd
Java 用戶主目錄:C:\Users\chenxd
Java 用戶目錄: D:\db-derby-10\bin
java.specification.name: Java Platform API Specification
java.specification.version: 21
java.runtime.version: 21.0.2+13-LTS-58
--------- Derby 信息 --------
[D:\db-derby-10\lib\derby.jar] 10.17.1.0 - (1913217)
[D:\db-derby-10\lib\derbytools.jar] 10.17.1.0 - (1913217)
[D:\db-derby-10\lib\derbynet.jar] 10.17.1.0 - (1913217)
[D:\db-derby-10\lib\derbyclient.jar] 10.17.1.0 - (1913217)
[D:\db-derby-10\lib\derbyshared.jar] 10.17.1.0 - (1913217)
D:\db-derby-10\bin>startNetworkServer
Tue May 14 10:47:20 CST 2024 : Apache Derby 網絡服務器 - 10.17.1.0 - (1913217) 已啟動并準備接受端口 1527
上的連接
運行ij,插入記錄,出現亂碼(JDK19及之前未曾出現這個問題):
D:\db-derby-10\bin>ij -p ij.properties
ij>connect 'chendb';
ij> drop table zipcodes;
ij> create table zipcodes(zipcode varchar(6), university varchar(20), city varchar(10));
ij> insert into zipcodes values ('100044', '北京交通大學', '北京');
ij> insert into zipcodes values ('200030', '上海交通大學', '上海');
ij> select * from zipcodes;
ZIPCO&|UNIVERSITY |CITY
--------------------------------------
100044|?????????? |????
200030|????????? |???
基于上回Java輸入輸出文件亂碼的經驗,基本確定就是控制臺字符集(GBK)和數據庫字符集(UTF-8)編碼不一致,需要修改ij運行時的字符集為GBK。由于ij運行時,實際是用java命令指定類名運行的,可以使用運行時指定 ”-Dderby.ui.codeset=GBK“ 來修改字符集為“GBK”。為了方便使用,直接使用配置文件ij.propertis,在其中加入字符集相關的屬性定義:
ij.driver=org.apache.derby.jdbc.ClientDriver
ij.protocol=jdbc:derby://localhost:1527/
#解決JDK21后,命令行漢字輸入亂碼問題
#默認命令行字符集為GBK(代碼頁936)而非UTF-8(代碼頁 65001)
#https://www.rfc-editor.org/rfc/rfc5646.html
derby.ui.locale=zh-Hans
derby.ui.codeset=GBK
重新運行ij:
D:\db-derby-10\bin>ij -p ij.properties
ij 版本 10.17
ij> connect 'chendb';
ij> insert into zipcodes values ('100044', '北京交通大學', '北京');
已插入/更新/刪除 1 行
ij> select * from zipcodes;
ZIPCO&|UNIVERSITY |CITY
--------------------------------------
100044|?????????? |????
200030|????????? |???
100044|北京交通大學 |北京
已選擇 3行
ij>
至此成功解決亂碼問題。
14_HttpRunner中文亂碼問題_01_悟空CRM 斷言中文失敗顯示亂碼_原因分析
測試目的:
通過瀏覽器登錄成功后,進入系統首頁,查看源代碼,準備把標題文字作為斷言用例執行是否成功的標志。
編寫測試用例如下:
- config:
name: 悟空CRM
- test:
name: 登錄
request:
url: http://192.168.1.102/72crm/index.html#/workbench/index
method: POST
data:
username: 13888888888
password: 123456
validate:
- eq: [status_code, 200]
- eq: [<title>(.*)CRM</title>, 悟空]
執行測試用例,直接失敗 :(
看看錯誤提示,發現是第二個斷言,即標題的斷言失敗了。
再仔細看輸出,實際結果提取出來的是亂碼,到這里就基本清楚了,字符編碼問題!!
我們編寫用例使用的是 UTF-8 字符編碼方式,這種方式下對常見中文的編碼規律是,每個漢字被編碼為三個字節,“悟空”是兩個漢字,編碼后對應六個字節,數數亂碼的字符數量,正好也是六個。
這六個亂碼是什么鬼。別著急,我們詳細分析一下。
這里我使用的常見的 EditPlus 文本編輯工具,新建一個空白文本文件,輸入“悟空”二字,并保存為“UTF-8”編碼方式(注意:這是重點! 重點!)
保存成功后,直接查看文件內容的十六進制編碼。
“悟空”二字的 UTF-8 編碼是: E6 82 9F E7 A9 BA 共六個字節
正常情況下,用UTF-8方式進行編碼,則解碼也必須是UTF-8方式,即編碼和解碼一致,否則就會出現亂碼。我們通過HttpRunner執行測試用例,返回的HTTP響應數據(即HTML文件)中,標題位置直接就輸出了亂碼(見截圖中劃綠線的紅色錯誤提示部分)。那么HttpRunner到底用的什么方式進行解碼呢?一般情況下,尤其是英文的軟件,都默認習慣使用ISO8859-1的字符編碼方式。
我們知道最早的字符編碼是 ASCII 碼,共表示128個字符,每個字符占用1B(1個字節)的大小,但實際只使用了其中的7位,高位補了0,如字符 'A'的編碼是 '0100 0001',最高位是一個0來占位的。
后續有些國家和地區對 ASCII 碼進行了擴展,即把最高位的0給使用了,這樣就可以表示256個字符。但是這些擴展互相間不兼容。
在 Windows 中運行命令:charmap ,打開字符映射工具,字符集分別選中“Windows 西歐”和“Windows中歐”,可以清楚的看到,從 0X80 編碼以后(即擴展出來的字符內容),二者出現很大的不同,西歐字符集中的一些字符,在中歐字符集中就根本沒有出現。也就是說,同樣的編碼如果使用不同的字符集解碼,可能產生不同的字符顯示,這就是亂碼形成的很大根源,說白了就是一句話:編碼和解碼不一致。
于是大牛出現了- ISO(國際標準化組織),他制定了一套統一的標準,即 ISO8859 字符集系列,分別把西歐、東歐、南歐、北歐等字符集分別編號為 ISO8859-1、ISO8859-2、ISO8859-3、ISO8859-4等。其中,最常用的就是 ISO8859-1 西歐這個標準,也稱Latin-1。
由于“悟空”二字的 UTF-8 編碼是: E6 82 9F E7 A9 BA ,這六個字節如果用西歐的 ISO8859-1來一個字節一個字節的解碼,每個字節就對應了一個西歐的字符。這些字符就是我們從錯誤提示信息中所看到的亂碼了。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。