乐于分享
好东西不私藏

【OpenClaw 入门指南】HTTP API 路由系统:/v1/models 与插件路由共存

【OpenClaw 入门指南】HTTP API 路由系统:/v1/models 与插件路由共存

模块:M1 Gateway 网关服务 | 预计阅读:40 分钟 | 难度:⭐⭐⭐⭐



💡 导语

Alex,上一篇我们讲了 WebSocket 协议——那是 OpenClaw 的”神经系统”,负责实时通信。但 Gateway 还有一个同样重要的面孔:HTTP REST API

为什么重要?

  1. 1. OpenAI 兼容接口 —— /v1/models/v1/chat/completions,让任何支持 OpenAI API 的工具都能直接调用 OpenClaw
  2. 2. 插件路由系统 —— 插件可以注册自己的 HTTP 端点,扩展 Gateway 的能力
  3. 3. 多路复用 —— 同一个端口同时服务 WebSocket、HTTP API、插件路由、静态文件
  4. 4. 认证统一 —— 所有路由共享同一套认证体系,不重复造轮子

理解这个路由系统,你就能明白为什么 OpenClaw 可以”一个端口走天下”,也能排查 API 调用失败、路由冲突、认证问题。


一、路由系统概览

1.1 架构图

1.2 路由优先级(关键!)

Gateway 处理 HTTP 请求时,按严格优先级匹配路由:

       

         
           
           
         

