ABAP 呼叫HTTP上傳附件(二)之中文亂碼

2023-03-20 12:02:37

1、這篇文章的由來

之前已經發表了《ABAP 呼叫HTTP上傳附件》的文章,詳細介紹瞭如何通過HTTP請求傳輸附件,可點選連結參考原有檔案

因為之前對傳輸檔案的中文件名處理上解釋不夠詳細,也因為不夠重視,導致又一次在相關問題上踩坑。而浪費一天時間的問題,最終原因竟然就是個這?哭笑不得!目瞪口呆!

為以上緣由,也因為只有「身體力行」的研究,才會更加深入的學習問題相關的知識,才能優化自己解決問題的思路和方法,無論這個方法論是「經驗所得」還是他人的「言傳身教」,都是比解決問題本身更有價值的收穫。

所以寫這篇檔案,介紹一下解決中文亂碼問題的整個過程。

2、詳細說明

2.1、問題背景

在《ABAP 呼叫HTTP上傳附件》文章中對於中文亂碼問題已經做了解釋:

"拼接上傳的檔名,並將檔名轉碼
  lv_name = i_filename.
  lv_name = cl_http_utility=>escape_url( lv_name ).
  lv_value = 'form-data; name="file"; filename="' && lv_name && '";'.

此程式碼cl_http_utility=>escape_url( lv_name )的作用是將中文轉碼:

轉換前:'測試檔案.txt'.
轉換後:%e6%b5%8b%e8%af%95%e6%96%87%e4%bb%b6.txt

但是上傳的檔名全部變成了如圖所示

 

直接傳送中文名稱,並在HTTP中設定UTF-8,沒有解決問題,所以只能繼續在轉碼上研究

2.2、解決過程

2.2.1、發現異常

在POSTMAN中上傳檔案測試正常。

因為此介面經過CPI,在POSTMAN中沒有發現有價值資訊,而在CPI中發現了POSTMAN上傳和程式碼上傳的紀錄檔有所不同

POSTMAN:

Content-Disposition: form-data; name="file"; filename="測試檔案.txt"; 
filename*=UTF-8''%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt

程式碼呼叫:

content-disposition: form-data; name="file"; filename="%e6%b5%8b%e8%af%95%e6%96%87%e4%bb%b6.txt";

除了POSTMAN呼叫時多了filename*用來將檔名轉換為UTF-8的中文名外,對應的中文件名編碼,一個字母全部大寫,一個字母全部小寫……

因為JAVA環境呼叫正常,所以在JAVA環境中程式碼模擬:

URI uri = null;
try {
    uri = new URI(null, null, "測試檔案.txt", null);
} catch (URISyntaxException e) {
    e.printStackTrace();
}
String fileName = uri.toASCIIString();
System.out.println(fileName);

結果:
%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt

至此,回想起研究RSA加密時,也發現了ABAP中用此方法直接轉換編碼時,得到的ASCII值為小寫。而當前對接的外圍系統無法解析字母為小寫的這串編碼,所以最終上傳的檔名就都變成了編碼符號,真相大白!真相大白!真相大白!

2.2.2、解決問題

開始研究ABAP的編碼轉換方法:

1、直接轉大寫

除了過於簡單粗暴外,還需要擷取字串,否則將檔案字尾也變成了大寫,如TXT,XLSX等,額……對於強迫症患者,還是算了

2、函數www_urlencode

函數轉換完,擴充套件名的「.」都被轉換了。額……繼續研究

3、預定義函數escape

此函數可以通過定義format = cl_abap_format=>e_url_full,得出和Java程式碼中同樣的效果,其實cl_abap_format=>e_uri_full在此處也滿足需求,兩者在符號「+」、「*」、「~」上有轉換區別

lv_name = escape( val = lv_name format = cl_abap_format=>e_url_full ).

幾種編碼測試對比:

一、
lv_name = '測試檔案.txt'.
DATA(lv_name1) = escape( val = lv_name format = cl_abap_format=>e_uri_full ).
DATA(lv_name2) = escape( val = lv_name format = cl_abap_format=>e_url_full ).
DATA(lv_name3) = cl_http_utility=>escape_url( lv_name ).
WRITE:/ 'escape e_uri_full:' && lv_name1.
WRITE:/ 'escape e_url_full:' && lv_name2.
WRITE:/ 'escape_url    小寫:' && lv_name3.

結果:
escape e_uri_full:%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
escape e_url_full:%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
escape_url   小寫:%e6%b5%8b%e8%af%95%e6%96%87%e4%bb%b6.txt

二、
lv_name = '+'.
DATA(lv_name1) = escape( val = lv_name format = cl_abap_format=>e_uri_full ).
DATA(lv_name2) = escape( val = lv_name format = cl_abap_format=>e_url_full ).
WRITE:/ 'escape e_uri_full:' && lv_name1.
WRITE:/ 'escape e_url_full:' && lv_name2.
結果:
escape e_uri_full:%2B
escape e_url_full:+

最終使用預定義函數escape解決問題,檔名稱正常