接手30个站后每个都要往三个API推链接,写了段Nginx反向代理把百度IndexNow搜狗合成一个入口以后10分钟全搞定
年初接手了一个跑路的SEO外包留下的摊子——30个企业站,内容都还在,但日常维护全断了。最要命的是收录推送:每个站每天新发的内容,需要分别推到百度站长API、IndexNow(覆盖Bing和Yandex)、搜狗站长API,三个平台的接口地址不同、认证方式不同、请求格式不同。30个站×3个API=90次切换操作,光切换token和URL就得花半小时。第一次手动搞完,手都麻了。
后来想了个办法:在服务器上搭一个Nginx反向代理,把三个外部API统一收口到一个内部地址。所有站点只需要往一个URL发请求,Nginx根据请求头里的站点标识自动匹配对应的API token、拼接正确的请求体、转发到对应的搜索引擎接口。写配置花了半小时,之后每天90次操作变成了一条curl命令。这篇文章把这个方案的思路和配置拆开讲,从最简的Nginx反代到上量后的API网关,适合手里有5个以上站、每天需要往多个API推送内容的人。
API批量转发的本质:把"N个站点×M个API"变成"1个入口"
| 1 | 统一入口:所有站点只发一个URL,Nginx根据域名或自定义Header自动路由到对应API |
| 2 | 自动鉴权:每个站点的API token存在Nginx变量里,转发时自动注入请求头,不需要手动填 |
| 3 | 格式转换:不同API的请求体格式不一样,Nginx+lua脚本在转发前自动重组JSON结构 |
一、什么情况下你需要API批量转发,而不是逐站手工调
先理清一个概念:API批量转发不是"批量调用API",而是"让多个站点通过一个统一的中间层去调多个不同的外部API"。两者的区别在于——批量调用只是把调用动作重复N次,而批量转发解决的是调用之前就存在的混乱问题:token管理分散、接口地址不统一、请求格式各异、调用结果需要汇总。

