public-apis:免费 API 选型、认证与 CORS 避坑指南
2026/9/18 17:07:24 网站建设 项目流程

我做侧项目最怕的不是写代码,是卡在"数据从哪来"这一步。想做个天气挂件、股票看板、翻译小工具,产品逻辑十分钟就能想清楚,可一去找免费接口,翻出来的不是几年前的博客链接早挂了,就是文档写得云里雾里、注册半天拿不到密钥,还有些写着"免费"但点进去发现早就改成付费墙了。后来有人把 public-apis 这个开源项目推给我,一个 GitHub 仓库,474k Star,专门收集公开可用的免费 API,从动物、动漫、天气到金融、机器学习、地理编码,全部用 Markdown 表格排好,认证方式、HTTPS 支持、跨域支持这些关键信息直接标在名称后面。这篇我想聊的不是"这个项目有多厉害"这种空话,而是作为一个真会去用它的人,怎么快速筛出能用的接口、清单里那几列到底什么意思、以及那些它没写、但踩过才知道的坑。不管你是刚入门的开发者,还是做了几年后端想找点现成数据源练手,下面这些应该都能直接拿去用。

1. 474k Star 背后:这个清单真正解决的是什么问题

1.1 找免费 API 这件事为什么一直很难

先说清楚痛点,不然后面讲的筛选技巧你体会不到价值。免费 API 这个领域有三个天然的混乱来源。第一是信息的半衰期很短,一个接口今天还能用、明天可能就因为维护者没钱付服务器费关掉了,或者被大厂收购后直接下线,而搜索引擎里排在前面的往往是三五年前的"XX 个免费 API 合集"文章,链接批量失效。第二是**"免费"这两个字的定义太模糊**,有的接口免费额度是每月 1000 次调用,有的是每天 100 次,有的要你绑卡才能用免费层,有的干脆只是"注册免费、调用收费"。第三是关键信息通常藏在文档深处,你最想知道的那几件事——要不要密钥、浏览器里能不能直接调、有没有跨域限制——往往要翻三四个页面才能凑齐。

public-apis 的价值恰好落在第三点上。它把每个接口最影响开发决策的几个属性抽出来,做成了固定列,让你在一个表格里横向对比。这看起来很简单,但一个维护了几年、被几十万人 Star 的清单,能做到"分类清晰 + 字段统一 + 持续更新",本身就是门槛。它不生产 API,它做的是索引和规模化筛选这件事。

1.2 仓库的组织方式:README 是目录,entries 才是正文

很多人第一次打开这个项目,会以为整份清单都在首页那个巨大的 README 里。实际上它的结构是分层的:根目录的README.md主要承担索引角色,按大类列出条目数量并链接到对应的分类文件;真正的条目明细放在entries/目录下,每个大类一个 Markdown 文件,比如动物一个文件、金融一个文件、机器学习一个文件。这么拆的好处很实在——单个文件不会大到打开就卡死浏览器,也方便贡献者只改自己关心的那一块,减少合并冲突。

你要做的第一件事不是从头往下读,而是直接定位到自己关心的分类文件。我自己的习惯是在仓库页面用 GitHub 的文件搜索(快捷键t)输entries/,然后按名字找;或者在本地 clone 下来之后直接用ls entries/看全貌。clone 下来还有个额外好处:可以配合文本工具做本地过滤。比如我想找所有不需要认证、又支持跨域的接口,直接在本地用 grep 一把梭,比在网页上一个个点快得多。

1.3 一个 Markdown 表格能撑起 474k Star 的合理性

有人会疑惑,一个纯文本清单凭什么有这么多 Star。我的理解是:它把"发现成本"压缩到了接近零。你不需要注册、不需要登录、不需要看广告,打开就能看到一个分类下几十个候选;它也不需要你信任某个平台的推荐算法,条目是中立的。这种"低摩擦的信息获取"在开发者工具里是非常稀缺的。

更关键的是它形成了一种正循环。因为用的人多,失效的链接会被更快地发现和提 issue;因为提 issue 和 PR 的门槛低(就是改一行表格),社区愿意维护;因为维护及时,清单的可信度维持在可用水平线之上。这套机制没有多高明,但它跑通了很多同类项目没跑通的"持续更新"这一环。这也是我在做自己的资源清单时会参考它的原因——结构简单可校验,比功能花哨但没人维护要强得多

提示:清单只负责告诉你"有这么个接口存在",不保证它此刻一定可用、一定免费、一定稳定。把它当成候选池,而不是合同。

2. 读懂条目表格里的四列关键信息

清单里每个条目的格式大致是:一个可点击的名称、一段功能描述,后面跟三到四个属性列。这几列才是精华,很多人扫一眼就过,结果选出来的接口根本用不了。下面逐列拆。

2.1 Auth 列:apiKey、OAuth、No 三种形态的实际差别

Auth 这一列通常有三种取值:apiKeyOAuth,以及No。它不是学术分类,直接对应你要写多少代码、走多少流程。

  • No:不需要任何认证,直接请求就能拿到数据。这类最适合做 Demo、原型、前端小工具,也最适合自动化脚本。但要注意,无认证的接口通常限流更严,而且随时可能因为被滥用而关闭或加认证。
  • apiKey:需要注册后拿到一串密钥,请求时带上。实现成本中等,麻烦的地方在密钥的保管。前端项目里绝对不要把这串密钥硬编码进打包产物,任何人打开浏览器开发者工具都能看到。正确做法是走自己的后端做一层代理,或者用平台提供的受限密钥机制配白名单。
  • OAuth:需要走授权流程,用户跳转到第三方页面同意授权,再回调拿令牌。这类接口功能往往更强(能代表用户操作数据),但接入成本明显更高,涉及回调地址配置、令牌刷新、过期处理。除非你确实需要访问用户私有数据,否则做小项目尽量避开。

我自己的取舍原则很简单:做一次性数据演示优先选 No,做自己有后端的产品优先选 apiKey,OAuth 只在必须代表用户身份时才上。清单把这一列标出来,就是让你在下拉文档之前先做一次成本判断。

2.2 HTTPS 与 CORS 两列:前端直连能不能跑通

这两列是最容易被忽略、却最影响"能不能跑起来"的。

HTTPS 列标的是该接口是否支持加密传输。如果你的页面本身跑在 HTTPS 下,去请求一个 HTTP 接口,浏览器会直接拦截(混合内容策略),控制台报错,数据一个都拿不到。这在部署上线阶段特别容易翻车——本地http://localhost调试一切正常,传到线上一换 HTTPS 域名,全部请求被拦。

CORS 列标的是接口是否返回允许跨域的头。这一列决定你能不能从浏览器页面里直接发起请求。如果 CORS 标的是NoUnknown,你在浏览器里 fetch 它会收到跨域错误,但在 Postman、curl、或者你自己的后端服务器里调用完全正常。原因在于浏览器的同源策略是浏览器单方面的限制,不是接口的限制。很多新手看到 Postman 通了就以为没问题,一搬到前端就傻眼。

常见取值对你的直接影响
AuthNo / apiKey / OAuth决定要不要注册、要不要后端代理
HTTPSYes / No决定 HTTPS 页面能否直接调用
CORSYes / No / Unknown决定浏览器能否直连,Unknown 要实测

注意:CORS 标Unknown不等于不能用,只表示维护者没验证。正确的做法是自己写个最小请求实测一遍,再决定要不要走后端代理。

2.3 描述列的信息密度与隐藏线索

描述列一般是一句短语,比如"获取实时天气数据""随机生成用户信息"。它短,但里面藏着线索。看到"实时""流式""历史数据"这类词,要意识到背后可能是不同的限流策略和成本结构。看到"随机""示例""测试"这类词,通常意味着数据是生成的、不能用于生产。看到某接口描述里强调"无需注册""无限调用",反而要警惕——这种通常活不长,或者某天会突然加限制。

我的习惯是:描述列先做粗筛,把明显不符合场景的划掉;然后对留下的候选,逐个去点原始文档链接看配额条款。清单不列配额,配额必须自己确认,因为这是最容易踩雷的地方。

3. 按场景挑接口:从天气到机器学习的落地思路

光知道列的含义还不够,真正省时间的是按场景建立一套挑接口的流程。下面这几条是我反复用过、比较顺手的路子。

3.1 做侧项目演示时怎么快速选出能用的候选

假设你要做一个"城市天气卡片"小工具,目标是最快跑起来。筛选顺序应该是:

  1. 打开天气分类对应的条目文件,Ctrl+F 找关键词如currentforecast
  2. 先看 Auth 列,优先挑No的,跳过需要注册的。
  3. 再看 CORS 列,如果你是纯前端页面,必须挑Yes;如果打算写个 Node/Python 小后端转发,CORS 可以放宽。
  4. 最后看 HTTPS 是不是Yes,确保上线不会翻车。
  5. 挑出两到三个候选,各自写一个最小请求实测,谁能稳定返回就留下谁。

