最近在帮一家制造企业做供应链数据接入,上游供应商的系统比较老旧,不提供标准 API,也没有消息中间件,只给了一台 SFTP 服务器上的指定目录。每天凌晨他们系统会自动把前一天的订单、发货单、对账文件丢进去,然后就等着我们自己想办法处理。这个场景在 SAP Cloud Integration 里最直接的解法,就是搭建一条入站 SFTP 连接,用轮询把文件定时“拉”进 SAP BTP。整套链路跑通之后,我觉得里面有不少值得深入说的细节——轮询不是简单填个目录地址就完事,认证方式、文件过滤、重复消费策略、网络打通方式,每一项都决定了这条链路稳不稳。
1. 为什么我用“轮询拉取”而不是让对方主动推送
1.1 一个让我按下 F5 的项目场景
这个供应链项目的需求本身不复杂:供应商每天固定生成一批 CSV 文件,内容涵盖订单、发货计划和对账数据,需要进到 SAP BTP 侧做后续处理和落库。但对方 IT 团队能投入的精力非常有限,明确表示“不能开发推送逻辑,也不方便对外开放接口”。那就只剩下一个方向:由我们这边主动去连对方的 SFTP 服务器,把文件拿回来。
一开始团队里也有人提议让对方把文件同步到某个共享网盘或者邮件发过来,但数据量、时效性、安全合规都不允许。最终确定用 SAP Cloud Integration 的 SFTP Sender 适配器来做入站连接。这个模式的本质是:SAP BTP 侧作为 SSH 客户端,按设定的节奏去远程目录探活,发现新文件就拿走。用一句话概括就是——从“对方推给我”变成“我自己去取”。
1.2 拉和推的差别,不只是方向
很多人觉得推送和轮询只是数据流方向不同,其实差别远不止方向。
推送模式要求对方系统主动调用我们暴露出来的端点,这意味着他们要了解我们的网络策略、认证方式、接口规范,还必须在每次数据产生时准确触发调用。问题在于:一旦对方没有处理好重试、幂等和监控,数据丢失了我们都不知道。轮询拉取则相反,主动权完全在我们手里,我们可以控制轮询节奏、重试策略、文件删除策略,断网了恢复后下一轮自动补拉。对于“每天固定几次文件交换”这类场景,轮询的可靠性远高于依赖对方负责任。
拿取快递做个类比:推送相当于快递员送货上门,你不在家就得反复打电话确认;轮询相当于自己去快递柜取件,柜门一开,有没有件一目了然。SFTP 轮询就是那个快递柜,数据文件是否生成、是否完整、是否已经取走,适配器每次连接都能确认。
1.3 SFTP Sender 适配器的能力边界
需要先明确一个容易混淆的点:虽然叫“入站”,但在外部 SFTP 服务器眼中,SAP Cloud Integration 其实是 SSH 客户端。SFTP Sender 适配器的职责很单纯——建立 SSH 连接、完成认证、按过滤器读取文件、把文件内容作为消息交给 Integration Flow 后续处理。
它不负责解析文件内容,后续的字段拆分、格式转换、值映射要靠流程里的其他步骤;它也不具备事件监听能力,文件刚上传进来不会立刻触发,必须等下一个轮询周期。这是“拉”模式的固有特性,理解这一点对后续配置非常重要。如果你需要秒级响应,轮询 SFTP 并不合适;但如果你处理的是每日批量和准实时数据,它反而是最稳、最省事的方式。
2. 搭建前必须敲定的网络、认证和文件约定
2.1 网络可达性:不是所有 SFTP 都能被 CPI 直接访问
这是很多项目一开始最容易忽略的问题。对方的 SFTP 服务器如果暴露在公网上,那很简单,直接在适配器里填主机名和端口就行。但如果对方的服务器在内网,SAP Cloud Integration 默认走互联网是连不过去的,必须提前把网络通道打通。
在 SAP BTP 体系里,常见的打通方案是借助 Cloud Connector 连接内部系统,或者使用私有链接服务。如果走 Cloud Connector,适配器配置里要把 Proxy Type 选成 OnPremise,并填写对应的虚拟主机和端口。还有一个更麻烦但必须提前搞定的点:对方的防火墙需要放行 SAP BTP 数据中心的出口 IP 段。这个不要拖到上线前才去协调,我见过好几个项目因为对方安全团队审批慢,最后硬生生延迟了两周上线。建议在项目启动初期就让集成顾问把 IP 清单和端口要求写清楚,发给对方网络管理员。
2.2 认证方式:优先公钥而不是密码
SFTP 适配器支持密码和公钥两种认证方式。如果只是快速联调,密码认证最省事,直接在 Security Material 里创建一个 User Credential,填入用户名和密码,然后在适配器里引用它的名称即可。但生产环境我强烈建议用公钥认证。
原因很现实:企业密码策略通常会要求定期改密,一旦对方侧修改了密码,而你的凭据没同步更新,轮询会静默失败——数据堆积在服务器上,直到业务人员发现问题。公钥认证不存在密码过期问题,只要私钥保管好,稳定性高得多。实现方式上,先在本机生成密钥对,把公钥交给对方配置到目标账号下,私钥上传到 SAP BTP 的 Keystore,并在适配器里选择对应的密钥条目。
这里有一个非常容易踩的坑:私钥格式。市面很多工具导出的私钥是 PuTTY 格式(.ppk),Cloud Integration 的 Keystore 通常要求 PEM 格式,也就是标准的 OpenSSH 私钥。如果是 .ppk,需要先转换,否则握手阶段直接报格式错误。我一般建议直接在 Linux 环境或者 Git Bash 里用 ssh-keygen 生成密钥对,一步到位就是 PEM 格式,省去转换的麻烦。
另外,安全要求高的项目还会配置 Known Hosts,也就是把对方服务器的 SSH 主机公钥指纹存到程序仓库里,连接时校验服务端身份,防止中间人攻击。这个配置虽然增加了一些前期工作量,但对强调数据安全的企业客户来说基本是硬性要求。
2.3 目录、文件名与“写完标志”约定
轮询最怕什么?最怕文件还没写完就被人读走了。比如对方程序正在流式写入一个大的 CSV,写到一半我们的轮询触发了,适配器读取到的就是一个残缺文件。这个问题的根源不在 SAP Cloud Integration 侧,而在文件生成的方式上。
最佳实践是和对方约定一个文件“完成标志”:数据文件先写到临时目录或使用临时后缀(例如 .tmp、.uploading),全部写入完成后,再把文件改名成正式文件名、移动到轮询扫描的目录。轮询适配器只匹配正式文件名,从机制上规避了半截文件的读取。这个约定必须在项目一开始就和对方敲定,并且写进接口文档,不要指望对方的开发人员默认理解这个需求。
文件名本身也要有规矩。我常用的是“业务类型_日期_序号”的格式,例如 supplier_order_20250101_001.csv。这样既方便轮询适配器按正则过滤,也方便出问题时按日期回溯查找文件。目录结构上,建议对方为每个业务类型建独立子目录,不要所有文件堆在一个目录里——轮询过滤器配置更清晰,排查问题也更快。
2.4 权限最小化:给 CPI 的账号“够用就行”
SFTP 账号的权限分配非常重要。给到 SAP Cloud Integration 的账号,原则上只需要“列出目录内容、读取文件”就够了,如果采用 Move 或 Delete 的文件后处理策略,再额外加上“删除、重命名”的权限。尽量不要给写权限,更不能给账号升级成管理员权限。
原因很直接:集成流程配置错误或者适配器异常时,一个拥有过高权限的账号可能会对对方服务器上的其他目录造成不可预期的操作。权限最小化不仅是安全要求,也是日常运维的边界保护。有一次我把账号的轮询目录配置早了一个层级,如果那个账号有目录级写权限,很可能会把归档文件移动到错误的位置。好在当时权限收得很紧,只是报了个目录不存在的错误,没造成实际影响。
3. 在 Cloud Integration 里配置入站 SFTP:逐步操作
3.1 创建 Integration Flow 并放入 SFTP Sender 适配器
打开 SAP Integration Suite 的 Web 设计器后,新建一个 Integration Flow,在消息处理区域拖入 Start Event,然后把发送方适配器选择为 SFTP。适配器配置界面上有几个字段需要认真填:
| 配置项 | 填写内容 | 说明 |
|---|---|---|
| Address | 对方 SFTP 服务器的主机名或 IP | 生产环境建议填主机名,避免 IP 变更 |
| Port | 22 | 如果对方改了端口需要对应调整 |
| Proxy Type | Internet 或 OnPremise | 公网直连选 Internet,内网走 Cloud Connector 选 OnPremise |
| Credential Name | Security Material 中的凭据名称 | 密码认证指向 User Credential,公钥认证指向密钥条目 |
这里提醒一句:Address 只填主机名,不要把 sftp:// 前缀写进去,适配器协议类型已经确定了。端口如果填错,会直接导致 TCP 连接失败,排查起来最基础也最容易忽略。
3.2 认证与密钥条目的实际配置
密码认证的方式:在 Security Material 里新建 User Credential,填入对方的 SFTP 用户名和密码,保存后把凭据名称填进适配器。这个方式联调阶段非常方便,改密码也只需要在 Security Material 里编辑一个条目,但前提是对方允许用密码登录。
公钥认证的方式分两步。第一步,把私钥文件上传到 Keystore 的 Key Pair 条目里,这一步要求私钥格式为 PEM。第二步,在 SFTP 适配器的认证类型里选择 Public Key,并在密钥别名里选到刚才上传的条目。整个过程里私钥是不落盘的,适配器运行时直接访问 Keystore 里的条目,这一点对安全审计很重要。
如果要配置 Known Hosts 指纹校验,一般需要在集成包里维护一个 known_hosts 文件,内容格式对标 OpenSSH 的标准写法。首次连接前,先从对方那里拿到服务器公钥指纹,或者用命令行 SSH 客户端自行获取,再填入配置。我对这个功能的建议是:生产环境尽量开,开发测试环境可以先不开,否则每连一个新环境都要维护一次指纹,联调效率会低不少。
3.3 轮询节奏与文件过滤器
入站 SFTP 适配器是典型的轮询触发器,它依赖 Scheduler 设置来决定多久去远程目录“看一眼”。在适配器的 Scheduler 区域,你可以选择固定间隔轮询(单位毫秒),也可以配置 cron 表达式。
比如每 10 分钟轮询一次:
0 0/10 * * * ?每天凌晨 1 点到 5 点之间每半小时一次:
0 0/30 1-5 * * ?轮询间隔的设置需要根据业务时效性来权衡。文件每天凌晨生成,那设置每 30 分钟轮询完全够用;如果业务要求准实时,才需要压到 1 到 5 分钟。我不建议把间隔压得太短,例如 30 秒一次。一方面,空轮询会对对方服务器产生没意义的连接压力;另一方面,SAP Cloud Integration 侧每个轮询动作都会产生日志和开销,太密集的轮询会让消息日志变得臃肿,真正有价值的消息反而被淹没。多个项目跑下来,5 到 15 分钟是比较舒服的区间。
文件过滤器建议用正则表达式。例如只处理 CSV 文件:
.*\.csv如果想要更精准地匹配订单文件:
^supplier_order_\d{8}_\d+\.csv$过滤器匹配的是文件名而不是完整路径,所以不用写目录前缀。每次轮询时,适配器会扫描指定目录下所有文件,把满足过滤条件的文件逐条生成消息。
3.4 文件处理完成之后:Delete、Move 还是 None
这是一个很多人配置时随手一填、结果后续出大问题的关键参数。轮询读取文件并交给流程处理之后,远程文件怎么处理,有三种策略:
| 策略 | 行为 | 适用场景 |
|---|---|---|
| None | 文件保留在源目录 | 需要外部配合改成文件名,否则极易重复消费 |
| Delete | 处理成功后立刻删除文件 | 追求简洁,不需要留底 |
| Move | 处理成功后移动到指定归档目录 | 推荐,兼顾排查与清理 |
适配器判定“处理成功”的依据是整个 Integration Flow 执行到了 End 事件。如果流程中途报错,文件不会被删除也不会被移动,这样设计是有道理的——保留原始文件可以让你修复流程后重跑,或者人工介入处理。但如果你的流程里没有做错误重试,失败消息就会一直留在源目录,下一轮轮询又会把它拉进来,导致同样的错误反复出现。所以选择 None 时,必须配套文件名变更机制或者其他幂等策略。
我自己的习惯是生产环境优先用 Move,把处理完的文件移动到 archive 子目录。这样业务侧随时能看到文件确实被取走了,技术侧排查问题时也有原始数据可回溯。如果双方约定确认无误、整体链路非常稳定,再考虑切到 Delete。
3.5 下游链路与异常分支
SFTP 读进来的文件只是原始字节流,要真正把它变成业务数据,后面还要接转换和处理步骤。一般我会在流程里放 Content Filter 做内容裁剪,用 Converter 把 CSV 转成 XML,再用 Mapping 映射到目标系统需要的消息结构,最后通过 HTTPS、Process Direct 或者其他适配器把数据发往目标。
这个链路中必须考虑目标系统不可用的情况。如果目标系统临时宕机,文件已经读进了流程,处理失败后远程文件还在,重试逻辑就显得很重要。我当时加了两个保险:一个是在流程里配置重试次数,让消息尝试多次投递;另一个是 Exception Subprocess,捕获异常后把失败信息转换成邮件告警,发送给集成运维邮箱,并附加 Message ID 方便回溯。
此外,如果文件非常大,建议在 SFTP 适配器里设置 Maximum Message Size。超过这个大小,适配器会直接报错而不是截断文件——这点和 FTP 某些行为不太一样,不会悄悄把文件截成半个就往下传。我通常在联调阶段会先用小文件跑通,再逐步调大阈值到真实业务文件大小。
4. 轮询上线后我踩过的三个坑
4.1 文件被反复拉取:轮询结束行为选错了
项目联调阶段,业务人员反馈同一个文件在目标系统里被重复处理后,我第一反应是去查消息日志。结果发现同一文件名的消息在短时间内出现了多次,而且每次都能完整执行到 End。问题根因并不复杂:适配器配置里 Polling End Action 选择了 None,文件读取后仍然留在服务器目录上,下一个轮询周期又把它当作新文件拉了一遍。
排查链路其实很简单:先看文件是否还留在源目录,再看轮询结束行为配置。把策略改成 Delete 或者 Move 后问题立刻消失。这里要特别提醒:如果你确实需要用 None,就必须配合“处理后文件改名”的机制,让对方脚本定期把处理过的文件移走或者改名,否则重复消费几乎必然发生。这个坑在现场极其常见,因为它不报错、不加日志,业务侧往往要隔一段时间才发现数据重复。
4.2 私钥握手失败:算法协商不通过
另一个印象很深的坑发生在生产环境首次连接时。适配器一直报握手失败,日志里出现了类似 “No matching key exchange method” 的报错。明眼人一看就知道是 SSH 密钥交换算法协商出了问题——对方服务器是比较老旧的 SSH 实现,默认的密钥交换算法在当前安全策略下可能不被接受。
我当时的排查过程分了三步。第一步,用本地的 SSH 客户端工具直接连对方的 SFTP 服务器,确认账密和网络都没问题;第二步,在客户端上查看双方协商出来的密钥交换算法,发现对方只支持老旧的 diffie-hellman-group14 之类算法,而 SAP Cloud Integration 适配器默认策略里这类算法的优先级并不高;第三步,联系对方系统管理员,评估是否可以通过调整 sshd 配置来启用更安全的算法组合。
这里要提一个安全取舍:不要为了跑通连接就无脑选择最弱的算法。如果确认是对方服务器过于老旧,宁愿推动对方升级 SSH 版本,或者暂时用密码认证过渡,也不要长期依赖已经淘汰的加密算法。数据安全是不能为了让流程跑起来而让步的。
4.3 半截文件被读出:写入未完成就触发轮询
这个问题我们因为事先有约定,踩得比较轻,但还是遇到过一次。对方某个批处理任务偶尔会晚启动,导致约定好的“先写 .tmp 再改名”流程没生效,文件还在落盘中途就被轮询拉走了。最明显的症状是 CSV 行数明显偏少,或者末尾字段解析异常。
根因清楚之后,修复方案有两层。第一层是短期应急:让对方在生成文件时确保完整落盘后再做改名,或者暂时把该业务文件的生成时间段挪到轮询窗口外。第二层是长期方案:在集成流程里加一个等待步骤,让消息在流程里停留几十秒再处理——这是一个治标不治本的办法,真正的根治还是需要文件“完成标志”机制。
如果你没法推动对方做改名机制,一个折中思路是在适配器里缩小文件过滤器范围,只匹配“不可能正在写入”的历史日期文件,例如只处理前一天生成的固定格式文件。只是这样时效性会降低,需要业务侧接受。
5. 上线后的运维清单与参数参考
5.1 如何监控“空轮询”和“真文件”
轮询适配器在没有新文件时,通常不会产生消息日志,但会有连接或审计日志记录它确实去访问了远程目录。这一点可以用来区分“链路正常但没有文件”和“链路断了所以没文件”。日常运维时,我建议每天固定时间检查一次该 Integration Flow 的消息日志,看看是否出现了预期数量的消息;同时开启失败消息的邮件告警,确保任何异常都能第一时间通知到运维人员。
如果你配置了 Move 策略,问题排查会轻松很多。文件被成功读走并归档后,源目录会清空,归档目录会看到新增文件;如果源目录出现“应该处理的文件却没被处理”,说明流程可能正在报错,需要立刻去消息日志里找红色状态的消息。这套监控逻辑几乎不需要额外开发,靠 Integration Suite 自带的日志和归档功能就能完成。
5.2 一套比较稳的参数模板
下面这组参数是我在多个项目上验证过、比较稳妥的起始配置,可以直接抄作业,再按实际业务微调:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| Polling Interval | 300000ms | 5 分钟一次,兼顾时效和服务器压力 |
| File Name Filter | .*.(csv|txt)$ | 按后缀过滤,业务命名复杂时用更严格的正则 |
| Polling End Action | Move | 归档到 archive 子目录,方便回溯 |
| Connection Timeout | 30000ms | 30 秒建连超时,太短容易误报 |
| Max Message Size | 等于最大业务文件大小的两倍 | 留出余量,防止误伤大文件 |
| Known Hosts | 配置服务器公钥指纹 | 生产环境打开,测试环境可先关闭 |
轮询间隔这个参数值得多说一句。它不是一个孤立的数值,而是要结合文件生成时间、目标系统处理能力、消息日志容量一起权衡。曾有客户让我把间隔改成 1 秒,理由是要“实时”,但他们的业务文件每天只有 3 个批次,1 秒轮询意味着每天产生 8 万多次无意义的连接尝试。我最后给出的建议是每 5 分钟一次,对方业务侧完全没感知到延迟。
5.3 这类链路的扩展玩法
跑通了最基础的“轮询读取 + 转换 + 发送”之后,还可以基于这条链路做不少扩展。
比如对方传过来的是 zip 压缩包,可以在读取后用解压脚本把压缩包拆成多个文件,再用 Splitter 按行拆分成多条消息逐一处理;又比如有多个业务目录需要轮询,可以建多个 Integration Flow,各自维护独立的过滤器和归档目录,避免所有文件的逻辑纠缠在一个流程里,出问题时隔离性更好。
再往上走,如果未来对方升级了系统、愿意提供 API,也可以把 SFTP 轮询作为降级通道保留,两者并行运行,通过消息去重防止同一份数据被处理两次。这套“一主一备”的思路在集成项目里非常实用,既满足现有系统的能力约束,也为后续演进留出了空间。
最后再分享一点个人体会:轮询 SFTP 看起来技术含量不高,但它是很多企业集成项目里最不起眼、却最不能出错的一环。文件没被及时拉取、被重复拉取、半截文件被处理,都会直接传导到下游业务数据准确性上。真正把它配置好,靠的不是某个花哨功能,而是把认证、网络、文件约定、轮询策略这四件事在项目初期就想清楚。按照上面的步骤走一遍,链路通常就能稳定跑很久。