Node给AI接口做SSE代理与鉴权

先把结论甩前面:别让浏览器直连大模型流式接口。中间架一层 Node 做 SSE 反向代理,顺手把鉴权和限流挡在这层,前端只管 fetch 自己后端,密钥不落地、谁能调你说了算。我上周刚因为没这层,被一个实习生用 devtools 把 key 抠出来,半天烧了三十多块 token,血的教训。

事情起因是这样。我们有个内部的写作辅助小工具,前端直接拿着模型的 stream endpoint 在跑。能用,但有两个雷:一是 key 写在前端,F12 一翻就有;二是没人拦着,谁手快谁多调,某天账单突然鼓了一截才发现。于是我把流量全收回 Node 这层。核心就是把上游的 text/event-stream 原样往下透,中间插一道鉴权和一个最朴素的令牌桶。代码大概长这样,没多少行:

javascript 复制代码
const express = require('express')
const app = express()

// 极简内存令牌桶,够内部用了
const buckets = new Map()
function rateLimit(uid, cap = 20, refill = 1) {
  const now = Date.now()
  const b = buckets.get(uid) || { tokens: cap, ts: now }
  b.tokens = Math.min(cap, b.tokens + (now - b.ts) / 1000 * refill)
  b.ts = now
  buckets.set(uid, b)
  if (b.tokens < 1) return false
  b.tokens -= 1
  return true
}

app.post('/api/chat', async (req, res) => {
  const uid = verifyToken(req.headers.authorization) // 自己的鉴权,过不了直接 401
  if (!uid) return res.status(401).end()
  if (!rateLimit(uid)) return res.status(429).end('慢点儿')

  const upstream = await fetch(UPSTREAM_URL, {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.MODEL_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(req.body),
  })

  // SSE 透传的关键:头要对,别被 nginx/代理缓冲住
  res.setHeader('Content-Type', 'text/event-stream')
  res.setHeader('Cache-Control', 'no-cache')
  res.setHeader('X-Accel-Buffering', 'no')
  res.flushHeaders()

  for await (const chunk of upstream.body) {
    res.write(chunk)         // 上游 data: 行原样往下倒
  }
  res.end()
})

踩过的坑提两个。X-Accel-Buffering: no 这行别漏,我们线上挂了 nginx,不加它流式会被攒成一坨一次性吐出来,前端那个逐字蹦的效果全没了,体验直接退化成转圈等。还有客户端断开要监听 req.on('close') 去 abort 上游,不然用户关了页面你这边还在烧 token------上面那段为了短我省了,真上线得补。学习曲线不算陡,但 SSE 透传这块第一次弄总会卡在缓冲和断连上,大半天就耗这儿了。

代理这层稳了之后我有点上头,想着前端那个写作工具的"脑子"能不能也别自己硬编。正好试了个零代码搭智能体的东西,拖一拖配一配,挂个现成模型、把我们团队的文案规范喂成知识库,十几分钟就出了个能用的小助手,发布成一个 API 接口。我那个 Node 代理后面接的上游,从直连模型换成了这玩意儿给的 endpoint,前端代码一行没动。说实话当时有点惊到------我对它说"按我们这套 tone 重写这段",它真就照知识库里的规矩改了,不是泛泛的客气话。缺点也有,第一版回答太干、太"正确",得反复调提示词和知识库切片才有人味儿;而且它只干内容生成这种杂活,工程的脏活累活还是 Node 这层自己扛。但能让我这种懒人不写后端逻辑就攒出个有业务知识的智能体,挺香。(模型/API 我走的讯飞 MaaS,现成调,没自己部署算力。)

绕回来说一句:鉴权限流这种事,放前端是侥幸,放 Node 这层才睡得着。你们的大模型流式接口是直连还是也加了代理层?评论区聊聊各自的令牌桶都用啥扛的。

相关推荐
kaixin_啊啊7 小时前
【零基础学AI】第 25 章课后练习与答案
人工智能
水如烟8 小时前
孤能子视角:逆溯法与传统方法比较
人工智能
jimmyleeee8 小时前
大模型安全之五十一:OWASP LLM Top 10 全景解读
人工智能·安全
飞哥数智坊8 小时前
DeepSeek-V4.1-Flash-1017 官方许愿案例太吸睛,我也复刻了一个
人工智能
深蓝AI9 小时前
自报提效 12 倍,模型进步加速 1.9 倍:METR 报告到底量了什么
人工智能·程序员
怕浪猫10 小时前
从工具到代理:一张图看懂 2026–2030 年 AI 如何重构 11 个行业
人工智能·程序员·产品
云和数据.ChenGuang10 小时前
LangGraph 异步 Node 的设计与写法实践
开发语言·人工智能·python·机器学习·php
会飞锦鲤11 小时前
工业AI视觉检测项目完整实施方案
人工智能·深度学习·视觉检测·缺陷检测·模型训练·ai项目·工业应用
优秘智能11 小时前
优秘智能增长智脑视角下的AI试点与验收
人工智能·知识管理·企业应用
天诰11 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程