如果你正在寻找 Frankfurter API 替代方案,你多半已经用它上线过某个项目了。对一整代业余项目来说,Frankfurter 就是默认的免费汇率 API:不需要 API 密钥、不需要注册、没有配额、REST 接口干净利落,开源代码一个下午就能读完。然后有些事情变了——一个合规问题、一个周末才出现的 bug、一位需要日内汇率的客户——于是你开始琢磨还有什么别的选择。
这份指南诚实地审视这个决定。它讲清楚 Frankfurter 在 2026 年究竟能做什么(大多数对比文章依据的是过时信息)、促使团队离开它的五个具体限制,以及三条现实可行的路径:自托管、迁移到带密钥的商业 API,或者做一个混合方案。文末附有迁移示例。
Frankfurter 在 2026 年究竟是什么
几乎所有「最佳免费货币 API」的盘点文章,仍然把 Frankfurter 描述为「欧洲央行汇率、约 30 种货币、没有周末数据」。这在过去几年是对的,但现在已经不准确了。
frankfurter.dev 上的 v2 API 追踪 84 家中央银行 的每日汇率,覆盖 201 种货币,历史数据可回溯至 1948 年。它对商业用途确实免费,无需认证,不设月度或日度配额,除 JSON 外还提供 CSV 和 NDJSON 输出。它有 OpenAPI 规范、llms.txt,以及面向智能体工作流的 MCP 服务器。你还可以用 Docker 自托管。
这比那些盘点文章给它的评价要强得多,而且有必要直说:对于大量项目而言,Frankfurter 就是正确答案,你不该迁移。 如果你在做个人理财记账工具、货币参考页面、每天定一次汇率的开票工具,或是拉取十年月度均值的数据分析笔记本,Frankfurter 做得很好,而且分文不取。
本文余下部分讲的是它不适用的那些情况。
促使团队寻找 Frankfurter API 替代方案的五个限制
1. 每日参考汇率不是实时汇率
这是结构性的,而且不是缺陷——数据源本身就是如此。中央银行参考汇率每个工作日发布一次。例如,欧洲央行每个工作日约在中欧时间 16:00 发布其欧元参考汇率。Frankfurter 忠实地把这些数字暴露出来。
这意味着你在 09:00 取到的汇率和在 15:00 取到的是同一个数字,哪怕市场在这期间波动了 1.2%。对于只做展示的换算器,没人会注意到。但对于结账页面、结算金额计算,或任何客户会拿你的数字和 Google 对比的场景,这个滞后就会变成一张客服工单。
如果你的产品需要在一天之内变动的汇率,你需要的是市场行情数据源,而不是参考汇率源。Finexly API 在市场时段内每分钟刷新一次,覆盖 170 多种货币——这是另一种数据模型,而不是同一种模型的更好版本。我们那篇汇率 API 的数据从哪里来更详细地讲了这个区别。
2. 没有周末和节假日的数据行
中央银行在周六、周日和法定假日不发布数据。所以查询 2026-08-23 不会返回有用结果,而一个月的时间序列大约有 21 行,而不是 31 行。
每个团队踩坑的方式都一样:夜间任务在周日运行,拿到空的或错位的结果,然后要么崩溃,要么——更糟——悄悄往账簿里写了个 null。如果你基于任何中央银行来源的每日汇率构建系统,你需要一条明确的前向填充策略,而且要把它写进文档,因为「使用最后发布的汇率」和「跳过这一行」会产出不同的财务报表。
3. 混合汇率在发布后仍可能变动
默认情况下,Frankfurter 会把所有贡献来源的汇率做混合。它自己的常见问题解答对后果坦率得令人耳目一新:随着新数据到来,最后几位小数可能会变动;出于合规考虑,你应当筛选到某个特定来源。
对通用场景而言这个设计完全合理。但如果你存下一个汇率、展示给用户,之后再重新拉取来对账,问题就来了:你会发现细微的差异,而这非常难向审计人员解释。在 Frankfurter 上的解法是传入 providers=ECB(或监管你的那家机构),而不是接受混合值。在你自己系统里的解法是持久化你在交易时刻实际使用的那个汇率,永远不要重新推导。这条规则适用于任何供应商,我们在汇率与税务申报指南中有详细说明。
4. 没有 API 密钥意味着没有配额——也没有可见性
「无需 API 密钥」是 Frankfurter 最好的特性,也是它最被低估的风险。因为没有密钥:
- 你没有按应用划分的配额。你和整个互联网共用一个公共限流器,包括此刻正用糟糕循环疯狂请求它的那个人。
- 你没有用量遥测。没有任何面板会告诉你上周二调用量翻了三倍。
- 你没有支持关系。有状态页面和 GitHub issue 跟踪器,这已经比很多免费服务好,但没有 SLA,也没有可以呼叫的人。
项目自己的建议很明确:高用量场景应缓存响应、自托管,或直接查询数据集。这是诚实的建议,也正是许多团队开始评估 Frankfurter API 替代方案 的时刻——不是因为数据有问题,而是因为他们承担了一个背后没有任何契约的生产依赖。
5. 没有换算端点
Frankfurter 是有意这样文档化的:取汇率,然后相乘。三行代码而已。
但这三行代码也会在你代码库的六个地方被写成略有差异的样子,其中某一处该乘的时候除了。专门的 convert 端点不是技术上的必需品;它是让舍入规则和方向规则只有一份实现的方式。如果你曾经上线过 EUR→USD 和 USD→EUR 相差 0.3% 的 bug,你就明白这为什么重要。我们的货币舍入与小数位指南覆盖了这片雷区的其余部分。
Frankfurter API 替代方案对比
下表的免费额度信息取自各家供应商撰稿时的公开页面。在做决定前请自行核实——免费额度的变化比文档更新更频繁。
| API | 免费额度 | 更新频率 | 认证 | 基准货币 | 适合 |
|---|---|---|---|---|---|
| Frankfurter | 无限(有防滥用限流,无 SLA) | 每日,工作日 | 无 | 任意 | 业余项目、记账、历史研究 |
| 自托管 Frankfurter | 免费 + 你的基础设施成本 | 每日,工作日 | 由你决定 | 任意 | 需要掌控权且已在用 Docker 的团队 |
| Finexly | 1,000 次/月 | 市场时段内每分钟 | Bearer 密钥 | 任意(高阶套餐支持自定义基准) | 需要日内汇率并要有支持渠道的产品 |
| ExchangeRate-API | 约 1,500 次/月 | 每日 | 密钥 | 任意 | 每天刷新一次的看板 |
| Open Exchange Rates | 1,000 次/月 | 每小时 | 密钥 | 免费版仅 USD | 能接受 USD 基准的服务端应用 |
| Fixer.io | 100 次/月 | 每小时 | 密钥 | 免费版仅 EUR | 遗留集成 |
我们在货币 API 对比和实时汇率 API 对比中对其中几家做了并排拆解。
方案一:自托管 Frankfurter
最被低估的答案。Frankfurter 发布了 Docker 镜像,自己运行它就消除了生产团队真正担心的两件事:共享限流器和缺乏掌控权。
docker run -d -p 8080:8080 --name frankfurter \
lineofflight/frankfurter你得到的是:无限的内部调用、自己掌握可用性,以及固定某个数据来源的能力。你要承担的是:一个容器、一个数据库、监控,以及在银行假日上游抓取中断时能察觉到的人。这是实打实的成本——大体上就是我们自建还是采购那篇分析的论点,只不过应用在一份别人已经写好的代码上。
当你的用量很高、延迟要求严格,而每日参考汇率确实够用时,自托管就是正确选择。但如果问题在于你需要日内汇率,它一点忙都帮不上——你只是在运行同一份每日数据的自有副本而已。
方案二:迁移到带密钥、提供日内汇率的 API
如果你来这里的原因是汇率新鲜度、冷门货币对的覆盖,或者需要有人回复你的邮件,那么带密钥的商业 API 就是诚实的答案。
同一件事在两边分别是这样。先看 Frankfurter:
curl "https://api.frankfurter.dev/v2/rate/USD/EUR"再看 Finexly 的等价写法:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.finexly.com/v1/rate?from=USD&to=EUR"{ "pair": "USD_EUR", "rate": 0.9215 }端点映射
| 任务 | Frankfurter v2 | Finexly v1 |
|---|---|---|
| 列出货币 | GET /v2/currencies | GET /v1/currencies |
| 单个货币对 | GET /v2/rate/EUR/USD | GET /v1/rate?from=EUR&to=USD |
| 多个货币对 | GET /v2/rates?base=USD"es=EUR,GBP | GET /v1/convert?q=USD_EUR,USD_GBP |
| 换算金额 | (无——自己相乘) | GET /v1/convert-amount?from=USD&to=EUR&amount=100 |
| 历史数据 | GET /v2/rates?date=1999-01-04 | 付费套餐——见历史汇率指南 |
BASE_QUOTE 货币对,这让你可以在同一个请求里取 USD_EUR 和 GBP_JPY,无需做交叉换算。一个迁移封装层
不要把新客户端散落到代码库各处。把两者放在同一个接口后面,这样切回去只是改个配置:
import os
import requests
FINEXLY_KEY = os.environ["FINEXLY_API_KEY"]
def get_rate(base: str, quote: str, provider: str = "finexly") -> float:
"""Return the mid-market rate for base->quote."""
if provider == "frankfurter":
r = requests.get(
f"https://api.frankfurter.dev/v2/rate/{base}/{quote}",
timeout=5,
)
r.raise_for_status()
return float(r.json()["rate"])
r = requests.get(
"https://api.finexly.com/v1/rate",
params={"from": base, "to": quote},
headers={"Authorization": f"Bearer {FINEXLY_KEY}"},
timeout=5,
)
r.raise_for_status()
return float(r.json()["rate"])
print(get_rate("USD", "EUR"))有两个细节值得照搬。API 密钥来自环境变量,绝不写在源码里——Finexly 文档指出,作为查询参数传递的密钥可能通过服务器访问日志和 HTTP Referrer 头泄露,所以生产环境应走 Authorization 头。另外每次调用都设了超时,因为大多数 HTTP 客户端的默认值是「永远等下去」。
留意响应头中的 X-RateLimit-Limit、X-RateLimit-Used 和 X-RateLimit-Units,可以实时看到配额消耗。这份遥测正是无认证 API 给不了你的东西,而它往往才是团队迁移的真正原因。
方案三:混合——缓存其一,故障时回退到另一个
大多数生产系统最终收敛到的模式。用你的主供应商,激进地缓存,并把免费的无认证 API 留作最后的兜底:
const CACHE = new Map();
const TTL_MS = 60_000;
async function getRate(base, quote) {
const key = `${base}_${quote}`;
const hit = CACHE.get(key);
if (hit && Date.now() - hit.at < TTL_MS) return hit.rate;
let rate;
try {
const res = await fetch(
`https://api.finexly.com/v1/rate?from=${base}&to=${quote}`,
{ headers: { Authorization: `Bearer ${process.env.FINEXLY_API_KEY}` } }
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
rate = (await res.json()).rate;
} catch (err) {
// Degrade to daily reference rates rather than failing the request
const res = await fetch(`https://api.frankfurter.dev/v2/rate/${base}/${quote}`);
rate = (await res.json()).rate;
}
CACHE.set(key, { rate, at: Date.now() });
return rate;
}在 1,000 次请求的免费套餐上加一个 60 秒缓存,足以从容支撑一个小型应用,因为你的调用量变成了时间的函数,而不是流量的函数。请在日志中标记回退响应,免得悄悄降级到昨天的汇率却一周都没人发现。关于 TTL 选择和重试行为,我们的缓存与错误处理指南里有更多内容。
一份决策清单
顺着这份清单往下走,在第一个「是」处停下:
- 汇率是否需要在交易日内变动? → 你需要行情数据 API,而不是参考汇率 API。
- 这是受监管或需审计的流程吗? → 固定一个具名来源,保存你用过的汇率,永不重新推导。
- 调用量很高但每日汇率够用? → 自托管 Frankfurter。
- 出问题时需要有人回应? → 你需要带密钥和支持等级的套餐。
- 以上都不是? → 就留在 Frankfurter。给它加缓存,处理好周末缺口,把时间花在别处。
大多数出去寻找 Frankfurter API 替代方案 的团队,会在第 5 步发现自己真正的问题是缺了一层缓存,以及一个没处理的星期天。
常见问题
Frankfurter API 真的能免费商用吗? 是的。项目声明其可免费商用,没有月度或日度配额——限流仅用于防止滥用。代价是没有 SLA,也没有支持合同,风险由你自己承担。
Frankfurter 只提供欧洲央行的汇率吗?
不再是了。v2 API 混合了 84 家中央银行、201 种货币的数据,你也可以用 providers 参数收敛到单一来源。流传甚广的「仅欧洲央行、30 种货币」说法指的是旧版本。
为什么 Frankfurter 周末没有数据? 因为中央银行在非工作日不发布参考汇率。任何基于中央银行数据构建的 API 都有同样的缺口。你要么用最后发布的汇率做前向填充,要么改用连续报价的行情数据源。
Frankfurter 最好的免费替代方案是什么? 取决于「免费」要为你换来什么。若要无限量的每日汇率,没有比 Frankfurter 更好的——自托管即可。若要带日内更新和真实 API 密钥的免费套餐,Finexly 的免费方案提供每月 1,000 次请求、覆盖 170 多种货币。更全面的图景见我们的免费货币 API 指南。
我可以同时使用 Frankfurter 和一个付费 API 吗? 可以,而且这是合理的架构。正常流量走主供应商,出错时回退到 Frankfurter,就像上面的混合示例那样。只要确保回退响应被记录下来,因为它们的新鲜度保证不同。
开始使用
如果每日参考汇率对你正在做的东西已经足够,那就留在 Frankfurter——它是个好项目,而且不会花你一分钱。如果你需要日内变动的汇率、超出中央银行参考集的覆盖范围,或是真正可监控的用量响应头,领取你的免费 Finexly API 密钥——无需信用卡。从每月 1,000 次请求、170 多种货币起步,随业务增长再升级;也可以先到我们的价格页面比较各档套餐。
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →