做开发这几年,我越来越觉得手边应该备几个“小工具API”——不是那种大而全的云服务,而是够简单、够便宜的轻量接口。今天这篇就聊两类我几乎天天用到的免费API:一类负责文本读写,帮你把一段话或一个JSON对象临时扔到云端,随时取回;另一类负责在线通知,让程序主动把消息推送到手机或电脑上。这个主题看着小,但用好了能省下不少自建服务的时间和维护成本,特别适合个人开发者、运维和自动化办公党。
先举两个场景。早上跑一个爬虫脚本,抓完了不想看终端日志,只想在微信里收到一句“今日数据已更新,共 120 条”。或者你正在调试一个API接口,需要往远程存一个临时变量,下次启动程序再读出来,又懒得为一句话搭数据库。这两种需求,恰恰就是文本读写API和在线通知API最擅长的领域。我实测过不下十种号称免费的服务,踩了不少坑,今天不会一个一个罗列,只挑真正稳定好用的讲。
1. 这个免费API能帮你省下什么
1.1 先分清两种API:远程文本存储和消息推送
很多朋友刚开始看到“文本读写API”会一头雾水,这不就是个HTTP接口吗?对,就是个HTTP接口。文本读写API的核心能力,是让你通过HTTP方法(GET/POST/PUT/DELETE)把一段内容保存到远端服务器,之后再用另一个请求把它取回来。它本质上是一个键值存储,只是把键和值都暴露成了URL的一部分。举个例子,getpantry.cloud 允许你把一个JSON对象存进某个Basket(可以理解成一个独立的存储格子),然后用URL定位到它。读取数据就像打开一个网页一样简单。
在线通知API则是另一码事。它要解决的是“程序如何主动找到你”的问题。典型的做法是,你在手机上安装一个客户端并订阅某个“主题”(topic),然后程序通过HTTP请求向服务端发出一条消息,服务端再把消息推送到所有订阅了该主题的终端。整个过程是异步的,你的程序不需要和手机保持长连接,只需要几行代码就能触发一次推送。
两者的关系很微妙:文本读写API解决数据持久化,通知API解决事件触达。你可以在业务里把它们组合起来,比如先用文本读写API存状态,再用通知API通知结果。这也是我在这篇文章里把它们放在一起讲的原因——它们单独用都很有价值,合起来能玩出的花样更多。
1.2 适合谁用,能解决哪些实际问题
先泼一盆冷水:如果你的业务已经是生产级、数据要严格保密,那我不建议依赖这类免费API。但是,对个人开发者、学生、运维工程师、RPA玩家来说,它们简直是效率神器。我总结过几个最典型的落地场景:
- 定时任务告警:备份失败、爬虫异常、服务器CPU过高,发一条通知给自己。
- 临时状态存储:脚本重启后需要恢复上次处理到哪一页、哪一行,又没有数据库权限,直接存到文本读写API。
- 轻量消息中转:多台服务器之间需要共享一段小数据,或者把一台机器上的结果传到另一台。
- 自动化办公:跑完Excel处理脚本,把结果摘要推送到微信。
这些场景的共同点是:需求简单、数据量小、不需要高可用。用免费API不会比自建服务差太多,成本却接近零。尤其是“通知到手机”这件事,自己从零实现一套推送通道需要处理证书、长连接、离线消息,想想就头大。用现成的API,一个小时就能跑通。
2. 免费方案怎么选:文本读写与在线通知的工具对比
2.1 文本读写:getpantry.cloud 和 JSONBin 实测体验
我最早用的是 JSONBin,它提供免费的Bin存储,可以直接把JSON数据放上去。它的优点是界面整洁,支持Collection(集合)管理,并且有免费的API前缀。不过免费版创建私有Bin需要登录,而且Bin数量有限。后来一个朋友推荐了 getpantry.cloud,我才发现它更适合“临时丢点东西”的场景。
getpantry.cloud 的使用方式很有意思:不需要繁琐的注册流程,你只要在主页输入一个名字,就能获得一个 Pantry ID。每个Pantry下面可以建多个Basket,每个Basket就是一个独立的JSON存储空间。官方给的免费额度虽然写着有限,但个人使用完全够了。API格式也很直观,比如读取一个Basket就是向/apiv1/pantry/{pantryId}/basket/{basketName}发一个GET请求。
我把两个服务放在一起用了一段时间,结论是:如果你的数据是一个结构化的JSON数组,选 getpantry.cloud 会更顺手;如果你需要更复杂的集合管理、或者想要一个更像数据库的界面,就选 JSONBin。另外,JSONBin 的免费档有请求次数限制,getpantry.cloud 目前看起来更宽松。两家都不建议存大文件,毕竟它们的定位是“小纸条”,不是“云盘”。
2.2 在线通知:ntfy.sh、Server酱、PushPlus 谁更顺手
聊完文本读写,再看在线通知。这个领域国内国外都有好选择,我今天只提三个:ntfy.sh、Server酱、PushPlus。
ntfy.sh 是我目前的主力。它开源、免费,而且不需要注册账号就能用。它的工作方式是“主题订阅”:你在任意一个终端打开https://ntfy.sh/你的topic名,或者用手机App订阅这个topic,然后任何人都能通过向这个URL POST一条消息来给你推送。正因为不需要注册,使用门槛极低,我写脚本时最常用它。有一点要注意:公开topic任何人都能订阅,所以别在公共topic里发敏感内容。如果你在意隐私,可以加上访问令牌,把topic变成私有的。
Server酱和PushPlus都是国内常见的微信推送方案。它们的原理相似:你通过微信公众号或企业微信接收消息,服务端提供一个SendKey,调用API时把这个Key放到URL里。Server酱的免费版每天能发一定数量的消息,PushPlus 每天也有免费额度。对于国内用户来说,微信接收消息的体验确实最亲切。缺点是它们对请求频率限制得比较死,而且依赖第三方服务器,偶尔会有延迟。
| 服务 | 推送渠道 | 免费额度 | 是否需要注册 | 备注 |
|---|---|---|---|---|
| ntfy.sh | App/Web/自建 | 公开topic无硬性限制 | 公开topic不需要 | 开源,可自建 |
| Server酱 | 微信 | 每日有数量限制 | 需要 | 国内接入方便 |
| PushPlus | 微信/企微 | 每日有数量限制 | 需要 | 公众号推送 |
怎么选?我给一个简单标准:追求“手边最方便、跨平台、开源可控”,选ntfy.sh;追求“推送直接进微信、不想装任何App”,选Server酱或PushPlus。我目前两个都在用,日常自动化跑批用ntfy.sh,重要告警再走一遍PushPlus,双保险。
2.3 我为什么不直接自建一个消息队列
可能有朋友会说,既然ntfy.sh可以自建,为什么不直接自己搭一个?这话没毛病,但分场景。自建一个消息推送服务,除了要跑一个常驻进程,还得考虑域名、证书、公网访问、数据持久化。如果你手头有一台闲置服务器,那当然可以折腾;但如果你和我一样只是需要“小纸条级”的通知,自建的成本明显高于收益。
同样的道理也适用于文本读写API。很多人想用Redis、MongoDB或者云数据库来实现,但为了存一个时有时无的状态字段,去维护一个数据库实例,属于典型的杀鸡用牛刀。免费API天然可以承受个人项目的低频率,而且不用你操心运维。我并不是劝大家永远不用自建方案,而是建议在需求明确之前,先用免费API把业务逻辑跑通。等到数据量上去了、稳定性要求高了,再平滑迁移到专业服务也不迟。
3. 从零接入:完整调用示例与代码实现
3.1 用 curl 发一条通知,1分钟接入 ntfy.sh
在接着写代码之前,我想先说明一点:这些免费API的接入过程都很相似,核心无非是“拼URL、发请求、处理响应”。我习惯先用 curl 做一次冒烟测试,确认通了再写正式代码。
ntfy.sh 的发送最简单。直接在终端执行:
curl -d "你好,ntfy" ntfy.sh/blog-demo如果一切正常,你会收到HTTP 200和一段JSON响应,同时所有打开这个主题的客户端都会收到一条消息。想加标题也很简单:
curl -H "Title: 任务完成" -d "爬虫更新了120条数据" ntfy.sh/blog-demo如果你在Python里调用,就是在requests库中指定一个POST请求:
import requests requests.post( "https://ntfy.sh/blog-demo", data="爬虫更新了120条数据".encode("utf-8"), headers={"Title": "任务完成"} )注意data字段要编码为UTF-8,否则中文可能显示成乱码。我用这个接口写过很多次自动化告警,实测延迟在1秒以内,个人项目完全够用。
3.2 用 Python 读写远程文本存储 getpantry.cloud
getpantry.cloud 的API结构稍微有点绕,但理解了就不难。我以Python为例,演示完整的“写入、读取、更新”流程。
首先你得有一个Pantry ID。打开getpantry.cloud官网,输入一个名字,比如my-pantry,点击创建,就会拿到一串ID。然后你可以直接在代码里用这个ID拼URL:
import requests PANTRY_ID = "你的pantry_id" BASKET_NAME = "my-note" url = f"https://getpantry.cloud/apiv1/pantry/{PANTRY_ID}/basket/{BASKET_NAME}" # 写入一个JSON对象 data = { "title": "我的临时笔记", "content": "把这行字存到云端" } resp = requests.put(url, json=data) print(resp.status_code, resp.json()) # 读取这个对象 resp = requests.get(url) print(resp.json())这里有个细节:getpantry.cloud 对HTTP动词有明确要求。写入和更新使用PUT,而不是POST。PUT会把整个Basket的内容替换成你新提交的JSON,POST则通常用来创建Basket本身。我第一次用的时候误把更新写成了POST,结果一直报404,花了不少时间排查。
如果你只是想存一段纯文本,而不是一个JSON对象,最简单的方式是把它包到一个JSON字段里:
content = "今天天气不错,适合写代码" requests.put(url, json={"text": content})实际用的时候,我还会在读取数据后加一个异常处理,因为免费服务偶尔会抽风。
3.3 串起来:一个定时任务+通知的完整脚本
下面把两个API组合起来,做一个完整的实战示例。假设我想写一个监控本地磁盘空间的脚本:把每次检查的结果写入getpantry.cloud存档,如果剩余空间低于20%,就用ntfy.sh发一条告警通知。脚本逻辑很简单:
import os import time import requests # 配置 PANTRY_ID = "你的pantry_id" BASKET_NAME = "disk-check" NTFY_TOPIC = "blog-demo" def get_disk_usage(): st = os.statvfs("/") total = st.f_blocks * st.f_frsize free = st.f_bavail * st.f_frsize used_percent = (1 - free / total) * 100 return round(used_percent, 2) def save_result(usage, alert): url = f"https://getpantry.cloud/apiv1/pantry/{PANTRY_ID}/basket/{BASKET_NAME}" payload = {"usage": usage, "alert": alert, "time": time.time()} try: requests.put(url, json=payload, timeout=10) except Exception as e: print("保存失败:", e) def send_notify(message): try: requests.post( f"https://ntfy.sh/{NTFY_TOPIC}", data=message.encode("utf-8"), headers={"Title": "磁盘告警"}, timeout=10 ) except Exception as e: print("通知失败:", e) if __name__ == "__main__": usage = get_disk_usage() alert = usage > 80 save_result(usage, alert) if alert: send_notify(f"当前使用率 {usage}%")这段代码里用了timeout参数,很重要。免费服务网络抖动或故障时,如果请求一直挂着,脚本会被拖死。我还会用系统cron或计划任务定时执行这个脚本,跑完就完事。通过这种方式,我几乎不关心“有没有一台服务器在跑服务”,只需要等手机弹通知就行。
4. 调用API最容易踩的坑和排查实录
4.1 401 Unauthorized:API Key没有对号入座
我翻了下最近搜索记录,发现大家问得最多的是401错误,原文大概是unexpected status 401 unauthorized: incorrect api key provided。这个错太典型了,几乎每个接API的人都遇过。它的含义很直白:你提交的API Key不对,或者服务端根本不认识这个Key。
我总结过三类最常见的根因:第一,Key复制多了空格或者换行符,这在终端里粘贴时特别常见;第二,请求头写错了位置,有些服务要求Authorization: Bearer 你的key,有些要求自定义头如X-Api-Key,混用就会401;第三,Key本身过期,或者是把A服务的Key放到B服务上。放到我们今天聊的主题上,ntfy.sh 的公开topic其实不需要API Key,但如果你启用了私有topic的访问令牌,就需要把它放在请求头里;getpantry.cloud 则是把Pantry ID当作路径的一部分,并不需要认证头。搞清楚每个服务的认证方式,是排错的第一步。
排查时可以这样做:先用print(env_var)确认Key是否为空;再用一个最简单的curl请求测试;最后仔细看官方文档里的认证样例。不要嫌麻烦,90%的401就是这些低级错误。
4.2 400 Bad Request:数据格式和长度问题
另一个高频报错是400。我之前看到一条很典型的AI服务报错:400 this model's maximum context length is 1048576 tokens。这虽然不是文本读写API的报错,但背后的排查思路是一样的:请求体超过了服务端限制,或者请求格式不对。
对文本存储API来说,最常碰到的情况是没有设置Content-Type: application/json。requests库在传json=参数时会自动设置,但如果你用的是data=传字符串,就很容易因为格式不对而收到400。另外,免费服务的存储空间有限,如果你试图往一个Basket里塞很大的文本,也可能被拒绝。我遇到过几次,处理方法是拆分数据或压缩内容,再写进去。
在通知API里,400还可能是标题字段或消息体太大。例如Server酱对desp参数有长度限制,ntfy.sh 的单条消息大小也有限制。解决方式很简单:先看报错信息里有没有提示长度上限,根据上限截断文本再发送。
4.3 429 Too Many Requests:免费额度怎么省着用
免费API最怕的不是报错,而是限流。有些服务会在单位时间内限制你的请求次数,比如Server酱免费版每天有发送条数限制,PushPlus也是类似。当请求过于频繁时,服务端会返回429 Too Many Requests。这个问题没有一劳永逸的解法,只能从用法上改变。
我的习惯是加一个简易的重试机制,但重试不是一直死磕,而是用指数退避:第一次失败等1秒,第二次等2秒,第三次等4秒。代码很简单:
import time import requests for attempt in range(3): try: resp = requests.post(url, data=msg, timeout=10) if resp.status_code == 429: time.sleep(2 ** attempt) continue resp.raise_for_status() break except requests.RequestException as e: print(f"第{attempt+1}次失败: {e}") time.sleep(1)同时,把多条通知合并成一条发送,也是节省免费额度的好办法。比如定时任务一天跑好几次,没必要每次成功都推送,只在失败或汇总结果时推一次即可。别把免费API当成生产级高并发工具,它不是。
4.4 数据安全和Key保护,免费工具更要注意
免费工具最容易让人放松警惕。有朋友图省事,把API Key直接写在代码里,然后推到公开仓库,结果被他人盗用。我见过好几个因为Key泄露被刷爆额度的例子。保护Key这件事,成本极低:用环境变量存,配置时写到.env文件,并在代码里通过os.getenv读取。对所有需要认证的API都适用。
还有一点值得提醒:不要在公开topic里发隐私内容。ntfy.sh的公开topic等于一个公开广场,任何知道topic名的人都能订阅并接收你的消息。如果你要发服务器IP、账号密码这类敏感信息,一定要使用私有topic或加访问令牌。文本读写API也是一样,getpantry.cloud 的Basket虽然不像公开广场那么显眼,但只要你知道了Pantry ID就能读取,所以不要存Token、Cookie等敏感数据。
退一步讲,免费服务的存储和传输通常只提供基础加密,适合“临时”和“非敏感”数据。如果你真的有敏感数据,请务必自建服务或选择有明确SLA的付费产品。
5. 进阶玩法和我的习惯
5.1 用 GitHub Actions 做免费定时推送
除了在本地跑脚本,你还可以用GitHub Actions免费执行定时任务,然后调用通知API。这样你不需要自己开一台服务器,也能每天定时收到推送。思路很简单:在仓库里放一个.github/workflows/daily.yml,配置cron触发,再在workflow中运行Python脚本。
name: daily-notify on: schedule: - cron: '0 8 * * *' jobs: notify: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: '3.11' - run: pip install requests - run: python notify.py env: NTFY_TOPIC: ${{ secrets.NTFY_TOPIC }}这个方案很适合做一些每日新闻、天气、股票的定时推送。唯一要提醒的是,GitHub Actions 的cron是基于UTC的,记得换算成北京时间,别到时候半夜被推送吵醒。
5.2 我坚持的这些使用习惯
最后分享几个我长期坚持的小习惯,也算是这篇博客的收尾。第一,能不发通知就不发通知,减少噪音才能让重要消息真正引起注意;第二,所有外呼请求都加上超时和重试,避免脚本被卡住;第三,定期清理文本存储的旧数据,不要放任Basket无限膨胀,否则免费额度很快会被占满;第四,也是最重要的,免费工具不是万能药,要时刻知道它什么时候该被替换。
我记得有一次,因为贪方便,在一个生产脚本里直接用了免费API,结果服务临时维护,告警全丢。那次之后,我才认真做了双通道通知和自我监控。工具本身没有错,但你要有一颗“随时准备出问题”的心。免费API适合作为个人效率工具,它让很多小需求变得无比轻巧,也让我更愿意把时间花在真正重要的代码逻辑上。希望这篇关于“文本读写/在线通知API”的实战记录,能帮你少走一些我走过的弯路。