ABAP 调用第三方 API,遇到乱码该怎么办?
這是 Jerry 2022 年第二篇原創文章,也是本公眾號第 370 篇原創文章。
之前有一個朋友在知乎上向我咨詢過這個問題,我覺得很有代表性,所以專門用一篇文章來講述一些相關知識點。
先看這位朋友遇到的具體問題。
用 Postman 調用第三方接口,里面的中文字符能夠正常顯示。
然而當用 ABAP 的 HTTP 工具類 CL_HTTP_CLIENT 的 response->get_data( ) 讀取響應之后,發現里面的中文字符,例如 “訪問成功” 是亂碼:
首先明確一點,既然 Postman 能正確顯示響應數據中的中文內容,說明 API provider 是不存在問題的,這個亂碼問題出現在接收方,即 ABAP 代碼的編程實現需要調整。
我們只要弄清楚出現亂碼的原因,就能有的放矢進行修復了。
上個世紀 60 年代,美國制定了一套字符編碼,定義了英文字符與二進制位之間的一一映射關系,稱為 ASCII 碼。將一個符號的圖形顯示,關聯到其二進制存儲位的這種行為,就稱之為字符編碼。ASCII 就是一種最簡單的字符集和字符編碼方式。
一個字節有 8 位,2 的 8 次方為 256,因此 1 個字節只能表示 256 種符號,而漢字的總數超過了 10 萬個,顯然無法用 1 個字節來存儲。
除了大家熟悉的英文字符和漢字外,還有很多歷史更悠久的文字,比如埃及象形文字:
以及周杰倫《愛在西元前》里提到的楔形文字:
有沒有這樣一種計算機編碼方式,能夠將這些稀奇古怪的符號都納入其中呢?有,這就是 Unicode,正如其命名暗示的,Unicode 將世界各種語言的每個字符都分配了一個唯一的編碼,以滿足跨語言、跨平臺的文本信息轉換。
我們根據 Unicode 編碼表,就能查到一個字符對應的 Unicode 編碼,比如漢字 "汪"對應的 Unicode 編碼為 00006C6A.
6C6A 的二進制表示為 0110 1100 0110 1010,需要兩個字節進行存儲。表示其他的符號,可能需要三個甚至四個字節存儲。
另一方面,對于原本就存在于 ASCII 編碼表中的英文字符,僅需 1 個字節就能存儲。如果 Unicode 強制要求每個字符按照最大需要的存儲空間,即 4 字節進行存儲,顯然對于英文字符來說,意味著極大的空間浪費。
因此,Unicode 僅僅定義字符到其編碼的映射關系。而這些編碼到底采取多少個字節進行存儲,由 Unicode 具體的實現方式,比如 UTF-8,UTF16 等來決定。
UTF-8 是一種變長的編碼方式,使用 1 到 4 個字節表示一個字符,符號不同,用于存儲的字節長度也不同。比如 “汪” 的 UTF-8 碼值為 E6B1AA,需要三個字節存儲。
根據 SAP 幫助文檔,ABAP 采用 UCS-2 編碼方式,可以看成 UTF-16 的子集,因為 UCS-2 不支持 UTF-16 的 surrogates 區間內定義的一些特殊符號。
所謂 UTF-16,就是所有字符固定都用兩個字節表示。
從下面這張表格能夠看出,UTF-16 又分 UTF-16BE 和 UTF-16LE 兩種實現方式。以漢字 “汪” 的 Unicode 編碼值 6C6A 為例,如果 6C 存儲在內存低位地址,6A 存儲在內存高位地址,這就是 Big Endian 即大尾序(有時也譯作大頭,大端)存儲方式,反之則為 Little Endian 即小尾序存儲方式。
這兩個名稱來自英國諷刺寓言作家斯威夫特的《格列佛游記》。書中的小人國爆發了內戰,戰爭起因竟然是人們爭論吃雞蛋時究竟應該從大頭(Big Endian)一端敲開,還是從小頭(Little Endian)敲開。
那么 ABAP 的 UCS-2(UTF-16 的子集), 到底是 BE 存儲還是 LE 存儲?一試便知。
在我的系統里,答案是 UTF-16LE.
另一種方式,直接檢查系統類 CL_ABAP_CHAR_UTILITIES 的屬性 ENDIAN. 在 Jerry 的系統里,該屬性的值為 L,代表 Little Endian:
我們了解了這些知識,再來修復文章開頭描述的亂碼問題。
仔細觀察 Postman 調用 API 的返回結果,發現還有一條重要信息:charset=GB18030,意思是 API 響應數據采取 GB18030 字符集編碼。
漢字 “訪” 的 GB18030 編碼值為 B7C3,完全不等同于 UTF-16LE 中的編碼值 BF8B.
如果我們在 ABAP 代碼里,按照默認的 UTF-16LE 的方式去讀取一個根據 GB18030 編碼的符號,當然不會得到期望的結果。這種張冠李戴的解碼方式見下圖第 55 行的 get_cdata 方法,最后就會出現亂碼。
正確的方式,采取第 57 行 get_data,返回一個 16 進制數據流,類型為 xstring:
在這個16 進制數據流里,我們已經看到了漢字 “訪” 和 “問” 對應的 GB18030 編碼值。
剩下的事情就容易了,使用字符集 GB18030 對這段數據流進行解碼。
我們首先打開數據庫表 TCP00, 根據關鍵詞 18030 查詢表字段 CPCOMMENT:
得到 GB18030 對應的 SAP Code Page 為 8401:
在下面這段代碼中,傳入 8401,變量 lv_binary 存儲的是 16 進制數據流,變量 lv_text 存放的就是基于 GB18030 的 API 響應內容:
可以看到亂碼已經消失了,在 ABAP 程序里顯示的內容已經和 Postman 里觀察到的完全一致了。
希望本文介紹的這個例子,能對大家在 ABAP 里處理中文亂碼問題有所啟發,感謝閱讀。
Jerry 的 ABAP 專集
-
Jerry的ABAP, Java和JavaScript亂燉
-
ABAP開發人員未來應該學些什么
-
Jerry 2017年的五一小長假:8種經典排序算法的ABAP實現
-
Jerry的ABAP原創技術文章合集
-
300行ABAP代碼實現一個最簡單的區塊鏈原型
-
使用Java+SAP云平臺+SAP Cloud Connector調用ABAP On-Premise系統里的函數
-
在SAP云平臺的CloudFoundry環境下消費ABAP On-Premise OData服務
-
ABAP vs Java, 蛙泳 vs 自由泳
-
聊聊C語言和ABAP
-
動手使用ABAP Channel開發一些小工具,提升日常工作效率
-
我用ABAP做過的那些無聊的事情
-
不喜歡SAP GUI?那試試用Eclipse進行ABAP開發吧
-
使用Visual Studio Code編寫和激活ABAP代碼
-
你的ABAP程序給佛祖開過光么?來試試Jerry這個小技巧
-
在SAP云平臺ABAP編程環境上編寫第一段ABAP程序
-
SAP官方發布的ABAP編程規范
-
ABAP Code Inspector那些隱藏的功能,您都知道嗎?
-
還在用ABAP進行SAP產品的二次開發?來了解下這種全新的二次開發理念吧
-
ABAP Netweaver體內的那些寄生式編程語言
-
從SAP社區上的一篇博客開始,聊聊SAP產品命名背后的那份情懷
-
云端的ABAP Restful服務開發
-
如何在SAP云平臺ABAP編程環境里把CDS view暴露成OData服務
-
使用abapGit在ABAP On-Premises系統和SAP云平臺ABAP環境之間進行代碼傳輸
-
30分鐘用Restful ABAP Programming模型開發一個支持增刪改查的Fiori應用
-
Jerry帶您了解Restful ABAP Programming模型系列之二:Action和Validation的實現
-
Jerry帶您了解Restful ABAP Programming模型系列之三:云端ABAP應用調試
-
SAP云平臺上的ABAP編程環境里如何消費第三方服務
-
ABAP開發者上云的時候到了 - 現在大家可以免費使用SAP云平臺ABAP環境的試用版了
-
學而不思則罔 - SAP云平臺ABAP編程環境的由來和適用場景
-
SAP云平臺里的三叉戟應用
-
如何基于Restful ABAP Programming模型開發并部署一個支持增刪改查的Fiori應用
-
SAP 2019 TechEd Key Note解讀:云時代下SAP從業人員如何做二次開發?
-
有哪些ABAP關鍵字和語法,到了ABAP云環境上就沒辦法用了?
-
ABAP開發環境終于支持以駝峰命名法自動格式化ABAP變量名了
-
利用ABAP 740的新關鍵字REDUCE完成一個實際工作任務
-
一段讓人瑟瑟發抖的ABAP代碼
-
昨日萬圣節ABAP怪獸級代碼謎團,公布答案啦
-
介紹一種在ABAP內核態進行內表高效拷貝的方法
-
使用SAP Cloud Application Programming模型開發OData的一個實際例子
-
當ABAP遇見普羅米修斯
-
使用ABAP繪制可伸縮矢量圖
-
ABAP開發環境語法高亮的那些事兒
-
SAP錯誤消息調試之七種武器:讓所有的錯誤消息都能被定位
-
使用ABAP操作Excel的幾種方法
-
SAP GUI里的收藏夾事務碼管理工具
-
SAP GUI和Windows注冊表
-
有了Debug權限就能干壞事?小心了,你的一舉一動盡在系統監控中
-
ABAP CCDEF, CCIMP, CCMAC, CCAU, CMXXX這些東東是什么鬼
-
實現ABAP條件斷點的三種方式
-
使用SAT跟蹤監控從瀏覽器打開的SAP應用的性能和調用棧
-
一個13年ABAP老兵的建議:了解這些基礎知識,對ABAP開發有百利而無一害
-
SAP ABAP Netweaver容器化, 不可能完成的任務嗎?
-
SAP產品增強技術回顧
-
SAP API開發方法大全
-
淺談Java和SAP ABAP的靜態代理和動態代理,以及ABAP面向切面編程的嘗試
-
SAP ABAP應用服務器的HTTP響應狀態碼(Status Code)
-
SAP ABAP里存在Java List這種集合工具類么?CL_OBJECT_COLLECTION了解一下
-
ABAP面試題系列:寫一組會出現死鎖(Deadlock)的ABAP程序
-
SAP ABAP Netweaver服務器的標準登錄方式講解
-
SAP ABAP關鍵字語法圖和ABAP代碼自動生成工具Code Composer
-
SAP ABAP SM50的另類用途 - ABAP工作進程對數據庫表讀取操作的檢測
-
關于SAP ABAP字符變量和字符串變量字符個數的一個知識點,和一個血案
-
SAP ABAP一組關鍵字 IS BOUND, IS NOT INITIAL和IS ASSIGNED的用法辨析
-
SAP ABAP和Java里的弱引用(WeakReference)和軟引用(SoftReference)
-
SAP AMDP介紹 - ABAP托管的HANA數據庫過程
-
給你的ABAP對象打上標簽(Tag)
-
歷史上的今天:編程語言中null引用的十億美元錯誤
-
ABAP Development Tool 代碼模板和其他一些實用技巧匯總
-
SAP ABAP Development Tool 提高開發效率的十個小技巧
-
如何在 SAP BTP 平臺 ABAP 編程環境里消費基于 SOAP 的 Web Service
-
ABAP 真的會過時嗎?聊聊 ABAP 的過去,現在和未來
-
基于 abapGit 和 abaplint 的 ABAP 持續集成的一個例子
-
不使用任何框架,手寫純 JavaScript 實現上傳本地文件到 ABAP 服務器
-
使用 JavaScript 上傳 PDF 和 Excel 等二進制文件到 ABAP 服務器并進行解析
-
從 ABAP Netweaver 到 ABAP Platform,我們一直在努力
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的ABAP 调用第三方 API,遇到乱码该怎么办?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电动化不是万能药:美国汽车制造商喜欢的大
- 下一篇: 迈向赛博朋克:媲美科幻小说的“洛克人 X