news 2026/7/16 9:55:36

【ABAP】REST/HTTP技术(二):消费外部API与JSON数据解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【ABAP】REST/HTTP技术(二):消费外部API与JSON数据解析

1. 从ABAP发起HTTP请求的基础操作

第一次用ABAP调用外部API时,我踩过不少坑。最典型的就是直接用CL_HTTP_CLIENT发请求,结果连最简单的GET请求都报错。后来发现是没设置Content-Type头信息。这里分享几个实战中总结的关键点:

创建HTTP客户端对象时,推荐用cl_http_client=>create_by_url方法。我习惯先用TRY...CATCH包裹这段代码,因为URL格式错误或者网络问题都会导致异常。下面是个典型的安全写法:

DATA: lo_client TYPE REF TO if_http_client. TRY. cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/data' IMPORTING client = lo_client ). CATCH cx_root INTO DATA(lx_error). " 这里处理错误 ENDTRY.

设置请求头时,这几个是必选项:

  • Content-Type: 通常用application/json
  • Accept: 建议设为application/json
  • 如果有认证需求,还要加Authorization
lo_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ). lo_client->request->set_header_field( name = 'Accept' value = 'application/json' ).

发送GET请求相对简单,但POST请求要注意body的格式。我遇到过最坑的情况是JSON字符串里的双引号被转义了。正确姿势是:

DATA(lv_json) = '{"key":"value"}'. lo_client->request->set_method( if_http_request=>co_request_method_post ). lo_client->request->set_cdata( lv_json ).

2. 处理API认证的实战技巧

去年做电商平台对接时,我花了三天时间调试OAuth2.0认证。不同API提供商的认证方案差异很大,这里分享几种常见情况的处理方式。

API Key认证是最简单的,通常放在URL参数或者Header里。比如:

" URL参数方式 lv_url = |https://api.weather.com/v1?apikey={ lv_api_key }|. " Header方式 lo_client->request->set_header_field( name = 'api-key' value = lv_api_key ).

Basic认证稍微复杂点,需要做Base64编码。ABAP里有现成的工具类:

DATA: lv_auth_string TYPE string. lv_auth_string = |{ lv_username }:{ lv_password }|. CALL FUNCTION 'SCMS_STRING_TO_XSTRING' EXPORTING text = lv_auth_string IMPORTING buffer = DATA(lv_xstring). DATA(lv_base64) = cl_http_utility=>encode_base64( lv_xstring ). lo_client->request->set_header_field( name = 'Authorization' value = |Basic { lv_base64 }| ).

OAuth2.0最麻烦,特别是要处理token过期的情况。我的经验是封装一个专门的认证类:

METHOD get_access_token. IF me->token_expiry_time < sy-datum AND me->token_expiry_time IS NOT INITIAL. " 调用refresh token逻辑 refresh_token( ). ELSEIF me->access_token IS INITIAL. " 首次获取token fetch_new_token( ). ENDIF. rv_token = me->access_token. ENDMETHOD.

3. 解析JSON响应的正确姿势

刚开始用ABAP处理JSON时,我被各种转换问题折磨得不轻。直到发现了/UI2/CL_JSON这个神器,效率直接翻倍。

先看最简单的场景 - 解析扁平结构的JSON:

{ "name": "张三", "age": 30, "active": true }

对应的ABAP处理代码:

DATA: ls_person TYPE ty_person. " 提前定义好结构 /ui2/cl_json=>deserialize( EXPORTING json = lv_json_response CHANGING data = ls_person ).

遇到嵌套结构时,比如:

{ "order": { "id": "1001", "items": [ { "sku": "A001", "qty": 2 } ] } }

需要先定义好对应的ABAP类型:

TYPES: BEGIN OF ty_order_item, sku TYPE string, qty TYPE i, END OF ty_order_item. TYPES: BEGIN OF ty_order, id TYPE string, items TYPE STANDARD TABLE OF ty_order_item WITH EMPTY KEY, END OF ty_order. TYPES: BEGIN OF ty_response, order TYPE ty_order, END OF ty_response.

