ABAP 调用第三方 API,遇到乱码该怎么办?_abap sicf接收边乱码-程序员宅基地

技术标签: SAP  Netweaver  abap  思爱普  ABAP  后台开发  

这是 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 专集

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/i042416/article/details/122514480

智能推荐

(2)RT-Thread-stm32f103精英开发板-SSD1306使用_rtthread使用ssd-程序员宅基地

文章浏览阅读609次,点赞3次,收藏4次。文章目录rt-u8g2u8g2 的特点:效果安装点击编译,下载,进入finsh界面rt-u8g2链接u8g2 原先是 Arduino 平台上的一个单色屏驱动,现在移植到了 rt-thread,可以满足各种各种各样的需求。u8g2 的特点:支持近 200 种单色屏,移植方便支持各种绘图函数、图像与非操作,自带用户按键检测支持 unicode 和 utf8,自带 100 多种字体和 100 多个 icon效果安装添加完后,是这样的,右击图标点击详细配置,勾选内容后,保存ctr_rtthread使用ssd

git提交之后再pull导致很多代码被修改,但是修改又不是你修改的_git 合并分支时,有许多不是项目的修改-程序员宅基地

文章浏览阅读974次。这样变基到当前仓库分支最新的提交,并将本地的提交应用到最新的提交之上,与普通git pull命令不同,git pull --reabse会将本地的提交变基到最新的提交之上,而不是将本地的提交和远程的提交合并。你本地没有拉master代码,但是你本地提交了一个评审,但是还没和入,这个之后pull一下会把你上次代码更新到这次所有的代码都进行一个对比,如何提交这个。git提交之后再pull导致很多代码被修改,但是修改又不是你修改的,导致你本地很多修改,怎么抛弃掉这些修改呢。然后我们本地执行下面这个命令。_git 合并分支时,有许多不是项目的修改

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

随便推点

HTTP图解读书笔记(第六章 HTTP首部)响应首部字段_web响应的首部内容-程序员宅基地

文章浏览阅读142次。Accept-Ranges告知客户端服务器是否可以处理范围请求(可以:bytes,不可以:none)Age告诉客户端,源服务器在多久前创建了响应,单位为秒ETag首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag值 另外,当资源更新时,ETag 值也需要更新。生成 ETag 值时,并没有统一的算法..._web响应的首部内容

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

推荐文章

热门文章

相关标签