这套顺序的核心是先用零成本属性淘汰,再花时间去接那些一定会通过的。反过来做——先接一个看着功能最强的,结果发现要 OAuth 授权、要回调地址,半小时搭进去还没拿到一个字段——就很亏。

3.2 数据类接口的配额与限流现实

金融、天气、新闻这类接口是最热门的,也是限流最狠的。清单里很多"免费"接口的真实额度大概是:每分钟若干次、每天几百到几千次不等。做个人项目基本够用,但有几个隐藏点必须提前想清楚。

第一是配额的计算口径。有的按 IP 算,有的按密钥算,有的按账号算。同一台机器上多个服务共用同一个出口 IP,很容易互相挤占额度。第二是超限后的行为。有的返回 429 并带Retry-After头,有的直接返回空数据或错误页,有的会静默降级。你不处理这些情况,页面上就会出现莫名其妙的空白。第三是密钥的复用边界。不要拿同一个免费密钥同时跑多个项目,一旦其中某个项目超量,其他项目一起遭殃。

我在做需要定时拉数据的脚本时,会习惯性加一个简单的本地缓存层:把响应按 URL 缓存几分钟到几十分钟,命中缓存就不发请求。这一层代码不到二十行,但能把实际请求量砍掉一大半,既省额度又提速,还能在接口抖动时兜底返回上一次的数据。

import time import requests _cache = {} TTL = 600 # 缓存十分钟 def get_cached(url, headers=None): now = time.time() if url in _cache: data, ts = _cache[url] if now - ts < TTL: return data resp = requests.get(url, headers=headers, timeout=8) resp.raise_for_status() _cache[url] = (resp.json(), now) return _cache[url][0]

3.3 把多个接口拼成一个完整功能

单个免费接口通常能力有限,真正有意思的做法是组合。举个我自己做过的例子:想做一个"输入城市名,显示当前天气和一张相关图片"的小页面。天气来自一个无认证的天气接口,配图来自一个支持关键词搜索的图片接口,城市名转经纬度用地理编码接口。三个接口分别来自不同类型,各自都不需要注册,拼起来就是一个完整的小产品。

组合时有两点要注意。一是字段对齐,不同接口对同一个概念的字段名不一样,城市名可能是citynamelocation,转换时写个映射表比到处 if-else 干净。二是失败隔离,不要让一个接口挂了导致整页空白,天气拿到了就先渲染天气,配图失败就显示占位图。这个思路听着简单,但很多 Demo 项目就是因为一个次要接口超时而整体白屏。

清单里还有机器学习相关的分类,列了一批提供推理、文本处理、图像识别能力的服务。这类接口的特点是免费层通常有严格的调用次数上限,适合做原型验证和功能演示,不适合直接扛生产流量。挑的时候务必先看清楚免费额度和是否需要绑卡,很多"免费"是要求先绑定支付方式再给额度的。

4. 免费 API 的四个典型坑与排查链路

这部分是全文最想写的地方。清单能帮你选接口,但接入过程中出的问题它管不了。下面这几个坑我基本都亲身踩过,把排查过程完整写出来,方便你遇到时按图索骥。

4.1 密钥申请了,调用却一直 401

现象:注册完拿到密钥,照着文档拼请求,服务端回 401 未授权,或者 403 禁止访问。

排查链路:先别怀疑密钥错了,按这个顺序走。

  1. 确认密钥放在哪个位置。有的接口要求放在请求头Authorization: Bearer xxx,有的要求放在查询参数?api_key=xxx,有的要求自定义头如X-API-Key。位置放错是最常见原因,很多人一看文档示例是 curl 就直接抄 query 形式,但自己用的是头形式。
  2. 确认头名称的大小写和拼写。HTTP 头理论上不区分大小写,但有些服务端的中间件实现会区分,照着文档原样抄最稳。
  3. 确认密钥有没有前置或后置空格。从网页复制粘贴时经常带上不可见字符,尤其是从某些富文本页面复制。用编辑器显示空白字符检查一遍。
  4. 确认密钥是否已经生效。有些服务的密钥审核是异步的,刚注册可能处于未激活状态,等几分钟或看邮件确认。
  5. 确认请求里有没有多余的凭据冲突。比如同时带了Authorization头和Cookie,有些服务会以此判定异常。