场景一:站群推送收录
20个站点,每天新内容需要推送到百度站长API、Bing IndexNow、搜狗推送,三个平台的token、域名、格式全不一样
场景二:多后端微服务
一个主站前端调了5个后端微服务API(用户、订单、商品、支付、物流),各自部署在不同端口甚至不同服务器
场景三:第三方API聚合
网站同时接入了AI生成API、翻译API、图片压缩API、邮件发送API,每次调用都要切换不同的认证方式和域名
场景四:多站点运维自动化
批量重启PHP、批量清理缓存、批量更新插件,每个站调用面板API的token和地址都不同
如果你只有2-3个站、只调1-2个API,逐站手工调完全没问题。但一旦站点数×API数超过10,手工操作的出错率和时间成本就会指数级上升。尤其是token管理——30个站的百度API token散落在30个配置文件里,有一个过期了没发现,那个站就停推了好几天。
二、方案一:Nginx反向代理,最轻量的统一转发入口
如果你的服务器上已经跑了Nginx(大部分Linux服务器都装了),那不需要额外装任何工具,直接用Nginx的proxy_pass就能搭一个API转发中间层。核心思路:所有站点把请求发到 http://你的服务器/api-push,Nginx根据请求路径自动匹配对应的API token,拼接正确的请求体,转发到目标API。
下面是完整的Nginx配置。每个站点+API组合用一个location块,里面通过proxy_set_header注入该站点的认证信息,然后proxy_pass指向对应的搜索引擎接口:
# /etc/nginx/conf.d/api-gateway.conf# API批量转发中间层server {listen 8080;server_name api-gateway.local;# ===== 百度站长API - 站点1 =====location /push/baidu/site1 {proxy_pass http://data.zz.baidu.com/urls?site=www.site1.com&token=站点1token;proxy_set_header Content-Type "text/plain";proxy_set_header Host data.zz.baidu.com;}# ===== 百度站长API - 站点2 =====location /push/baidu/site2 {proxy_pass http://data.zz.baidu.com/urls?site=www.site2.com&token=站点2token;proxy_set_header Content-Type "text/plain";proxy_set_header Host data.zz.baidu.com;}# ===== IndexNow - 站点1 =====location /push/indexnow/site1 {proxy_pass https://api.indexnow.org/IndexNow;proxy_set_header Content-Type "application/json";proxy_set_header Host api.indexnow.org;}# ===== 搜狗站长API - 站点1 =====location /push/sogou/site1 {proxy_pass https://api.zhanzhang.sogou.com/push;proxy_set_header Content-Type "application/json";proxy_set_header Host api.zhanzhang.sogou.com;}}使用方式:站点侧只需要发一条请求
站点1要推送URL到百度,直接curl:curl -X POST http://api-gateway.local:8080/push/baidu/site1 -d 'http://www.site1.com/new-page.html'
Nginx自动拼接token和域名参数,转发到百度接口。所有token集中管理在Nginx配置里,站点侧不需要知道任何token。
Nginx方案的优势
• 零额外依赖,服务器已有Nginx就能用
• 配置直观,一个location一个站点
• 性能极高,C语言实现无额外开销
• 天然支持负载均衡(upstream)
Nginx方案的短板
• 站点多了配置文件会膨胀
• 改配置要reload,不能热更新
• 请求体格式转换需额外lua脚本
• 没有可视化面板,排查靠grep日志
适用场景:5-30个站点,调3-5个外部API,有基本的Nginx配置能力。配置写一次,之后新增站点复制粘贴改三行就行。30个站点以下用这个方案最合适,简单可控。
三、方案二:Nginx + OpenResty Lua脚本,解决请求体格式转换
上面的纯Nginx方案有个问题:它只能原样转发请求体,但不同搜索引擎API要求的JSON格式不一样。百度站长API接受纯文本URL列表(一行一个URL),IndexNow要求 {"host":"xxx","key":"xxx","urlList":[...]},搜狗要求 {"data":{"urls":[...],"token":"xxx"}}。如果你希望站点侧统一用一种格式发请求,由转发层自动转换成各个API需要的格式,就需要在Nginx里嵌入Lua脚本来做这件事。
OpenResty是Nginx的增强版,内置了LuaJIT引擎,可以在Nginx的请求处理流程中执行Lua脚本,实现请求体的读取、解析、重组:
# 站点统一用JSON格式发请求,Nginx自动转成各平台格式location /push/baidu/site1 {access_by_lua_block {ngx.req.read_body()local body = ngx.req.get_body_data()local cjson = require "cjson"local data = cjson.decode(body)-- 站点侧发来:{"urls":["http://...","http://..."]}-- 百度要求:纯文本,一行一个URLngx.req.set_body_data(table.concat(data.urls, "\n"))ngx.req.set_header("Content-Type", "text/plain")}proxy_pass http://data.zz.baidu.com/urls?site=www.site1.com&token=站点1token;}location /push/indexnow/site1 {access_by_lua_block {ngx.req.read_body()local body = ngx.req.get_body_data()local cjson = require "cjson"local data = cjson.decode(body)-- 转换成IndexNow要求的格式local idx_body = cjson.encode({host = "www.site1.com",key = "站点1的IndexNow密钥",keyLocation = "https://www.site1.com/indexnow-key.txt",urlList = data.urls})ngx.req.set_body_data(idx_body)}proxy_pass https://api.indexnow.org/IndexNow;}Lua脚本需要注意的两个问题
请求体大小限制:Nginx默认client_body_buffer_size是8K/16K,如果一次性推送几百个URL,需在server块设大:client_body_buffer_size 512k;
Lua性能:每次请求解析JSON有几毫秒开销,但相对于API调用的网络延迟(通常100-500ms)可忽略不计。50个站点以内完全不用操心。
适用场景:站点数量30-100个,需要做请求体格式转换或请求头动态注入,有基本的Lua读写能力(不需要精通,改JSON字段名和结构即可)。