处理数组时有个坑要注意 - ABAP内表需要明确指定WITH EMPTY KEY,否则解析会失败。

对于不确定结构的动态JSON,可以用反序列化到引用变量的方式:

DATA: lo_data TYPE REF TO data. /ui2/cl_json=>deserialize( EXPORTING json = lv_json_response IMPORTING data = lo_data ).

4. 异常处理与调试技巧

调试HTTP请求时,我习惯把这些信息记录下来:

  1. 完整的请求URL
  2. 请求头信息
  3. 请求体内容
  4. 响应状态码
  5. 响应头
  6. 响应体

可以封装一个日志工具方法:

METHOD log_request. DATA: lv_message TYPE string. lv_message = |URL: { iv_url }\n| && |Method: { iv_method }\n| && |Headers: { iv_headers }\n| && |Body: { iv_body }\n| && |Status: { iv_status }\n| && |Response: { iv_response }|. " 写入应用日志或数据库 ENDMETHOD.

处理HTTP状态码时,常见的需要特殊处理的情况:

CASE lv_status_code. WHEN 401. " 未授权 " 刷新token或重新认证 WHEN 403. " 禁止访问 " 检查权限设置 WHEN 429. " 请求过多 " 实现重试机制 WHEN 500. " 服务器错误 " 记录错误并通知管理员 ENDCASE.

对于超时问题,我推荐设置合理的超时参数:

lo_client->request->set_header_field( name = '~timeout' value = '30' ). " 30秒超时

调试小技巧:在SE80里创建HTTP测试客户端,可以直观地查看请求和响应:

  1. 事务码SE80
  2. 选择"Repository Browser"
  3. 右键 → Create → HTTP Test Client
  4. 输入URL和参数进行测试

5. 性能优化实战经验

在大数据量场景下,我总结了这些优化点:

连接池管理:频繁创建销毁HTTP客户端很耗资源。可以维护一个连接池:

CLASS zcl_http_pool DEFINITION. PUBLIC SECTION. METHODS get_client IMPORTING iv_url TYPE string RETURNING VALUE(ro_client) TYPE REF TO if_http_client. METHODS release_client IMPORTING io_client TYPE REF TO if_http_client. ENDCLASS.

批量请求:如果API支持,尽量使用批量接口。比如:

" 不好的做法:循环调用单条API LOOP AT lt_items INTO DATA(ls_item). CALL_API( ls_item ). ENDLOOP. " 好的做法:使用批量接口 CALL_BATCH_API( lt_items ).

缓存策略:对不常变的数据实现缓存:

METHOD get_cached_data. DATA: lv_cache_key TYPE string. lv_cache_key = |API_CACHE_{ iv_key }|. " 先从缓存读取 TRY. rv_data = zcl_cache=>get( lv_cache_key ). RETURN. CATCH zcx_cache_miss. ENDTRY. " 缓存不存在则调用API rv_data = call_api( iv_key ). " 写入缓存 zcl_cache=>set( iv_key = lv_cache_key iv_data = rv_data iv_expiry = 3600 ). " 缓存1小时 ENDMETHOD.

异步处理:对于耗时操作,可以考虑后台作业:

DATA: lv_jobname TYPE tbtcjob-jobname VALUE 'API_SYNC'. CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = DATA(lv_jobcount). SUBMIT zapi_sync_program WITH p_param1 = lv_param1 VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN. CALL FUNCTION 'JOB_CLOSE' EXPORTING jobname = lv_jobname jobcount = lv_jobcount.

6. 真实业务场景案例

去年我们对接物流跟踪系统时,需要实时获取快递状态。这个案例很有代表性:

需求分析

  • 每30分钟同步一次物流信息
  • 支持多家物流公司API
  • 异常状态实时预警