# 先用 curl 排除前端和框架的干扰,直接看服务端返回 curl -i -H "Authorization: Bearer YOUR_KEY" \ "https://api.example.com/v1/weather?city=beijing"

-i会把响应头一起打出来,很多错误原因就写在头里或响应体里,比前端控制台里那句干巴巴的 401 有用得多。如果 curl 通了、浏览器不通,问题就转移到 CORS 上了,接着看下一条。

4.2 浏览器里跑不通,Postman 却一切正常

现象:在 Postman 里请求返回 200,写进前端页面就报跨域错误,控制台提示请求被拦截。

根因:浏览器出于安全考虑,对跨域请求做了限制。对于"简单请求",浏览器会直接发送,但会检查响应里有没有允许跨域的头;对于"非简单请求"(比如带自定义头、用 PUT/DELETE 方法、Content-Type 是application/json),浏览器会先发一个 OPTIONS 预检请求,服务端必须正确响应预检,真正的请求才会发出。

排查链路

  1. 打开浏览器开发者工具的 Network 面板,看有没有一条 OPTIONS 请求。如果有且返回异常,说明是预检没通过,服务端没配好跨域头。
  2. 看响应头里有没有Access-Control-Allow-Origin,它的值是不是*或者你的来源域名。没有这个头,浏览器就会拦。
  3. 如果你的请求带了自定义头(比如认证头),要确认响应里有Access-Control-Allow-Headers并且包含你用的那个头名。

解法:接口本身不支持跨域的话,前端怎么改都没用,只能加一层自己的后端做代理,把请求从服务端发出,再把结果转给前端。这一层代理写起来不复杂,但要注意别把自己的代理写成新的安全漏洞——不要做成任意 URL 转发,要限制白名单。

// 前端调用自己的代理,而不是直接打第三方接口 const res = await fetch(`/api/weather?city=${encodeURIComponent(city)}`); const data = await res.json();

注意:清单里 CORS 标Unknown的条目,务必实测一次再决定架构。很多项目推到上线前才发现跨域,返工成本比一开始就加代理高得多。

4.3 接口还活着,数据却已经变了

现象:请求返回 200,没有报错,但字段名变了、数据结构变了、或者数值明显不对。

根因:接口提供方在升级版本、调整字段、或者改变了数据口径,但没有通知你。免费接口尤其容易发生这种情况,因为提供方没有义务为免费用户保持向后兼容。

排查链路:先在请求里把完整响应原文打印出来,和文档里写的字段结构逐项对照,确认是字段缺失、重命名,还是类型变化。如果只是字段重命名,加一层本地映射就能兼容;如果结构大改,就得重新评估是否继续用这个接口。

我的应对方式是给关键接口写一层适配器,把第三方返回的数据归一化成自己项目内部的统一结构。这样第三方再怎么改字段,我只需要改适配器那一处,业务代码完全不受影响。这个习惯是从被坑了两次之后养成的,前期多花十分钟,后期省下来的时间不止一点。

4.4 接口悄悄失效了,页面却毫无提示

现象:接口已经彻底不可用,但你的页面没有任何报错,用户看到的是空白或者一直转圈。

根因:很多前端代码只处理了成功路径,没有处理失败和超时。请求失败时没有提示,用户一脸茫然。

排查链路:给所有外部请求加上超时时间和显式错误处理,超时就中断并展示兜底内容。有条件的话,给关键接口配一个定时健康检查,每天跑一次最小请求,失败就告警。这一步对个人项目来说可以很简单,一个 cron 加一个脚本就够。

典型表现核心解法
认证失败401 / 403核对密钥位置、头名称、空格、生效状态
跨域拦截浏览器报错,Postman 正常加后端代理或确认 CORS 属性
数据结构变更200 但字段异常加适配层归一化,隔离变更影响
静默失效页面空白无提示全链路超时与错误处理,加健康检查

5. 给清单加一条:贡献流程和字段规范

5.1 条目格式要求和自动化校验

这个项目能保持这么多年的字段一致性,靠的不是人自觉,是自动化校验。仓库里有一套脚本,在提交合并前会跑格式检查(表格列数、字段取值是否在允许集合内、排序是否正确)和链接检查(条目里的 URL 是否还能访问)。这意味着你随手改的那一行如果没有按规范写,CI 会直接标红,PR 就过不了。

