Flue 框架从入门到精通
Part 3 · 进阶实战

§09 路由与安全:把 Agent 接到你的服务里

app.ts + 鉴权中间件,把 Agent 安全接进你的服务

📑 本章目录

09.1 没加鉴权,被人刷了

去年一个项目,Agent 直接暴露在公网,没加鉴权。一周被刷掉 200 刀 API 费。

Agent 写好了,不能谁都能调。这章讲怎么把它接进你的服务,并守好门。

09.2 app.ts:你的 Hono 应用

src/app.ts 是可选的入口。它本质是个 Hono 应用。你把自己的路由、中间件和 Flue 拼一起。

// src/app.ts
import { flue } from '@flue/runtime/routing';
import { Hono, type MiddlewareHandler } from 'hono';
import { authenticate } from './auth.ts';

// 这行是关键:先验证用户
const requireUser: MiddlewareHandler = async (c, next) => {
  const user = await authenticate(c.req.raw);
  if (!user) return c.json({ error: 'Unauthorized' }, 401);
  await next();
};

const app = new Hono();
app.get('/health', (c) => c.json({ ok: true }));
app.use('/agents/*', requireUser);     // 给 Agent 路由加锁
app.use('/workflows/*', requireUser);
app.route('/', flue());                // 挂载 Flue
export default app;

09.3 暴露哪种传输,你自己定

每个 Agent 文件用导出决定"怎么被访问":

导出 暴露方式
route POST /agents/名/:id 的 HTTP
websocket GET /agents/名/:id 的 WebSocket
都不导 只通过 dispatch() 内部调用

只接 webhook、不对外暴露的 Agent,两个都不用导。安全。

09.4 异步事件用 dispatch

聊天平台、队列消息,用 dispatch 异步喂给 Agent:

app.post('/webhooks/support-comments', async (c) => {
  const event = await verifySupportWebhook(c.req.raw);
  // 这行是关键:异步投递,不等回复
  const receipt = await dispatch(supportAssistant, {
    id: event.ticketId,
    session: 'customer-follow-up',
    input: { type: 'support.comment.created', text: event.text },
  });
  return c.json(receipt, 202);
});

注意:provider 注册只在 app.ts 有效。

这是 §07 提过的坑,在路由里再强调一次:registerProvider 放 Agent 文件里会被丢弃。所有顶层副作用,都进 app.ts

标叔的经验:鉴权别只挂在 Agent 上。

我吃过亏,只在 Agent 的 route 里校验,结果工作流路由漏了。现在统一在 app.ts 用中间件锁 /agents/*/workflows/*,一处管全站,省心。

门守住了。下一章,让 Agent 的运行"看得见"。