技术方案

  1. 使用CL_HTTP_CLIENT调用各物流公司API
  2. 用/UI2/CL_JSON解析返回的JSON
  3. 数据存入自定义表ZLOGISTICS
  4. 后台作业定时执行
  5. 异常状态触发工作流通知

核心代码结构:

CLASS zcl_logistics_tracker DEFINITION. PUBLIC SECTION. METHODS: sync_all_carriers, sync_carrier IMPORTING iv_carrier TYPE string. PRIVATE SECTION. METHODS: call_carrier_api IMPORTING iv_tracking_no TYPE string RETURNING VALUE(rv_data) TYPE string, parse_response IMPORTING iv_json TYPE string EXPORTING es_status TYPE zlogistics_status, save_to_db IMPORTING is_status TYPE zlogistics_status, check_alert IMPORTING is_status TYPE zlogistics_status. ENDCLASS.

处理不同API的兼容性问题时,我用了策略模式:

CLASS zcl_carrier_adapter DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: get_tracking_status ABSTRACT IMPORTING iv_tracking_no TYPE string EXPORTING es_status TYPE zlogistics_status. ENDCLASS. " 针对不同物流公司实现具体适配器 CLASS zcl_sf_adapter DEFINITION INHERITING FROM zcl_carrier_adapter. METHODS: get_tracking_status REDEFINITION. ENDCLASS.

7. 常见问题解决方案

SSL证书问题是最常见的拦路虎。遇到证书错误时,可以这样处理:

  1. 首先检查系统是否安装了根证书

    • 事务码STRUST
    • 查看SSL客户端标准PSE
  2. 如果还是有问题,可以临时关闭证书验证(仅限测试环境!)

lo_client->ssl_id = 'ANONYM'.

中文乱码问题通常是因为编码不一致。确保全程使用UTF-8:

" 设置请求编码 lo_client->request->set_content_type( 'application/json; charset=utf-8' ). " 处理响应时指定编码 lv_response = cl_http_utility=>if_http_utility~decode_utf8( lo_client->response->get_cdata( ) ).

大数据量分页处理方案:

METHOD get_all_data. DATA: lv_page TYPE i VALUE 1, lt_all_items TYPE ty_item_tt. DO. DATA(lv_url) = |{ iv_base_url }?page={ lv_page }&size=100|. DATA(lv_response) = call_api( lv_url ). DATA(lt_items) = parse_items( lv_response ). IF lt_items IS INITIAL. EXIT. ENDIF. APPEND LINES OF lt_items TO lt_all_items. lv_page = lv_page + 1. ENDDO. rt_items = lt_all_items. ENDMETHOD.

接口限流处理建议:

METHOD call_api_with_retry. DATA: lv_retry TYPE i VALUE 0, lv_wait TYPE i VALUE 1. WHILE lv_retry < 3. TRY. RETURN call_api( iv_url ). CATCH zcx_api_limit_exceeded INTO DATA(lx_error). lv_retry = lv_retry + 1. WAIT UP TO lv_wait SECONDS. lv_wait = lv_wait * 2. " 指数退避 ENDTRY. ENDWHILE. RAISE EXCEPTION TYPE zcx_api_failed. ENDMETHOD.

8. 高级技巧与最佳实践

自动化测试方案:我们可以为API调用编写单元测试

CLASS ltc_api_test DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. PRIVATE SECTION. METHODS: test_get_success FOR TESTING, test_post_success FOR TESTING, test_error_handling FOR TESTING. ENDCLASS. CLASS ltc_api_test IMPLEMENTATION. METHOD test_get_success. " 准备测试数据 " 调用被测方法 " 验证结果 ENDMETHOD. ENDCLASS.

监控指标建议收集这些数据:

  • 平均响应时间
  • 成功率
  • 失败分类统计
  • 数据量大小

可以用事务码ST03N查看HTTP调用性能数据。

安全加固措施:

  1. 敏感信息加密存储
  2. 使用API网关集中管理
  3. 实现请求签名
  4. 定期轮换密钥