四、方案三:APISIX / Kong 开源API网关,站点上百以后的正规军
当站点数量超过100个、API调用频率达到每分钟几百次、而且不只是推送收录还涉及支付回调、订单同步等业务API时,Nginx的手工配置方式就撑不住了。这时候需要专业的API网关来接管。
市面上主流的开源API网关有三个:Apache APISIX、Kong、Traefik。它们本质上是"超级增强版Nginx",在反向代理的基础上加了动态路由、插件系统、可视化管理面板、限流熔断、监控告警等能力。
| 对比维度 | Apache APISIX | Kong | Traefik |
|---|---|---|---|
| 开发语言 | Lua(基于Nginx+LuaJIT) | Lua(基于Nginx+LuaJIT) | Go |
| 配置热更新 | 支持,亚毫秒级生效 | 部分支持,通过DB轮询 | 支持,Provider监听机制 |
| 内置插件数 | 100+ | 60+ | 约30个中间件 |
| 管理面板 | 内置Dashboard | Kong Manager(企业版) | 内置控制台 |
| 外部依赖 | 需部署etcd集群 | 需PostgreSQL/Cassandra | 无外部依赖 |
| 适合规模 | 100-1000+站点 | 100-1000+站点 | 中小规模,Docker/K8s环境 |
| 运维复杂度 | 中(需维护etcd) | 中高(需维护数据库) | 低(容器化最友好) |
对于站群场景来说,APISIX和Kong最核心的能力不是转发(Nginx也能做),而是插件体系。以收录推送为例,可以挂载以下插件链:
API网关挂载的典型插件链
key-auth插件 → 校验请求是否携带了合法的站点API Key,拦截非法请求
limit-count插件 → 限制每个站点每天的推送次数(百度API有每日配额,超了白推)
proxy-rewrite插件 → 把站点侧统一格式的请求体重写成百度/IndexNow/搜狗各自要求的格式
prometheus插件 → 输出调用次数、成功率、延迟等监控指标,异常自动告警
file-logger插件 → 每次推送的结果写日志,方便排查"为什么这个站上周推送了但没收录"
适用场景:100个站点以上,API调用频繁且涉及业务逻辑(不仅仅是收录推送),有专人维护基础设施。APISIX和Kong的上手成本比Nginx高不少——需要部署etcd或数据库、学习路由和插件概念——但一旦搭好,后续新增一个站点的API转发只需要在Dashboard上点几下,不用改配置文件。
五、三种方案怎么选,看站点数量和你的技术栈
| 选择条件 | 推荐方案 | 原因 |
|---|---|---|
| 5-30个站,只推收录 | Nginx反向代理 | 零依赖,半小时配好,够用 |
| 30-100个站,需要格式转换 | Nginx + OpenResty Lua | 在Nginx基础上加脚本,不引入新系统 |
| 100+站,多业务API | APISIX或Kong | 可视化面板+热更新+插件生态 |
| Docker/K8s环境 | Traefik | 原生容器发现,配置最简 |
| 只有收录推送需求 | 写个Shell脚本就够了 | 不需要搭网关,一个for循环搞定 |
很多时候不需要一步到位上API网关。先看自己的实际需求:如果只是每天往百度推几十条URL,一个20行的Shell脚本比搭一套APISIX省心得多。但如果你已经有5个以上的站、接了3个以上的外部API、而且不止一个人在使用这些API,那Nginx反代的投资回报率就很高了——写一次配置,用一年。
六、转发层搭好之后,别忘了做三件事
API调用日志集中存储
每个站每次推送的结果(成功/失败/返回码/剩余配额)都要记下来。Nginx用access_log单独输出一个日志文件,每天定时汇总。不记日志的话,三个月后某个站一直没收录,你完全不知道是API推送失败还是百度那边的问题。
配额监控和预警
百度站长API每天有推送配额限制,IndexNow虽然没有硬限制但频率过高也可能被限速。转发层加上limit-count计数,配额用完前自动告警,避免白推了好几天才发现。
Token过期自动检测
百度站长平台的token有时会因账号安全策略变更而失效。加一个定时任务,每天早上自动用每个站点的token发一条测试请求,如果返回token失效错误码,立即通知去更新。
七、当API转发变成常态,系统化管理比手写脚本更可持续
前面讲的三种方案都是技术层面的"转发",它们解决的是请求怎么到达目标API的问题。但站群运营中真正耗时间的,往往不是"调API"这个动作本身,而是调之前要准备好URL列表、调之后要检查推送结果、发现某个站连续几天推送成功率下降后要去排查原因。这些操作串起来,就形成了一个需要持续维护的工作流。
如果你的站点数量已经多到需要搭API转发层了,大概率也会需要一套能把内容产出→URL生成→API推送→收录结果监控串起来的系统。比如UC建站系统的做法:WP底层负责内容管理和HTML直出,AI管理层负责差异化内容生成和发布策略,多站看板统一监控每个站的索引量、收录率、排名变化。API推送被整合进了"发布→自动推送→监控收录"的闭环里——文章写完发布的同时,URL自动进入推送队列,转发层按站点匹配token和格式、分发给百度IndexNow搜狗,推送结果回写到看板。手工模式下你需要做的"生成URL→切token→改格式→发请求→查结果"五个步骤,系统化之后变成一步:文章写完点发布。
手工流程 vs 系统化流程,30个站每天推送的效率差
手工模式:整理URL列表(15分钟)→ 逐站切换token调百度API(20分钟)→ 切换格式调IndexNow(15分钟)→ 调搜狗(15分钟)→ 逐个检查推送结果(15分钟)。每天约80分钟。
Nginx转发+脚本:整理URL列表(15分钟)→ 一条脚本批量curl统一入口(2分钟)→ 看日志检查失败项(5分钟)。每天约22分钟。
系统化闭环:文章发布即自动推送,看板统一监控异常,每天只需花5分钟扫一眼看板。时间投入趋近于零。
差距不在技术难度上,在"有没有把重复劳动串成自动化流程"的意识上。
说穿了,API批量转发这件事的技术门槛其实很低——Nginx配置、Lua脚本、API网关,都是现成的轮子。真正拉开效率差距的不是技术选型,而是你有没有意识到"每次手工切换token和URL格式"这件事本身就不应该存在。2-3个站手工搞没问题,但一旦站点数量上了两位数,花半小时写个Nginx反代配置,之后一年每天省下一小时,这笔账怎么算都值。
