camel ftp组件通过轮询而非监听获取xml文件,需配置filename匹配、move避免重复、consumer.delay控制间隔,binary=true和charset=utf-8保障xml完整性,onexception处理解析异常,connecttimeout等参数提升连接稳定性。

用 ftp 组件监听目录并拉取 XML 文件
Camel 的 ftp 组件本质是基于 Apache Commons Net 实现的,它不“监听”文件系统事件(比如 inotify),而是轮询(polling):定期列出远程目录,对比上次获取的文件名,决定是否拉取新文件。XML 只是文件内容类型,Camel 不会自动解析或校验,你得自己处理。
关键点:
-
fileName参数控制匹配规则,推荐用fileName=.*\.xml(注意双反斜杠转义) -
move或preMove必须设置,否则重复拉取同一文件(默认不移动,下次轮询还会看到) -
consumer.delay决定轮询间隔(毫秒),太短易被 FTP 服务器限流,太长则延迟高 - 用户名密码不能明写在 URI 中,应通过
password属性或org.apache.camel.component.file.remote.RemoteFileConfiguration注入
from("ftp://user@ftp.example.com/inbox?password=secret&binary=false&fileName=.*\.xml&consumer.delay=30000&move=done/${file:name}")
.to("log:received-xml?showBody=true");
避免 XML 解析失败导致路由中断
FTP 拉取的文件可能不完整(如上传中)、编码异常、或根本不是合法 XML。Camel 默认遇到 Exception 会停止该 Exchange,并可能影响后续轮询(取决于错误处理器配置)。必须显式捕获并处理解析异常。
推荐做法:
- 用
onException捕获org.xml.sax.SAXParseException和java.io.IOException - 使用
handled(true)防止重试和死信队列干扰主流程 - 把出错文件移到
error/目录,保留原始内容便于人工排查
onException(SAXParseException.class, IOException.class)
.handled(true)
.to("file:error?fileName=${file:name}.failed");
from("ftp://...")
.convertBodyTo(String.class) // 确保是 String,避免 InputStream 导致 SAX 解析失败
.to("xslt:strip-namespace.xsl") // 可选:预处理命名空间
.unmarshal().jacksonXml(); // 或用 .jaxb(),但需提前定义类
FTP 连接不稳定时的重试与超时控制
企业级 FTP 服务器常有连接空闲断开、LIST 超时、PASV 模式失败等问题。Camel 的 ftp 组件底层复用连接,但默认不重试失败的 LIST 或 RETR 命令。
必须显式配置:
-
connectTimeout和soTimeout(单位毫秒),建议都设为 30000 -
maximumReconnectAttempts控制连接级重试次数(非单个文件) -
stepwise设为false可绕过某些 FTP 服务器的路径切换问题 - 若用被动模式(PASV)失败,尝试加
passiveMode=true并确认防火墙放行数据端口范围
from("ftp://user@ftp.example.com/inbox?password=secret&connectTimeout=30000&soTimeout=30000&maximumReconnectAttempts=3&stepwise=false&passiveMode=true&fileName=.*\.xml")
生产环境必须关闭 binary=false 吗?
不是必须,但强烈建议设为 true。FTP 协议本身区分 ASCII 和 binary 模式:binary=false(即 ASCII 模式)会触发换行符转换(CRLF ↔ LF),而 XML 对换行和空白敏感——尤其是带 xml:space="preserve" 的节点或 CDATA 段。一旦被改写,unmarshal().jacksonXml() 会直接抛 SAXParseException。
唯一例外是明确知道远端 XML 全为 Unix 风格换行且无 CDATA,且你愿意承担风险。否则一律用:
binary=true-
charset=UTF-8(显式声明,避免平台默认 charset 干扰)
from("ftp://user@ftp.example.com/inbox?password=secret&binary=true&charset=UTF-8&fileName=.*\.xml")
FTP 路由真正难的不是语法,而是对协议行为的理解:它不保证原子性,不通知变更,也不校验内容。你得自己补上幂等性(靠 idempotentRepository)、完整性(加 MD5 校验)、以及失败隔离(别让一个坏 XML 卡住整条轮询线程)。