METHOD add_signature. DATA: lv_timestamp TYPE string, lv_signature TYPE string. GET TIME STAMP FIELD lv_timestamp. lv_signature = compute_hmac( iv_data = |{ lv_timestamp }{ iv_body }| iv_key = me->api_secret ). lo_client->request->set_header_field( name = 'X-Signature' value = lv_signature ). lo_client->request->set_header_field( name = 'X-Timestamp' value = lv_timestamp ). ENDMETHOD.

文档化建议为每个API封装创建技术文档:

"! @testingClass LTC_API_TEST "! @description 物流信息查询API封装 "! @configNote 需要在表ZAPI_CONFIG配置访问密钥 CLASS zcl_logistics_api DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. "! 根据运单号查询物流信息 "! @parameter iv_tracking_no | 运单号 "! @parameter rt_status | 物流状态信息 METHODS get_tracking_status IMPORTING iv_tracking_no TYPE string RETURNING VALUE(rt_status) TYPE zlogistics_tt. ENDCLASS.
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 9:54:44

macOS Tahoe高效技巧:剪贴板历史与Spotlight计算器

1. macOS Tahoe 剪贴板历史&#xff1a;被90%用户忽略的高效神器在最新发布的macOS Tahoe系统中&#xff0c;苹果对Spotlight搜索功能进行了深度优化&#xff0c;其中最具革命性却鲜为人知的功能就是剪贴板历史管理。这个功能完美解决了我在跨应用协作时最头疼的问题——频繁切…

作者头像 李华
网站建设 2026/7/16 9:53:48

微信JSSDK开发实战:从入门到企业级应用

1. 什么是JSSDK及其核心价值JSSDK&#xff08;JavaScript Software Development Kit&#xff09;是平台方提供给网页开发者的工具包&#xff0c;它架起了网页与原生应用之间的桥梁。以微信JSSDK为例&#xff0c;它让H5页面能够调用微信客户端的原生能力&#xff0c;比如&#x…

作者头像 李华
网站建设 2026/7/16 9:53:06

本地知识库构建:Ollama与AnythingLLM的RAG实践指南

1. 项目概述&#xff1a;本地知识库的技术价值与选型思路在信息爆炸的时代&#xff0c;如何高效管理和利用本地文档已成为知识工作者的核心痛点。传统方案存在两大局限&#xff1a;一是基于关键词的检索方式难以理解语义&#xff0c;二是静态知识库缺乏智能交互能力。这正是RAG…

作者头像 李华
网站建设 2026/7/16 9:52:57

第九篇:《集成测试与质量门禁:让流水线“会判断”》

构建和部署自动化只是 CI/CD 的“躯体”&#xff0c;而质量门禁&#xff08;Quality Gate&#xff09; 才是它的“大脑”——它让流水线有能力判断“这次构建是否值得继续推进”。没有质量门禁的流水线只是一条“传输带”&#xff0c;无论代码质量如何都会一路送到生产环境。本…

作者头像 李华
网站建设 2026/7/16 9:52:43

RustRover深度解析:JetBrains自研语义引擎与跨平台IDE架构

1. 这不是又一个“套壳VS Code”的 Rust 工具——RustRover 是 JetBrains 用十年 IDE 经验重写的 Rust 开发中枢 你可能已经试过 VS Code rust-analyzer&#xff0c;也大概率在终端里敲过 cargo build、cargo test、rustup update&#xff0c;甚至为调试 tokio 异步任务反复修…

作者头像 李华
网站建设 2026/7/16 9:52:06

大华MVP全局通信实战:打通视觉与PLC/机器人的数据链路

1. 全局通信功能&#xff1a;工业自动化的神经中枢 在工业4.0时代&#xff0c;生产线上最令人头疼的问题莫过于设备间的"语言不通"。想象一下&#xff0c;视觉系统检测到产品缺陷&#xff0c;却要人工拿着对讲机通知PLC停机——这种场景就像用摩斯电码指挥高铁运行。…

作者头像 李华