
作为传统 ABAP 开发者阅读mcp-abap-abap-adt-api以及底层abap-adt-api源码时如果没先搞清 CSRF Token、stateful/stateless会话模式等概念很容易被底层复杂的 HTTP 封装绕晕。本文将通过Postman 实际调用 SAP ADT REST 服务把这些抽象的底层概念变成“看得见、摸得着”的可观测实例。示例对象为程序YJW_DEMO01。1.获取x-csrf-token服务URL:http://ip:port/sap/bc/adt/compatibility/graphHTTP方法get请求信息header参数:X-CSRF-Token,值:Fetch响应结果在 Response 的 Headers 中会返回一个随机生成的x-csrf-token字符串X-CSRF-Token用来防 CSRF跨站请求伪造它防的是什么浏览器会自动带上已登录站点的 Cookie。如果只靠 Cookie 鉴权恶意网页可以偷偷让你的浏览器对 SAP 发 POST改对象、解锁、删东西服务器会当成“你本人操作”。CSRF Token 的思路是服务器先发一个不可预测的 token写操作必须由客户端显式放进请求头带回恶意第三方页面通常读不到你从 ADT 拿到的 token同源策略没有正确 token → 拒绝常见 403Cookie 证明“浏览器里有会话”Token 证明“这是知情的客户端主动发起的写请求”。为什么 ADT 需要用到它ADT 的 lock / unlock / 改源码都是会改系统状态的写操作。SAP 对这类请求校验同一会话 Cookie 匹配的 X-CSRF-Token才允许写操作Cookie 证明你登录了CSRF Token 证明这次写操作是你或你的工具发起的不是别人借你的浏览器偷偷发的。abap-mcp-adt的相关代码GitHub - marcellourbani/abap-adt-api: Abap Developer Tools client · GitHub路径src/AdtHTTP.ts方法 _request2.加锁对象GitHub - mario-andreschak/mcp-abap-abap-adt-api: MCP-Server for SAP ABAP wrapping abap-adt-api · GitHub代码路径src/handlers/ObjectLockHandlers.ts// 1. 在调用底层的 lock 之前显式将客户端状态修改为 stateful this.adtclient.stateful session_types.stateful; // 2. 然后调用 adt client 的 lock 方法加锁对象 const lockResult await this.adtclient.lock(args.objectUrl, args.accessMode);2.1 切换成有状态在调用底层的lock之前将客户端状态改为了session_types.statefulthis.adtclient.stateful session_types.stateful本质上设置adt rest服务的请求头header的属性X-sap-adt-sessiontype为stateful参考4.会话状态的说明2.2 然后调用adt client的lock方法加锁对象const lockResult await this.adtclient.lock(args.objectUrl, args.accessMode);SAP enqueue 成功后发的 会话锁令牌。后续setObjectSource/unLock都要带上它证明持有这次锁。会话断开或unLock后就失效。测试加锁测试程序YJW_DEMO01服务URL:http://ip:port/sap/bc/adt/programs/programs/yjw_demo01?_actionLOCKaccessModeMODIFYHTTP方法post输入步骤1获取到x-csrf-token设置X-sap-adt-sessiontype成stateful注意一定要stateful才触发加锁响应结果接口成功后会返回一段 XML解析后可以拿到一个加密的lockHandle会话锁令牌?xml version1.0 encodingutf-8? asx:abap version1.0 xmlns:asxhttp://www.sap.com/abapxml asx:values DATA LOCK_HANDLE0DDA6DC1A34A39BDA3AEB448769520EFA8736FE5/LOCK_HANDLE CORRNR/ CORRUSER/ CORRTEXT/ IS_LOCALX/IS_LOCAL IS_LINK_UP/ MODIFICATION_SUPPORT/ SCOPE_MESSAGES/ /DATA /asx:values /asx:abap此时保持 Postman 连通状态登录 SAP GUI 进入事务码SM12查看锁记录会看到程序YJW_DEMO01已经被当前使用的 HTTP 帐号成功锁定了adt.client.lock的底层代码路径async function lock(h, objectUrl, accessMode MODIFY) { (0, AdtException_1.ValidateObjectUrl)(objectUrl); (0, AdtException_1.ValidateStateful)(h); const qs { _action: LOCK, accessMode }; const response await h.request(objectUrl, { headers: { Accept: application/*,application/vnd.sap.asxml;charsetUTF-8;datanamecom.sap.adt.lock.result }, method: POST, qs }); const raw (0, utilities_1.parse)(response.body); const locks (0, utilities_1.xmlArray)(raw, asx:abap, asx:values, DATA); return locks[0]; }3.解锁对象请求头 (Headers)同样需要携带有效的 X-CSRF-Token 和 X-sap-adt-sessiontype: stateful。URL 参数必须将步骤 2 中获取的 lockHandle 作为 URL 参数传入证明你持有这次锁的所有权。HTTP 方法POST服务 URLhttp://ip:端口/sap/bc/adt/programs/programs/yjw_demo01?_actionUNLOCKaccessModeMODIFYlockHandle0DDA6DC1A34A39BDA3AEB448769520EFA8736FE5请求发送成功后再次进入 SAP 后台刷新SM12该程序的锁记录已消失资源成功释放。路径src/handlers/ObjectLockHandlers.ts4.会话状态X-sap-adt-sessiontype属性是 SAP ABAP 核心开发团队在设计ADT (ABAP Development Tools, 即 Eclipse 及 VS Code/Cursor 插件底层的 REST API)时使用的内部/私有扩展 HTTP 头部字段。它的核心作用是指导 ABAP 后端的 ICF (Internet Communication Framework) 处理程序该如何维护用户的上下文Roll Area。Stateless无状态默认每个 HTTP 请求到达后端后系统会分配一个独立的内存上下文Roll Area请求处理完毕后立即释放。Stateful有状态当客户端通过X-sap-adt-sessiontype: stateful发送请求时ABAP 后端会将其绑定到一个固定的工作进程上下文中。只要会话未超时或未显式关闭全局变量、锁机制如排他性编辑锁都会保留在内存中。adt客户端设置状态的代码代码路径经常在mcp的代码里看到设置状态的代码this.adtclient.stateful session_types.stateful;本质上是设置adt rest服务的请求头header的属性X-sap-adt-sessiontype为statefulconst SESSION_HEADER X-sap-adt-sessiontype5.总结X-CSRF-Token是前后端安全通信的门票。X-sap-adt-sessiontype: stateful是在无状态的 HTTP 世界里拉起 ABAP 工作进程 Roll Area、维持ENQUEUE锁的隐形纽带。理解了这两点再去看MCP源码思路就会豁然开朗。