想贡献一个条目,需要满足的基本要求大概是:条目加在正确的分类文件里,按字母顺序插入,改动严格遵守现有的表格列格式,描述简洁客观(不写营销词、不堆形容词),Auth、HTTPS、CORS 三列取值必须从约定集合里选,不能自创。这些看着琐碎,但正是它们让清单可以被机器校验、可以被长期维护。很多同类项目死在"格式全靠人工把关"上。

5.2 提交 PR 时最常被退回的原因

根据我观察和一些维护者的反馈,被退回的原因通常集中在几类:

  • 文件放错分类。比如把一个天气接口放到了地理分类,看起来差不多,但维护者会要求挪到对的文件里。
  • 排序位置不对。条目没有按字母顺序插进正确的位置,这个用 CI 能自动发现,但改起来烦。
  • 链接不可达。文档地址拼错、重定向到登录页、或者干脆 404,链接检查会拦下。
  • 描述里带了推广语气。比如写"业界最好的免费天气接口",这类描述会被要求改成中性的事实陈述。
  • 属性列填写与实测不符。最典型的是把实际需要密钥的接口标成No,或者把不支持跨域的标成Yes。这会让别人按你的标注选型后踩坑,是维护者比较在意的问题。

我自己的经验是,提 PR 之前先把改动在本地按现有条目的格式对齐,排列顺序用编辑器的排序功能处理一下,链接用 curl 逐个验证一遍,这样一次过的概率会高很多。说到底,向这类社区清单贡献,遵守格式规范本身就是对维护者最大的尊重。

6. 把公共清单变成自己的可用接口台账

6.1 从"收藏"到"台账"的差别

大多数人用这个清单的方式是收藏一下、需要时翻一翻。但清单是公共的、不针对你的场景,你要真正高效,得建立自己的台账。做法很简单:建一个表格,字段比公共清单更贴合你的需求——接口用途、当前状态、你自己的实测结果、免费额度、最近一次验证时间、备用方案。每用过一个接口就往里填一行。

这个台账的价值在于沉淀你自己的经验。公共清单告诉你 CORS 标的是Yes,但你可能实测发现它偶尔抽风;公共清单不知道某个接口在你所在网络的延迟,但你的台账可以记。用久了,这份台账就是这个清单对你的私有增强版。

6.2 健康检查与降级方案

外部接口一定会出问题,区别只是早晚。想让项目不因为某个免费接口挂掉而整体不可用,至少要做两件事。一是准备备用方案,同一类数据尽量记下两到三个候选,主接口失败时切到备用。免费接口的淘汰率高,单一依赖是风险。二是关键路径做降级,接口拿不到数据时展示缓存、占位内容或友好提示,不要让用户面对一个白屏。

健康检查不用做得很重。一个每天跑一次的脚本,对台账里每个接口发一次最小请求,记录状态码和响应时间,失败就发个通知给自己,这就够支撑个人和小团队规模的项目了。真正麻烦的从来不是写这个脚本,而是记得去做——我就是因为偷懒没做,某次上线后才发现主接口已经挂了一个星期。

# 简化的健康检查骨架 targets = [ {"name": "weather", "url": "https://api.example.com/current?city=beijing"}, {"name": "geo", "url": "https://api.example.com/geo?q=beijing"}, ] for t in targets: try: r = requests.get(t["url"], timeout=8) print(t["name"], r.status_code, round(r.elapsed.total_seconds(), 2)) except Exception as e: print(t["name"], "FAILED", e)

我个人的体会是,public-apis 这类清单最大的意义不是给你一堆现成接口,而是帮你把"接口选型"这件事从凭印象搜索,变成一个可以结构化比较、可以快速验证、可以持续沉淀的流程。用得越久你越会发现,真正稀缺的从来不是"有多少个免费接口",而是"哪些接口现在真的能用、以及当它不能用时你怎么办"。把清单当起点,把自己实测过的台账当终点,中间配上代理层、缓存层和健康检查这几个便宜又管用的小零件,你的侧项目就不会再被一个突然下线的接口卡住。有个小技巧我一直用:每次验证完一个接口,顺手在描述后面记一句"实测可用,返回结构是 xxx,注意字段 yyy 可能为空",半年后再回来看,这句话能帮你省下重新摸索的半小时。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询