本文涉及的模块: Integration Flow Helper
SAP CPI 中的未知 header 和属性:在静默失败之前发现它们
为什么 SAP CPI 中拼错或缺失的 header 或 exchange property 不会报错就失败,常见原因有哪些,以及如何在设计时和运行时发现它们。

从未被设置的 header 不会让 SAP CPI iFlow 停下来。读取它的表达式返回空值,Router 条件变为 false,负载字段留空,消息照常继续。真正的错误(如果有的话)会在几个步骤之后或在接收系统中才出现。
本文解释为什么缺失的 header 和 exchange property 会静默失败、反复出现的原因,以及能比消息更早发现它们的检查方法。
为什么缺失的名称不会报错
Apache Camel 把不存在的 header 或属性当作空值,而不是错误。这对可选值来说很方便,但也正因如此,一个拼写错误可以在 iFlow 中潜伏好几个月。你看到的现象取决于读取该名称的位置:
- 像
${property.orderId}这样的 Content Modifier 值会变成空字符串。 - 像
${header.orderType} = 'EXPRESS'这样的 Router 或 Filter 条件求值为 false,消息于是走另一条路由,通常是默认路由。 - 像
/orders/${property.orderId}这样的接收方地址会调用/orders/,接收系统返回的错误里根本不会提到缺失的属性。 - 在 Groovy 脚本中,
message.getHeader("orderId", String)返回 null,脚本随后因空指针错误而失败,或者把文本 null 写进负载。
常见原因
- 属性名拼写错误或大小写不对:exchange property 名称区分大小写,因此
orderID和orderId是两个不同的属性。header 名称不区分大小写。 - 多余的空格,例如
${header.orderId }:带空格的名称是另一个名称。 - 某个值只在 Router 的一条路由上设置,却在各路由汇合之后被读取。
- 发送方发送了 header,但没有放行:HTTPS 发送方只会放行 iFlow 的 Runtime Configuration 中 Allowed Header(s) 所列的自定义 header。
- 期望从另一个 iFlow 传来的属性:exchange property 不会随 ProcessDirect 调用传递,只有 header 会(参见 ProcessDirect 和 JMS 文章)。
- header 行读取了同一个 Content Modifier 中设置的属性,而 Content Modifier 会先处理 header 表,再处理属性表。
让缺失的值明确地报错
对于流程离不开的值,请在需要它们的地方就报错,而不是三个步骤之后。在流程开头加一个简短的 Groovy 步骤就足够了:
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
def orderId = message.getProperty("orderId")
if (orderId == null || orderId.toString().trim().isEmpty()) {
throw new IllegalStateException("Exchange property orderId is not set")
}
return message
}这样,消息会以错误结束,并带有一句点名缺失属性的说明,可以在消息处理日志中看到。对于 Router 条件,请让默认路由承担明确的用途:如果不应出现没有匹配任何路由的情况,就以 Error End 事件结束它,而不是让消息沿着原本作为后备的路径继续前进。
测试时,请把 iFlow 的日志级别设为 Trace。Trace 会显示每个步骤中的 header 和 exchange property,让你准确看到某个值是在哪里消失的。
部署前的检查清单
- 列出 iFlow 读取的每个 header 和属性:在表达式、条件、适配器字段和脚本中。
- 为每一个找到设置它的步骤,到达读取位置的每一条路径都要检查。
- 比较确切的拼写,包括属性的大小写以及任何空格。
- 对于来自发送方的 header,确认它们已列在 Allowed Header(s) 中。
- 对于来自另一个 iFlow 的值,确认它们以 header 而不是属性的形式传递。
在大型 iFlow 上手动完成这项检查要花不少时间,这也是它最值得优先自动化的原因。
避免问题的命名习惯
- 选定一种风格(例如 camelCase),并在整个 package 的所有 header 和属性中统一使用。
- 把整个流程依赖的值集中在靠近开头的一个 Content Modifier 中设置,这样只需在一个地方查找。
- 把
SAP_和Camel前缀留给 SAP 和 Apache Camel;为你自己的名称采用不同的形式。 - 只在本 iFlow 内需要的值使用属性,只有需要离开本 iFlow 的值才使用 header。
关于 Camel Simple 表达式的文章解释了这份清单中每个名称背后的语法。
Kitegra 如何帮你
浏览器扩展 Kitegra 会在 SAP Integration Suite 设计器中执行这份检查清单。它的 Lint 面板会在你部署之前标出 iFlow 中没有任何地方设置的 header 和属性、未闭合的 ${,以及表达式中多余的空格。
当你输入 ${ 或 $ 时,它只提示 iFlow 中已设置的名称(包括在 Groovy 和 JavaScript 脚本中设置的名称),以及 SAP 和 Camel 的标准 header,因此从一开始就更不容易拼错。只在部分路径上设置的名称会标注为“仅在部分路径上设置”。它从不保存、部署或编辑 iFlow 的内容;只有在你点击四个指定操作之一时,tenant 才会发生变化,而且这些操作可以关闭。
如果某个值在运行时为空,逐步跟踪消息可以显示每个步骤之前的 header 和属性,而 iFlow 审查清单则涵盖了背后的设计错误。
没有 Kitegra 账户时,每个模块可用于 5 个 iFlow。Free 套餐涵盖 50 个,Starter 100 个,Pro 300 个;Business 不限。比较各套餐。
在下一个 iFlow 中试试
了解 Kitegra 在 SAP Integration Suite 设计器中能做什么,或在 Kitegra 的其他 Chrome 扩展旁查看它。
常见问题
为什么 header 缺失时 SAP CPI 不报错?
对于不存在的 header 或属性,Apache Camel 返回空值。问题只会在这个空值造成损害的地方显现,通常是几个步骤之后。
为什么我能看到 exchange property 已经设置,它却是 null?
请检查大小写:exchange property 名称区分大小写。还要确认设置它的步骤在消息实际经过的路径上执行了,并且这个值不是指望通过 ProcessDirect 调用传过来的。
为什么发送方发来的 header 没有到达我的 iFlow?
HTTPS 发送方只放行 iFlow 的 Runtime Configuration 中 Allowed Header(s) 所列的自定义 header。请把该 header 名称添加到那里。
如何查看每个步骤中的 header 和属性?
把 iFlow 的日志级别设为 Trace 并运行一条消息。监控中的 Trace 会显示每个步骤的 header 和 exchange property。
必需的值缺失时,如何让流程停止?
添加一个脚本步骤来检查该值,并抛出带有清晰消息的异常;或者把 Router 的默认分支指向 Error End 事件。
能在部署之前检查吗?
可以,方法是把 iFlow 读取的每个名称与它设置的名称进行比对。Kitegra 的 Lint 面板会在设计器中完成这项工作。