問題觸發環境
1. java中使用org.apache.commons.net.ftp.FTPClient包
2. 通過chrome瀏覽器的file標簽上傳文件
3. 在windows上部署的FileZilla服務上傳的文件名正常顯示,在linux上的vsftpd服務文件名顯示亂碼
4. 直接chrome瀏覽器訪問linux的ftp目錄(chrome的默認編碼是UTF-8),正常顯示
5. 亂碼出現后,嘗試了各種方式編碼處理,造成了環境的各種不可追溯
解決過程
1. 查詢資料:FTP協議規定文件名編碼為iso-8859-1,所以上傳的文件目錄或文件名需要轉碼
2. 參考FileZilla的流程,會向FTP服務器發送OPTS UTF8 ON命令,開啟服務器對UTF-8的支持。
3. 仿照FileZilla的方式,可向服務器發送該指令,如果服務器支持UTF-8則使用UTF-8,否則使用本地編碼(GBK)處理中文名
4. 起作用的java關鍵代碼
private static String LOCAL_CHARSET = "GBK"; // FTP協議中規定的文件名編碼為: iso-8859-1 private static String FTP_CHARSET = "ISO-8859-1"; ... if (ftpClient.login(user, pwd)) { if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) { // 開啟服務器對UTF-8的支持,如果服務器支持就用UTF-8,否則使用本地編碼(GBK) LOCAL_CHARSET = "UTF-8"; } ftpClient.setControlEncoding(LOCAL_CHARSET); // 設置被動模式 ftpClient.setLocalPassiveMode(); ... } ftpClient.changeWorkingDirectory(encodingServerPath(remotePath)) // 上傳的時候使用 ftpClient.storeFile(encodingServerPath(fileName), inputStream); /** * 編碼文件路徑 */ private static String encodingServerPath(String path) throws UnsupportedEncodingException { // FTP協議里面,規定文件名編碼為iso-8859-1,所以目錄名或文件名需要轉碼,replace處理文件路徑 return new String(path.replace("\\", "/").replaceAll("//", "/").getBytes(LOCAL_CHARSET), FTP_CHARSET); } // 下載的時候使用 ftpClient.retrieveFile(encodingServerPath(fileName), outputStream); // 打印ftp工作目錄時需要切換轉碼 System.out.println("當前工作目錄:"+ new String(ftp.printWorkingDirectory().getBytes(FTP_CHARSET), LOCAL_CHARSET));
個人理解的轉碼和解碼過程如下:
filePath 的原始編碼: origin_charset => start java后台: new String(filePath.getBytes(Local_CHARSET), "ISO-8859-1") => step_1 FTP Protocol: new String(filePath.getBytes("ISO-8859-1"), FTP_CHARSET) => step_2 FTP 服務器的默認編碼: new String(filePath.getBytes(FTP_CHARSET), server_charset) => end if(Local_CHARSET == FTP_CHARSET) upload正常, else upload異常(無法創建和切換目錄) if(origin_charset == server_charset) 文件名在FTP服務器上顯示正常, else 文件在FTP服務器顯示亂碼,download異常 如果filePath的編碼與上傳時的編碼不一致,download異常
web項目開發中出現亂碼,要從傳值開始分析編碼,逐步排查,確保編碼一致。要注意瀏覽器和某些方法的默認行為(場景較多,需要時查詢即可,不在此處羅列)
測試后的代碼托管在GitHub中,地址https://github.com/Hlingoes/file-message-server,位於application/FtpService中,供參考和提出改進建議