ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SAP BTP ABAP调用本地RFC全流程:Cloud Connector与ACO_PROXY实践

SAP BTP ABAP调用本地RFC全流程:Cloud Connector与ACO_PROXY实践 在 SAP BTP 的 ABAP 环境也就是常说的 Steampunk 云 ABAP里调 On-Premise 的 RFC 函数第一反应很容易是“找个 RFC Destination 直接 CALL FUNCTION”。我最初做这个集成时也这么想结果被网络边界和安全模型反复打脸。折腾了几天后终于把一条完整链路跑通Cloud Connector 放行、通信场景配置、ACO_PROXY 元数据导入、Service Consumption Model 生成代理类最后在自定义 ABAP 代码里调用本地 RFC Function Module。这篇文章把整个落地过程、踩坑点和关键代码都记录下来给后面接同一类需求的同学当个参考。1. 云上 ABAP 调 On-Premise RFC难点不在函数名而在对象模型1.1 云和本地之间的“墙”是怎么绕过去的SAP BTP 的 ABAP 环境本身跑在云基础设施上网络层面无法直接访问你公司内网里的 ECC 或 S/4HANA。传统的 SAP 系统之间可以用 SM59 配一个 RFC Destination然后 CALL FUNCTION BAPI_XXX DESTINATION ECC_001。但在 BTP ABAP 环境里这套逻辑不成立——云上没有 SM59也不能随便开放内网端口。此时需要用两个组件来搭桥Cloud Connector部署在内网负责建立从 BTP 子账户到本地系统的安全隧道。BTP 子账户的 Destination 服务云端服务通过 Destination 找到 Cloud Connector 对应的后端系统。Cloud Connector 就像一条加密的“甬道”你要在甬道的两侧分别开放权限一侧是 BTP 子账户允许访问哪些后端资源另一侧是本地系统允许哪个 Cloud Connector 实例访问哪些端口。RFC 通常走 TCP 33xx 端口比如 3300、3320、3321 等需要在 Cloud Connector 的“服务/端口”配置里明确放行。但这里有个容易混淆的点Cloud Connector 放行的是网络通道不代表应用层就能直接调 RFC。ABAP 环境层的安全模型要求所有出站通信都必须通过“通信安排”和“通信系统”统一管理而不是像传统 S/4 那样直接在代码里写死逻辑地址。1.2 为什么不能照搬 CALL FUNCTION 的写法在传统 ABAP 里一个 RFC 调用大概长这样CALL FUNCTION ZHR_GET_EMP_DETAIL DESTINATION NONE EXPORTING pernr 100001 IMPORTING ename ls_result.放到 BTP ABAP 环境里你找不到DESTINATION这个参数可以用的地方——因为 ABAP 环境根本不允许低层级通讯对象裸露在业务代码里。所有外部通信必须通过系统自动生成的代理对象去完成这是一个强制约束不是可选优化。这样的好处是安全性和可治理性更强。每个出站调用都会被映射到某个“通信安排”运维人员可以清楚看到这个 ABAP 服务在跟哪个外部系统交互。代价则是你首先要让系统认识这个 RFC 接口的“元数据”然后出站调用才有路可走。这也是标题里“ACO_PROXY 元数据”和“Service Consumption Model”出现的原因。它们本质上就是用来把“一个 On-Premise RFC 函数”转化为“云 ABAP 环境可以实例化的代理对象”的中间层。1.3 ACO_PROXY 元数据到底是什么ACO_PROXY 可以理解为一个外部通信代理的元数据命名空间。当你在本地系统里用事务代码 SPROXY 或 SE80 的“代理对象”功能为一个 RFC 函数生成代理时系统会把接口的操作名、参数名、结构类型、表类型等全部抽成无关于网络的元数据内容。这些元数据通常以ACO_PROXY_开头后续跟着 RFC 函数模块名或服务接口名比如ACO_PROXY_ZHR_GET_EMP_DETAIL_REQUESTACO_PROXY_ZHR_GET_EMP_DETAIL_RESPONSEACO_PROXY_STRUCTURE_ZEI_PERSON_INFO为什么叫“ACO”而不是传统“Proxy”因为在 BTP ABAP 环境的对象模型里ABAP Cloud 的通信对象有独立命名规则“ACO”可以简单记为 ABAP Cloud Outbound 的缩写。你在本地 ABAP 里看到的 Proxy 对象是给传统 PI/PO 用的而 ACO_PROXY 是给云环境出站通信用的两者不能互相替代。元数据本身不干任何事它只描述接口签名。真正“干活”的是后续基于这份元数据生成的代理类。2. 环境准备Cloud Connector、通信场景、Destination 三件套2.1 在 Cloud Connector 里放行 RFC 端口先说结论没有 Cloud Connector 的放行后面的所有配置都是空中楼阁。在 Cloud Connector 管理界面里需要建立一个到本地 SAP 系统的连接。操作路径大致是添加后端系统类型选择“ABAP”。添加资源协议选“RFC”端口填本地系统的 RFC 端口通常查 SM51 里的 RFC 服务端口常见 3300 或 3320。配置可访问的“虚拟主机”和“虚拟端口”建议用系统主机名对应。保存后测试连接确认“可达”且“已授权”。这里有一个很多项目会踩的坑Cloud Connector 默认会拦截所有未明确放行的路径所以如果只配置了 HTTPS 端口RFC 请求照样会被拒绝。还有,如果你的本地系统有多个 AS ABAP 实例每个实例端口不同务必把实际需要访问的那个端口精确加上。另一个建议是单独建一个 Cloud Connector 节点或区域给 RFC 协议用不要和 HTTP 服务混在一个 Access Control 里。原因是 RFC 服务和 HTTP 服务的访问策略、日志监控方式不同混在一起会提高排障难度。2.2 在 BTP ABAP 环境里创建通信系统与通信安排本地通道通之后云端还要配置“通信管理”三件套通信系统Communication System、通信场景Communication Scenario、通信安排Communication Arrangement。通信系统代表你要连接的那个 On-Premise 系统。在 BTP ABAP 环境的 Fiori App“Communication Systems”里创建一条记录填上系统名称、逻辑地址、Cloud Connector 关联信息等。通信场景定义一组对外交互的接口集合。如果使用系统预置的场景可以在 Communication Arrangement 里直接选。如果要自己扩展需要先在 Communication Scenarios 里创建自定义场景。通信安排将通信系统绑定到指定通信场景并生成通信用户、入站出站配置等。听起来繁琐但可以类比传统 SAP 里的 SM59 加上权限对象组合。每个通信安排最终会生成一个对应的“出站服务”ABAP 代码通过这个出站服务去拿 Destination而不是直接拼一个逻辑地址。有一点需要特别留意在配置通信系统时要预先在 On-Premise 系统上创建一个专用的通信用户并分配调用该 RFC 函数模块的权限。很多 RFC 调不通不是因为网络问题而是通信用户没有 S_ RFC 授权被本地系统直接拒绝。2.3 为什么要用 Destination 而不是 SM59BTP ABAP 环境的代码里依然可以引用 Destination 名比如DATA(lv_dest) MY_RFC_DEST.但这个 Destination 的解析是交给平台运行时完成的它不维护在 SM59而维护在子账户的“Destination 配置”里。运行时通过 Communication Arrangement 绑定的通信系统结合 Cloud Connector 映射最终找到本地实际系统。用这么多年 ABAP 的同学可能会有个执念以前在 SM59 里改个 IP、改个负载均衡配置很方便云上就“看不见摸不着”了。实际上这只是视角变了。在云环境里我们把“连接配置”提升到了平台层统一审计、统一管理、统一分发。代码里只保留逻辑名反而更干净。3. 从 ACO_PROXY 元数据到 Service Consumption Model落地关键步骤3.1 在 On-Premise 端导出 RFC 函数模块的元数据这一节是整个集成里比较让人困惑的地方因为传统 RFC 没有天然的“接口文件”给你下载。好在 ABAP 环境的开发工具ADT支持通过“Service Consumption Model”导入外部服务的元数据。对于 RFC 而言我们需要先把 On-Premise 的函数模块转成代理对象。实操中我一般这样做在本地 S/4 系统里用 SPROXY 创建一个新的 Proxy 对象。在“外部接口”中选择 RFC Function Module输入你要调用的函数名比如ZHR_GET_EMP_DETAIL。让 SPROXY 自动生成 Proxy 的数据类型、方法签名和消息结构。导出这个 Proxy 对象的元数据通常是 XML 或 WSDL 风格的文件保存到本地。这里就会看到 ACO_PROXY 的身影生成的元数据默认命名空间或前缀很可能就是ACO_PROXY_。这和你直接在 BTP ABAP 环境里“新建服务消费模型”时看到的导入文件是同一套体系。如果你在 SPROXY 里找不到接口编号或者在本地系统里想通过接口编号去反查函数模块可以在 SPROXY“代理对象树”里按接口编号即 ESR 里的接口名称搜。这个操作在项目里很常见尤其是当多个系统间对象的命名不规范时。注意ACO_PROXY 元数据文件里也会保留接口编号后续排查参数不匹配问题时很有用。3.2 在 ADT 中创建 Service Consumption Model接下来是核心动作在 BTP ABAP 环境的 ABAP 项目里右键点击包节点选择New → Service Consumption Model。进入向导后选择“RFC”对应的消费模型类型不同 Release 的选项名称略有差异但思路一致然后将前面导出的 ACO_PROXY 元数据文件作为输入上传。向导会完成以下工作解析元数据里的接口名、结构类型和表类型。在包/项目里生成对应的 ABAP 类和其他对象。生成一个可供业务代码直接实例化的代理对象。生成的类名通常可以自定义但方法和参数名会尽量沿用元数据中的原始定义。比如本地 RFC 函数模块ZHR_GET_EMP_DETAIL生成的消费模型里很可能有一个同名方法ZHR_GET_EMP_DETAIL参数依然是PERNR、ENAME等。这个在 ADT 里的模型创建过程本质上把“外部函数签名”转换成了“本地 ABAP 类的方法签名”。你把模型创建好之后不需要关心底层是同步 RFC 还是异步调用也不需要手动组装 XML 报文。这正是 Service Consumption Model 与普通“HTTP 客户端封装”相比最大的卖点。3.3 生成的 ABAP 代理类能做什么生成完代理类之后你可以在代码里看到类似这样的对象结构代理类实例ZCL_ACO_HR_EMP_V2输入结构ZACO_PROXY_HR_EMP_REQUEST输出结构ZACO_PROXY_HR_EMP_RESPONSE表类型ZACO_PROXY_TT_EMP_LIST这些对象全部以 ACO_PROXY 元数据为源头一旦本地 RFC 接口结构发生变化你需要重新导出元数据并再次生成或更新 Service Consumption Model否则数据读取时很容易出现短转储或字段丢失。还有一个容易被忽略的点生成的代理类并不是每次调用都现场去连本地系统它通常持有平台运行时的上下文。所以不要在循环里反复创建代理类实例尽量复用单例或类属性否则连接管理开销会拖慢整体性能。4. 落地代码调用与问题排查实录4.1 使用生成的代理对象调 RFC FM完成 Service Consumption Model 后剩下就是代码调用。以下是我在项目里用过的一种标准写法DATA(lo_proxy) zcl_aco_hr_emp_v2create_instance( destination MY_RFC_DEST communication_scenario ZZ_OUTBOUND_HR ). DATA: ls_request TYPE zaco_proxy_hr_emp_request, ls_response TYPE zaco_proxy_hr_emp_response, lt_result TYPE zaco_proxy_tt_emp_list. ls_request-pernr 100001. TRY. CALL METHOD lo_proxy-zhr_get_emp_detail EXPORTING request ls_request IMPORTING response ls_response CHANGING emp_list lt_result. CATCH cx_aco_proxy INTO DATA(lx). cl_demo_outputdisplay( lx-get_text( ) ). ENDTRY.要注意几点destination参数不一定需要代码里写死可以放到配置表里便于不同环境切换。communication_scenario必须和你在通信安排里选择的场景一致。导入和导出参数与原始 RFC 的参数顺序、名称一一对应如果你在本地函数模块里改了参数名代理类不会自动同步必须重新生成消费模型。我在实际项目里习惯封装一层“服务接口类”把代理对象藏起来业务代码只关心业务数据结构比如DATA(lo_hr_service) NEW zcl_hr_service( ). DATA(ls_emp) lo_hr_service-get_employee( 100001 ).这样做的好处是未来如果要从本地 RFC 切换到 S/4HANA 的 OData 或者 BAPI只需要换掉服务接口类的内部实现上层调用代码完全不动。4.2 常见报错与处理速查表云上 ABAP 调本地 RFC 的报错样式比传统 ECC 里复杂不少因为这些错误可能来自网络层、平台层和本地系统层。我整理了一张排查表现象大概率原因处理办法调用超时Cloud Connector 未放行端口或本地系统防火墙拦截检查 Cloud Connector 资源列表端口是否精确匹配Destination 解析失败通信安排未绑定通信系统或场景不一致进入 Communication Arrangement重新绑定提示用户无权限通信用户没有调用 FM 的 S_RFC 授权在本地系统给通信用户分配授权通常为 S_RFC 对象元数据错误/字段缺失本地 RFC 接口结构已变化消费模型未更新重新导出 ACO_PROXY 元数据更新 Service Consumption Model序列化/反序列化异常导入导出参数类型不匹配核对 ACO_PROXY 中的消息结构与 FM 参数通信用户密码过期通信系统密码失效更新通信系统里的密码并重新测试其中比较典型的坑是“Destination 能通但总报权限错误”。网络层和平台层都正常但通信用户没有被授权的案例占了我整个排障过程的三分之一以上。别急着看代码先到本地系统 SU01 里检查通信用户的权限和角色是否完整。4.3 几个值得记住的排查经验第一配置完成后先用“连接测试”功能而不是直接跑业务代码。BTP ABAP 环境的通信安排界面上一般都有测试按钮能快速验证路由是否通。如果你一上来就调代码报错信息会比较隐晦也容易吓到业务同事。第二引用元数据时一定要关注“版本”。RFC 函数模块在 On-Premise 端被反复修改是常事但每次修改都要重新出 ACO_PROXY 元数据否则云端代理类和实际接口可能处于“带病运行”状态。我在项目里强制要求 On-Premise 开发同事每次修改接口后都同步更新元数据包放到同一个传输请求里管理。第三善用日志。BTP ABAP 环境里可以通过“出站服务日志”或运行时日志来查看每次调用的输入输出。你可以把传入的request结构和返回的response临时写到应用日志表里排完障再移除。但不建议在生产环境长期打印完整报文可能会把敏感数据落盘。第四对于一些确实不适合 RFC 直通的场景比如本地系统太老、没有 SPROXY 支持或者你需要跨网络拓扑更复杂的链路可以考虑在 On-Premise 侧通过 ABAP Process OrchestrationPO把 RFC 函数包装成 Web 服务再回 BTP 消费。那是一条备选路径但会增加一个中间层调用链路的可靠性和排查复杂度都会上升。对大多数项目而言RFC 直通加 Service Consumption Model 这种方案链路短、结构清晰是最容易落地的一种。前提是你要把 ACO_PROXY 元数据当成“一等公民”来维护而不是一个可有可无的临时文件。我在实际项目中涉及这个集成的代码量其实不大大量精力都花在元数据对齐和权限配置上。事后回想最值的做法是在项目一开始就组织一场“接口结构化梳理”把每个待调用 FM 的输入、输出、表参数、异常类型全部列成清单再逐个导元数据、生成消费模型。这样后面联调时基本就是走流程很少被奇怪的问题卡住。如果后续环境里要接入的 RFC 函数越来越多建议尽早用命名规范区分不同业务域。比如ZCL_ACO_HR_*负责 HR 域接口ZCL_ACO_FI_*负责财务域接口ZACO_PROXY_HR_*只放元数据生成的结构这样一来你看到代理类的名字就能知道它在管什么业务排查问题的时候也能更快找到对应的消费模型位置。
返回列表