当前位置: 首页 > news >正文

【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.
http://www.cnnetsun.cn/news/3419386.html

相关文章:

  • macOS Tahoe高效技巧:剪贴板历史与Spotlight计算器
  • 微信JSSDK开发实战:从入门到企业级应用
  • 本地知识库构建:Ollama与AnythingLLM的RAG实践指南
  • 第九篇:《集成测试与质量门禁:让流水线“会判断”》
  • RustRover深度解析:JetBrains自研语义引擎与跨平台IDE架构
  • 大华MVP全局通信实战:打通视觉与PLC/机器人的数据链路
  • NVMe SSD在AI集群中的性能优势与优化实践
  • 模糊C均值聚类算法原理与C++实现详解
  • Codex Desktop Linux移植:从Electron跨平台构建到桌面集成
  • ARM Cortex-M开发板ISP升级指南与实战
  • Linux内核Lockup机制:Soft与Hard Lockup原理及调优
  • 0.96寸OLED显示屏驱动开发与优化实践
  • Ubuntu系统安装与优化全指南
  • C++配置管理利器:yaml-cpp核心原理与实战指南
  • NextChat生产级部署:Docker+Nginx+环境变量全链路实战
  • WildFly 21配置文件体系与Java应用服务器配置实战
  • ODL PDF解析器:面向RAG的数据清洗专用引擎
  • Grafana企业版SCIM API权限提升漏洞CVE-2025-41115分析与实战利用
  • 环保领域“固废处理”高价值专利案例:垃圾焚烧炉SNCR脱硝系统动态建模方法
  • 3分钟掌握Topit:让Mac窗口管理效率翻倍的免费神器
  • sshd配置实战:从基础安全到高级调优
  • DeepSeek最强提示词:只要一句话,AI自动替你多想五步
  • Python数据分析实战:Numpy、Pandas、Matplotlib完整工作流指南
  • Witty-Insight未来展望:路线图规划与社区贡献指南
  • HarmonyOS7 金额前后缀输入框:用 caretColor 把金额输入做得更顺手
  • HarmonyOs应用《重要日》开发第2篇 - 开发环境搭建与项目创建
  • 宋恭帝赵㬎:身不由己的南宋亡国幼帝
  • 拍手开关电路设计:从原理到实战优化
  • 鸿蒙应用开发第一步:个人开发者账号注册与实名认证全流程解析
  • 基于VLC media player的RTSP流媒体服务器搭建与跨设备测试