优先级 路由阶段 路径示例 说明
1 Health Probes /health, /ready 存活/就绪检查,最先处理
2 Hooks 插件钩子 插件预处理
3 OpenAI Models /v1/models 模型列表/详情
4 Embeddings /v1/embeddings 嵌入向量
5 Tools Invoke /tools/invoke 工具调用
6 Session Kill /sessions/*/kill 终止会话
7 Session History /sessions/*/history 会话历史
8 OpenResponses /v1/responses OpenAI Responses API
9 Chat Completions /v1/chat/completions 聊天补全(最核心)
10 Plugin Node Auth 插件节点能力 节点能力路由认证
11 Plugin Routes /plugin/* 插件自定义路由
12 Chat Media /api/chat/media/* 聊天媒体文件
13 Control UI /control/* Web 控制面板
14 404 无匹配路由

       

     

核心设计原则

  • 系统路由优先于插件路由 —— 防止插件覆盖核心功能
  • 精确匹配优先于通配匹配 —— /v1/models/v1/* 之前
  • 认证在路由之后 —— 先确定路由,再检查权限

二、核心源码解析

2.1 路由分发器:createGatewayHttpServer

源码位置:dist/server.impl-yVEQugR-.js:846

function createGatewayHttpServer(opts) {
  const
 { 
    clients, 
    controlUiEnabled, 
    openAiChatCompletionsEnabled,
    openAiChatCompletionsConfig,
    openResponsesEnabled,
    handleHooksRequest,
    handlePluginRequest,
    resolvedAuth,
    rateLimiter,
    getReadiness 
  } = opts;
  
  // 创建 HTTP/HTTPS 服务器

  const
 httpServer = opts.tlsOptions 
    ? createServer$1(opts.tlsOptions, handleRequestWithTrace)
    : createServer(handleRequestWithTrace);

关键设计

  • • 支持 HTTP 和 HTTPS(通过 tlsOptions 配置)
  • • 所有请求走 handleRequestWithTrace,自动附加诊断追踪
  • • WebSocket Upgrade 请求在这里被拦截,转给 WebSocket 处理器

2.2 请求处理主流程

async function handleRequest(req, res) {
  // 1. 设置安全头

  setDefaultSecurityHeaders
(res, { strictTransportSecurity: strictTransportSecurityHeader });
  
  // 2. WebSocket Upgrade 直接返回(由 upgrade 处理器处理)

  if
 ((req.headers.upgrade ?? "").toLowerCase() === "websocket") return;
  
  // 3. 解析请求路径

  const
 requestPath = parseGatewayRequestPath(req.url);
  if
 (requestPath === void 0) {
    sendGatewayAuthFailure
(res, { ok: false, reason: "unauthorized" });
    return
;
  }
  
  // 4. 快速路径:Health Probe(无需认证)

  if
 (GATEWAY_PROBE_STATUS_BY_PATH.get(requestPath) === "live") {
    await
 handleGatewayProbeRequest(req, res, requestPath, ...);
    return
;
  }
  
  // 5. 加载配置

  const
 configSnapshot = loadGatewayConfig();
  const
 trustedProxies = configSnapshot.gateway?.trustedProxies ?? [];
  
  // 6. 解析插件节点能力路由(如 /node/camera/snap)

  const
 scopedNodeCapability = normalizePluginNodeCapabilityScopedUrl(req.url ?? "/");
  ...
  
  // 7. 构建请求阶段管道

  const
 requestStages = [...];
  
  // 8. 按优先级执行各阶段

  if
 (await runGatewayHttpRequestStages(requestStages)) return;
  
  // 9. 无匹配路由 → 404

  res.statusCode = 404;
  res.end("Not Found");
}

解析

  • • 第 2 步:WebSocket 的 Upgrade 请求不在这里处理,由 attachGatewayUpgradeHandler 专门处理
  • • 第 4 步:Health Probe 是”绿色通道”,不经过认证,快速返回
  • • 第 6 步:插件节点能力路由有特殊的 URL 格式(/node/{capability}/{command}
  • • 第 7-8 步:这是核心——阶段管道(Request Stages)

2.3 阶段管道设计模式

这是 Gateway 路由系统最精妙的设计:

const requestStages = [
  {
    name
: "gateway-probes",
    run
: () => handleGatewayProbeRequest(...)
  },
  {
    name
: "hooks",
    run
: () => handleHooksRequest(...)
  }
];

// OpenAI 兼容路由

if
 (openAiCompatEnabled && isOpenAiModelsPath(scopedRequestPath)) {
  requestStages.push({
    name
: "models",
    run
: async () => (await getModelsHttpModule()).handleOpenAiModelsHttpRequest(...)
  });
}

if
 (openAiCompatEnabled && isEmbeddingsPath(scopedRequestPath)) {
  requestStages.push({
    name
: "embeddings",
    run
: async () => (await getEmbeddingsHttpModule()).handleOpenAiEmbeddingsHttpRequest(...)
  });
}

// ... 更多阶段


// 插件路由

requestStages.push(...buildPluginRequestStages(...));

// 执行管道

if
 (await runGatewayHttpRequestStages(requestStages)) return;

为什么用阶段管道?

  1. 1. 优先级明确 —— 数组顺序就是优先级
  2. 2. 按需加载 —— 只有匹配的路径才加载对应的处理模块(懒加载)
  3. 3. 短路返回 —— 每个阶段返回 true 表示”已处理,停止后续”
  4. 4. 可扩展 —— 插件可以插入自己的阶段

2.4 路径匹配函数

源码位置:dist/server.impl-yVEQugR-.js:676-700

function isOpenAiModelsPath(pathname) {
  return
 pathname === "/v1/models" || pathname.startsWith("/v1/models/");
}

function
 isEmbeddingsPath(pathname) {
  return
 pathname === "/v1/embeddings";
}

function
 isOpenAiChatCompletionsPath(pathname) {
  return
 pathname === "/v1/chat/completions";
}

function
 isOpenResponsesPath(pathname) {
  return
 pathname === "/v1/responses";
}

function
 isToolsInvokePath(pathname) {
  return
 pathname === "/tools/invoke";
}

function
 isManagedOutgoingImagePath(pathname) {
  return
 pathname.startsWith("/api/chat/media/outgoing/");
}

function
 isSessionKillPath(pathname) {
  return
 /^\/sessions\/[^/]+\/kill$/.test(pathname);
}

function
 isSessionHistoryPath(pathname) {
  return
 /^\/sessions\/[^/]+\/history$/.test(pathname);
}

设计特点

  • • 每个路由都有独立的判断函数,清晰可维护
  • • 支持精确匹配(===)和前缀匹配(startsWith
  • • 正则表达式用于动态路径(如 /sessions/{id}/kill

三、OpenAI 兼容 API 详解

3.1 /v1/models —— 模型列表

源码位置:dist/models-http-CoMLW6oP.js

async function handleOpenAiModelsHttpRequest(req, res, opts) {
  // 1. 路径检查

  const
 requestPath = resolveRequestPath(req);
  if
 (requestPath !== "/v1/models" && !requestPath.startsWith("/v1/models/")) 
    return
 false;
  
  // 2. 方法检查

  if
 (req.method !== "GET") {
    sendMethodNotAllowed
(res, "GET");
    return
 true;
  }
  
  // 3. 认证

  const
 requestAuth = await authorizeRequest(req, res, opts);
  if
 (!requestAuth) return true;
  
  // 4. 权限检查

  const
 scopeAuth = authorizeOperatorScopesForMethod("models.list", ...);
  if
 (!scopeAuth.allowed) {
    sendMissingScopeForbidden
(res, scopeAuth.missingScope);
    return
 true;
  }
  
  // 5. 加载模型列表

  const
 ids = loadAgentModelIds();
  
  // 6. 返回模型列表

  if
 (requestPath === "/v1/models") {
    sendJson
(res, 200, {
      object
: "list",
      data
: ids.map(toOpenAiModel)
    });
    return
 true;
  }
  
  // 7. 返回单个模型详情

  const
 encodedId = requestPath.slice(11); // 去掉 "/v1/models/"
  ...
}

模型 ID 格式

function loadAgentModelIds() {
  const
 cfg = getRuntimeConfig();
  const
 defaultAgentId = resolveDefaultAgentId(cfg);
  const
 ids = new Set([OPENCLAW_MODEL_ID, OPENCLAW_DEFAULT_MODEL_ID]);
  
  // 格式:openclaw/{agentId}

  ids.add(`openclaw/${defaultAgentId}`);
  for
 (const agentId of listAgentIds(cfg)) {
    ids.add(`openclaw/${agentId}`);
  }
  return
 Array.from(ids);
}

返回示例

{
  "object"
: "list",
  "data"
: [
    {

      "id"
: "openclaw",
      "object"
: "model",
      "created"
: 0,
      "owned_by"
: "openclaw",
      "permission"
: []
    }
,
    {

      "id"
: "openclaw/marketing-content-creator",
      "object"
: "model",
      "created"
: 0,
      "owned_by"
: "openclaw",
      "permission"
: []
    }

  ]

}

3.2 /v1/chat/completions —— 聊天补全

源码位置:dist/openai-http-BAjJ0ljy.js:461

这是整个 HTTP API 最复杂的端点,支持:

  • • 普通请求(非流式)
  • • SSE 流式响应
  • • 工具调用(function calling)
  • • 图片输入
  • • 多轮对话

请求处理流程

async function handleOpenAiHttpRequest(req, res, opts) {
  // 1. 解析限流配置

  const
 limits = resolveOpenAiChatCompletionsLimits(opts.config);
  
  // 2. 处理 POST JSON 请求(通用辅助函数)

  const
 handled = await handleGatewayPostJsonEndpoint(req, res, {
    pathname
: "/v1/chat/completions",
    requiredOperatorMethod
: "chat.send",
    resolveOperatorScopes
: resolveOpenAiCompatibleHttpOperatorScopes,
    auth
: opts.auth,
    maxBodyBytes
: opts.maxBodyBytes ?? limits.maxBodyBytes
  });
  if
 (handled === false) return false;
  if
 (!handled) return true;
  
  // 3. 检查模型覆盖权限

  const
 modelOverrideAuth = authorizeOpenAiCompatibleHttpModelOverride(...);
  
  // 4. 解析请求体

  const
 payload = coerceRequest(handled.body);
  const
 stream = Boolean(payload.stream);
  const
 model = typeof payload.model === "string" ? payload.model : "openclaw";
  
  // 5. 解析采样参数

  const
 maxTokens = payload.max_completion_tokens ?? payload.max_tokens;
  const
 temperature = payload.temperature;
  const
 topP = payload.top_p;
  ...
  
  // 6. 解析工具调用

  const
 { tools, toolChoice } = payload;
  const
 { resolvedClientTools, toolChoicePrompt, toolChoiceConstraint } = applyChatToolChoice({ tools, toolChoice });
  
  // 7. 解析图片

  const
 images = await resolveImagesForRequest(activeTurnContext, limits);
  
  // 8. 构建 Agent 命令输入

  const
 commandInput = buildAgentCommandInput({
    prompt
: { message, extraSystemPrompt, images },
    clientTools
: resolvedClientTools,
    modelOverride,
    sessionKey,
    runId,
    ...
  });
  
  // 9. 发送命令到 Agent

  const
 result = await sendAgentCommand(commandInput);
  
  // 10. 返回响应(流式或非流式)

  if
 (stream) {
    return
 await sendOpenAiStreamResponse(res, result, ...);
  } else {
    return
 await sendOpenAiJsonResponse(res, result, ...);
  }
}

关键设计

  • • 第 2 步:handleGatewayPostJsonEndpoint 是通用辅助函数,处理认证、权限、请求体解析
  • • 第 3 步:模型覆盖权限检查——防止用户通过 model 参数切换到未授权的 Agent
  • • 第 6 步:工具调用解析——将 OpenAI 的 tools/tool_choice 格式转换为 OpenClaw 内部格式
  • • 第 7 步:图片解析——支持 base64 和 URL 两种格式
  • • 第 10 步:流式响应使用 SSE(Server-Sent Events),非流式返回完整 JSON

流式响应示例

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1698140000,"model":"openclaw","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1698140000,"model":"openclaw","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1698140000,"model":"openclaw","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

四、插件路由系统

4.1 插件如何注册路由

插件通过 gateway.http API 注册自定义路由:

// 插件代码示例
export
 default definePlugin({
  name
: "my-plugin",
  setup
(ctx) {
    ctx.gateway.http.get("/plugin/my-plugin/status", async (req, res) => {
      res.json({ status: "ok", version: "1.0.0" });
    });
    
    ctx.gateway.http.post("/plugin/my-plugin/webhook", async (req, res) => {
      const
 payload = req.body;
      // 处理 webhook

      res.json({ received: true });
    });
  }
});

4.2 插件路由的优先级

插件路由在阶段管道中的位置:

// 系统路由优先
requestStages.push(
  { name: "gateway-probes", ... },
  { name: "hooks", ... },
  { name: "models", ... },
  { name: "chat-completions", ... },
  // ... 更多系统路由

);

// 插件路由在后

requestStages.push(...buildPluginRequestStages(...));

// 最后是 404

设计意图

  • • 系统路由(如 /v1/chat/completions)不能被插件覆盖
  • • 插件路由以 /plugin/{pluginName}/ 为前缀,避免冲突
  • • 插件可以注册钩子(hooks)在系统路由之前执行

4.3 插件节点能力路由

特殊的路由格式:/node/{capability}/{command}

// 示例:调用节点的摄像头
POST
 /node/camera/snap
{
  "target"
: "ios-device-001",
  "params"
: { "quality": "high" }
}

处理流程

  1. 1. Gateway 解析 capability 和 command
  2. 2. 查找具有该 capability 的在线 node
  3. 3. 通过 WebSocket 转发命令到 node
  4. 4. Node 执行后返回结果
  5. 5. Gateway 将结果返回给 HTTP 客户端

五、认证与限流

5.1 统一认证体系

所有 HTTP 路由共享同一套认证:

async function authorizeRequest(req, res, opts) {
  // 1. 提取认证信息

  const
 auth = extractAuthFromRequest(req);
  
  // 2. 验证 token

  const
 validated = await validateToken(auth.token);
  if
 (!validated) {
    sendGatewayAuthFailure
(res, { ok: false, reason: "unauthorized" });
    return
 null;
  }
  
  // 3. 检查 scopes

  const
 scopes = validated.scopes;
  if
 (!scopes.includes("operator.read")) {
    sendMissingScopeForbidden
(res, "operator.read");
    return
 null;
  }
  
  return
 validated;
}

认证方式

  • Bearer TokenAuthorization: Bearer {token}
  • API KeyX-API-Key: {key}
  • 共享密钥Authorization: Shared {secret}(内部使用)

5.2 限流机制

const limits = resolveOpenAiChatCompletionsLimits(config);
// {

//   maxBodyBytes: 10485760,  // 10 MB

//   maxRequestsPerMinute: 60,

//   maxTokensPerRequest: 4096

// }

限流维度

  • • 请求体大小(默认 10 MB)
  • • 每分钟请求数(默认 60)
  • • 每请求最大 token 数(默认 4096)
  • • 并发流式连接数

🎯 总结

OpenClaw 的 HTTP API 路由系统体现了几个核心设计原则:

  1. 1. 优先级明确 —— 系统路由优先,精确匹配优先,防止冲突
  2. 2. 阶段管道 —— 数组顺序即优先级,按需加载,短路返回
  3. 3. OpenAI 兼容 —— 零成本迁移,任何支持 OpenAI API 的工具都能用
  4. 4. 插件可扩展 —— 插件注册自己的路由,不侵入核心代码
  5. 5. 认证统一 —— 所有路由共享认证,不重复造轮子
  6. 6. 限流保护 —— 多维度限流,防止滥用

理解这个路由系统,你就能:

  • • ✅ 排查 API 调用失败、路由冲突、认证问题
  • • ✅ 开发支持 OpenAI API 的第三方工具
  • • ✅ 编写插件扩展 Gateway 能力
  • • ✅ 优化 Gateway 性能和安全性

💬 互动话题

你在使用 OpenClaw 的 HTTP API 时遇到过哪些问题?是路由冲突、认证失败,还是流式响应异常?欢迎在评论区分享你的排查经验 👇


📚 系列文章:OpenClaw 入门指南 | M1 Gateway 网关服务

上一篇:[OG_M1_002] WebSocket 协议设计:connect → hello-ok → req/res 全流程

下一篇:[OG_M1_004] 热重载机制:不停机更新 Gateway 配置

关注「云境易贸」公众号,回复 “OpenClaw” 获取完整源码解析系列。