# API7 中文文档 > AISIX AI 网关、AISIX Cloud、Apache APISIX、API7 网关、API7 Ingress Controller、APISIX Ingress Controller 以及网关插件的官方中文文档。 ## hub 探索 Apache APISIX 与 API7 网关的插件文档,包括适用于网关和 Ingress Controller 工作流的配置参考与示例。 - [欢迎来到 API 网关插件中心](https://docs.apiseven.com/hub.md): 探索 Apache APISIX 与 API7 网关的插件文档,包括适用于网关和 Ingress Controller 工作流的配置参考与示例。 ### acl ACL(访问控制列表)插件通过验证用户是否在允许列表中,精细控制对 Apache APISIX 上游资源的访问权限,为企业级 API 网关提供强大的授权管理能力。 - [acl](https://docs.apiseven.com/hub/acl.md): ACL(访问控制列表)插件通过验证用户是否在允许列表中,精细控制对 Apache APISIX 上游资源的访问权限,为企业级 API 网关提供强大的授权管理能力。 #### configuration 参数 - [ACL](https://docs.apiseven.com/hub/acl/configuration.md): 参数 ### ai-aliyun-content-moderation AI Aliyun Content Moderation 插件集成阿里云内容安全服务,在 AI 网关代理 LLM 请求时实时检测提示词输入风险,自动拦截超过安全阈值的请求,保障 AI 应用合规。 - [ai-aliyun-content-moderation](https://docs.apiseven.com/hub/ai-aliyun-content-moderation.md): AI Aliyun Content Moderation 插件集成阿里云内容安全服务,在 AI 网关代理 LLM 请求时实时检测提示词输入风险,自动拦截超过安全阈值的请求,保障 AI 应用合规。 #### configuration 参数 - [AI Aliyun Content Moderation](https://docs.apiseven.com/hub/ai-aliyun-content-moderation/configuration.md): 参数 ### ai-aws-content-moderation AI AWS Content Moderation 插件集成 AWS Comprehend,在 AI 网关代理 LLM 请求时检测提示词毒性内容,自动拦截超过阈值的有害请求,保障 AI 应用安全合规。 - [ai-aws-content-moderation](https://docs.apiseven.com/hub/ai-aws-content-moderation.md): AI AWS Content Moderation 插件集成 AWS Comprehend,在 AI 网关代理 LLM 请求时检测提示词毒性内容,自动拦截超过阈值的有害请求,保障 AI 应用安全合规。 #### configuration 参数 - [AI AWS Content Moderation](https://docs.apiseven.com/hub/ai-aws-content-moderation/configuration.md): 参数 ### ai-cache ai-cache 插件将完全匹配和语义相似的 LLM 响应存储在 Redis 中,从而降低响应延迟并减少重复的上游模型调用。 - [ai-cache](https://docs.apiseven.com/hub/ai-cache.md): ai-cache 插件将完全匹配和语义相似的 LLM 响应存储在 Redis 中,从而降低响应延迟并减少重复的上游模型调用。 #### configuration 参数 - [AI Cache](https://docs.apiseven.com/hub/ai-cache/configuration.md): 参数 ### ai-lakera-guard ai-lakera-guard 插件通过 Lakera Guard API 筛查 AI 流量,检测请求和 LLM 响应中的提示词注入及其他不安全内容。 - [ai-lakera-guard](https://docs.apiseven.com/hub/ai-lakera-guard.md): ai-lakera-guard 插件通过 Lakera Guard API 筛查 AI 流量,检测请求和 LLM 响应中的提示词注入及其他不安全内容。 #### configuration 参数 - [AI Lakera Guard](https://docs.apiseven.com/hub/ai-lakera-guard/configuration.md): 参数 ### ai-prompt-decorator AI Prompt Decorator 插件在 AI 网关层为 LLM 请求的用户提示词自动添加前缀和后缀,无需修改客户端代码即可统一注入系统指令,简化 AI API 管理与内容生成流程。 - [ai-prompt-decorator](https://docs.apiseven.com/hub/ai-prompt-decorator.md): AI Prompt Decorator 插件在 AI 网关层为 LLM 请求的用户提示词自动添加前缀和后缀,无需修改客户端代码即可统一注入系统指令,简化 AI API 管理与内容生成流程。 #### configuration 参数 - [AI Prompt Decorator](https://docs.apiseven.com/hub/ai-prompt-decorator/configuration.md): 参数 ### ai-prompt-guard AI Prompt Guard 插件通过允许/拒绝模式在 AI 网关层过滤 LLM 提示词,支持检查最新消息或完整对话历史,有效防止提示词注入攻击,保障 AI 应用安全。 - [ai-prompt-guard](https://docs.apiseven.com/hub/ai-prompt-guard.md): AI Prompt Guard 插件通过允许/拒绝模式在 AI 网关层过滤 LLM 提示词,支持检查最新消息或完整对话历史,有效防止提示词注入攻击,保障 AI 应用安全。 #### configuration 参数 - [AI Prompt Guard](https://docs.apiseven.com/hub/ai-prompt-guard/configuration.md): 参数 ### ai-prompt-template AI Prompt Template 插件为 AI 网关提供预配置提示词模板,支持以填空方式让客户端传入变量,统一规范发送给 LLM 的请求格式,简化 AI API 管理与集成。 - [ai-prompt-template](https://docs.apiseven.com/hub/ai-prompt-template.md): AI Prompt Template 插件为 AI 网关提供预配置提示词模板,支持以填空方式让客户端传入变量,统一规范发送给 LLM 的请求格式,简化 AI API 管理与集成。 #### configuration 参数 - [AI Prompt Template](https://docs.apiseven.com/hub/ai-prompt-template/configuration.md): 参数 ### ai-proxy AI Proxy 插件将 API 网关请求转换为 OpenAI、DeepSeek、Anthropic、Gemini 等 LLM 所需格式,支持多模型统一接入,并可在访问日志中记录 Token 用量和首字节响应时间。 - [ai-proxy](https://docs.apiseven.com/hub/ai-proxy.md): AI Proxy 插件将 API 网关请求转换为 OpenAI、DeepSeek、Anthropic、Gemini 等 LLM 所需格式,支持多模型统一接入,并可在访问日志中记录 Token 用量和首字节响应时间。 #### configuration 参数 - [AI Proxy](https://docs.apiseven.com/hub/ai-proxy/configuration.md): 参数 ### ai-proxy-multi ai-proxy-multi 插件通过负载均衡、重试、故障转移和健康检查扩展 ai-proxy 的能力,简化与 OpenAI、DeepSeek 及其他 OpenAI 兼容 API 的集成。 - [ai-proxy-multi](https://docs.apiseven.com/hub/ai-proxy-multi.md): ai-proxy-multi 插件通过负载均衡、重试、故障转移和健康检查扩展 ai-proxy 的能力,简化与 OpenAI、DeepSeek 及其他 OpenAI 兼容 API 的集成。 #### configuration 静态配置 - [AI Proxy Multi](https://docs.apiseven.com/hub/ai-proxy-multi/configuration.md): 静态配置 ### ai-proxy-protocol-reference 了解 ai-proxy 和 ai-proxy-multi 如何检测客户端请求协议,以及如何将 Anthropic Messages 请求转换为 OpenAI Chat Completions。 - [协议参考](https://docs.apiseven.com/hub/ai-proxy-protocol-reference.md): 了解 ai-proxy 和 ai-proxy-multi 如何检测客户端请求协议,以及如何将 Anthropic Messages 请求转换为 OpenAI Chat Completions。 ### ai-rag AI RAG 插件在代理 LLM 请求之前,使用 Azure OpenAI 嵌入和 Azure AI Search 检索上下文。 - [ai-rag](https://docs.apiseven.com/hub/ai-rag.md): AI RAG 插件在代理 LLM 请求之前,使用 Azure OpenAI 嵌入和 Azure AI Search 检索上下文。 #### configuration 插件参数 - [AI RAG](https://docs.apiseven.com/hub/ai-rag/configuration.md): 插件参数 ### ai-rate-limiting AI Rate Limiting 插件专为 AI 网关设计,基于 Token 用量对 LLM API 请求进行速率限制,有效控制 AI 服务成本,防止资源滥用,保障 AI API 的稳定可用性。 - [ai-rate-limiting](https://docs.apiseven.com/hub/ai-rate-limiting.md): AI Rate Limiting 插件专为 AI 网关设计,基于 Token 用量对 LLM API 请求进行速率限制,有效控制 AI 服务成本,防止资源滥用,保障 AI API 的稳定可用性。 #### configuration 参数 - [AI Rate Limiting](https://docs.apiseven.com/hub/ai-rate-limiting/configuration.md): 参数 ### ai-request-rewrite AI Request Rewrite 插件在 API 网关层动态改写发往 LLM 的请求参数,支持修改模型、温度等配置,实现请求的灵活路由与转换,简化 AI 服务的统一管理。 - [ai-request-rewrite](https://docs.apiseven.com/hub/ai-request-rewrite.md): AI Request Rewrite 插件在 API 网关层动态改写发往 LLM 的请求参数,支持修改模型、温度等配置,实现请求的灵活路由与转换,简化 AI 服务的统一管理。 #### configuration 参数 - [AI Request Rewrite](https://docs.apiseven.com/hub/ai-request-rewrite/configuration.md): 参数 ### attach-consumer-label Attach Consumer Label 插件为经过身份认证的消费者请求自动附加标签,便于在 Apache APISIX 中实现基于消费者属性的精细化流量管理、监控和访问控制策略。 - [attach-consumer-label](https://docs.apiseven.com/hub/attach-consumer-label.md): Attach Consumer Label 插件为经过身份认证的消费者请求自动附加标签,便于在 Apache APISIX 中实现基于消费者属性的精细化流量管理、监控和访问控制策略。 #### configuration 参数 - [Attach Consumer Label](https://docs.apiseven.com/hub/attach-consumer-label/configuration.md): 参数 ### authz-keycloak Authz Keycloak 插件将 Apache APISIX 与 Keycloak 授权服务集成,支持基于策略的细粒度访问控制,为 API 网关提供企业级的身份与访问管理(IAM)能力。 - [authz-keycloak](https://docs.apiseven.com/hub/authz-keycloak.md): Authz Keycloak 插件将 Apache APISIX 与 Keycloak 授权服务集成,支持基于策略的细粒度访问控制,为 API 网关提供企业级的身份与访问管理(IAM)能力。 #### configuration 参数 - [Authz Keycloak](https://docs.apiseven.com/hub/authz-keycloak/configuration.md): 参数 ### aws-lambda AWS Lambda 插件将 Apache APISIX 与 AWS Lambda 无服务器函数集成,支持将 API 请求直接代理到 Lambda 函数,实现 Serverless 架构下的 API 网关统一管理。 - [aws-lambda](https://docs.apiseven.com/hub/aws-lambda.md): AWS Lambda 插件将 Apache APISIX 与 AWS Lambda 无服务器函数集成,支持将 API 请求直接代理到 Lambda 函数,实现 Serverless 架构下的 API 网关统一管理。 #### configuration 属性 - [AWS Lambda](https://docs.apiseven.com/hub/aws-lambda/configuration.md): 属性 ### basic-auth Basic Auth 插件为 Apache APISIX 路由添加 HTTP 基本访问认证,要求客户端提供用户名和密码才能访问上游资源,快速为 API 网关启用简单身份认证保护。 - [basic-auth](https://docs.apiseven.com/hub/basic-auth.md): Basic Auth 插件为 Apache APISIX 路由添加 HTTP 基本访问认证,要求客户端提供用户名和密码才能访问上游资源,快速为 API 网关启用简单身份认证保护。 #### configuration 参数 - [Basic Auth](https://docs.apiseven.com/hub/basic-auth/configuration.md): 参数 ### body-transformer Body Transformer 插件在 API 网关层对请求和响应的消息体进行格式转换,支持 JSON 与 XML 互转及自定义模板,实现不同系统间的数据格式无缝对接。 - [body-transformer](https://docs.apiseven.com/hub/body-transformer.md): Body Transformer 插件在 API 网关层对请求和响应的消息体进行格式转换,支持 JSON 与 XML 互转及自定义模板,实现不同系统间的数据格式无缝对接。 #### configuration 参数 - [Body Transformer](https://docs.apiseven.com/hub/body-transformer/configuration.md): 参数 ### chaitin-waf Chaitin WAF 插件将长亭科技 Web 应用防火墙集成到 Apache APISIX,在 API 网关层实时检测并拦截 SQL 注入、XSS 等 Web 攻击,为 API 提供企业级安全防护。 - [chaitin-waf](https://docs.apiseven.com/hub/chaitin-waf.md): Chaitin WAF 插件将长亭科技 Web 应用防火墙集成到 Apache APISIX,在 API 网关层实时检测并拦截 SQL 注入、XSS 等 Web 攻击,为 API 提供企业级安全防护。 #### configuration 参数 - [Chaitin WAF](https://docs.apiseven.com/hub/chaitin-waf/configuration.md): 参数 ### clickhouse-logger clickhouse-logger 插件将请求和响应日志分批推送到 ClickHouse 数据库,并支持自定义日志格式,以增强数据管理能力。 - [clickhouse-logger](https://docs.apiseven.com/hub/clickhouse-logger.md): clickhouse-logger 插件将请求和响应日志分批推送到 ClickHouse 数据库,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [ClickHouse Logger](https://docs.apiseven.com/hub/clickhouse-logger/configuration.md): 参数 ### consumer-restriction Consumer Restriction 插件基于消费者身份对 Apache APISIX 路由访问进行精细控制,支持白名单和黑名单模式,实现 API 网关层的消费者级别访问授权管理。 - [consumer-restriction](https://docs.apiseven.com/hub/consumer-restriction.md): Consumer Restriction 插件基于消费者身份对 Apache APISIX 路由访问进行精细控制,支持白名单和黑名单模式,实现 API 网关层的消费者级别访问授权管理。 #### configuration 参数 - [Consumer Restriction](https://docs.apiseven.com/hub/consumer-restriction/configuration.md): 参数 ### cors CORS 插件为 Apache APISIX 路由启用跨源资源共享(CORS),支持灵活配置允许的来源、方法和请求头,解决前端跨域问题,提升 API 的可访问性与兼容性。 - [cors](https://docs.apiseven.com/hub/cors.md): CORS 插件为 Apache APISIX 路由启用跨源资源共享(CORS),支持灵活配置允许的来源、方法和请求头,解决前端跨域问题,提升 API 的可访问性与兼容性。 #### configuration 参数 - [CORS](https://docs.apiseven.com/hub/cors/configuration.md): 参数 ### data-mask Data Mask 插件在 Apache APISIX 日志记录前对敏感字段进行脱敏处理,支持自定义掩码规则,保护用户隐私数据,帮助 API 网关满足数据安全合规要求。 - [data-mask](https://docs.apiseven.com/hub/data-mask.md): Data Mask 插件在 Apache APISIX 日志记录前对敏感字段进行脱敏处理,支持自定义掩码规则,保护用户隐私数据,帮助 API 网关满足数据安全合规要求。 #### configuration 参数 - [Data Mask](https://docs.apiseven.com/hub/data-mask/configuration.md): 参数 ### datadog datadog 插件与 Datadog 集成,将指标分批发送到 DogStatsD,以改进 API 监控和性能跟踪。 - [datadog](https://docs.apiseven.com/hub/datadog.md): datadog 插件与 Datadog 集成,将指标分批发送到 DogStatsD,以改进 API 监控和性能跟踪。 #### configuration 参数 - [Datadog](https://docs.apiseven.com/hub/datadog/configuration.md): 参数 ### degraphql DeGraphQL 插件将 RESTful API 请求转换为 GraphQL 查询,让客户端无需了解 GraphQL 语法即可访问 GraphQL 后端,通过 API 网关实现 REST 到 GraphQL 的无缝桥接。 - [degraphql](https://docs.apiseven.com/hub/degraphql.md): DeGraphQL 插件将 RESTful API 请求转换为 GraphQL 查询,让客户端无需了解 GraphQL 语法即可访问 GraphQL 后端,通过 API 网关实现 REST 到 GraphQL 的无缝桥接。 #### configuration 参数 - [degraphql](https://docs.apiseven.com/hub/degraphql/configuration.md): 参数 ### dingtalk-auth dingtalk-auth 插件提供了钉钉 OAuth 2.0 身份认证能力,验证客户端请求中携带的免登录授权码并获取用户信息,适用于钉钉企业内部应用的访问控制场景。 - [dingtalk-auth 企业版](https://docs.apiseven.com/hub/dingtalk-auth.md): dingtalk-auth 插件提供了钉钉 OAuth 2.0 身份认证能力,验证客户端请求中携带的免登录授权码并获取用户信息,适用于钉钉企业内部应用的访问控制场景。 #### configuration 参数 - [DingTalk Auth](https://docs.apiseven.com/hub/dingtalk-auth/configuration.md): 参数 ### elasticsearch-logger elasticsearch-logger 插件将请求和响应日志分批推送到 Elasticsearch,并支持自定义日志格式,以增强数据管理能力。 - [elasticsearch-logger](https://docs.apiseven.com/hub/elasticsearch-logger.md): elasticsearch-logger 插件将请求和响应日志分批推送到 Elasticsearch,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [Elasticsearch Logger](https://docs.apiseven.com/hub/elasticsearch-logger/configuration.md): 参数 ### error-log-collect Error Log Collect 插件捕获处理指定请求时产生的错误日志,包括所配置日志级别通常会丢弃的低级别日志,并将其写入网关错误日志,便于针对性调试。 - [error-log-collect 企业版](https://docs.apiseven.com/hub/error-log-collect.md): Error Log Collect 插件捕获处理指定请求时产生的错误日志,包括所配置日志级别通常会丢弃的低级别日志,并将其写入网关错误日志,便于针对性调试。 #### configuration 参数 - [Error Log Collect](https://docs.apiseven.com/hub/error-log-collect/configuration.md): 参数 ### error-log-logger Error Log Logger 插件将 Apache APISIX 产生的错误日志推送到远程日志服务,支持集中化错误日志管理,帮助运维团队及时发现和处理 API 网关的异常情况。 - [error-log-logger](https://docs.apiseven.com/hub/error-log-logger.md): Error Log Logger 插件将 Apache APISIX 产生的错误日志推送到远程日志服务,支持集中化错误日志管理,帮助运维团队及时发现和处理 API 网关的异常情况。 #### configuration 参数 - [Error Log Logger](https://docs.apiseven.com/hub/error-log-logger/configuration.md): 参数 ### error-page Error Page 插件可自定义网关生成的 404、500、502 和 503 响应,但不会修改上游服务返回的响应。 - [error-page](https://docs.apiseven.com/hub/error-page.md): Error Page 插件可自定义网关生成的 404、500、502 和 503 响应,但不会修改上游服务返回的响应。 #### configuration 参数 - [Error Page](https://docs.apiseven.com/hub/error-page/configuration.md): 参数 ### exit-transformer Exit Transformer 插件可在 APISIX 向客户端发送响应前,自定义由网关插件或缺失路由生成的响应。 - [exit-transformer](https://docs.apiseven.com/hub/exit-transformer.md): Exit Transformer 插件可在 APISIX 向客户端发送响应前,自定义由网关插件或缺失路由生成的响应。 #### configuration 参数 - [Exit Transformer](https://docs.apiseven.com/hub/exit-transformer/configuration.md): 参数 ### fault-injection Fault Injection 插件在 Apache APISIX 中模拟 API 故障场景,支持注入延迟和自定义错误响应,用于混沌工程测试,验证微服务架构在 API 网关层的容错能力。 - [fault-injection](https://docs.apiseven.com/hub/fault-injection.md): Fault Injection 插件在 Apache APISIX 中模拟 API 故障场景,支持注入延迟和自定义错误响应,用于混沌工程测试,验证微服务架构在 API 网关层的容错能力。 #### configuration 参数 - [Fault Injection](https://docs.apiseven.com/hub/fault-injection/configuration.md): 参数 ### feishu-auth feishu-auth 插件支持飞书 OAuth 2.0 身份认证,允许客户端在访问上游资源前通过飞书账号完成认证,增强 API 安全性。 - [feishu-auth 企业版](https://docs.apiseven.com/hub/feishu-auth.md): feishu-auth 插件支持飞书 OAuth 2.0 身份认证,允许客户端在访问上游资源前通过飞书账号完成认证,增强 API 安全性。 #### configuration 参数 - [Feishu Auth](https://docs.apiseven.com/hub/feishu-auth/configuration.md): 参数 ### forward-auth Forward Auth 插件将 Apache APISIX 的认证请求转发到外部认证服务,支持与任意 OAuth2、JWT 或自定义认证系统集成,实现 API 网关层的灵活外部鉴权。 - [forward-auth](https://docs.apiseven.com/hub/forward-auth.md): Forward Auth 插件将 Apache APISIX 的认证请求转发到外部认证服务,支持与任意 OAuth2、JWT 或自定义认证系统集成,实现 API 网关层的灵活外部鉴权。 #### configuration 参数 - [Forward Auth](https://docs.apiseven.com/hub/forward-auth/configuration.md): 参数 ### google-cloud-logging google-cloud-logging 插件将请求和响应日志分批推送到 Google Cloud Logging Service,并支持自定义日志格式。 - [google-cloud-logging](https://docs.apiseven.com/hub/google-cloud-logging.md): google-cloud-logging 插件将请求和响应日志分批推送到 Google Cloud Logging Service,并支持自定义日志格式。 #### configuration 参数 - [Google Cloud Logging](https://docs.apiseven.com/hub/google-cloud-logging/configuration.md): 参数 ### graphql-limit-count graphql-limit-count 插件使用固定窗口限制 GraphQL 文档的累计成本,默认以选择集深度作为度量。 - [graphql-limit-count](https://docs.apiseven.com/hub/graphql-limit-count.md): graphql-limit-count 插件使用固定窗口限制 GraphQL 文档的累计成本,默认以选择集深度作为度量。 #### configuration 参数 - [GraphQL Limit Count](https://docs.apiseven.com/hub/graphql-limit-count/configuration.md): 参数 ### graphql-proxy-cache GraphQL Proxy Cache 插件在 Apache APISIX 层缓存 GraphQL 查询响应,减少对后端 GraphQL 服务的重复请求,显著提升 API 响应速度,降低后端服务负载。 - [graphql-proxy-cache](https://docs.apiseven.com/hub/graphql-proxy-cache.md): GraphQL Proxy Cache 插件在 Apache APISIX 层缓存 GraphQL 查询响应,减少对后端 GraphQL 服务的重复请求,显著提升 API 响应速度,降低后端服务负载。 #### configuration 静态配置 - [GraphQL Proxy Cache](https://docs.apiseven.com/hub/graphql-proxy-cache/configuration.md): 静态配置 ### grpc-transcode gRPC Transcode 插件将 HTTP/JSON 请求转换为 gRPC 协议,让 RESTful 客户端无缝访问 gRPC 后端服务,通过 Apache APISIX 实现 REST 与 gRPC 的协议桥接。 - [grpc-transcode](https://docs.apiseven.com/hub/grpc-transcode.md): gRPC Transcode 插件将 HTTP/JSON 请求转换为 gRPC 协议,让 RESTful 客户端无缝访问 gRPC 后端服务,通过 Apache APISIX 实现 REST 与 gRPC 的协议桥接。 #### configuration 参数 - [gRPC Transcode](https://docs.apiseven.com/hub/grpc-transcode/configuration.md): 参数 ### grpc-web gRPC Web 插件使 Apache APISIX 支持 gRPC-Web 协议,让浏览器端应用能够直接调用 gRPC 后端服务,解决 Web 客户端与 gRPC 服务之间的协议兼容问题。 - [grpc-web](https://docs.apiseven.com/hub/grpc-web.md): gRPC Web 插件使 Apache APISIX 支持 gRPC-Web 协议,让浏览器端应用能够直接调用 gRPC 后端服务,解决 Web 客户端与 gRPC 服务之间的协议兼容问题。 #### configuration 参数 - [gRPC Web](https://docs.apiseven.com/hub/grpc-web/configuration.md): 参数 ### hmac-auth HMAC Auth 插件为 Apache APISIX 提供基于 HMAC 签名的 API 身份认证,通过验证请求签名确保请求完整性和来源可信,为 API 网关提供防篡改的安全认证机制。 - [hmac-auth](https://docs.apiseven.com/hub/hmac-auth.md): HMAC Auth 插件为 Apache APISIX 提供基于 HMAC 签名的 API 身份认证,通过验证请求签名确保请求完整性和来源可信,为 API 网关提供防篡改的安全认证机制。 #### configuration 参数 - [HMAC Auth](https://docs.apiseven.com/hub/hmac-auth/configuration.md): 参数 ### http-logger http-logger 插件将请求和响应日志作为 JSON 对象分批推送到 HTTP(S) 服务器,并支持自定义日志格式,以增强数据管理能力。 - [http-logger](https://docs.apiseven.com/hub/http-logger.md): http-logger 插件将请求和响应日志作为 JSON 对象分批推送到 HTTP(S) 服务器,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [HTTP Logger](https://docs.apiseven.com/hub/http-logger/configuration.md): 参数 ### ip-restriction IP Restriction 插件基于客户端 IP 地址对 Apache APISIX 路由进行访问控制,支持 IP 白名单和黑名单配置,快速实现 API 网关层的网络访问限制与安全防护。 - [ip-restriction](https://docs.apiseven.com/hub/ip-restriction.md): IP Restriction 插件基于客户端 IP 地址对 Apache APISIX 路由进行访问控制,支持 IP 白名单和黑名单配置,快速实现 API 网关层的网络访问限制与安全防护。 #### configuration 参数 - [IP Restriction](https://docs.apiseven.com/hub/ip-restriction/configuration.md): 参数 ### jwe-decrypt JWE Decrypt 插件解密 JWE 紧凑序列化 Token,并在配置的请求头中转发明文。 - [jwe-decrypt](https://docs.apiseven.com/hub/jwe-decrypt.md): JWE Decrypt 插件解密 JWE 紧凑序列化 Token,并在配置的请求头中转发明文。 #### configuration 参数 - [JWE Decrypt](https://docs.apiseven.com/hub/jwe-decrypt/configuration.md): 参数 ### jwt-auth JWT Auth 插件为 Apache APISIX 提供基于 JSON Web Token 的 API 身份认证,支持 HS256、RS256 等多种签名算法,在 API 网关层实现无状态的安全身份认证。 - [jwt-auth](https://docs.apiseven.com/hub/jwt-auth.md): JWT Auth 插件为 Apache APISIX 提供基于 JSON Web Token 的 API 身份认证,支持 HS256、RS256 等多种签名算法,在 API 网关层实现无状态的安全身份认证。 #### configuration 参数 - [JWT Auth](https://docs.apiseven.com/hub/jwt-auth/configuration.md): 参数 ### kafka-logger kafka-logger 插件将请求和响应日志作为 JSON 对象分批推送到 Apache Kafka 集群,并支持自定义日志格式,以增强数据管理能力。 - [kafka-logger](https://docs.apiseven.com/hub/kafka-logger.md): kafka-logger 插件将请求和响应日志作为 JSON 对象分批推送到 Apache Kafka 集群,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [Kafka Logger](https://docs.apiseven.com/hub/kafka-logger/configuration.md): 参数 ### key-auth Key Auth 插件为 Apache APISIX 提供基于 API Key 的身份认证,支持通过请求头或查询参数传递密钥,快速为 API 网关启用简单高效的 API 密钥认证保护。 - [key-auth](https://docs.apiseven.com/hub/key-auth.md): Key Auth 插件为 Apache APISIX 提供基于 API Key 的身份认证,支持通过请求头或查询参数传递密钥,快速为 API 网关启用简单高效的 API 密钥认证保护。 #### configuration 参数 - [Key Auth](https://docs.apiseven.com/hub/key-auth/configuration.md): 参数 ### ldap-auth-advanced LDAP Auth Advanced 插件对接 OpenLDAP、Active Directory 等 LDAP 目录完成客户端认证,并可把认证到的目录用户映射为消费者,使目录身份能够复用消费者级插件、限流与用量统计。 - [ldap-auth-advanced](https://docs.apiseven.com/hub/ldap-auth-advanced.md): LDAP Auth Advanced 插件对接 OpenLDAP、Active Directory 等 LDAP 目录完成客户端认证,并可把认证到的目录用户映射为消费者,使目录身份能够复用消费者级插件、限流与用量统计。 #### configuration 参数 - [LDAP Auth Advanced](https://docs.apiseven.com/hub/ldap-auth-advanced/configuration.md): 参数 ### limit-conn Limit Conn 插件基于并发连接数对 Apache APISIX 路由进行限流,防止后端服务因连接数过多而过载,保障 API 网关在高并发场景下的稳定性和服务质量。 - [limit-conn](https://docs.apiseven.com/hub/limit-conn.md): Limit Conn 插件基于并发连接数对 Apache APISIX 路由进行限流,防止后端服务因连接数过多而过载,保障 API 网关在高并发场景下的稳定性和服务质量。 #### configuration 参数 - [Limit Conn](https://docs.apiseven.com/hub/limit-conn/configuration.md): 参数 ### limit-count Limit Count 插件使用固定窗口算法对 Apache APISIX 路由进行请求速率限制,在指定时间窗口内限制请求次数,超出配额的请求将被拒绝,保护 API 网关后端服务。 - [limit-count](https://docs.apiseven.com/hub/limit-count.md): Limit Count 插件使用固定窗口算法对 Apache APISIX 路由进行请求速率限制,在指定时间窗口内限制请求次数,超出配额的请求将被拒绝,保护 API 网关后端服务。 #### configuration 参数 - [Limit Count](https://docs.apiseven.com/hub/limit-count/configuration.md): 参数 ### limit-count-advanced Limit Count Advanced 插件提供企业级 API 速率限制能力,支持多维度限流策略和共享计数器,在 Apache APISIX 网关层实现精细化的请求频率控制与流量管理。 - [limit-count-advanced 企业版](https://docs.apiseven.com/hub/limit-count-advanced.md): Limit Count Advanced 插件提供企业级 API 速率限制能力,支持多维度限流策略和共享计数器,在 Apache APISIX 网关层实现精细化的请求频率控制与流量管理。 #### configuration 参数 - [Limit Count Advanced](https://docs.apiseven.com/hub/limit-count-advanced/configuration.md): 参数 ### limit-req Limit Req 插件使用漏桶算法对 Apache APISIX 路由进行请求速率平滑限流,有效防止流量突刺对后端服务造成冲击,保障 API 网关的平稳运行和服务稳定性。 - [limit-req](https://docs.apiseven.com/hub/limit-req.md): Limit Req 插件使用漏桶算法对 Apache APISIX 路由进行请求速率平滑限流,有效防止流量突刺对后端服务造成冲击,保障 API 网关的平稳运行和服务稳定性。 #### configuration 参数 - [Limit Req](https://docs.apiseven.com/hub/limit-req/configuration.md): 参数 ### loki-logger loki-logger 插件通过 Loki HTTP API 将请求和响应日志作为 JSON 对象分批发送到 Grafana Loki,并支持自定义日志格式,以增强数据管理能力。 - [loki-logger](https://docs.apiseven.com/hub/loki-logger.md): loki-logger 插件通过 Loki HTTP API 将请求和响应日志作为 JSON 对象分批发送到 Grafana Loki,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [Loki Logger](https://docs.apiseven.com/hub/loki-logger/configuration.md): 参数 ### mcp-tools-acl mcp-tools-acl 插件为 openapi-to-mcp 路由上的 MCP 工具调用提供基于消费者的访问控制,支持基于规则的白名单和黑名单模式,并可通过表达式条件进行条件匹配。 - [mcp-tools-acl 企业版](https://docs.apiseven.com/hub/mcp-tools-acl.md): mcp-tools-acl 插件为 openapi-to-mcp 路由上的 MCP 工具调用提供基于消费者的访问控制,支持基于规则的白名单和黑名单模式,并可通过表达式条件进行条件匹配。 #### configuration 参数 - [MCP Tools ACL](https://docs.apiseven.com/hub/mcp-tools-acl/configuration.md): 参数 ### mocking Mocking 插件在 Apache APISIX 网关层返回预设的模拟响应,无需启动后端服务即可进行 API 开发和测试,加速前后端并行开发,提升 API 开发效率。 - [mocking](https://docs.apiseven.com/hub/mocking.md): Mocking 插件在 Apache APISIX 网关层返回预设的模拟响应,无需启动后端服务即可进行 API 开发和测试,加速前后端并行开发,提升 API 开发效率。 #### configuration 参数 - [Mocking](https://docs.apiseven.com/hub/mocking/configuration.md): 参数 ### mqtt-proxy MQTT Proxy 插件使 Apache APISIX 支持 MQTT 协议代理,将物联网设备的 MQTT 消息路由到对应的后端 Broker,实现 API 网关对 IoT 设备的统一接入与管理。 - [mqtt-proxy](https://docs.apiseven.com/hub/mqtt-proxy.md): MQTT Proxy 插件使 Apache APISIX 支持 MQTT 协议代理,将物联网设备的 MQTT 消息路由到对应的后端 Broker,实现 API 网关对 IoT 设备的统一接入与管理。 #### configuration 参数 - [MQTT Proxy](https://docs.apiseven.com/hub/mqtt-proxy/configuration.md): 参数 ### multi-auth Multi Auth 插件允许在 Apache APISIX 路由上同时配置多种认证方式,按顺序尝试各认证插件,灵活支持多种客户端认证机制,提升 API 网关的认证兼容性。 - [multi-auth](https://docs.apiseven.com/hub/multi-auth.md): Multi Auth 插件允许在 Apache APISIX 路由上同时配置多种认证方式,按顺序尝试各认证插件,灵活支持多种客户端认证机制,提升 API 网关的认证兼容性。 #### configuration 参数 - [Multi Auth](https://docs.apiseven.com/hub/multi-auth/configuration.md): 参数 ### oas-validator OAS Validator 插件在请求转发到上游服务前,根据 OpenAPI 规范校验传入的 HTTP 请求。 - [oas-validator](https://docs.apiseven.com/hub/oas-validator.md): OAS Validator 插件在请求转发到上游服务前,根据 OpenAPI 规范校验传入的 HTTP 请求。 #### configuration 参数 - [OAS Validator](https://docs.apiseven.com/hub/oas-validator/configuration.md): 参数 ### opa OPA 插件将 Apache APISIX 与 Open Policy Agent 集成,在 API 网关层实现基于策略的细粒度授权决策,支持复杂的访问控制逻辑,满足企业级合规要求。 - [OPA](https://docs.apiseven.com/hub/opa.md): OPA 插件将 Apache APISIX 与 Open Policy Agent 集成,在 API 网关层实现基于策略的细粒度授权决策,支持复杂的访问控制逻辑,满足企业级合规要求。 #### configuration 参数 - [OPA](https://docs.apiseven.com/hub/opa/configuration.md): 参数 ### openapi-to-mcp OpenAPI to MCP 插件将 OpenAPI 规范自动转换为 MCP(Model Context Protocol)工具,使 AI Agent 能够通过 API 网关直接调用 REST API,加速 AI 应用与 API 的集成。 - [openapi-to-mcp 企业版](https://docs.apiseven.com/hub/openapi-to-mcp.md): OpenAPI to MCP 插件将 OpenAPI 规范自动转换为 MCP(Model Context Protocol)工具,使 AI Agent 能够通过 API 网关直接调用 REST API,加速 AI 应用与 API 的集成。 #### configuration 静态配置 - [OpenAPI to MCP](https://docs.apiseven.com/hub/openapi-to-mcp/configuration.md): 静态配置 ### openid-connect OpenID Connect 插件为 Apache APISIX 提供标准的 OIDC 身份认证,支持与 Keycloak、Okta、Auth0 等身份提供商集成,在 API 网关层实现企业级单点登录(SSO)。 - [openid-connect](https://docs.apiseven.com/hub/openid-connect.md): OpenID Connect 插件为 Apache APISIX 提供标准的 OIDC 身份认证,支持与 Keycloak、Okta、Auth0 等身份提供商集成,在 API 网关层实现企业级单点登录(SSO)。 #### configuration 参数 - [OpenID Connect](https://docs.apiseven.com/hub/openid-connect/configuration.md): 参数 ### opentelemetry OpenTelemetry 插件将 Apache APISIX 的请求追踪数据上报到 OpenTelemetry Collector,支持与 Jaeger、Zipkin 等后端集成,实现 API 网关的分布式追踪。 - [OpenTelemetry](https://docs.apiseven.com/hub/opentelemetry.md): OpenTelemetry 插件将 Apache APISIX 的请求追踪数据上报到 OpenTelemetry Collector,支持与 Jaeger、Zipkin 等后端集成,实现 API 网关的分布式追踪。 #### configuration 参数 - [OpenTelemetry](https://docs.apiseven.com/hub/opentelemetry/configuration.md): 参数 ### prometheus Prometheus 插件与 Prometheus 集成,用于收集指标和持续监控,从而增强 API 可观测性。 - [Prometheus](https://docs.apiseven.com/hub/prometheus.md): Prometheus 插件与 Prometheus 集成,用于收集指标和持续监控,从而增强 API 可观测性。 #### configuration 静态配置 - [Prometheus](https://docs.apiseven.com/hub/prometheus/configuration.md): 静态配置 ### proxy-buffering Proxy Buffering 插件控制 Apache APISIX 对上游响应的缓冲行为,支持在网关层缓存响应数据后再转发给客户端,优化大响应体的传输性能和客户端体验。 - [proxy-buffering](https://docs.apiseven.com/hub/proxy-buffering.md): Proxy Buffering 插件控制 Apache APISIX 对上游响应的缓冲行为,支持在网关层缓存响应数据后再转发给客户端,优化大响应体的传输性能和客户端体验。 #### configuration 参数 - [Proxy Buffering](https://docs.apiseven.com/hub/proxy-buffering/configuration.md): 参数 ### proxy-cache Proxy Cache 插件在 Apache APISIX 网关层缓存上游 API 响应,支持磁盘和内存两种缓存模式,显著减少后端请求压力,提升 API 响应速度和整体服务性能。 - [proxy-cache](https://docs.apiseven.com/hub/proxy-cache.md): Proxy Cache 插件在 Apache APISIX 网关层缓存上游 API 响应,支持磁盘和内存两种缓存模式,显著减少后端请求压力,提升 API 响应速度和整体服务性能。 #### configuration 静态配置 - [Proxy Cache](https://docs.apiseven.com/hub/proxy-cache/configuration.md): 静态配置 ### proxy-mirror Proxy Mirror 插件将 Apache APISIX 的 API 请求实时镜像到指定目标服务,用于流量复制、灰度测试和线上问题复现,在不影响正常流量的情况下进行 API 调试。 - [proxy-mirror](https://docs.apiseven.com/hub/proxy-mirror.md): Proxy Mirror 插件将 Apache APISIX 的 API 请求实时镜像到指定目标服务,用于流量复制、灰度测试和线上问题复现,在不影响正常流量的情况下进行 API 调试。 #### configuration 静态配置 - [Proxy Mirror](https://docs.apiseven.com/hub/proxy-mirror/configuration.md): 静态配置 ### proxy-rewrite Proxy Rewrite 插件在 Apache APISIX 转发请求前修改请求的 URI、请求头和请求方法,实现 API 网关层的路由重写与请求改造,支持灵活的 API 路由策略配置。 - [proxy-rewrite](https://docs.apiseven.com/hub/proxy-rewrite.md): Proxy Rewrite 插件在 Apache APISIX 转发请求前修改请求的 URI、请求头和请求方法,实现 API 网关层的路由重写与请求改造,支持灵活的 API 路由策略配置。 #### configuration 参数 - [Proxy Rewrite](https://docs.apiseven.com/hub/proxy-rewrite/configuration.md): 参数 ### public-api Public API 插件将 Apache APISIX 内部 API(如自定义插件接口)暴露为公开可访问的端点,支持为内部服务创建公共 API 路由,扩展 API 网关的服务暴露能力。 - [public-api](https://docs.apiseven.com/hub/public-api.md): Public API 插件将 Apache APISIX 内部 API(如自定义插件接口)暴露为公开可访问的端点,支持为内部服务创建公共 API 路由,扩展 API 网关的服务暴露能力。 #### configuration 参数 - [Public API](https://docs.apiseven.com/hub/public-api/configuration.md): 参数 ### real-ip Real IP 插件从请求头(如 X-Forwarded-For)中提取真实客户端 IP 地址,替换 Apache APISIX 获取到的代理 IP,确保 API 网关后端服务获取准确的客户端来源信息。 - [real-ip](https://docs.apiseven.com/hub/real-ip.md): Real IP 插件从请求头(如 X-Forwarded-For)中提取真实客户端 IP 地址,替换 Apache APISIX 获取到的代理 IP,确保 API 网关后端服务获取准确的客户端来源信息。 #### configuration 参数 - [Real IP](https://docs.apiseven.com/hub/real-ip/configuration.md): 参数 ### request-id Request ID 插件为每个经过 Apache APISIX 的 API 请求自动生成唯一标识符,并添加到请求头中,便于分布式系统中的请求追踪、日志关联和问题排查。 - [request-id](https://docs.apiseven.com/hub/request-id.md): Request ID 插件为每个经过 Apache APISIX 的 API 请求自动生成唯一标识符,并添加到请求头中,便于分布式系统中的请求追踪、日志关联和问题排查。 #### configuration 参数 - [Request ID](https://docs.apiseven.com/hub/request-id/configuration.md): 参数 ### request-validation Request Validation 插件在 Apache APISIX 网关层根据 JSON Schema 验证 API 请求的参数和请求体,在请求到达后端前过滤非法数据,提升 API 安全性和数据质量。 - [request-validation](https://docs.apiseven.com/hub/request-validation.md): Request Validation 插件在 Apache APISIX 网关层根据 JSON Schema 验证 API 请求的参数和请求体,在请求到达后端前过滤非法数据,提升 API 安全性和数据质量。 #### configuration 参数 - [Request Validation](https://docs.apiseven.com/hub/request-validation/configuration.md): 参数 ### response-rewrite Response Rewrite 插件在 Apache APISIX 返回响应前修改响应状态码、响应头和响应体,实现 API 网关层的响应格式统一化,无需修改后端服务即可调整 API 输出。 - [response-rewrite](https://docs.apiseven.com/hub/response-rewrite.md): Response Rewrite 插件在 Apache APISIX 返回响应前修改响应状态码、响应头和响应体,实现 API 网关层的响应格式统一化,无需修改后端服务即可调整 API 输出。 #### configuration 参数 - [Response Rewrite](https://docs.apiseven.com/hub/response-rewrite/configuration.md): 参数 ### rocketmq-logger rocketmq-logger 插件将请求和响应日志作为 JSON 对象分批推送到 RocketMQ 集群,并支持自定义日志格式,以增强数据管理能力。 - [rocketmq-logger](https://docs.apiseven.com/hub/rocketmq-logger.md): rocketmq-logger 插件将请求和响应日志作为 JSON 对象分批推送到 RocketMQ 集群,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [RocketMQ Logger](https://docs.apiseven.com/hub/rocketmq-logger/configuration.md): 参数 ### saml-auth SAML Auth 插件为 Apache APISIX 提供基于 SAML 2.0 协议的身份认证,支持与企业 IdP(身份提供商)集成,在 API 网关层实现企业级联合身份认证与单点登录。 - [saml-auth](https://docs.apiseven.com/hub/saml-auth.md): SAML Auth 插件为 Apache APISIX 提供基于 SAML 2.0 协议的身份认证,支持与企业 IdP(身份提供商)集成,在 API 网关层实现企业级联合身份认证与单点登录。 #### configuration 参数 - [SAML Auth](https://docs.apiseven.com/hub/saml-auth/configuration.md): 参数 ### serverless-functions Serverless Functions 插件允许在 Apache APISIX 的请求处理阶段动态执行自定义 Lua 函数,无需重启网关即可扩展 API 网关功能,实现灵活的 Serverless 逻辑处理。 - [Serverless Functions](https://docs.apiseven.com/hub/serverless-functions.md): Serverless Functions 插件允许在 Apache APISIX 的请求处理阶段动态执行自定义 Lua 函数,无需重启网关即可扩展 API 网关功能,实现灵活的 Serverless 逻辑处理。 #### configuration 参数 - [Serverless Functions](https://docs.apiseven.com/hub/serverless-functions/configuration.md): 参数 ### skywalking SkyWalking 插件将 Apache APISIX 的分布式追踪数据上报到 Apache SkyWalking,实现 API 网关与微服务全链路追踪,帮助团队快速定位性能瓶颈和故障根因。 - [SkyWalking](https://docs.apiseven.com/hub/skywalking.md): SkyWalking 插件将 Apache APISIX 的分布式追踪数据上报到 Apache SkyWalking,实现 API 网关与微服务全链路追踪,帮助团队快速定位性能瓶颈和故障根因。 #### configuration 静态配置 - [skywalking](https://docs.apiseven.com/hub/skywalking/configuration.md): 静态配置 ### skywalking-logger skywalking-logger 插件将请求和响应日志作为 JSON 对象分批推送到 SkyWalking OAP 服务器,并支持自定义日志格式,以增强数据管理能力。 - [skywalking-logger](https://docs.apiseven.com/hub/skywalking-logger.md): skywalking-logger 插件将请求和响应日志作为 JSON 对象分批推送到 SkyWalking OAP 服务器,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [SkyWalking Logger](https://docs.apiseven.com/hub/skywalking-logger/configuration.md): 参数 ### soap SOAP 插件使 Apache APISIX 支持将 RESTful 请求转换为 SOAP 协议请求,让现代 API 客户端无缝访问传统 SOAP Web 服务,通过 API 网关实现新旧系统的协议桥接。 - [soap 企业版](https://docs.apiseven.com/hub/soap.md): SOAP 插件使 Apache APISIX 支持将 RESTful 请求转换为 SOAP 协议请求,让现代 API 客户端无缝访问传统 SOAP Web 服务,通过 API 网关实现新旧系统的协议桥接。 #### configuration 静态配置 - [SOAP](https://docs.apiseven.com/hub/soap/configuration.md): 静态配置 ### splunk-hec-logging splunk-hec-logging 插件将请求和响应上下文信息序列化为 Splunk Event Data 格式,再分批推送到 Splunk HTTP Event Collector(HEC),并支持自定义日志格式,以增强数据管理能力。 - [splunk-hec-logging](https://docs.apiseven.com/hub/splunk-hec-logging.md): splunk-hec-logging 插件将请求和响应上下文信息序列化为 Splunk Event Data 格式,再分批推送到 Splunk HTTP Event Collector(HEC),并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [splunk-hec-logging](https://docs.apiseven.com/hub/splunk-hec-logging/configuration.md): 参数 ### syslog syslog 插件将请求和响应日志作为 JSON 对象分批推送到 syslog 服务器,并支持自定义日志格式,以增强数据管理能力。 - [syslog](https://docs.apiseven.com/hub/syslog.md): syslog 插件将请求和响应日志作为 JSON 对象分批推送到 syslog 服务器,并支持自定义日志格式,以增强数据管理能力。 #### configuration 参数 - [syslog](https://docs.apiseven.com/hub/syslog/configuration.md): 参数 ### traffic-label Traffic Label 插件对请求表达式求值,并通过加权方式修改请求头,以实现基于条件的流量管理。 - [traffic-label](https://docs.apiseven.com/hub/traffic-label.md): Traffic Label 插件对请求表达式求值,并通过加权方式修改请求头,以实现基于条件的流量管理。 #### configuration 参数 - [Traffic Label](https://docs.apiseven.com/hub/traffic-label/configuration.md): 参数 ### traffic-split Traffic Split 插件在 Apache APISIX 中实现按比例的流量分割,支持灰度发布、蓝绿部署和 A/B 测试,通过 API 网关层的流量控制降低新版本发布风险。 - [traffic-split](https://docs.apiseven.com/hub/traffic-split.md): Traffic Split 插件在 Apache APISIX 中实现按比例的流量分割,支持灰度发布、蓝绿部署和 A/B 测试,通过 API 网关层的流量控制降低新版本发布风险。 #### configuration 参数 - [Traffic Split](https://docs.apiseven.com/hub/traffic-split/configuration.md): 参数 ### ua-restriction UA Restriction 插件基于 User-Agent 请求头对 Apache APISIX 路由进行访问控制,支持白名单和黑名单配置,有效阻止爬虫或未授权客户端访问 API 网关资源。 - [ua-restriction](https://docs.apiseven.com/hub/ua-restriction.md): UA Restriction 插件基于 User-Agent 请求头对 Apache APISIX 路由进行访问控制,支持白名单和黑名单配置,有效阻止爬虫或未授权客户端访问 API 网关资源。 #### configuration 参数 - [UA Restriction](https://docs.apiseven.com/hub/ua-restriction/configuration.md): 参数 ### workflow Workflow 插件允许在 Apache APISIX 中定义多步骤的请求处理工作流,支持条件判断和动作编排,实现复杂的 API 网关流量治理逻辑,无需编写自定义插件代码。 - [workflow](https://docs.apiseven.com/hub/workflow.md): Workflow 插件允许在 Apache APISIX 中定义多步骤的请求处理工作流,支持条件判断和动作编排,实现复杂的 API 网关流量治理逻辑,无需编写自定义插件代码。 #### configuration 参数 - [Workflow](https://docs.apiseven.com/hub/workflow/configuration.md): 参数 ### zipkin Zipkin 插件将 Apache APISIX 的分布式追踪数据上报到 Zipkin,支持与 Zipkin 兼容的追踪后端集成,为 API 网关提供请求链路追踪能力,助力微服务性能分析。 - [zipkin](https://docs.apiseven.com/hub/zipkin.md): Zipkin 插件将 Apache APISIX 的分布式追踪数据上报到 Zipkin,支持与 Zipkin 兼容的追踪后端集成,为 API 网关提供请求链路追踪能力,助力微服务性能分析。 #### configuration 静态配置 - [Zipkin](https://docs.apiseven.com/hub/zipkin/configuration.md): 静态配置 ## ai-gateway 通过专门的网关层路由 AI 请求,集中管理服务提供方密钥、模型别名、路由和流量策略。 - [AISIX AI 网关](https://docs.apiseven.com/ai-gateway.md): 通过专门的网关层路由 AI 请求,集中管理服务提供方密钥、模型别名、路由和流量策略。 ### agent-gateway #### agent-access-control 将每个 AISIX 调用方 API Key 的权限范围限定为精确的 A2A Agent 名称、名称模式或所有已注册 Agent。默认拒绝 A2A 访问。 - [控制 Agent 访问权限](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md): 将每个 AISIX 调用方 API Key 的权限范围限定为精确的 A2A Agent 名称、名称模式或所有已注册 Agent。默认拒绝 A2A 访问。 #### observability 查看 AISIX AI 网关中 A2A Agent 调用产生的用量事件和 Prometheus 指标,并通过协议标签将 A2A 流量与模型流量区分开。 - [可观测性](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md): 查看 AISIX AI 网关中 A2A Agent 调用产生的用量事件和 Prometheus 指标,并通过协议标签将 A2A 流量与模型流量区分开。 #### overview 通过 AISIX 公开 A2A Agent,并应用调用方访问控制、上游身份认证、限流、AISIX Cloud 预算和遥测。 - [Agent 网关概述](https://docs.apiseven.com/ai-gateway/agent-gateway/overview.md): 通过 AISIX 公开 A2A Agent,并应用调用方访问控制、上游身份认证、限流、AISIX Cloud 预算和遥测。 #### setup 在 AISIX Cloud 或开源 AISIX 网关中注册 A2A Agent,授予调用方访问权限,并使用官方 A2A Go SDK 客户端进行验证。 - [配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md): 在 AISIX Cloud 或开源 AISIX 网关中注册 A2A Agent,授予调用方访问权限,并使用官方 A2A Go SDK 客户端进行验证。 #### streaming-and-discovery 使用官方 A2A Go SDK 客户端测试 AISIX Agent 网关的流式传输,并通过公共源地址验证 Agent Card 发现。 - [A2A 流式传输与 Agent Card 发现](https://docs.apiseven.com/ai-gateway/agent-gateway/streaming-and-discovery.md): 使用官方 A2A Go SDK 客户端测试 AISIX Agent 网关的流式传输,并通过公共源地址验证 Agent Card 发现。 #### traffic-controls 对 AISIX 中的 A2A 调用应用调用方 API Key 请求和并发限制,并使用 AISIX Cloud 预算管理调用方的所有流量。 - [限流和预算](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md): 对 AISIX 中的 A2A 调用应用调用方 API Key 请求和并发限制,并使用 AISIX Cloud 预算管理调用方的所有流量。 #### upstream-authentication 配置 AISIX 如何在不使用凭证、使用 Bearer Token 或使用由网关保管的 API Key 时,向上游 A2A Agent 进行身份认证。 - [上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md): 配置 AISIX 如何在不使用凭证、使用 Bearer Token 或使用由网关保管的 API Key 时,向上游 A2A Agent 进行身份认证。 ### cloud #### admin-tokens 创建和管理用于组织级自动化的 AISIX Cloud Admin Token,包括权限范围、过期、轮换、吊销和 SCIM 访问。 - [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md): 创建和管理用于组织级自动化的 AISIX Cloud Admin Token,包括权限范围、过期、轮换、吊销和 SCIM 访问。 #### connect-a-gateway 使用控制台签发的 mTLS 凭证、部署片段和连接验证,将 AISIX 网关作为 AISIX Cloud 环境的数据面接入。 - [连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md): 使用控制台签发的 mTLS 凭证、部署片段和连接验证,将 AISIX 网关作为 AISIX Cloud 环境的数据面接入。 #### custom-roles 了解 AISIX Cloud 的 owner、admin、member 和自定义角色,并在控制面中分配细粒度权限与环境范围访问权限。 - [角色与自定义角色](https://docs.apiseven.com/ai-gateway/cloud/custom-roles.md): 了解 AISIX Cloud 的 owner、admin、member 和自定义角色,并在控制面中分配细粒度权限与环境范围访问权限。 #### high-availability 使用冗余 AISIX 网关、高韧性的控制面连接和上游故障转移,设计高可用的 AISIX Cloud 流量路径。 - [高可用](https://docs.apiseven.com/ai-gateway/cloud/high-availability.md): 使用冗余 AISIX 网关、高韧性的控制面连接和上游故障转移,设计高可用的 AISIX Cloud 流量路径。 #### kubernetes 使用 api7/aisix Helm Chart、HorizontalPodAutoscaler 或 KEDA,在 Kubernetes 上部署和扩缩作为 AISIX Cloud 数据面的 AISIX 网关。 - [在 Kubernetes 上部署 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md): 使用 api7/aisix Helm Chart、HorizontalPodAutoscaler 或 KEDA,在 Kubernetes 上部署和扩缩作为 AISIX Cloud 数据面的 AISIX 网关。 #### logging-and-auditing 了解 AISIX Cloud 控制面如何记录网关请求和资源变更。 - [日志与审计](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md): 了解 AISIX Cloud 控制面如何记录网关请求和资源变更。 #### members 为 AISIX Cloud 控制面访问或 API Key 归属添加组织成员。 - [成员](https://docs.apiseven.com/ai-gateway/cloud/members.md): 为 AISIX Cloud 控制面访问或 API Key 归属添加组织成员。 #### model-pricing 了解 AISIX Cloud 控制面如何计算每个请求的成本,以及如何为目录未覆盖的模型设置价格。 - [模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md): 了解 AISIX Cloud 控制面如何计算每个请求的成本,以及如何为目录未覆盖的模型设置价格。 #### offline-resilience 了解 AISIX 网关在控制面中断期间如何使用缓存配置提供服务,以及重启、预算、遥测和恢复行为。 - [离线韧性](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md): 了解 AISIX 网关在控制面中断期间如何使用缓存配置提供服务,以及重启、预算、遥测和恢复行为。 #### organizations-and-environments 创建和了解 AISIX Cloud 组织与环境,以及环境资源如何到达已连接的 AISIX 网关。 - [组织与环境](https://docs.apiseven.com/ai-gateway/cloud/organizations-and-environments.md): 创建和了解 AISIX Cloud 组织与环境,以及环境资源如何到达已连接的 AISIX 网关。 #### overview 了解 AISIX Cloud 如何提供集中管理能力,同时由你的环境中的 AISIX 网关直接处理 AI 流量。 - [AISIX Cloud](https://docs.apiseven.com/ai-gateway/cloud/overview.md): 了解 AISIX Cloud 如何提供集中管理能力,同时由你的环境中的 AISIX 网关直接处理 AI 流量。 #### playground 了解 AISIX Cloud Playground 请求与网关请求分别可以验证哪些内容。 - [Playground](https://docs.apiseven.com/ai-gateway/cloud/playground.md): 了解 AISIX Cloud Playground 请求与网关请求分别可以验证哪些内容。 #### resource-projection 了解 AISIX Cloud 如何投射环境资源,以及如何验证发布、网关应用和调用方可见行为。 - [资源投射](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md): 了解 AISIX Cloud 如何投射环境资源,以及如何验证发布、网关应用和调用方可见行为。 #### scim-directory-sync 使用 SCIM 2.0 从身份提供方自动预配 AISIX 组织成员。 - [SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md): 使用 SCIM 2.0 从身份提供方自动预配 AISIX 组织成员。 #### teams 将 AISIX Cloud 成员组织为团队,绑定调用方 API Key 以归因流量,并配置团队预算、限流和 MCP 访问权限。 - [团队](https://docs.apiseven.com/ai-gateway/cloud/teams.md): 将 AISIX Cloud 成员组织为团队,绑定调用方 API Key 以归因流量,并配置团队预算、限流和 MCP 访问权限。 #### usage-reporting 了解 AISIX Cloud 控制面如何上报网关用量、支出和预算相关信号。 - [用量上报](https://docs.apiseven.com/ai-gateway/cloud/usage-reporting.md): 了解 AISIX Cloud 控制面如何上报网关用量、支出和预算相关信号。 ### deployment #### configuration-propagation 了解资源变更如何到达 AISIX 网关、安全地重新加载声明式资源文件,并验证已应用的配置。 - [配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md): 了解资源变更如何到达 AISIX 网关、安全地重新加载声明式资源文件,并验证已应用的配置。 #### forward-proxy 将 AISIX 部署在终止 TLS 的出口代理之后,以统一治理 IDE AI 流量。本指南以 GitHub Copilot IDE 扩展和 Copilot CLI 为例进行说明。 - [IDE AI 流量正向代理](https://docs.apiseven.com/ai-gateway/deployment/forward-proxy.md): 将 AISIX 部署在终止 TLS 的出口代理之后,以统一治理 IDE AI 流量。本指南以 GitHub Copilot IDE 扩展和 Copilot CLI 为例进行说明。 #### health-checks 选择并解读 AISIX 网关的进程存活、流量就绪、模型健康和配置状态检查。 - [健康检查](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md): 选择并解读 AISIX 网关的进程存活、流量就绪、模型健康和配置状态检查。 #### network-and-security 使用正确的监听器暴露、配置来源隔离和凭证处理方式运行 AISIX AI 网关。 - [网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md): 使用正确的监听器暴露、配置来源隔离和凭证处理方式运行 AISIX AI 网关。 #### performance-and-sizing 了解 AISIX AI 网关的预期代理开销和吞吐能力,并根据请求量估算所需 CPU。 - [性能与容量规划](https://docs.apiseven.com/ai-gateway/deployment/performance-and-sizing.md): 了解 AISIX AI 网关的预期代理开销和吞吐能力,并根据请求量估算所需 CPU。 #### production 通过规划容量、依赖、网络暴露、健康检查、恢复和关闭,为 AISIX AI 网关接入生产流量做好准备。 - [生产就绪](https://docs.apiseven.com/ai-gateway/deployment/production.md): 通过规划容量、依赖、网络暴露、健康检查、恢复和关闭,为 AISIX AI 网关接入生产流量做好准备。 #### startup-configuration 配置 AISIX AI 网关启动设置,包括资源来源、监听器、运行时依赖、可观测性和 AISIX Cloud 连接。 - [启动配置](https://docs.apiseven.com/ai-gateway/deployment/startup-configuration.md): 配置 AISIX AI 网关启动设置,包括资源来源、监听器、运行时依赖、可观测性和 AISIX Cloud 连接。 #### thread-per-core-workers 配置 AISIX AI 网关的 Worker 线程和每核一线程服务模式,验证当前模式,并规划各 Worker 独立的上游连接池与共享监听器。 - [每核一线程 Worker](https://docs.apiseven.com/ai-gateway/deployment/thread-per-core-workers.md): 配置 AISIX AI 网关的 Worker 线程和每核一线程服务模式,验证当前模式,并规划各 Worker 独立的上游连接池与共享监听器。 #### tls-and-mtls 为 AISIX AI 网关配置监听器 TLS、上游信任、etcd mTLS 和 AISIX Cloud 控制面 mTLS。 - [TLS 与 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md): 为 AISIX AI 网关配置监听器 TLS、上游信任、etcd mTLS 和 AISIX Cloud 控制面 mTLS。 #### troubleshooting 诊断 AISIX AI 网关的启动、配置、调用方访问、策略、上游和 AISIX 网关故障。 - [故障排除](https://docs.apiseven.com/ai-gateway/deployment/troubleshooting.md): 诊断 AISIX AI 网关的启动、配置、调用方访问、策略、上游和 AISIX 网关故障。 #### url-rewriting 使用入口级重写规则将旧版或外部 URL 形式映射到 AISIX AI 网关端点,使现有客户端无需更改配置即可迁移。 - [URL 重写](https://docs.apiseven.com/ai-gateway/deployment/url-rewriting.md): 使用入口级重写规则将旧版或外部 URL 形式映射到 AISIX AI 网关端点,使现有客户端无需更改配置即可迁移。 ### endpoints #### anthropic-messages 了解 AISIX AI 网关如何处理 Anthropic 风格 Messages 请求,包括调用方密钥、模型别名、上游转换、Token 计数和错误处理。 - [Anthropic 风格 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md): 了解 AISIX AI 网关如何处理 Anthropic 风格 Messages 请求,包括调用方密钥、模型别名、上游转换、Token 计数和错误处理。 #### audio 了解 AISIX AI 网关如何处理 OpenAI 风格的音频转录、翻译和语音端点。 - [语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md): 了解 AISIX AI 网关如何处理 OpenAI 风格的音频转录、翻译和语音端点。 #### batch-files-fine-tuning 通过 AISIX AI 网关运行兼容 OpenAI 的 Files、Batch 和 Fine-tuning API,由网关管理服务提供方路由和批处理用量归因。 - [Batch、Files 与 Fine-tuning](https://docs.apiseven.com/ai-gateway/endpoints/batch-files-fine-tuning.md): 通过 AISIX AI 网关运行兼容 OpenAI 的 Files、Batch 和 Fine-tuning API,由网关管理服务提供方路由和批处理用量归因。 #### chat-audio 通过 AISIX 向兼容 OpenAI 的聊天模型发送音频,并保存非流式 Chat Completions 响应生成的音频。 - [使用 Chat Completions 输入和输出音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md): 通过 AISIX 向兼容 OpenAI 的聊天模型发送音频,并保存非流式 Chat Completions 响应生成的音频。 #### embeddings 了解 AISIX AI 网关如何处理 OpenAI 兼容的 embeddings 端点,包括请求格式和服务提供方限制。 - [向量嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md): 了解 AISIX AI 网关如何处理 OpenAI 兼容的 embeddings 端点,包括请求格式和服务提供方限制。 #### image-editing 通过 AISIX AI 网关的 /v1/images/edits 端点编辑图像,支持 multipart 上传、模型别名、提示词安全护栏和 Token 用量核算。 - [图像编辑](https://docs.apiseven.com/ai-gateway/endpoints/image-editing.md): 通过 AISIX AI 网关的 /v1/images/edits 端点编辑图像,支持 multipart 上传、模型别名、提示词安全护栏和 Token 用量核算。 #### image-generation 了解 AISIX AI 网关如何处理 OpenAI 图像生成端点及服务提供方支持情况。 - [图像生成](https://docs.apiseven.com/ai-gateway/endpoints/image-generation.md): 了解 AISIX AI 网关如何处理 OpenAI 图像生成端点及服务提供方支持情况。 #### openai-client-to-anthropic 使用兼容 OpenAI 的客户端调用由 Anthropic 支持的 AISIX 模型别名,并了解网关如何转换请求和响应。 - [OpenAI 客户端接入 Anthropic 上游](https://docs.apiseven.com/ai-gateway/endpoints/openai-client-to-anthropic.md): 使用兼容 OpenAI 的客户端调用由 Anthropic 支持的 AISIX 模型别名,并了解网关如何转换请求和响应。 #### openai-compatible-chat 了解 AISIX AI 网关如何处理兼容 OpenAI 的 POST /v1/chat/completions 请求、模型别名、身份认证、服务提供方转换和错误。 - [兼容 OpenAI 的 Chat Completions](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md): 了解 AISIX AI 网关如何处理兼容 OpenAI 的 POST /v1/chat/completions 请求、模型别名、身份认证、服务提供方转换和错误。 #### overview 比较 AISIX 面向调用方的 API 系列和代理路由,包括支持的操作、模型发现、健康检查和共享网关行为。 - [支持的端点](https://docs.apiseven.com/ai-gateway/endpoints/overview.md): 比较 AISIX 面向调用方的 API 系列和代理路由,包括支持的操作、模型发现、健康检查和共享网关行为。 #### provider-passthrough 通过 AISIX 透传路由中继服务提供方原生 API 和正向代理流量,并实施匹配、身份认证、凭证、管控和遥测。 - [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md): 通过 AISIX 透传路由中继服务提供方原生 API 和正向代理流量,并实施匹配、身份认证、凭证、管控和遥测。 #### realtime 通过 AISIX AI 网关连接 OpenAI Realtime WebSocket 客户端,由网关管理认证、策略执行和会话用量跟踪。 - [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md): 通过 AISIX AI 网关连接 OpenAI Realtime WebSocket 客户端,由网关管理认证、策略执行和会话用量跟踪。 #### request-lifecycle 了解 AISIX 如何认证调用方、解析模型别名、应用控制策略、路由到服务提供方并记录每个 AI 请求的用量。 - [请求生命周期](https://docs.apiseven.com/ai-gateway/endpoints/request-lifecycle.md): 了解 AISIX 如何认证调用方、解析模型别名、应用控制策略、路由到服务提供方并记录每个 AI 请求的用量。 #### rerank 了解 AISIX AI 网关如何通过支持重排序能力的服务提供方代理 rerank 请求。 - [重排序](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md): 了解 AISIX AI 网关如何通过支持重排序能力的服务提供方代理 rerank 请求。 #### responses-api 了解 AISIX AI 网关如何处理 OpenAI Responses API 及服务提供方支持情况。 - [Responses API 代理](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md): 了解 AISIX AI 网关如何处理 OpenAI Responses API 及服务提供方支持情况。 #### streaming 了解 AISIX AI 网关的流式响应行为,包括 OpenAI 风格和 Anthropic 风格流式链路。 - [流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md): 了解 AISIX AI 网关的流式响应行为,包括 OpenAI 风格和 Anthropic 风格流式链路。 #### text-completions 了解 AISIX AI 网关如何处理兼容 OpenAI 的文本补全请求。 - [文本补全](https://docs.apiseven.com/ai-gateway/endpoints/text-completions.md): 了解 AISIX AI 网关如何处理兼容 OpenAI 的文本补全请求。 #### tool-calling 了解 AISIX AI 网关中的工具调用行为,包括兼容 OpenAI 的请求和 Anthropic 转换。 - [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md): 了解 AISIX AI 网关中的工具调用行为,包括兼容 OpenAI 的请求和 Anthropic 转换。 #### video-generation 通过 AISIX AI 网关的 /v1/videos 端点异步提交任务、轮询状态并下载视频。 - [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md): 通过 AISIX AI 网关的 /v1/videos 端点异步提交任务、轮询状态并下载视频。 ### getting-started #### aisix-cloud-quickstart 使用 Docker Compose 部署 On-Premises AISIX Cloud 控制面、配置模型,并通过已连接的 AISIX 网关发送第一个请求。 - [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md): 使用 Docker Compose 部署 On-Premises AISIX Cloud 控制面、配置模型,并通过已连接的 AISIX 网关发送第一个请求。 #### anthropic-sdk 配置兼容 Anthropic 的客户端,通过 /v1/messages 代理 API 调用 AISIX AI 网关。 - [Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md): 配置兼容 Anthropic 的客户端,通过 /v1/messages 代理 API 调用 AISIX AI 网关。 #### gateway-quickstart 在单个容器中运行开源 AISIX 网关,在 resources.yaml 文件中声明模型服务提供方密钥、模型和调用方 API Key,并发送第一个请求。 - [开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md): 在单个容器中运行开源 AISIX 网关,在 resources.yaml 文件中声明模型服务提供方密钥、模型和调用方 API Key,并发送第一个请求。 #### openai-sdk 配置 OpenAI 官方 SDK,通过兼容 OpenAI 的代理 API 调用 AISIX AI 网关。 - [OpenAI SDK](https://docs.apiseven.com/ai-gateway/getting-started/openai-sdk.md): 配置 OpenAI 官方 SDK,通过兼容 OpenAI 的代理 API 调用 AISIX AI 网关。 #### products-and-deployment-options 对比开源 AISIX 网关与 AISIX Cloud 的 On-Premises 和 Hybrid Cloud 控制面部署选项。 - [AISIX 产品与部署选项](https://docs.apiseven.com/ai-gateway/getting-started/products-and-deployment-options.md): 对比开源 AISIX 网关与 AISIX Cloud 的 On-Premises 和 Hybrid Cloud 控制面部署选项。 ### integrations 将 SDK、编码 Agent、应用框架、AI 应用平台和语音 Agent 平台接入 AISIX AI 网关。 - [集成](https://docs.apiseven.com/ai-gateway/integrations.md): 将 SDK、编码 Agent、应用框架、AI 应用平台和语音 Agent 平台接入 AISIX AI 网关。 #### application-platforms 将 AI 应用平台连接到 AISIX AI 网关,治理模型访问,同时由平台继续运行工作流、工具、RAG 和用户界面。 - [AI 应用平台](https://docs.apiseven.com/ai-gateway/integrations/application-platforms.md): 将 AI 应用平台连接到 AISIX AI 网关,治理模型访问,同时由平台继续运行工作流、工具、RAG 和用户界面。 - [Dify](https://docs.apiseven.com/ai-gateway/integrations/application-platforms/dify.md): 配置 Dify 的 OpenAI-API-compatible 模型服务提供方插件,通过 AISIX AI 网关发送应用和 Agent 的模型请求。 - [n8n](https://docs.apiseven.com/ai-gateway/integrations/application-platforms/n8n.md): 配置 n8n OpenAI Chat Model,使用调用方密钥和模型别名,通过 AISIX AI 网关发送 AI Agent 和链的请求。 - [Open WebUI](https://docs.apiseven.com/ai-gateway/integrations/application-platforms/open-webui.md): 将 Open WebUI 连接到 AISIX AI 网关的兼容 OpenAI 端点,支持调用方身份认证、模型发现、流式响应和工具调用。 #### coding-agents 将编码 Agent 直接接入 AISIX,或通过正向代理接入,以使用 AISIX 的访问控制和遥测功能统一治理模型、工具及官方服务流量。 - [编码 Agent](https://docs.apiseven.com/ai-gateway/integrations/coding-agents.md): 将编码 Agent 直接接入 AISIX,或通过正向代理接入,以使用 AISIX 的访问控制和遥测功能统一治理模型、工具及官方服务流量。 - [Claude Code](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/claude-code.md): 配置 Claude Code 通过 AISIX AI 网关发送 Anthropic Messages 请求。 - [Cline](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/cline.md): 配置 Cline 通过 AISIX AI 网关发送兼容 OpenAI 的模型请求。 - [Codex](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/codex.md): 配置 Codex 通过 AISIX AI 网关发送 Responses API 请求。 - [Cursor](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/cursor.md): 配置 Cursor 通过 AISIX AI 网关发送兼容 OpenAI 的聊天流量。 #### frameworks - [CrewAI](https://docs.apiseven.com/ai-gateway/integrations/frameworks/crewai.md): 配置 CrewAI 通过 AISIX AI 网关发送兼容 OpenAI 的聊天流量。 - [Haystack](https://docs.apiseven.com/ai-gateway/integrations/frameworks/haystack.md): 配置 Haystack 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 - [Instructor](https://docs.apiseven.com/ai-gateway/integrations/frameworks/instructor.md): 配置 Instructor 通过 AISIX AI 网关发送 OpenAI Responses API 结构化输出请求。 - [LangChain 和 LangGraph](https://docs.apiseven.com/ai-gateway/integrations/frameworks/langchain.md): 配置 LangChain 和 LangGraph 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 - [LlamaIndex](https://docs.apiseven.com/ai-gateway/integrations/frameworks/llamaindex.md): 配置 LlamaIndex 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 - [Microsoft Agent Framework](https://docs.apiseven.com/ai-gateway/integrations/frameworks/microsoft-agent-framework.md): 配置 Microsoft Agent Framework 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 - [OpenAI Agents SDK](https://docs.apiseven.com/ai-gateway/integrations/frameworks/openai-agents-sdk.md): 配置 OpenAI Agents SDK 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 - [Pydantic AI](https://docs.apiseven.com/ai-gateway/integrations/frameworks/pydantic-ai.md): 配置 Pydantic AI 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 - [Vercel AI SDK](https://docs.apiseven.com/ai-gateway/integrations/frameworks/vercel-ai-sdk.md): 配置 Vercel AI SDK 通过 AISIX AI 网关发送 OpenAI Responses API 流量。 #### voice-agents 将语音 Agent 平台接入 AISIX AI 网关,使其文本模型请求使用网关身份认证、模型别名、路由、策略和遥测。 - [语音 Agent 平台](https://docs.apiseven.com/ai-gateway/integrations/voice-agents.md): 将语音 Agent 平台接入 AISIX AI 网关,使其文本模型请求使用网关身份认证、模型别名、路由、策略和遥测。 - [ElevenLabs Agents](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/elevenlabs.md): 配置 ElevenLabs Agent,将 AISIX AI 网关用作其 Custom LLM 端点,并使用受限的调用方 Key 和模型别名。 - [LiveKit Agents](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/livekit.md): 配置 LiveKit Agents OpenAI 插件,使用调用方 Key 和模型别名通过 AISIX AI 网关流式发送 Chat Completions 请求。 - [Pipecat](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/pipecat.md): 配置 Pipecat OpenAILLMService,在 Pipecat 运行语音流水线的同时,通过 AISIX AI 网关流式发送 Chat Completions 请求。 - [Vapi](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/vapi.md): 配置 Vapi 语音助手,将 AISIX AI 网关用作经过身份认证、兼容 OpenAI 的 Custom LLM 端点。 ### mcp-gateway #### access-policies 跨 AISIX Cloud 环境和团队管理 MCP 工具访问权限,并与每个调用方 API Key 自身的授权组合生效。 - [使用策略管理 MCP 访问权限](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md): 跨 AISIX Cloud 环境和团队管理 MCP 工具访问权限,并与每个调用方 API Key 自身的授权组合生效。 #### client-authentication 选择 MCP 客户端如何向 AISIX AI 网关进行身份认证——使用网关 API Key、通过 OAuth 登录,或从可信网络匿名访问。 - [客户端身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/client-authentication.md): 选择 MCP 客户端如何向 AISIX AI 网关进行身份认证——使用网关 API Key、通过 OAuth 登录,或从可信网络匿名访问。 #### cursor 使用调用方 API Key 将 Cursor 连接到 AISIX MCP 网关,发现已授权工具,并验证一次经由 AISIX 的完整工具调用。 - [将 Cursor 连接到 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/cursor.md): 使用调用方 API Key 将 Cursor 连接到 AISIX MCP 网关,发现已授权工具,并验证一次经由 AISIX 的完整工具调用。 #### guardrails 在 AISIX AI 网关中,对 MCP 工具调用参数和工具结果应用与模型流量相同的安全护栏,并在请求到达上游前阻断风险调用。 - [安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md): 在 AISIX AI 网关中,对 MCP 工具调用参数和工具结果应用与模型流量相同的安全护栏,并在请求到达上游前阻断风险调用。 #### observability 查看 AISIX AI 网关中 MCP 工具调用产生的用量事件和 Prometheus 指标,并通过协议标签将 MCP 流量与模型流量区分开。 - [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md): 查看 AISIX AI 网关中 MCP 工具调用产生的用量事件和 Prometheus 指标,并通过协议标签将 MCP 流量与模型流量区分开。 #### openapi-servers 使用 REST API 的 OpenAPI 文档注册该 API,让 AISIX AI 网关从其操作生成 MCP 工具,并把工具调用作为 HTTP 请求执行。 - [把 REST API 公开为 MCP 工具](https://docs.apiseven.com/ai-gateway/mcp-gateway/openapi-servers.md): 使用 REST API 的 OpenAPI 文档注册该 API,让 AISIX AI 网关从其操作生成 MCP 工具,并把工具调用作为 HTTP 请求执行。 #### overview 通过 AISIX AI 网关公开上游 MCP 服务器,并应用调用方 API Key 访问控制、上游身份认证、安全护栏、遥测和自动 MCP 协议版本协商。 - [MCP 网关概览](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md): 通过 AISIX AI 网关公开上游 MCP 服务器,并应用调用方 API Key 访问控制、上游身份认证、安全护栏、遥测和自动 MCP 协议版本协商。 #### server-review 在把 MCP 服务器注册和变更发布到网关前,通过 AISIX Cloud 进行审查,并撤销不再成立的批准。 - [审查并批准 MCP 服务器](https://docs.apiseven.com/ai-gateway/mcp-gateway/server-review.md): 在把 MCP 服务器注册和变更发布到网关前,通过 AISIX Cloud 进行审查,并撤销不再成立的批准。 #### setup 在 AISIX Cloud 或开源 AISIX 网关中注册上游 MCP 服务器,授权一个工具,并验证允许和拒绝的 MCP 调用。 - [设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md): 在 AISIX Cloud 或开源 AISIX 网关中注册上游 MCP 服务器,授权一个工具,并验证允许和拒绝的 MCP 调用。 #### tool-access-control 使用精确名称、按服务器通配符或全局通配符,把每把调用方 API Key 限定为可在 AISIX AI 网关中列出和调用的 MCP 工具。 - [控制 MCP 工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md): 使用精确名称、按服务器通配符或全局通配符,把每把调用方 API Key 限定为可在 AISIX AI 网关中列出和调用的 MCP 工具。 #### traffic-controls 以调用方 API Key 为边界,在 AISIX AI 网关中配置 MCP 请求和并发限制,以及 AISIX Cloud 预算。 - [限流和预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md): 以调用方 API Key 为边界,在 AISIX AI 网关中配置 MCP 请求和并发限制,以及 AISIX Cloud 预算。 #### upstream-authentication 配置 AISIX AI 网关如何通过无凭证、Bearer Token、API Key 或 OAuth 2.0 客户端凭证向每个上游 MCP 服务器执行身份认证。 - [上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md): 配置 AISIX AI 网关如何通过无凭证、Bearer Token、API Key 或 OAuth 2.0 客户端凭证向每个上游 MCP 服务器执行身份认证。 #### vscode 使用受保护的调用方密钥将 Visual Studio Code 连接到 AISIX MCP 网关,发现已授权工具,并验证一次完整工具调用。 - [将 VS Code 连接到 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/vscode.md): 使用受保护的调用方密钥将 Visual Studio Code 连接到 AISIX MCP 网关,发现已授权工具,并验证一次完整工具调用。 ### models #### model-aliases 在 AISIX 网关部署中配置直接模型别名和通配符模型别名,包括重试、定价、限流及其他模型级行为。 - [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md): 在 AISIX 网关部署中配置直接模型别名和通配符模型别名,包括重试、定价、限流及其他模型级行为。 #### provider-key-rotation 通过原地轮换和渐进迁移流程,在不同 AISIX 网关部署中轮换上游服务提供方凭证,同时保持调用方 API Key 和模型别名稳定。 - [服务提供方密钥轮换](https://docs.apiseven.com/ai-gateway/models/provider-key-rotation.md): 通过原地轮换和渐进迁移流程,在不同 AISIX 网关部署中轮换上游服务提供方凭证,同时保持调用方 API Key 和模型别名稳定。 #### provider-keys 在不同 AISIX 网关部署中配置服务提供方密钥,包括上游凭证、端点、适配器、请求头、兼容性覆盖和轮换。 - [服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md): 在不同 AISIX 网关部署中配置服务提供方密钥,包括上游凭证、端点、适配器、请求头、兼容性覆盖和轮换。 #### reasoning-effort-mapping 为每个直接模型改写推理力度值,无需修改客户端请求。 - [推理力度映射](https://docs.apiseven.com/ai-gateway/models/reasoning-effort-mapping.md): 为每个直接模型改写推理力度值,无需修改客户端请求。 #### resource-model 了解服务提供方密钥、模型、调用方 API Key、路由、流量控制和策略如何在不同 AISIX 网关部署中协同工作。 - [资源模型](https://docs.apiseven.com/ai-gateway/models/resource-model.md): 了解服务提供方密钥、模型、调用方 API Key、路由、流量控制和策略如何在不同 AISIX 网关部署中协同工作。 #### upstream-request-headers 在 AISIX 的任意代理面上把允许的调用方请求头转发给上游、在服务提供方密钥上注入请求上下文请求头,并了解 AISIX 绝不中继的请求头。 - [上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md): 在 AISIX 的任意代理面上把允许的调用方请求头转发给上游、在服务提供方密钥上注入请求上下文请求头,并了解 AISIX 绝不中继的请求头。 ### observability #### exporters 通过两种配置路径将 AISIX 网关请求遥测发送到 OTLP 收集器、对象存储、Datadog 或阿里云 SLS。 - [可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md): 通过两种配置路径将 AISIX 网关请求遥测发送到 OTLP 收集器、对象存储、Datadog 或阿里云 SLS。 #### load-logs-into-snowflake 将 AISIX 网关请求遥测导出到 Amazon S3 或 Azure Blob,通过 Snowpipe 摄取记录,并通过 Snowflake 视图查询。 - [将请求遥测加载到 Snowflake](https://docs.apiseven.com/ai-gateway/observability/load-logs-into-snowflake.md): 将 AISIX 网关请求遥测导出到 Amazon S3 或 Azure Blob,通过 Snowpipe 摄取记录,并通过 Snowflake 视图查询。 #### metrics-and-logs 使用 Prometheus 指标、结构化访问日志、响应头和可导出的逐次尝试用量事件监控 AISIX 网关流量。 - [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md): 使用 Prometheus 指标、结构化访问日志、响应头和可导出的逐次尝试用量事件监控 AISIX 网关流量。 ### on-premises #### deployment 规划生产资源,并通过 Docker Compose、Helm 或离线包在自有基础设施中安装 AISIX Cloud 控制面。 - [私有化安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md): 规划生产资源,并通过 Docker Compose、Helm 或离线包在自有基础设施中安装 AISIX Cloud 控制面。 #### external-database 为使用 Helm 安装的 AISIX Cloud 控制面准备外部 PostgreSQL 数据库和最小权限角色,无需授予超级用户权限。 - [外部数据库](https://docs.apiseven.com/ai-gateway/on-premises/external-database.md): 为使用 Helm 安装的 AISIX Cloud 控制面准备外部 PostgreSQL 数据库和最小权限角色,无需授予超级用户权限。 #### upgrade AISIX 支持的升级路径、控制面优先的升级顺序,以及部署包安装、Helm 安装和网关的升级方法。 - [升级 AISIX](https://docs.apiseven.com/ai-gateway/on-premises/upgrade.md): AISIX 支持的升级路径、控制面优先的升级顺序,以及部署包安装、Helm 安装和网关的升级方法。 ### providers #### adapters 了解 AISIX 网关部署可用的 OpenAI、Anthropic、Amazon Bedrock、Google Vertex AI 和 Azure OpenAI 协议适配器族。 - [适配器协议族](https://docs.apiseven.com/ai-gateway/providers/adapters.md): 了解 AISIX 网关部署可用的 OpenAI、Anthropic、Amazon Bedrock、Google Vertex AI 和 Azure OpenAI 协议适配器族。 #### amazon-nova 将 Amazon Nova 直连 API 接入 AISIX 网关部署。配置 API 凭证、Nova 模型别名、调用方 API Key 和模型访问控制。 - [Amazon Nova API](https://docs.apiseven.com/ai-gateway/providers/amazon-nova.md): 将 Amazon Nova 直连 API 接入 AISIX 网关部署。配置 API 凭证、Nova 模型别名、调用方 API Key 和模型访问控制。 #### anthropic 通过原生 Messages API 或兼容 OpenAI 的 API,将 Anthropic Claude 接入 AISIX 网关部署,并配置凭证、模型别名和调用方访问权限。 - [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md): 通过原生 Messages API 或兼容 OpenAI 的 API,将 Anthropic Claude 接入 AISIX 网关部署,并配置凭证、模型别名和调用方访问权限。 #### aws-bedrock 使用 SigV4 将 AWS Bedrock 接入 AISIX 网关部署,并配置区域端点、模型或推理配置文件别名、调用方密钥和访问控制。 - [AWS Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md): 使用 SigV4 将 AWS Bedrock 接入 AISIX 网关部署,并配置区域端点、模型或推理配置文件别名、调用方密钥和访问控制。 #### azure-openai 使用资源 API Key 或 Microsoft Entra ID 将 Azure OpenAI 接入 AISIX 网关部署,并配置部署别名、调用方密钥和访问控制。 - [Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md): 使用资源 API Key 或 Microsoft Entra ID 将 Azure OpenAI 接入 AISIX 网关部署,并配置部署别名、调用方密钥和访问控制。 #### baseten 将 Baseten Model APIs 或专用端点接入 AISIX 网关部署。配置凭证、模型别名、调用方密钥和访问控制。 - [Baseten](https://docs.apiseven.com/ai-gateway/providers/baseten.md): 将 Baseten Model APIs 或专用端点接入 AISIX 网关部署。配置凭证、模型别名、调用方密钥和访问控制。 #### bring-your-own-endpoint 将 AISIX 网关部署连接到 vLLM、SGLang 或 Ollama 等私有 OpenAI 兼容端点,并配置凭证、别名和自定义 Token 定价。 - [自带端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md): 将 AISIX 网关部署连接到 vLLM、SGLang 或 Ollama 等私有 OpenAI 兼容端点,并配置凭证、别名和自定义 Token 定价。 #### cerebras 通过 OpenAI 兼容 API 将 Cerebras Inference 接入 AISIX 网关部署。配置凭证、模型别名、调用方密钥和访问控制。 - [Cerebras](https://docs.apiseven.com/ai-gateway/providers/cerebras.md): 通过 OpenAI 兼容 API 将 Cerebras Inference 接入 AISIX 网关部署。配置凭证、模型别名、调用方密钥和访问控制。 #### cloudflare-workers-ai 将 Cloudflare Workers AI 接入 AISIX。配置账户范围的凭证、模型别名、原生 Responses 和调用方访问权限。 - [Cloudflare Workers AI](https://docs.apiseven.com/ai-gateway/providers/cloudflare-workers-ai.md): 将 Cloudflare Workers AI 接入 AISIX。配置账户范围的凭证、模型别名、原生 Responses 和调用方访问权限。 #### cohere 将 Cohere 接入 AISIX 网关部署,用于 Command 聊天模型、Embedding 和 rerank。配置服务提供方凭证、模型别名和调用方访问权限。 - [Cohere](https://docs.apiseven.com/ai-gateway/providers/cohere.md): 将 Cohere 接入 AISIX 网关部署,用于 Command 聊天模型、Embedding 和 rerank。配置服务提供方凭证、模型别名和调用方访问权限。 #### compatibility 对比 AISIX 网关部署中的服务提供方协议和代理端点支持,包括聊天、向量嵌入、媒体、Realtime 和任务 API。 - [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md): 对比 AISIX 网关部署中的服务提供方协议和代理端点支持,包括聊天、向量嵌入、媒体、Realtime 和任务 API。 #### databricks 将 Databricks Model Serving 接入 AISIX 网关部署。配置工作区端点、服务提供方凭证、模型别名、调用方密钥和访问控制。 - [Databricks](https://docs.apiseven.com/ai-gateway/providers/databricks.md): 将 Databricks Model Serving 接入 AISIX 网关部署。配置工作区端点、服务提供方凭证、模型别名、调用方密钥和访问控制。 #### deepinfra 将 DeepInfra 接入 AISIX,并配置 OpenAI 兼容端点、原生 Messages 端点、凭证、模型别名和调用方访问权限。 - [DeepInfra](https://docs.apiseven.com/ai-gateway/providers/deepinfra.md): 将 DeepInfra 接入 AISIX,并配置 OpenAI 兼容端点、原生 Messages 端点、凭证、模型别名和调用方访问权限。 #### deepseek 通过 OpenAI 兼容 API 将 DeepSeek 模型接入 AISIX 网关部署,并配置服务提供方凭证、模型别名、调用方密钥和访问控制。 - [DeepSeek](https://docs.apiseven.com/ai-gateway/providers/deepseek.md): 通过 OpenAI 兼容 API 将 DeepSeek 模型接入 AISIX 网关部署,并配置服务提供方凭证、模型别名、调用方密钥和访问控制。 #### digitalocean-gradient-ai 将 DigitalOcean Gradient AI 接入 AISIX。配置推理凭证、模型别名、原生 Responses、调用方密钥和访问控制。 - [DigitalOcean Gradient AI](https://docs.apiseven.com/ai-gateway/providers/digitalocean-gradient-ai.md): 将 DigitalOcean Gradient AI 接入 AISIX。配置推理凭证、模型别名、原生 Responses、调用方密钥和访问控制。 #### fireworks-ai 通过兼容 OpenAI 的 API 将 Fireworks AI 接入 AISIX。配置凭证、模型别名、原生 Responses、推理和调用方访问权限。 - [Fireworks AI](https://docs.apiseven.com/ai-gateway/providers/fireworks-ai.md): 通过兼容 OpenAI 的 API 将 Fireworks AI 接入 AISIX。配置凭证、模型别名、原生 Responses、推理和调用方访问权限。 #### gemini 通过 AI Studio 兼容 OpenAI 的 API 将 Google Gemini 接入 AISIX 网关部署。配置凭证、模型别名、调用方密钥和访问控制。 - [Gemini (Google AI Studio)](https://docs.apiseven.com/ai-gateway/providers/gemini.md): 通过 AI Studio 兼容 OpenAI 的 API 将 Google Gemini 接入 AISIX 网关部署。配置凭证、模型别名、调用方密钥和访问控制。 #### google-vertex-ai 将 Google Vertex AI 接入 AISIX。配置服务账号凭证、全局或区域端点与模型别名,并了解适配器限制。 - [Google Vertex AI](https://docs.apiseven.com/ai-gateway/providers/google-vertex-ai.md): 将 Google Vertex AI 接入 AISIX。配置服务账号凭证、全局或区域端点与模型别名,并了解适配器限制。 #### groq 通过兼容 OpenAI 的 API 将 Groq 接入 AISIX。配置凭证、模型别名、原生 Responses、音频、批处理和调用方访问权限。 - [Groq](https://docs.apiseven.com/ai-gateway/providers/groq.md): 通过兼容 OpenAI 的 API 将 Groq 接入 AISIX。配置凭证、模型别名、原生 Responses、音频、批处理和调用方访问权限。 #### huggingface 将 Hugging Face Inference Providers 接入 AISIX。配置路由器凭证、模型别名、原生 Responses、路由和调用方访问权限。 - [Hugging Face](https://docs.apiseven.com/ai-gateway/providers/huggingface.md): 将 Hugging Face Inference Providers 接入 AISIX。配置路由器凭证、模型别名、原生 Responses、路由和调用方访问权限。 #### jina 将 Jina AI Embedding 和重排序模型接入 AISIX 网关部署,并了解模型、路由、透传和核算边界。 - [Jina](https://docs.apiseven.com/ai-gateway/providers/jina.md): 将 Jina AI Embedding 和重排序模型接入 AISIX 网关部署,并了解模型、路由、透传和核算边界。 #### meta-llama-api 通过兼容 OpenAI 的端点将 Meta Llama API 接入 AISIX,并使用正确的 API Base、示例模型和路由边界。 - [Meta Llama API](https://docs.apiseven.com/ai-gateway/providers/meta-llama-api.md): 通过兼容 OpenAI 的端点将 Meta Llama API 接入 AISIX,并使用正确的 API Base、示例模型和路由边界。 #### minimax 通过 OpenAI 和 Anthropic 兼容 API 将 MiniMax 模型接入 AISIX,并配置端点、凭证、别名和调用方访问权限。 - [MiniMax](https://docs.apiseven.com/ai-gateway/providers/minimax.md): 通过 OpenAI 和 Anthropic 兼容 API 将 MiniMax 模型接入 AISIX,并配置端点、凭证、别名和调用方访问权限。 #### mistral 将 Mistral AI 接入 AISIX 的 Chat 和兼容端点,并配置模型别名、结构化响应边界与透传路由。 - [Mistral AI](https://docs.apiseven.com/ai-gateway/providers/mistral.md): 将 Mistral AI 接入 AISIX 的 Chat 和兼容端点,并配置模型别名、结构化响应边界与透传路由。 #### modelscope 将 ModelScope API-Inference 接入 AISIX 网关部署。配置兼容 OpenAI 的端点、带命名空间的模型 ID、模型服务提供方密钥和调用方访问权限。 - [ModelScope](https://docs.apiseven.com/ai-gateway/providers/modelscope.md): 将 ModelScope API-Inference 接入 AISIX 网关部署。配置兼容 OpenAI 的端点、带命名空间的模型 ID、模型服务提供方密钥和调用方访问权限。 #### moonshotai 将 Moonshot AI 和 Kimi 模型接入 AISIX 网关部署。配置区域端点、凭证、模型别名、思考模式和调用方访问权限。 - [Moonshot AI(Kimi)](https://docs.apiseven.com/ai-gateway/providers/moonshotai.md): 将 Moonshot AI 和 Kimi 模型接入 AISIX 网关部署。配置区域端点、凭证、模型别名、思考模式和调用方访问权限。 #### nebius-token-factory 通过兼容 OpenAI 的 API 将 Nebius Token Factory 接入 AISIX,并配置模型别名、端点兼容性和面向原生 API 的透传路由。 - [Nebius Token Factory](https://docs.apiseven.com/ai-gateway/providers/nebius-token-factory.md): 通过兼容 OpenAI 的 API 将 Nebius Token Factory 接入 AISIX,并配置模型别名、端点兼容性和面向原生 API 的透传路由。 #### novita-ai 通过兼容 OpenAI 的 API 将 Novita AI 接入 AISIX,并配置模型别名、端点兼容性、批处理工作流和透传路由。 - [Novita AI](https://docs.apiseven.com/ai-gateway/providers/novita-ai.md): 通过兼容 OpenAI 的 API 将 Novita AI 接入 AISIX,并配置模型别名、端点兼容性、批处理工作流和透传路由。 #### nvidia-nim 将托管或私有部署的 NVIDIA NIM 模型连接到 AISIX 网关部署,并配置端点凭证、带命名空间的模型别名和调用方访问权限。 - [NVIDIA NIM](https://docs.apiseven.com/ai-gateway/providers/nvidia-nim.md): 将托管或私有部署的 NVIDIA NIM 模型连接到 AISIX 网关部署,并配置端点凭证、带命名空间的模型别名和调用方访问权限。 #### ollama 将 Ollama 服务器接入 AISIX,并配置私有端点、原生 Responses、通过透传访问的 Anthropic 兼容 Messages,以及模型别名。 - [Ollama](https://docs.apiseven.com/ai-gateway/providers/ollama.md): 将 Ollama 服务器接入 AISIX,并配置私有端点、原生 Responses、通过透传访问的 Anthropic 兼容 Messages,以及模型别名。 #### openai 将 OpenAI 聊天模型和 Sora 视频生成接入 AISIX 网关部署,并配置凭证、模型别名、调用方 API Key、访问控制、限流和请求验证。 - [OpenAI](https://docs.apiseven.com/ai-gateway/providers/openai.md): 将 OpenAI 聊天模型和 Sora 视频生成接入 AISIX 网关部署,并配置凭证、模型别名、调用方 API Key、访问控制、限流和请求验证。 #### openai-compatible-vendors 使用明确的 API 端点、服务提供方凭证、模型别名和调用方密钥,在 AISIX 网关部署中配置公开的 OpenAI 兼容 LLM 服务提供方。 - [其他 OpenAI 兼容服务提供方](https://docs.apiseven.com/ai-gateway/providers/openai-compatible-vendors.md): 使用明确的 API 端点、服务提供方凭证、模型别名和调用方密钥,在 AISIX 网关部署中配置公开的 OpenAI 兼容 LLM 服务提供方。 #### openrouter 通过兼容 OpenAI 的 API 将 OpenRouter 接入 AISIX。配置凭证、带命名空间的模型别名、原生 Responses、路由和调用方访问权限。 - [OpenRouter](https://docs.apiseven.com/ai-gateway/providers/openrouter.md): 通过兼容 OpenAI 的 API 将 OpenRouter 接入 AISIX。配置凭证、带命名空间的模型别名、原生 Responses、路由和调用方访问权限。 #### overview 对比 AISIX 网关部署支持的托管 AI 服务提供方接口和私有模型服务器,包括原生适配器、社区服务提供方、Ollama 和 vLLM。 - [选择服务提供方上游](https://docs.apiseven.com/ai-gateway/providers/overview.md): 对比 AISIX 网关部署支持的托管 AI 服务提供方接口和私有模型服务器,包括原生适配器、社区服务提供方、Ollama 和 vLLM。 #### ovhcloud-ai-endpoints 将 OVHcloud AI Endpoints 接入 AISIX。配置凭证、模型别名、原生 Responses、调用方密钥和端点限制。 - [OVHcloud AI Endpoints](https://docs.apiseven.com/ai-gateway/providers/ovhcloud-ai-endpoints.md): 将 OVHcloud AI Endpoints 接入 AISIX。配置凭证、模型别名、原生 Responses、调用方密钥和端点限制。 #### perplexity 通过 OpenAI 兼容 API 将 Perplexity Sonar 模型连接到 AISIX 网关部署,并配置凭证、模型别名、调用方密钥和访问控制。 - [Perplexity](https://docs.apiseven.com/ai-gateway/providers/perplexity.md): 通过 OpenAI 兼容 API 将 Perplexity Sonar 模型连接到 AISIX 网关部署,并配置凭证、模型别名、调用方密钥和访问控制。 #### qwen 将 Qwen 和 Wan 接入 AISIX,并配置区域 Model Studio 端点、原生 Responses、模型别名、视频生成和调用方访问权限。 - [Qwen(阿里云)](https://docs.apiseven.com/ai-gateway/providers/qwen.md): 将 Qwen 和 Wan 接入 AISIX,并配置区域 Model Studio 端点、原生 Responses、模型别名、视频生成和调用方访问权限。 #### runwayml 通过 AISIX 视频 API 将 RunwayML 视频生成连接到 AISIX 网关部署,并配置凭证、模型别名、调用方密钥和访问控制。 - [RunwayML](https://docs.apiseven.com/ai-gateway/providers/runwayml.md): 通过 AISIX 视频 API 将 RunwayML 视频生成连接到 AISIX 网关部署,并配置凭证、模型别名、调用方密钥和访问控制。 #### siliconflow 通过 OpenAI 兼容 API 将 SiliconFlow 连接到 AISIX 网关部署。配置凭证、带命名空间的模型 ID、别名和调用方访问权限。 - [SiliconFlow](https://docs.apiseven.com/ai-gateway/providers/siliconflow.md): 通过 OpenAI 兼容 API 将 SiliconFlow 连接到 AISIX 网关部署。配置凭证、带命名空间的模型 ID、别名和调用方访问权限。 #### snowflake-cortex 将 Snowflake Cortex 连接到 AISIX 网关部署。配置账户专用的 OpenAI 兼容端点、凭证、模型别名和调用方访问权限。 - [Snowflake Cortex](https://docs.apiseven.com/ai-gateway/providers/snowflake-cortex.md): 将 Snowflake Cortex 连接到 AISIX 网关部署。配置账户专用的 OpenAI 兼容端点、凭证、模型别名和调用方访问权限。 #### together 通过 OpenAI 兼容 API 将 Together AI 接入 AISIX 网关部署,并配置服务提供方凭证、模型别名、调用方密钥和访问控制。 - [Together AI](https://docs.apiseven.com/ai-gateway/providers/together.md): 通过 OpenAI 兼容 API 将 Together AI 接入 AISIX 网关部署,并配置服务提供方凭证、模型别名、调用方密钥和访问控制。 #### vllm 将私有 vLLM 服务器接入 AISIX,并配置原生 Responses、通过透传访问的 Anthropic 兼容 Messages、凭证和模型别名。 - [vLLM](https://docs.apiseven.com/ai-gateway/providers/vllm.md): 将私有 vLLM 服务器接入 AISIX,并配置原生 Responses、通过透传访问的 Anthropic 兼容 Messages、凭证和模型别名。 #### volcengine-ark 将 Volcengine Ark 接入 AISIX,以使用原生 Responses 和 Messages、豆包聊天及 Seedance 视频,并配置凭证、别名和调用方访问权限。 - [Volcengine Ark (Doubao)](https://docs.apiseven.com/ai-gateway/providers/volcengine-ark.md): 将 Volcengine Ark 接入 AISIX,以使用原生 Responses 和 Messages、豆包聊天及 Seedance 视频,并配置凭证、别名和调用方访问权限。 #### wandb-inference 通过 OpenAI 兼容 API 将 Weights & Biases Inference 连接到 AISIX 网关部署。配置凭证、模型别名和调用方访问权限。 - [Weights & Biases Inference](https://docs.apiseven.com/ai-gateway/providers/wandb-inference.md): 通过 OpenAI 兼容 API 将 Weights & Biases Inference 连接到 AISIX 网关部署。配置凭证、模型别名和调用方访问权限。 #### xai 通过原生 Responses 和 Chat Completions API 将 xAI Grok 模型连接到 AISIX。配置凭证、别名、区域端点和调用方访问权限。 - [xAI (Grok)](https://docs.apiseven.com/ai-gateway/providers/xai.md): 通过原生 Responses 和 Chat Completions API 将 xAI Grok 模型连接到 AISIX。配置凭证、别名、区域端点和调用方访问权限。 #### zhipuai 将 Zhipu AI 接入 AISIX 网关部署,用于 GLM Chat 和 CogVideoX 视频生成,并配置 API 凭证、模型别名和调用方访问权限。 - [Zhipu AI (GLM)](https://docs.apiseven.com/ai-gateway/providers/zhipuai.md): 将 Zhipu AI 接入 AISIX 网关部署,用于 GLM Chat 和 CogVideoX 视频生成,并配置 API 凭证、模型别名和调用方访问权限。 ### reference #### cli AISIX 网关命令参考,包括验证声明式资源以及将 etcd 配置导出到 resources.yaml 文件。 - [CLI 参考](https://docs.apiseven.com/ai-gateway/reference/cli.md): AISIX 网关命令参考,包括验证声明式资源以及将 etcd 配置导出到 resources.yaml 文件。 #### cloud-admin-api AISIX Cloud Admin API 的各发布版本参考文档与版本间变更对照。 - [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md): AISIX Cloud Admin API 的各发布版本参考文档与版本间变更对照。 #### config-status AISIX 网关配置状态端点和指标参考,包括已应用、被拒绝、使用陈旧值提供服务和部分兼容的资源。 - [配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md): AISIX 网关配置状态端点和指标参考,包括已应用、被拒绝、使用陈旧值提供服务和部分兼容的资源。 #### configuration-files AISIX 网关启动配置格式、资源来源、连接设置、加载优先级和常用选项参考。 - [启动配置参考](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md): AISIX 网关启动配置格式、资源来源、连接设置、加载优先级和常用选项参考。 #### environment-variables AISIX AI 网关用于配置文件、启动覆盖、AISIX 网关和运行时调优的环境变量参考。 - [环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md): AISIX AI 网关用于配置文件、启动覆盖、AISIX 网关和运行时调优的环境变量参考。 #### headers-and-error-codes AISIX 网关代理、MCP、A2A 和透传路由的响应头、状态码与错误信封参考。 - [响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md): AISIX 网关代理、MCP、A2A 和透传路由的响应头、状态码与错误信封参考。 #### metric-labels 配置每个 Prometheus 指标输出的标签,并查询所有支持的变量和默认标签。 - [指标标签与变量](https://docs.apiseven.com/ai-gateway/reference/metric-labels.md): 配置每个 Prometheus 指标输出的标签,并查询所有支持的变量和默认标签。 #### metrics AISIX AI 网关 Prometheus 指标参考,涵盖流量、延迟、Token、成本、缓存、安全护栏和上游健康状态。 - [指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md): AISIX AI 网关 Prometheus 指标参考,涵盖流量、延迟、Token、成本、缓存、安全护栏和上游健康状态。 #### on-premises-configuration 在自有基础设施中运行 AISIX Cloud 控制面所使用的 Docker Compose 环境变量和 Helm 配置值参考。 - [On-Premises 配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md): 在自有基础设施中运行 AISIX Cloud 控制面所使用的 Docker Compose 环境变量和 Helm 配置值参考。 #### ports AISIX 网关和 AISIX Cloud 控制面的默认端口、流量方向、配置方式与建议网络暴露范围参考。 - [端口参考](https://docs.apiseven.com/ai-gateway/reference/ports.md): AISIX 网关和 AISIX Cloud 控制面的默认端口、流量方向、配置方式与建议网络暴露范围参考。 #### proxy-api AISIX 网关代理路由、身份认证、模型发现、路由行为和端点约束参考。 - [代理 API 参考](https://docs.apiseven.com/ai-gateway/reference/proxy-api.md): AISIX 网关代理路由、身份认证、模型发现、路由行为和端点约束参考。 #### resources-file 使用本参考中的受支持集合、字段、环境变量插值和校验规则,通过 resources.yaml 配置 AISIX AI 网关。 - [资源文件参考](https://docs.apiseven.com/ai-gateway/reference/resources-file.md): 使用本参考中的受支持集合、字段、环境变量插值和校验规则,通过 resources.yaml 配置 AISIX AI 网关。 ### release-notes 各 AISIX AI 网关版本的新功能、改进和修复。 - [发布说明](https://docs.apiseven.com/ai-gateway/release-notes.md): 各 AISIX AI 网关版本的新功能、改进和修复。 ### routing #### ensemble-models 在 AISIX 网关部署中配置合议模型,以并发分发聊天请求、合成合议成员响应,并管理延迟、成本和失败。 - [合议模型](https://docs.apiseven.com/ai-gateway/routing/ensemble-models.md): 在 AISIX 网关部署中配置合议模型,以并发分发聊天请求、合成合议成员响应,并管理延迟、成本和失败。 #### proxy-errors-and-retries 了解客户端应用应如何处理 AISIX AI 网关代理错误、重试信号和上游故障。 - [代理错误与重试](https://docs.apiseven.com/ai-gateway/routing/proxy-errors-and-retries.md): 了解客户端应用应如何处理 AISIX AI 网关代理错误、重试信号和上游故障。 #### routing-and-failover 在 AISIX 网关部署中配置并测试多目标路由和故障转移,包括选择策略、重试、运行时过滤和恢复。 - [多目标路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md): 在 AISIX 网关部署中配置并测试多目标路由和故障转移,包括选择策略、重试、运行时过滤和恢复。 #### semantic-routing 在 AISIX 网关部署中配置语义路由,根据请求语义选择直接模型、调整相似度阈值,并定义安全的回退行为。 - [语义路由](https://docs.apiseven.com/ai-gateway/routing/semantic-routing.md): 在 AISIX 网关部署中配置语义路由,根据请求语义选择直接模型、调整相似度阈值,并定义安全的回退行为。 ### traffic-controls #### budget-alerts 配置 AISIX Cloud 预算告警,在 AI 支出超过预算限额的指定百分比时,通过 Webhook 或 Slack 通知运维人员。 - [预算告警与通知](https://docs.apiseven.com/ai-gateway/traffic-controls/budget-alerts.md): 配置 AISIX Cloud 预算告警,在 AI 支出超过预算限额的指定百分比时,通过 Webhook 或 Slack 通知运维人员。 #### budgets 配置 AISIX Cloud 预算,在组织、环境、调用方 API Key、服务提供方密钥、团队和成员范围内执行 AI 支出限额。 - [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md): 配置 AISIX Cloud 预算,在组织、环境、调用方 API Key、服务提供方密钥、团队和成员范围内执行 AI 支出限额。 #### caching 在 AISIX Cloud 和开源 AISIX 网关部署中,为符合条件的 Chat Completions 请求配置 Memory 或 Redis 响应缓存。 - [响应缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/caching.md): 在 AISIX Cloud 和开源 AISIX 网关部署中,为符合条件的 Chat Completions 请求配置 Memory 或 Redis 响应缓存。 #### caller-api-keys 配置 AISIX 网关部署的调用方 API Key,包括模型访问控制、过期、禁用、轮换、身份认证和验证。 - [调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md): 配置 AISIX 网关部署的调用方 API Key,包括模型访问控制、过期、禁用、轮换、身份认证和验证。 #### claim-mappings 通过按优先级排序的规则,将 AISIX 中已验证的 JWT Claim 映射到调用方 API Key,以共享访问控制并按身份归因用量。 - [JWT Claim 映射](https://docs.apiseven.com/ai-gateway/traffic-controls/claim-mappings.md): 通过按优先级排序的规则,将 AISIX 中已验证的 JWT Claim 映射到调用方 API Key,以共享访问控制并按身份归因用量。 #### guardrails - [Alibaba Cloud Content Moderation](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/alibaba-cloud-ai.md): 通过 AISIX Cloud 或资源文件配置 Alibaba Cloud Content Moderation,并验证 TextModerationPlus 风险等级执行行为。 - [Alibaba Cloud AI Guardrails](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/alibaba-cloud-ai-guardrails.md): 通过 AISIX Cloud 或资源文件配置 Alibaba Cloud AI Guardrails,并验证 MultiModalGuard 阻断和敏感数据脱敏。 - [AWS Bedrock Guardrails](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/aws-bedrock.md): 通过 AISIX Cloud 或资源文件配置 AWS Bedrock Guardrails,并在 AISIX AI 网关中验证阻断和 PII 匿名化。 - [Azure AI Content Safety 安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/azure-content-safety.md): 通过 AISIX Cloud 或资源文件配置 Azure AI Content Safety,并在 AISIX 中验证 Prompt Shield 和 Text Moderation 行为。 - [安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md): 了解 AISIX 安全护栏的检查位置、执行模式、作用域差异、流式输出控制、远程故障和调用方行为。 - [自定义脚本安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/custom-script.md): 通过 AISIX Cloud 或资源文件配置自定义 JavaScript 安全护栏,以运行检查逻辑,包括调用内容策略服务。 - [内置关键词安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/keyword.md): 通过 AISIX Cloud 或资源文件配置 AISIX 内置关键词安全护栏,并验证阻断、监控模式和作用域行为。 - [Lakera Guard](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/lakera.md): 通过 AISIX Cloud 或资源文件配置 Lakera Guard,并在 AISIX AI 网关中验证提示词注入阻断和 PII 脱敏。 - [OpenAI Moderation 安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/openai-moderation.md): 通过 AISIX Cloud 或资源文件配置 OpenAI Moderation,并在 AISIX AI 网关中验证阻断及按分类调整阈值。 - [选择安全护栏服务提供方](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/overview.md): 按评估位置、检测范围、执行操作和配置路径,比较 AISIX 内置及远程安全护栏服务提供方。 - [PII 检测与脱敏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/pii.md): 通过 AISIX Cloud 或资源文件配置 AISIX 内置 PII 检测,并验证脱敏、阻断和自定义敏感数据模式。 - [Presidio 安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/presidio.md): 在自己的基础设施中部署 Presidio analyzer 与 anonymizer,将其接入 AISIX 安全护栏,并验证 PII 匿名化和阻断。 - [Qwen3Guard 安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/qwen3guard.md): 在你自己的基础设施中运行开源安全分类模型 Qwen3Guard,并通过自定义脚本安全护栏接入 AISIX,检查请求和模型响应。 - [语义筛查安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/semantic-screening.md): 通过 AISIX Cloud 或资源文件配置 AISIX 内置语义筛查安全护栏,按语义而非措辞阻断流量,并依据实测分数校准相似度阈值。 - [校准语义筛查安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/semantic-screening-calibration.md): 用样本分数和真实流量分数校准 AISIX 语义筛查阈值,解读请求遥测数据,并在升级后复核策略。 #### jwt-authentication 在 AISIX 网关部署中配置 OIDC 信任和 JWT 认证,包括签发者发现、声明校验,以及将外部身份映射到调用方 API Key。 - [JWT 认证](https://docs.apiseven.com/ai-gateway/traffic-controls/jwt-authentication.md): 在 AISIX 网关部署中配置 OIDC 信任和 JWT 认证,包括签发者发现、声明校验,以及将外部身份映射到调用方 API Key。 #### keycloak-integration 经过验证的端到端演练:配置 Keycloak Realm,让每位用户使用自己的 JWT 在网关进行身份认证,并通过 Claim 映射将部门和用户组映射到调用方 API Key。 - [Keycloak 集成](https://docs.apiseven.com/ai-gateway/traffic-controls/keycloak-integration.md): 经过验证的端到端演练:配置 Keycloak Realm,让每位用户使用自己的 JWT 在网关进行身份认证,并通过 Claim 映射将部门和用户组映射到调用方 API Key。 #### overview 了解调用方身份、限流、AISIX Cloud 预算、安全护栏和缓存如何管理通过 AISIX 的请求。 - [流量控制](https://docs.apiseven.com/ai-gateway/traffic-controls/overview.md): 了解调用方身份、限流、AISIX Cloud 预算、安全护栏和缓存如何管理通过 AISIX 的请求。 #### prompt-caching 在 AISIX Cloud 或开源 AISIX 网关中启用 Anthropic 自动提示词缓存,使重复的提示词前缀获得模型服务提供方缓存折扣。 - [Anthropic 提示词缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/prompt-caching.md): 在 AISIX Cloud 或开源 AISIX 网关中启用 Anthropic 自动提示词缓存,使重复的提示词前缀获得模型服务提供方缓存折扣。 #### rate-limit-policies 配置支持条件流量匹配、独立配额桶、经典单作用域规则和暂停计划的 AISIX 限流策略。 - [限流策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md): 配置支持条件流量匹配、独立配额桶、经典单作用域规则和暂停计划的 AISIX 限流策略。 #### rate-limits 在 AISIX Cloud 和开源 AISIX 网关中配置并验证调用方 API Key 与模型的请求数、Token 和并发限制。 - [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md): 在 AISIX Cloud 和开源 AISIX 网关中配置并验证调用方 API Key 与模型的请求数、Token 和并发限制。 #### semantic-caching 基于向量相似度为语义相近的提示词返回缓存的 Chat Completions 响应,支持配置阈值、共享范围与缓存清空。 - [语义缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/semantic-caching.md): 基于向量相似度为语义相近的提示词返回缓存的 Chat Completions 响应,支持配置阈值、共享范围与缓存清空。 ## api7-gateway ### 3.9.x #### ai-gateway - [5 分钟代理第一个大语言模型请求](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/get-started.md): 在 5 分钟内配置 API7 AI 网关并代理第一个 OpenAI 请求,包含分步说明和代码示例。 - [接入 Anthropic Claude](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/anthropic.md): 通过 API7 网关路由 Anthropic Claude API 流量,集中实施安全、限流和可观测性策略。 - [集成 Azure OpenAI Service](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/azure-openai.md): 通过 API7 网关管理 Azure OpenAI Deployment,集中处理资源名称、API 版本和身份认证。 - [将流量路由到 DeepSeek 模型](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/deepseek.md): 通过 API7 网关代理 DeepSeek API 请求,集中管理身份认证、启用故障转移并监控用量。 - [接入 Google Gemini](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/google-gemini.md): 通过 API7 网关代理 Google Gemini API 请求,集中管理 API Key(API 密钥)并监控 AI 流量。 - [将流量路由到 OpenAI](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/openai.md): 通过 API7 网关代理和保护 OpenAI API 请求,集中管理身份认证、启用故障转移并监控用量。 - [接入任意 OpenAI 兼容大语言模型](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/openai-compatible.md): 通过 API7 网关代理任意 OpenAI 兼容 API,接入自托管模型、自定义端点或小众服务提供方。 - [通过 OpenRouter 接入数百种大语言模型](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/openrouter.md): 通过 API7 AI 网关接入 OpenRouter,使用一个 API 访问 200 多种大语言模型,同时保持企业级安全控制。 - [将企业 AI 流量路由到 Vertex AI](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/llm-providers/vertex-ai.md): 通过 API7 网关安全代理 Google Cloud Vertex AI 请求,支持服务账户身份认证和区域路由。 - [管理和保护 AI 流量](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/overview.md): 使用 API7 AI 网关集中管理大语言模型访问,通过一个平台将流量路由到多个服务提供方、实施安全护栏并控制成本。 - [监控 AI 流量并跟踪大语言模型成本](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/ai-observability-and-cost-tracking.md): 使用 API7 AI 网关的可观测性功能,洞察大语言模型用量、Token 消耗、延迟和成本。 - [使用 AI 重写转换 API 请求](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/ai-request-transformation.md): 在网关层使用大语言模型智能地转换、丰富或重构 API 请求与响应。 - [实施 AI 安全护栏并保护 PII](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/content-safety-and-guardrails.md): 使用 API7 AI 网关安全护栏,在请求到达大语言模型前阻止提示词注入、检测有害内容并脱敏 PII。 - [将 REST API 暴露为 AI Agent 的 MCP 工具](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/expose-apis-as-mcp-tools.md): 将现有 OpenAPI 服务转换为 MCP 兼容工具,使 AI Agent(AI 智能体)能够自动发现并调用 API。 - [通过 API7-MCP 在 AI 客户端中管理 API7 企业版](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/manage-api7-with-mcp.md): 部署 API7-MCP,让 Cursor、Claude Desktop、Cline 等 AI 客户端读取 API7 企业版资源、查看 Prometheus 指标、管理基于角色的访问控制(RBAC),并通过网关发送测试流量。 - [配置多模型路由和自动故障转移](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/multi-llm-routing-and-fallback.md): 使用加权负载均衡、自动故障转移和健康检查,在多个模型服务提供方之间路由 AI 流量。 - [实现提示词模板和装饰器](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/prompt-engineering-and-templating.md): 使用 API7 AI 网关的可复用提示词模板和自动系统提示词注入,规范大语言模型交互。 - [将 Anthropic Messages 转换为 OpenAI Chat Completions](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/protocol-conversion.md): 使用 API7 AI 网关透明地将 Anthropic Messages API 请求转换为 OpenAI Chat Completions API 格式,使团队能够通过 Anthropic SDK 使用任意 OpenAI 兼容后端。 - [在网关层实现 RAG](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/retrieval-augmented-generation.md): 使用 API7 AI 网关内置的检索增强生成(RAG),通过相关上下文提升大语言模型响应质量。 - [使用基于 Token 的限流控制 AI 成本](https://docs.apiseven.com/api7-gateway/3.9.x/ai-gateway/use-cases/token-rate-limiting-and-quota-management.md): 实施基于 Token 的限流,防止大语言模型被滥用,并按路由和模型实例控制 AI 成本。 #### api-consumption - [应用基于列表的访问控制](https://docs.apiseven.com/api7-gateway/3.9.x/api-consumption/consumer-restriction.md): 遵循本指南在 API7 企业版中实施基于列表的访问控制,通过白名单和黑名单实现对消费者访问的精确管理。 - [管理消费者凭证](https://docs.apiseven.com/api7-gateway/3.9.x/api-consumption/manage-consumer-credentials.md): 按照本指南在 API7 企业版中管理消费者凭证,使你能够设置和配置各种 API 访问的身份验证方法。 #### api-observability - [触发网关告警](https://docs.apiseven.com/api7-gateway/3.9.x/api-observability/alert.md): 按照本指南在 API7 企业版中创建告警策略,以便接收特定事件的通知并监控系统性能。 - [在访问日志中记录消费者标签](https://docs.apiseven.com/api7-gateway/3.9.x/api-observability/log-consumer-label-in-access-log.md): 按照本指南在 API7 企业版的访问日志中记录消费者标签,以增强 API 的管理和安全性。 - [记录 API 流量日志](https://docs.apiseven.com/api7-gateway/3.9.x/api-observability/logging.md): 按照本指南在 API7 企业版中配置 API 流量日志记录,与各种日志平台集成以捕获详细的访问日志。 - [监控 API 指标](https://docs.apiseven.com/api7-gateway/3.9.x/api-observability/monitoring.md): 按照本指南在 API7 企业版中监控 API 指标,利用 Prometheus 插件来有效追踪和可视化 HTTP 指标。 - [追踪 API 流量](https://docs.apiseven.com/api7-gateway/3.9.x/api-observability/tracing.md): 按照本指南在 API7 企业版中使用 opentelemetry 插件设置追踪,实现对请求在系统中的旅程的监控。 #### api-portal - [自定义开发者门户](https://docs.apiseven.com/api7-gateway/3.9.x/api-portal/custom-portal.md): 使用 API7 开发者门户脚手架自定义开发者门户,包括配置、品牌化、SSO 集成以及 Portal SDK。 - [使用 Okta 为开发者门户配置 SCIM 自动配置](https://docs.apiseven.com/api7-gateway/3.9.x/api-portal/custom-portal-enable-scim-okta.md): 了解如何使用 Okta 为你的自定义开发者门户配置 SCIM 自动配置(Provisioning),从而实现自动化的用户同步。 - [使用提供方门户设置开发者门户](https://docs.apiseven.com/api7-gateway/3.9.x/api-portal/getting-started.md): 了解如何通过将提供方门户与示例开发者门户连接,来设置和使用 API7 API 开发者门户,以发布 API 并管理开发者访问权限。 - [使用 Keycloak 配置动态客户端注册(DCR)](https://docs.apiseven.com/api7-gateway/3.9.x/api-portal/keycloak-dcr.md): 了解如何使用动态客户端注册(DCR)将 API7 企业版开发者门户与 Keycloak 集成,以进行 OAuth 2.0 身份验证。 - [产品化服务](https://docs.apiseven.com/api7-gateway/3.9.x/api-portal/productize-services.md): 遵循本指南在 API7 企业版中创建和管理 API 产品,简化开发工作流程并确保关联服务的自动更新。 #### api-security - [设置 API 认证](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/api-authentication.md): 按照本指南在 API7 企业版中设置 API 认证,通过各种认证插件确保只有授权的消费者才能访问你的 API。 - [引用 AWS Secrets Manager 中的密钥](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/aws-secrets-manager.md): 按照本指南将 API7 企业版与 AWS Secrets Manager 集成,实现敏感信息的安全管理和密钥的自动轮换。 - [限制访问 API 的 IP 地址](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/block-ip.md): 按照本指南在 API7 企业版中配置 IP 地址限制,通过阻止指定的 IP 地址来防止不受欢迎的用户访问你的 API。 - [在客户端和 API7 网关之间配置 mTLS](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/client-mtls.md): 按照本指南在客户端和 API 网关之间配置双向 TLS (mTLS),通过双方的相互身份验证来增强安全性。 - [引用 HashiCorp Vault 中的密钥](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/hashicorp-vault.md): 按照本指南将 API7 企业版与 HashiCorp Vault 集成,实现 API 密钥和密码等敏感信息的安全存储和检索。 - [引用 Kubernetes Secret 中的密钥](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/kubernetes-secret.md): 按照本指南将 API7 企业版与 Kubernetes 集成,实现 API 密钥和密码等敏感信息的安全存储和检索。 - [对日志进行数据脱敏](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/mask-data.md): 按照本指南使用 API7 企业版隐藏日志中的敏感数据,确保机密信息不会在日志文件中泄露。 - [对 API 应用限流](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/rate-limiting.md): 按照本指南在 API7 企业版中应用限流,控制对 API 的请求数量,并保护你的后端免受过多流量的影响。 - [在 API7 企业版和上游之间配置 mTLS](https://docs.apiseven.com/api7-gateway/3.9.x/api-security/upstream-mtls.md): 按照本指南在 API 网关和上游之间配置双向 TLS (mTLS),通过双方的相互身份验证来增强安全性。 #### api7-mcp-server-guide - [部署 API7-MCP](https://docs.apiseven.com/api7-gateway/3.9.x/api7-mcp-server-guide/deploy-api7-mcp.md): 配置 API7-MCP,让兼容 MCP 的 AI 客户端检查 API7 企业版资源和监控数据、管理 RBAC,并发送测试流量。 #### best-practices - [API 版本控制](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/api-version-control.md): 按照本指南在 API7 企业版中实施 API 版本控制,在发生更改后也能保持部署的一致性,并在管理 API 功能时实现更平滑的回滚。 - [配置蓝绿发布](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/blue-green-deployment.md): 按照本指南在 API7 企业版中设置蓝绿发布,通过使用两个相同的环境,将应用程序更新期间的停机时间和风险降至最低。 - [代理 gRPC 流量](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/configure-grpc.md): 按照本指南配置 API7 网关以代理 gRPC 流量,使你能够使用 HTTP/2 处理高性能的远程过程调用(RPC)。 - [添加自定义插件](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/custom-plugin.md): 遵循本指南在 API7 企业版中添加自定义插件,通过使用 Lua 编程定制逻辑来扩展功能和管理 API 流量。 - [使用 LDAP 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/dashboard-sso/ldap.md): 按照本指南在 API7 企业版中使用 LDAP 协议配置单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Auth0 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/dashboard-sso/oidc/auth0.md): 按照本指南在 API7 企业版中使用 OIDC 协议配置基于 Auth0 的单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Microsoft Entra ID 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/dashboard-sso/oidc/azure-ad.md): 按照本指南在 API7 企业版中使用 OIDC 协议配置基于 Microsoft Entra ID (Azure AD) 的单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Keycloak 配置控制台单点登录 (SSO)](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/dashboard-sso/oidc/keycloak.md): 按照本指南在 API7 企业版中使用 OIDC 和 Keycloak 配置单点登录 (SSO),从而简化用户身份验证并增强安全性。 - [使用 Microsoft Entra ID 和 SAML 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/dashboard-sso/saml/azure-ad.md): 按照本指南在 API7 企业版中使用 SAML 协议配置基于 Microsoft Entra ID (Azure AD) 的单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Okta 和 SAML 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/dashboard-sso/saml/okta.md): 按照本指南在 API7 企业版中使用 SAML 协议配置基于 Okta 的单点登录 (SSO),简化用户身份验证并在控制台中启用角色映射。 - [在访问日志中脱敏敏感数据](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/data-masking-access-log.md): 了解如何在 API 网关访问日志中有效脱敏诸如电子邮件地址之类的敏感数据,以增强安全性并确保可靠的 API 管理。 - [设计自定义角色系统](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/design-custom-role-system.md): 按照本指南在 API7 企业版中设计并实现自定义角色系统,授予用户细粒度的访问权限以增强安全性和数据完整性。 - [声明式管理 API7 企业版](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/devops-adc.md): 按照本指南使用 API7 声明式 CLI(ADC)声明式地管理 API7 企业版配置,轻松与版本控制系统和 CI/CD 流水线集成。 - [有条件地禁用全局插件](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/disable-global-plugins-conditionally.md): 了解如何在 API7 企业版中有条件地禁用全局插件执行,使你可以根据特定要求灵活控制插件的执行。 - [将外部认证的用户信息转发到上游](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/forward-auth-user-info-to-upstream.md): 在使用 OpenID Connect 或 SAML Auth 等认证插件时,你可能需要将经过身份验证的用户信息传递给上游服务。这使上游应用程序能够基于用户身份实现额外的业务逻辑,例如个性化、审计和访问控制。 - [将 Kubernetes 的错误日志转发至 Splunk](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/gateway-error-log-kubernetes-splunk.md): 了解如何将部署在 Kubernetes 环境中的多个网关的错误日志转发至 Splunk,以进行集中式的日志管理。 - [执行网关健康检查探针](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/gateway-health-probe.md): 按照本指南在 API7 企业版中启用健康检查探针,通过监控上游节点的健康状况来确保网关的稳定性和可靠性。 - [使用网关组在多环境中管理服务](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/manage-services-in-multi-environments.md): 了解如何使用 API7 企业版中的网关组在多个环境中管理服务,从而优化工作流程并减少 API 运维中的错误。 - [使用 Token 集成 GitOps 工作流](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/manage-token.md): 按照本指南在 API7 企业版中实施基于 Token 的身份验证,实现与 GitOps 工作流的无缝集成并增强安全性。 - [代理 TCP 流量](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/proxy-tcp-traffic.md): 按照本指南配置 API7 网关以处理 TCP 和 UDP 流量,从而为 MySQL 等各种后端服务启用传输层 (四层) 代理。 - [设置路由优先级和匹配条件 (Ingress Controller)](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/route-priority-matching-conditions.md): 遵循本指南使用 Ingress Controller 配置路由优先级和高级匹配条件,以实现更细粒度的 API 管理。 - [使用 Okta 配置 SCIM 账号同步](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/scim/okta.md): 按照本指南在 API7 企业版中配置基于 Okta 的 SCIM 账号同步,实现身份提供商和 API7 控制台之间的用户自动同步。 - [使用服务发现配置上游](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/service-discovery.md): 按照本指南在 API7 企业版中配置服务发现机制,以支持动态探测上游节点并增强 API 管理的灵活性。 - [优化遥测数据传输](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/telemetry-compression.md): 按照本指南配置从 API7 企业版数据面(DP)到控制面(CP)的遥测数据压缩,以提高网络性能并降低 CPU 使用率。 - [确保上游高可用性](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/upstream-ha.md): 按照本指南在 API7 企业版中通过添加多个上游节点、修改负载均衡类型以及启用健康检查来确保上游的高可用性。 - [验证 API7 镜像签名](https://docs.apiseven.com/api7-gateway/3.9.x/best-practices/verify-api7-image-signatures.md): 遵循本指南使用 Cosign 验证 API7 Docker 镜像签名,确保软件供应链中镜像的真实性和完整性。 #### configure-and-manage - [在 AWS EKS 上运行基准](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/benchmark-on-aws-eks.md): 在 AWS EKS 上重现已发布的 API7 网关性能基准。演练涵盖 EKS 集群设置、三个独立节点组、Helm 安装、NGINX 上游和 wrk2 部署以及运行完整的场景套件。 - [API7 网关控制面配置参考](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/configure-control-plane.md): API7 网关控制面的详细配置参考,涵盖控制台和 DP Manager 配置文件。 - [API7 网关数据面配置参考](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/configure-data-plane.md): API7 网关数据面的详细配置参考,基于 config-default.yaml 结构。 - [数据面弹性](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/data-plane-resilience.md): 为 API7 网关数据面节点配置备用存储,使其在控制面长时间中断时仍能重启并继续运行。 - [API7 网关多可用区部署](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/deployment-scenarios/multi-az-deployment.md): 用于跨多个可用区部署 API7 网关的配置和架构,以实现高可用性和容错能力。 - [多区域部署模式](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/deployment-scenarios/multi-region-deployment.md): 跨多个地理区域部署 API7 网关以实现全球覆盖和灾难恢复的架构和注意事项。 - [数据面高可用性](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/high-availability-data-plane.md): 设计具有多个节点、健康检查和负载均衡器故障转移的高可用 API7 网关数据面。 - [许可证管理](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/license-management.md): 管理 API7 网关许可证,了解核心数额度和许可证状态,并配置许可证文件路径以实现自动化部署。 - [性能基准](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/performance-benchmark.md): 了解 API7 网关在 AWS EKS 和单主机环境中的性能基准结果,以及复现基准测试的方法和优化建议。 - [生产最佳实践](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/production-best-practices.md): 在生产中管理 API7 网关的操作最佳实践,包括 GitOps、变更管理和灾难恢复。 - [在生产环境中运行](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/run-in-production.md): API7 网关的上线前检查清单和部署指南,用于确保生产环境稳定且安全。 - [扩缩容数据面](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/scale-data-plane.md): 水平扩展 API7 网关数据面节点以提高吞吐量并为高可用性部署做好准备。 - [共享内存容量规划](https://docs.apiseven.com/api7-gateway/3.9.x/configure-and-manage/shared-dict-sizing.md): 根据部署规模为 API7 Gateway 的指标、服务发现、开发者门户和链路追踪等共享内存合理分配容量,避免溢出导致数据丢失。 #### deployment - [使用 Docker Compose 部署](https://docs.apiseven.com/api7-gateway/3.9.x/deployment/docker.md): 本指南提供了使用 Docker Compose 部署 API7 企业版控制面和数据面的步骤,以实现高效的 API 管理。 - [在 Kubernetes 上部署 API7 Ingress Controller](https://docs.apiseven.com/api7-gateway/3.9.x/deployment/ingress-controller.md): 了解如何在 Kubernetes 上部署 API7 网关和 Ingress Controller,从而实现声明式的 API 管理。 - [在 OpenShift 上安装 API7 Ingress Controller](https://docs.apiseven.com/api7-gateway/3.9.x/deployment/ingress-controller-openshift.md): 按照本指南在 OpenShift 集群上部署 API7 Ingress Controller,确保为你的环境进行正确配置和设置。 - [在 OpenShift 上安装 API7 企业版](https://docs.apiseven.com/api7-gateway/3.9.x/deployment/openshift.md): 按照本指南在 OpenShift 集群上部署 API7 企业版,确保为你的环境进行正确的配置和设置。 #### enterprise-features - [告警和联系人](https://docs.apiseven.com/api7-gateway/3.9.x/enterprise-features/alerts-and-contact-points.md): 了解 API7 网关中的告警和联系人,以及如何监控异常并及时发送通知。 - [控制台单点登录](https://docs.apiseven.com/api7-gateway/3.9.x/enterprise-features/dashboard-sso.md): 了解 API7 网关中的单点登录(SSO),使用现有凭证进行身份认证,轻松访问控制台。 - [高可用性](https://docs.apiseven.com/api7-gateway/3.9.x/enterprise-features/high-availability.md): 了解 API7 网关中的高可用性,为关键业务应用持续提供可靠服务。 - [安全加固](https://docs.apiseven.com/api7-gateway/3.9.x/enterprise-features/security-hardening.md): 了解 API7 网关中的安全加固能力,保护 API 基础设施免受威胁和漏洞影响。 #### getting-started - [新增网关组](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/add-gateway-group.md): 按照本教程学习如何在 API7 企业版中新增网关组,从而实现对 API 网关实例的有效管理和组织。 - [新增网关实例](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/add-gateway-instance.md): 按照本教程了解如何将网关实例新增到你的 API7 企业版网关组中,确保高效的路由和 API 处理。 - [使用审计日志追踪操作员活动](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/audit-logging.md): 按照本教程在 API7 企业版中使用审计日志功能,实现对用户活动的详细追踪,并提升安全性和合规性。 - [配置金丝雀流量转移](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/canary-upstream.md): 按照本教程在 API7 企业版中配置金丝雀流量转移,通过逐步路由流量来安全地测试新的上游。 - [创建自定义角色](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/create-custom-role.md): 按照本教程在 API7 企业版中创建自定义角色,从而实现针对特定需求量身定制的细粒度权限管理。 - [安装 API7 企业版](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/install-api7-ee.md): 按照本教程在 Docker 上安装 API7 企业版,包括用于管理 API 网关和确保无缝设置的基本组件。 - [配置 Kubernetes 服务发现](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/k8s-service-discovery.md): 按照本指南在 API7 企业版中配置 Kubernetes 服务发现,以支持动态探测 Kubernetes 集群中的上游节点。 - [发布你的第一个 API](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/launch-your-first-api.md): 学习如何在 API7 企业版上发布并验证你的第一个 API,包括创建已发布的服务、路由,以及通过 HTTP 请求进行测试。 - [深入了解 API7 产品和 APISIX](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/learn-more.md): 了解 API7 产品系列、API7 企业版与 Apache APISIX 的关系,以及它们如何融入你的 API 管理策略。 - [续订许可证](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/license.md): 了解如何获取和续订 API7 企业版许可证,以确保你可以持续访问各项功能和服务。 - [发布服务版本](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/publish-service.md): 按照本教程在 API7 企业版中发布服务版本,从而实现对跨不同网关组的 API 进行有效的版本控制和管理。 - [快速开始](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/quick-start.md): 使用 Docker Compose 在本地运行 API7 网关,并在 10 分钟内代理首个 API 请求。 - [更新用户角色](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/rbac.md): 按照本教程在 API7 企业版中管理基于角色的访问控制(RBAC),通过角色和权限策略简化用户权限管理。 - [回滚服务](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/rollback-service.md): 按照本教程在 API7 企业版中将服务回滚到以前的版本,以便在较新版本出现问题时能够快速恢复。 - [在网关组之间同步服务](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/sync-service.md): 按照本教程在 API7 企业版中的网关组之间同步已发布的服务版本,从而实现跨环境的平滑更新。 - [教程:通过插件代理和管理 API 请求](https://docs.apiseven.com/api7-gateway/3.9.x/getting-started/tutorial-proxying-api-requests.md): 通过动手实践,学习代理 API 请求、使用 `key-auth` 插件添加身份认证,以及启用 `limit-count` 插件实施限流。 #### high-availability - [数据面弹性概览](https://docs.apiseven.com/api7-gateway/3.9.x/high-availability/cp-outage-overview.md): 了解 API7 企业版如何通过确保网关节点在控制面(CP)不可用时继续运行和提供服务,从而实现数据面弹性。 - [使用 AWS S3 实现数据面弹性](https://docs.apiseven.com/api7-gateway/3.9.x/high-availability/cp-outage/dp-resilience-aws-s3.md): 在 API7 企业版中通过带有 IAM 角色或访问密钥的 AWS S3 配置数据面弹性,以便在控制面不可用时保持网关运行。 - [使用 Azure Blob Storage 实现数据面高可用](https://docs.apiseven.com/api7-gateway/3.9.x/high-availability/cp-outage/dp-resilience-azure-blob.md): 在 API7 企业版中配置基于 Azure Blob Storage 的数据面(DP)高可用性。你可以使用 Workload Identity 或访问密钥进行认证,确保在控制面(CP)故障期间网关能够继续运行。 - [高可用安装](https://docs.apiseven.com/api7-gateway/3.9.x/high-availability/high-availability-installation.md): 遵循本指南安装 API7 网关及其组件以实现高可用,防止单点故障。 - [API7 高可用性概览](https://docs.apiseven.com/api7-gateway/3.9.x/high-availability/overview.md): 了解 API7 中高可用性 (HA) 的概念,确保系统中的连续服务和故障恢复能力。 - [准备高可用环境](https://docs.apiseven.com/api7-gateway/3.9.x/high-availability/prepare-for-high-availability.md): 了解如何为 API7 企业版高可用部署做准备,包括前置条件和配置要求。 #### how-to-guides - [配置数据脱敏](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/api-security/data-masking.md): 使用 data-mask 插件,在请求数据写入访问日志和日志插件输出前对敏感字段进行遮盖、替换或移除,帮助满足 GDPR、HIPAA 和 PCI-DSS 要求。 - [配置就绪和存活探针](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/ops/configure-readiness-probe.md): 为 Kubernetes、Docker 和其他非 Helm 部署中的 API7 网关数据面配置就绪和存活检查。 - [创建自定义角色](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/ops/create-custom-role.md): 通过定义权限策略、将其附加到角色并将角色分配给用户,在 API7 网关中创建自定义角色。 - [设计自定义角色体系](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/ops/design-custom-role-system.md): 通过组合角色、权限策略、标签和权限边界,在 API7 网关中设计可扩展的自定义角色体系。 - [管理网关组](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/ops/multi-gateway-group.md): 了解如何创建和管理多个网关组,以便按环境或团队组织和隔离 API 流量。 - [配置密钥管理](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/ops/secret-manager.md): 了解如何配置密钥提供方,并在 API7 企业版中引用外部密钥,避免在网关资源中硬编码敏感值。 - [实施灰度发布](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/traffic-management/canary-release.md): 了解如何使用 traffic-split 插件逐步将流量迁移到新版后端服务。 - [配置上游健康检查](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/traffic-management/health-check.md): 了解如何为上游服务配置主动和被动健康检查,以确保高可用。 - [改写代理请求](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/traffic-management/proxy-rewrite.md): 了解如何在将请求代理到上游服务前修改请求 URI、方法和请求头。 - [配置限流](https://docs.apiseven.com/api7-gateway/3.9.x/how-to-guides/traffic-management/rate-limiting.md): 了解如何为 API 配置简单和高级限流,以防止滥用并确保公平使用。 #### install - [部署高可用环境](https://docs.apiseven.com/api7-gateway/3.9.x/install/deploy-high-availability.md): 以高可用配置部署 API7 网关控制面和数据面,消除单点故障。 - [在 Kubernetes 上部署 API7 企业版](https://docs.apiseven.com/api7-gateway/3.9.x/install/deploy-on-kubernetes.md): 使用 Helm 在 Kubernetes 上部署 API7 企业版,包括控制面安装、使用 mTLS 配置数据面,以及 AWS EKS、GCP GKE 和 Azure AKS 专用指南。 - [在 OpenShift 上部署](https://docs.apiseven.com/api7-gateway/3.9.x/install/deploy-on-openshift.md): 使用正确的安全上下文约束(SCC)、服务账号和 Helm Chart 配置,在 Red Hat OpenShift 上部署 API7 网关。 - [使用 Docker Compose 部署](https://docs.apiseven.com/api7-gateway/3.9.x/install/deploy-with-docker-compose.md): 使用 Docker Compose 在本地部署 API7 企业版。该开发和测试环境会启动包含 PostgreSQL、Prometheus、Jaeger、集成控制台和 DP Manager 的控制面,然后通过控制台生成的 Docker 命令添加数据面网关。 - [安装常见问题](https://docs.apiseven.com/api7-gateway/3.9.x/install/installation-faq.md): 安装过程中的常见问题和故障排查方法。 - [支持的版本和互操作性](https://docs.apiseven.com/api7-gateway/3.9.x/install/supported-versions-and-interoperability.md): API7 网关组件和基础设施的版本兼容性矩阵。 - [系统要求](https://docs.apiseven.com/api7-gateway/3.9.x/install/system-requirements.md): 安装 API7 企业版所需的硬件、操作系统和网络要求。 #### introduction 探索 API7 企业版,这是一个基于 Apache APISIX 构建的 API 网关,专为企业需求量身定制,提供全生命周期的 API 管理。 - [概览](https://docs.apiseven.com/api7-gateway/3.9.x/introduction.md): 探索 API7 企业版,这是一个基于 Apache APISIX 构建的 API 网关,专为企业需求量身定制,提供全生命周期的 API 管理。 - [架构](https://docs.apiseven.com/api7-gateway/3.9.x/introduction/architecture.md): 探索 API7 企业版的架构,这是一个基于 Apache APISIX 的云原生 API 网关,具有可扩展的数据平面和控制平面,可满足企业需求。 #### key-concepts - [API 门户](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/api-portal.md): API7 门户(API Portal)是一个集中式的在线平台,充当 API 提供者(API Providers)与开发者(Developers)之间的桥梁。 - [API 产品](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/api-products.md): 了解 API7 企业版中的 API 产品,它们将 API 捆绑在一起,以简化使用、管理,并为开发者提供有针对性的服务。 - [架构](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/architecture.md): 深入了解 API7 企业版控制面与数据面解耦的架构。 - [证书](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/certificates.md): 了解 API7 企业版如何支持 TLS 和 mTLS,以确保客户端、API 网关和服务之间的安全通信和信任。 - [消费者](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/consumers.md): 探索 API7 企业版中的消费者管理,重点关注身份验证、访问控制和安全的 API 请求处理。 - [消费者和凭证](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/consumers-and-credentials.md): 使用消费者和凭证进行身份管理与身份认证。 - [开发者](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/developers.md): 了解开发者在 API7 企业版中的角色,使他们能够通过 API 门户有效地发现、学习和集成 API。 - [网关组与网关实例](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/gateway-groups.md): 了解 API7 企业版中的网关组如何通过组合多个网关实例来进行有效的扩展,从而简化管理。 - [概览](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/overview.md): 探索 API7 企业版的架构,以实现高效的 API 请求管理,从而提升现代应用程序的性能、安全性和可扩展性。 - [插件](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/plugins.md): 了解 API7 企业版中如何通过插件扩展功能,满足你在流量管理、安全性、请求转换等方面的定制化需求。 - [角色与权限策略](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/roles-and-permission-policies.md): 了解 API7 企业版中的角色和权限策略,实现细粒度的访问控制和用户管理,确保 API 操作的安全性。 - [路由](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/routes.md): 了解 API7 企业版路由如何管理 HTTP 请求和响应,优化到后端服务的流量,从而实现无缝的 API 性能。 - [密钥](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/secrets.md): 了解如何在 API7 企业版中使用密钥对象和提供程序安全地管理敏感信息,以增强 API 数据保护。 - [服务发现](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/service-discovery.md): API7 网关中的动态上游解析,无需硬编码 IP,即可从 Kubernetes Service、Nacos 和 Consul 注册中心自动发现后端端点。 - [服务](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/services.md): 探索 API7 企业版中的服务,了解如何通过强大的路由、出色的可扩展性以及对后端应用性能的增强来简化 API 管理。 - [服务与路由](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/services-and-routes.md): 了解如何使用服务与路由对 API 流量进行分组和路由。 - [SNI](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/snis.md): 探索 API7 企业版如何使用服务器名称指示(SNI)允许多个主机名共享 SSL 证书,从而提高安全性和效率。 - [SSL 证书](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/ssl-certificates.md): 了解 API7 网关如何管理 SSL/TLS 证书和终止安全连接。 - [四层路由](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/stream-routes.md): 了解 API7 企业版中的四层路由,它们支持管理 TCP/UDP 流量并对服务进行细粒度的访问控制。 - [上游](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/upstreams.md): 了解 API7 企业版中的上游,它们将后端服务分组以实现高效路由、负载均衡和增强 API 性能。 - [上游与负载均衡](https://docs.apiseven.com/api7-gateway/3.9.x/key-concepts/upstreams-and-load-balancing.md): 后端目标定义,包括负载均衡算法和健康检查。 #### observability - [配置告警](https://docs.apiseven.com/api7-gateway/3.9.x/observability/alerts.md): 配置 API7 网关告警策略和联系人,当网关离线、证书过期或错误率超过阈值时通过邮件或 Webhook 接收通知。 - [在访问日志中包含消费者标签](https://docs.apiseven.com/api7-gateway/3.9.x/observability/consumer-label-based-logging.md): 在 API7 网关访问日志中包含消费者标签,以便按消费者跟踪和分析流量。 - [使用调试会话捕获请求链路](https://docs.apiseven.com/api7-gateway/3.9.x/observability/debug-sessions.md): 了解网关处理单个请求时的完整行为,包括插件执行顺序、耗时和日志。你可以按需捕获,也可以在告警触发时自动捕获。 - [使用现有 Prometheus](https://docs.apiseven.com/api7-gateway/3.9.x/observability/external-prometheus.md): 将 API7 网关指向现有的外部 Prometheus,并从 Docker Compose 部署中移除内置实例,同时确保控制台的 Monitoring 页面持续正常工作。 - [将 Kubernetes 错误日志发送到 Splunk](https://docs.apiseven.com/api7-gateway/3.9.x/observability/kubernetes-error-log-forwarding.md): 使用 Splunk OpenTelemetry Collector,将 Kubernetes 中 API7 网关容器的错误日志转发到 Splunk。 - [配置集中式日志记录](https://docs.apiseven.com/api7-gateway/3.9.x/observability/logging.md): 了解 API7 网关生成的访问日志和错误日志,配置格式与详细程度,并将日志转发到集中式日志管理系统。 - [监控指标](https://docs.apiseven.com/api7-gateway/3.9.x/observability/metrics.md): 通过控制台内置监控页面或抓取数据面公开的 Prometheus 端点,监控 API7 网关指标。 - [将访问日志发送到 Splunk](https://docs.apiseven.com/api7-gateway/3.9.x/observability/splunk-integration.md): 使用 HTTP Event Collector(HEC)日志插件,将 API7 网关访问日志发送到 Splunk。 - [配置分布式追踪](https://docs.apiseven.com/api7-gateway/3.9.x/observability/tracing.md): 使用 OpenTelemetry 插件在 API7 网关中配置分布式追踪、OTLP Collector、采样策略和路由跨度,以可视化请求流并分析延迟瓶颈。 #### overview 了解 API7 网关 3.9.x 版本的架构、功能和部署模型。 - [API7 网关](https://docs.apiseven.com/api7-gateway/3.9.x/overview.md): 了解 API7 网关 3.9.x 版本的架构、功能和部署模型。 #### performance - [准备测试环境 (AWS EKS)](https://docs.apiseven.com/api7-gateway/3.9.x/performance/aws-eks.md): 在 AWS EKS 上搭建 API7 企业版性能测试环境,包括配置和资源分配。 - [建立性能基准](https://docs.apiseven.com/api7-gateway/3.9.x/performance/benchmark.md): 了解如何为 API7 企业版 API 网关建立性能基准,以确保准确评估其能力。 - [性能测试基准](https://docs.apiseven.com/api7-gateway/3.9.x/performance/performance-testing.md): 探索测试方法和结果,以评估 API7 企业版在不同负载条件下的性能。 #### production - [自动扩缩容 API7 Gateway (K8s)](https://docs.apiseven.com/api7-gateway/3.9.x/production/scaling/autoscale-api7-gateway.md): 了解如何使用水平 Pod 自动扩缩容(HPA)在 Kubernetes 上对 API7 Gateway 进行自动扩缩容,以在不同的流量负载下保持一致的 API 性能。 #### reference CLI 工具 - [API 参考](https://docs.apiseven.com/api7-gateway/3.9.x/reference.md): CLI 工具 - [ADC 参考](https://docs.apiseven.com/api7-gateway/3.9.x/reference/adc.md): 使用 API 声明式 CLI(ADC)以声明式方式管理 API7 企业版网关配置。 - [告警变量与模板](https://docs.apiseven.com/api7-gateway/3.9.x/reference/alert-template.md): 在 API7 企业版中使用预定义变量自定义告警通知,从而在告警消息和电子邮件中实现动态内容。 - [构建 API 端点](https://docs.apiseven.com/api7-gateway/3.9.x/reference/api-implementation/build-api-endpoints.md): API 端点为您的 API 提供实际的业务逻辑和数据。在将 API 与 API7 企业版集成之前,您需要开发并部署它们。 - [注解 (Annotations)](https://docs.apiseven.com/api7-gateway/3.9.x/reference/api7-ingress-controller/annotation.md): 了解注解如何在 API7 Ingress Controller 中扩展 Kubernetes Ingress 和 IngressClass 资源的功能,以配置路由、安全性和网关行为。 - [自定义资源定义 API 参考](https://docs.apiseven.com/api7-gateway/3.9.x/reference/api7-ingress-controller/api-reference.md): 浏览 API7 Ingress Controller 支持的自定义资源定义 (CRD) 的详细参考文档。 - [配置文件](https://docs.apiseven.com/api7-gateway/3.9.x/reference/api7-ingress-controller/configuration-file.md): 使用 config.yaml 文件配置 API7 Ingress Controller,包括日志设置、领导者选举、指标和同步行为等配置。 - [配置示例](https://docs.apiseven.com/api7-gateway/3.9.x/reference/api7-ingress-controller/examples.md): 探索展示 API7 Ingress Controller 配置的各种示例,以帮助你根据你的环境有效地调整设置。 - [Ingress 与 Gateway API 支持](https://docs.apiseven.com/api7-gateway/3.9.x/reference/api7-ingress-controller/ingress-and-gateway-api-support.md): 了解 API7 Ingress Controller 支持的 Gateway API 和 Ingress 资源及其当前功能。 - [审批变量与模板](https://docs.apiseven.com/api7-gateway/3.9.x/reference/approval-variables.md): 了解如何在 API7 企业版中使用审批变量,为审批通知和模板创建动态内容。 - [内置变量](https://docs.apiseven.com/api7-gateway/3.9.x/reference/built-in-variables.md): 了解 API7 网关中可用的内置变量,包括 NGINX、APISIX 和自定义变量,这些变量可用于路由匹配、日志自定义和插件配置。 - [配置文件](https://docs.apiseven.com/api7-gateway/3.9.x/reference/configuration.md): 了解 API7 企业版中使用的配置文件,包括用于有效管理设置的默认和用户定义文件。 - [设计 API](https://docs.apiseven.com/api7-gateway/3.9.x/reference/design-apis.md): 作为工程师,您需要根据业务需求明确 API 的功能目的,然后将业务语言转化为技术语言。精心设计的 API 的好处包括改善开发者体验、加快文档编写速度并提高 API 的采用率。 - [环境变量](https://docs.apiseven.com/api7-gateway/3.9.x/reference/environment-variables.md): 探索在 API7 企业版中使用环境变量来配置消费者凭证、SSL 证书和插件。 - [API7 表达式](https://docs.apiseven.com/api7-gateway/3.9.x/reference/expressions.md): 了解如何在 API7 企业版中使用表达式进行路由匹配、请求过滤和配置中的条件逻辑。 - [安全加固参考](https://docs.apiseven.com/api7-gateway/3.9.x/reference/hardening.md): 了解在 API7 企业版中保护敏感信息的做法,包括存储、加密和通信实践,以防御各种威胁。 - [从控制台获取令牌](https://docs.apiseven.com/api7-gateway/3.9.x/reference/obtain-dashboard-token.md): 在 API7 控制台中创建令牌,并将其用于 API7 网关 Admin API 和 ADC 身份认证。 - [OpenAPI 转换器参考](https://docs.apiseven.com/api7-gateway/3.9.x/reference/openapi-adc.md): 了解如何使用支持的扩展和自定义属性将 OpenAPI 规范转换为 ADC 配置。 - [权限策略的操作与资源](https://docs.apiseven.com/api7-gateway/3.9.x/reference/permission-policy-action-and-resource.md): 查阅 API7 企业版权限策略框架中可用的操作和资源,以实现细粒度的访问控制。 - [权限策略示例](https://docs.apiseven.com/api7-gateway/3.9.x/reference/permission-policy-examples.md): 查看 API7 企业版中的权限策略示例,以在你的环境中有效地创建和管理访问控制。 #### release-notes - [更新日志](https://docs.apiseven.com/api7-gateway/3.9.x/release-notes.md) #### scalability - [在 Kubernetes 上自动扩缩容数据面](https://docs.apiseven.com/api7-gateway/3.9.x/scalability/autoscale-on-kubernetes.md): 使用 Kubernetes 的 Horizontal Pod Autoscaler(HPA)自动扩缩容 API7 网关数据面 Pod,以应对流量变化。 #### security-and-compliance - [访问控制列表(ACL)](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/access-control-lists.md): 使用 API7 网关的 `consumer-restriction` 插件限制 API 访问。按消费者名称、消费者组 ID、服务 ID 或路由 ID 配置允许列表和拒绝列表,实现细粒度安全控制。 - [审计日志](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/audit-logs.md): 通过详细的审计日志跟踪 API7 控制面中的所有管理变更。了解如何查看、管理和导出审计记录,满足安全与合规要求。 - [控制面与数据面之间的双向 TLS](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/authenticate/mutual-tls-cp-dp.md): 了解 API7 网关如何使用基于 PKI 的可靠双向 TLS(mTLS)模型,保护控制面与数据面之间的所有通信。 - [为控制台配置 SCIM 预配](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/authenticate/scim.md): 使用受支持的身份提供商,为 API7 控制台配置 SCIM 用户预配。 - [使用 Microsoft Entra ID 进行 SCIM 预配](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/authenticate/scim-microsoft-entra-id.md): 为 API7 控制台配置 Microsoft Entra ID SCIM 预配。 - [使用 Okta 进行 SCIM 预配](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/authenticate/scim-okta.md): 为 API7 控制台配置 Okta SCIM 预配。 - [控制面 IP 限制](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/ip-restrictions-control-plane.md): 使用控制面内置 IP 允许列表限制可访问 API7 控制面(控制台和 Admin API)的客户端 IP 地址,并结合网络级控制实现纵深防御。 - [OAuth 2.0 和 OIDC](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/oauth-oidc.md): 使用现代化的令牌身份认证保护 API,并了解如何将 API7 网关与 Okta、Keycloak 等 OAuth 2.0 和 OpenID Connect(OIDC)提供商集成。 - [开源许可证](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/open-source-licenses.md): 了解 API7 网关对开源软件和许可证合规的承诺,以及所使用的主要开源组件及其许可证。 - [安全与合规概览](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/overview.md): 了解 API7 网关如何通过身份认证、授权、加密和审计等完整的安全与合规能力保护 API。 - [权限策略和权限边界](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/permission-policies-and-boundaries.md): 使用原生 JSON 文档格式在 API7 网关中编写权限策略。了解 `statement` 结构、允许的操作、ARN 风格资源、基于标签的条件,以及权限边界如何限制用户的最大权限范围。 - [基于角色的访问控制(RBAC)](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/role-based-access-control.md): 使用基于角色的访问控制管理用户对 API7 网关控制面的访问。为用户分配角色、挂载权限策略,并在网关组之间实施最小权限访问。 - [安全凭证管理](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/secure-credentials.md): 使用 API7 网关安全凭证管理保护敏感信息。了解如何管理 SSL 证书,以及如何与 HashiCorp Vault 等外部密钥管理器集成。 - [控制台单点登录(SSO)](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/sso-dashboard.md): 使用单点登录(SSO)集中管理 API7 控制台用户访问。支持 OIDC、SAML、LDAP 和 CAS 协议,并可自动映射角色。 - [使用 LDAP 实现单点登录](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/sso-ldap.md): 使用 LDAP 为 API7 控制台配置单点登录(SSO),使用户能够使用现有目录服务凭证认证。 - [使用 OIDC 配置 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/sso-oidc.md): 使用 OpenID Connect(OIDC)为 API7 控制台配置单点登录(SSO),并提供 Keycloak、Microsoft Entra ID 和 Auth0 的提供商专用配置指引。 - [使用 SAML 配置 SSO](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/sso-saml.md): 使用 SAML 2.0 为 API7 控制台配置单点登录(SSO),并提供 Microsoft Entra ID 和 Okta 的提供商专用配置指引。 - [信任中心](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/trust-center.md): API7 信任中心集中提供所有安全与合规信息,包括认证、安全报告和最佳实践指南。 - [验证镜像签名](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/verify-image-signatures.md): 使用 Cosign 和基于 OIDC 的无密钥验证来验证 API7 企业版容器镜像签名,确认每个镜像均由 API7.ai 构建和签名,以保护软件供应链。 - [漏洞扫描](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/vulnerability-scanning.md): 了解 API7.ai 针对 API7 网关实施的安全测试和漏洞扫描实践,包括 CVE 报告和补丁流程。 - [Web 应用防火墙(WAF)](https://docs.apiseven.com/api7-gateway/3.9.x/security-and-compliance/web-application-firewall.md): 了解何时将 Web 应用防火墙与 API7 网关结合使用、WAF 在安全模型中的作用,以及当前文档提供的集成方式。 #### tools - [CLI 工具](https://docs.apiseven.com/api7-gateway/3.9.x/tools/cli-tools.md) - [声明式 API](https://docs.apiseven.com/api7-gateway/3.9.x/tools/declarative-api.md) #### upgrade-guides - [备份与恢复](https://docs.apiseven.com/api7-gateway/3.9.x/upgrade-guides/backup-and-restore.md): 了解如何备份和恢复你的 API7 企业版数据,包含数据库备份、声明式配置备份和数据恢复过程的逐步说明。 - [API 网关集群迁移](https://docs.apiseven.com/api7-gateway/3.9.x/upgrade-guides/cluster-migration.md): 一份详细的分步指南,旨在帮助你在零停机时间的情况下,将 API7 API 网关部署迁移至新集群。 - [双集群升级](https://docs.apiseven.com/api7-gateway/3.9.x/upgrade-guides/dual-cluster.md): 逐步执行 API7 企业版双集群升级的指南,涵盖新集群部署、流量切换和回滚过程。 - [就地升级](https://docs.apiseven.com/api7-gateway/3.9.x/upgrade-guides/in-place.md): 逐步执行 API7 企业版控制平面就地升级的指南,涵盖数据库重用、配置更新和验证过程。 - [滚动升级](https://docs.apiseven.com/api7-gateway/3.9.x/upgrade-guides/rolling-upgrade.md): 逐步执行 API7 企业版数据平面节点滚动升级的指南,在维持 API 请求处理和服务连续性的同时确保零停机时间。 - [升级至 API7 企业版 3.x.x](https://docs.apiseven.com/api7-gateway/3.9.x/upgrade-guides/upgrade.md): API7 企业版升级的综合指南,涵盖控制面原地升级、数据面滚动升级、数据备份及稳定性注意事项。 ### ai-agent-skills 使用 Claude Code、Cursor 等 AI 编程 Agent,通过自然语言配置和管理 API7 企业版网关。 - [API7 网关 AI Agent Skills](https://docs.apiseven.com/api7-gateway/ai-agent-skills.md): 使用 Claude Code、Cursor 等 AI 编程 Agent,通过自然语言配置和管理 API7 企业版网关。 #### a7-persona-developer 面向使用 a7 CLI 在 API7 企业版中构建和测试 API 的 API 开发者角色 Skill,提供基于服务的 API 设计、路由配置、插件配置以及本地到云端开发工作流的决策框架。 - [API7 网关 AI Agent Skill:开发者角色](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-persona-developer.md): 面向使用 a7 CLI 在 API7 企业版中构建和测试 API 的 API 开发者角色 Skill,提供基于服务的 API 设计、路由配置、插件配置以及本地到云端开发工作流的决策框架。 #### a7-persona-operator 面向使用 a7 CLI 管理 API7 企业版实例的平台运维人员和 DevOps 工程师角色 Skill,提供网关组、企业版基于角色的访问控制(RBAC)、复杂部署、故障排查和灾难恢复的决策框架。 - [API7 网关 AI Agent Skill:运维角色](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-persona-operator.md): 面向使用 a7 CLI 管理 API7 企业版实例的平台运维人员和 DevOps 工程师角色 Skill,提供网关组、企业版基于角色的访问控制(RBAC)、复杂部署、故障排查和灾难恢复的决策框架。 #### a7-plugin-ai-content-moderation 用于通过 a7 CLI 配置 API7 企业版 AI 内容审核插件的 Skill,涵盖 ai-aws-content-moderation(AWS Comprehend,仅请求)和 ai-aliyun-content-moderation(阿里云,请求与响应并支持流式传输)、毒性阈值、类别过滤以及与 ai-proxy 的集成。 - [API7 网关 AI Agent Skill:AI 内容审核插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-ai-content-moderation.md): 用于通过 a7 CLI 配置 API7 企业版 AI 内容审核插件的 Skill,涵盖 ai-aws-content-moderation(AWS Comprehend,仅请求)和 ai-aliyun-content-moderation(阿里云,请求与响应并支持流式传输)、毒性阈值、类别过滤以及与 ai-proxy 的集成。 #### a7-plugin-ai-prompt-decorator 用于通过 a7 CLI 配置 API7 企业版 ai-prompt-decorator 插件的 Skill,涵盖向 LLM 请求添加系统、用户和助手消息前缀或后缀、设置对话上下文以及强制执行安全指南。 - [API7 网关 AI Agent Skill:ai-prompt-decorator 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-ai-prompt-decorator.md): 用于通过 a7 CLI 配置 API7 企业版 ai-prompt-decorator 插件的 Skill,涵盖向 LLM 请求添加系统、用户和助手消息前缀或后缀、设置对话上下文以及强制执行安全指南。 #### a7-plugin-ai-prompt-template 用于通过 a7 CLI 配置 API7 企业版 ai-prompt-template 插件的 Skill,涵盖定义带变量占位符的可复用提示词模板、强制执行提示词结构,以及与 ai-proxy 组合构建完整的 AI 网关流水线。 - [API7 网关 AI Agent Skill:ai-prompt-template 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-ai-prompt-template.md): 用于通过 a7 CLI 配置 API7 企业版 ai-prompt-template 插件的 Skill,涵盖定义带变量占位符的可复用提示词模板、强制执行提示词结构,以及与 ai-proxy 组合构建完整的 AI 网关流水线。 #### a7-plugin-ai-proxy 用于通过 a7 CLI 配置 API7 企业版 ai-proxy 插件的 Skill,涵盖将请求代理到模型服务提供方(OpenAI、Azure OpenAI、DeepSeek、Anthropic、Gemini、Vertex AI 等)、按服务提供方配置身份认证、模型、流式传输、日志以及路由和服务用法。 - [API7 网关 AI Agent Skill:ai-proxy 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-ai-proxy.md): 用于通过 a7 CLI 配置 API7 企业版 ai-proxy 插件的 Skill,涵盖将请求代理到模型服务提供方(OpenAI、Azure OpenAI、DeepSeek、Anthropic、Gemini、Vertex AI 等)、按服务提供方配置身份认证、模型、流式传输、日志以及路由和服务用法。 #### a7-plugin-basic-auth 用于通过 a7 CLI 配置 API7 企业版 basic-auth 插件的 Skill,涵盖路由上的 HTTP Basic Authentication、带用户名和密码的消费者凭证关联、hide_credentials、匿名消费者回退以及常见运维模式。 - [API7 网关 AI Agent Skill:basic-auth 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-basic-auth.md): 用于通过 a7 CLI 配置 API7 企业版 basic-auth 插件的 Skill,涵盖路由上的 HTTP Basic Authentication、带用户名和密码的消费者凭证关联、hide_credentials、匿名消费者回退以及常见运维模式。 #### a7-plugin-consumer-restriction 用于通过 a7 CLI 配置 API7 企业版 consumer-restriction 插件的 Skill,涵盖按消费者名称、服务 ID 或路由 ID 进行访问限制,白名单/黑名单模式以及按消费者限制 HTTP 方法。 - [API7 网关 AI Agent Skill:consumer-restriction 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-consumer-restriction.md): 用于通过 a7 CLI 配置 API7 企业版 consumer-restriction 插件的 Skill,涵盖按消费者名称、服务 ID 或路由 ID 进行访问限制,白名单/黑名单模式以及按消费者限制 HTTP 方法。 #### a7-plugin-cors 用于通过 a7 CLI 配置 API7 企业版 cors 插件的 Skill,涵盖路由上的跨源资源共享(CORS)、allow_origins、allow_methods、allow_headers、凭证处理、正则来源匹配、预检缓存以及常见运维模式。 - [API7 网关 AI Agent Skill:cors 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-cors.md): 用于通过 a7 CLI 配置 API7 企业版 cors 插件的 Skill,涵盖路由上的跨源资源共享(CORS)、allow_origins、allow_methods、allow_headers、凭证处理、正则来源匹配、预检缓存以及常见运维模式。 #### a7-plugin-datadog 用于通过 a7 CLI 配置 API7 企业版 datadog 插件的 Skill,涵盖通过 DogStatsD 向 Datadog 推送自定义指标、指标标签、批处理、全局 DogStatsD 服务器配置的插件元数据以及 Datadog Agent 集成。 - [API7 网关 AI Agent Skill:datadog 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-datadog.md): 用于通过 a7 CLI 配置 API7 企业版 datadog 插件的 Skill,涵盖通过 DogStatsD 向 Datadog 推送自定义指标、指标标签、批处理、全局 DogStatsD 服务器配置的插件元数据以及 Datadog Agent 集成。 #### a7-plugin-ext-plugin 用于通过 a7 CLI 配置 API7 企业版外部插件系统(ext-plugin-pre-req、ext-plugin-post-req、ext-plugin-post-resp)的 Skill,涵盖 Plugin Runner 架构、Go/Java/Python Runner 配置、RPC 协议、优雅降级以及性能注意事项。 - [API7 网关 AI Agent Skill:ext-plugin 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-ext-plugin.md): 用于通过 a7 CLI 配置 API7 企业版外部插件系统(ext-plugin-pre-req、ext-plugin-post-req、ext-plugin-post-resp)的 Skill,涵盖 Plugin Runner 架构、Go/Java/Python Runner 配置、RPC 协议、优雅降级以及性能注意事项。 #### a7-plugin-fault-injection 用于通过 a7 CLI 配置 API7 企业版 fault-injection 插件的 Skill,涵盖为混沌工程注入延迟和 HTTP 中断、基于百分比的采样、通过 vars 表达式进行条件注入,以及自定义响应头和带 NGINX 变量插值的响应体。 - [API7 网关 AI Agent Skill:fault-injection 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-fault-injection.md): 用于通过 a7 CLI 配置 API7 企业版 fault-injection 插件的 Skill,涵盖为混沌工程注入延迟和 HTTP 中断、基于百分比的采样、通过 vars 表达式进行条件注入,以及自定义响应头和带 NGINX 变量插值的响应体。 #### a7-plugin-grpc-transcode 用于通过 a7 CLI 配置 API7 企业版 grpc-transcode 插件的 Skill,涵盖将 RESTful HTTP 请求转换为 gRPC、proto 文件管理、用于数据类型转换的 pb_option 设置、错误详情解码以及网关组作用域。 - [API7 网关 AI Agent Skill:grpc-transcode 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-grpc-transcode.md): 用于通过 a7 CLI 配置 API7 企业版 grpc-transcode 插件的 Skill,涵盖将 RESTful HTTP 请求转换为 gRPC、proto 文件管理、用于数据类型转换的 pb_option 设置、错误详情解码以及网关组作用域。 #### a7-plugin-hmac-auth 用于通过 a7 CLI 配置 API7 企业版 hmac-auth 插件的 Skill,涵盖 HMAC 签名身份认证、带 key_id/secret_key 的消费者凭证关联、允许的算法、时钟偏差处理、请求体校验、签名请求头以及常见运维模式。 - [API7 网关 AI Agent Skill:hmac-auth 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-hmac-auth.md): 用于通过 a7 CLI 配置 API7 企业版 hmac-auth 插件的 Skill,涵盖 HMAC 签名身份认证、带 key_id/secret_key 的消费者凭证关联、允许的算法、时钟偏差处理、请求体校验、签名请求头以及常见运维模式。 #### a7-plugin-http-logger 用于通过 a7 CLI 配置 API7 企业版 http-logger 插件的 Skill,涵盖批量向 HTTP/HTTPS 端点推送访问日志、自定义日志格式以及网关组作用域。 - [API7 网关 AI Agent Skill:http-logger 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-http-logger.md): 用于通过 a7 CLI 配置 API7 企业版 http-logger 插件的 Skill,涵盖批量向 HTTP/HTTPS 端点推送访问日志、自定义日志格式以及网关组作用域。 #### a7-plugin-ip-restriction 用于通过 a7 CLI 配置 API7 企业版 ip-restriction 插件的 Skill,涵盖路由上的 IP 白名单/黑名单、CIDR 范围、IPv4/IPv6、代理后提取真实客户端 IP、自定义错误消息以及常见运维模式。 - [API7 网关 AI Agent Skill:ip-restriction 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-ip-restriction.md): 用于通过 a7 CLI 配置 API7 企业版 ip-restriction 插件的 Skill,涵盖路由上的 IP 白名单/黑名单、CIDR 范围、IPv4/IPv6、代理后提取真实客户端 IP、自定义错误消息以及常见运维模式。 #### a7-plugin-jwt-auth 用于通过 a7 CLI 配置 API7 企业版 jwt-auth 插件的 Skill,涵盖 JSON Web Token(JWT)身份认证、HS256/RS256 算法选择、消费者凭证关联、从请求头、查询参数或 Cookie 查找令牌、声明处理、时钟偏差、密钥管理以及常见运维模式。 - [API7 网关 AI Agent Skill:jwt-auth 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-jwt-auth.md): 用于通过 a7 CLI 配置 API7 企业版 jwt-auth 插件的 Skill,涵盖 JSON Web Token(JWT)身份认证、HS256/RS256 算法选择、消费者凭证关联、从请求头、查询参数或 Cookie 查找令牌、声明处理、时钟偏差、密钥管理以及常见运维模式。 #### a7-plugin-kafka-logger 用于通过 a7 CLI 配置 API7 企业版 kafka-logger 插件的 Skill,涵盖向 Apache Kafka 主题推送访问日志、Broker 配置、SASL 身份认证以及网关组作用域。 - [API7 网关 AI Agent Skill:kafka-logger 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-kafka-logger.md): 用于通过 a7 CLI 配置 API7 企业版 kafka-logger 插件的 Skill,涵盖向 Apache Kafka 主题推送访问日志、Broker 配置、SASL 身份认证以及网关组作用域。 #### a7-plugin-key-auth 用于通过 a7 CLI 配置 API7 企业版 key-auth 插件的 Skill,涵盖路由上的 API Key(API 密钥)身份认证、消费者凭证关联、从请求头、查询参数或 Cookie 查找 API Key、hide_credentials、匿名消费者回退以及常见运维模式。 - [API7 网关 AI Agent Skill:key-auth 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-key-auth.md): 用于通过 a7 CLI 配置 API7 企业版 key-auth 插件的 Skill,涵盖路由上的 API Key(API 密钥)身份认证、消费者凭证关联、从请求头、查询参数或 Cookie 查找 API Key、hide_credentials、匿名消费者回退以及常见运维模式。 #### a7-plugin-limit-count 用于通过 a7 CLI 配置 API7 企业版 limit-count 插件的 Skill,涵盖固定窗口限流、count/time_window 配置、Key 类型、用于分布式限流的 Redis 和 Redis 集群策略、基于组的共享配额、消费者级与路由级限流、响应头以及常见运维模式。 - [API7 网关 AI Agent Skill:limit-count 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-limit-count.md): 用于通过 a7 CLI 配置 API7 企业版 limit-count 插件的 Skill,涵盖固定窗口限流、count/time_window 配置、Key 类型、用于分布式限流的 Redis 和 Redis 集群策略、基于组的共享配额、消费者级与路由级限流、响应头以及常见运维模式。 #### a7-plugin-limit-req 用于通过 a7 CLI 配置 API7 企业版 limit-req 插件的 Skill,涵盖漏桶限流、rate/burst 配置、nodelay 行为、Key 类型、用于分布式限流的 Redis 策略、流量平滑以及与 limit-count 组合使用等常见运维模式。 - [API7 网关 AI Agent Skill:limit-req 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-limit-req.md): 用于通过 a7 CLI 配置 API7 企业版 limit-req 插件的 Skill,涵盖漏桶限流、rate/burst 配置、nodelay 行为、Key 类型、用于分布式限流的 Redis 策略、流量平滑以及与 limit-count 组合使用等常见运维模式。 #### a7-plugin-openid-connect 用于通过 a7 CLI 配置 API7 企业版 openid-connect 插件的 Skill,涵盖 OpenID Connect(OIDC)授权码流程、Bearer 令牌校验、令牌内省与 JWKS 校验、会话管理、Keycloak、Auth0、Okta 等身份提供方配置、重定向 URI 以及常见运维模式。 - [API7 网关 AI Agent Skill:openid-connect 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-openid-connect.md): 用于通过 a7 CLI 配置 API7 企业版 openid-connect 插件的 Skill,涵盖 OpenID Connect(OIDC)授权码流程、Bearer 令牌校验、令牌内省与 JWKS 校验、会话管理、Keycloak、Auth0、Okta 等身份提供方配置、重定向 URI 以及常见运维模式。 #### a7-plugin-prometheus 用于通过 a7 CLI 配置 API7 企业版 prometheus 插件的 Skill,涵盖在路由级和全局启用 Prometheus 指标导出、公开的指标(HTTP 状态、延迟、带宽、上游健康状况)以及网关组作用域。 - [API7 网关 AI Agent Skill:prometheus 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-prometheus.md): 用于通过 a7 CLI 配置 API7 企业版 prometheus 插件的 Skill,涵盖在路由级和全局启用 Prometheus 指标导出、公开的指标(HTTP 状态、延迟、带宽、上游健康状况)以及网关组作用域。 #### a7-plugin-proxy-rewrite 用于通过 a7 CLI 配置 API7 企业版 proxy-rewrite 插件的 Skill,涵盖将请求 URI、主机、方法、请求头和协议重写后再转发到上游,包括正则 URI 重写、请求头操作以及网关组作用域。 - [API7 网关 AI Agent Skill:proxy-rewrite 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-proxy-rewrite.md): 用于通过 a7 CLI 配置 API7 企业版 proxy-rewrite 插件的 Skill,涵盖将请求 URI、主机、方法、请求头和协议重写后再转发到上游,包括正则 URI 重写、请求头操作以及网关组作用域。 #### a7-plugin-redirect 用于通过 a7 CLI 配置 API7 企业版 redirect 插件的 Skill,涵盖 URI 重定向、HTTP 到 HTTPS 重定向、基于正则的 URI 重写、查询字符串处理以及网关组作用域。 - [API7 网关 AI Agent Skill:redirect 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-redirect.md): 用于通过 a7 CLI 配置 API7 企业版 redirect 插件的 Skill,涵盖 URI 重定向、HTTP 到 HTTPS 重定向、基于正则的 URI 重写、查询字符串处理以及网关组作用域。 #### a7-plugin-response-rewrite 用于通过 a7 CLI 配置 API7 企业版 response-rewrite 插件的 Skill,涵盖向客户端返回前重写响应状态码、响应头和响应体,包括使用 vars 条件执行、正则响应体过滤器以及网关组作用域。 - [API7 网关 AI Agent Skill:response-rewrite 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-response-rewrite.md): 用于通过 a7 CLI 配置 API7 企业版 response-rewrite 插件的 Skill,涵盖向客户端返回前重写响应状态码、响应头和响应体,包括使用 vars 条件执行、正则响应体过滤器以及网关组作用域。 #### a7-plugin-serverless 用于通过 a7 CLI 配置 API7 企业版 serverless-pre-function 和 serverless-post-function 插件的 Skill,涵盖在可配置请求阶段执行内联 Lua 函数、函数签名、闭包模式、可用 Lua API 以及执行顺序。 - [API7 网关 AI Agent Skill:serverless 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-serverless.md): 用于通过 a7 CLI 配置 API7 企业版 serverless-pre-function 和 serverless-post-function 插件的 Skill,涵盖在可配置请求阶段执行内联 Lua 函数、函数签名、闭包模式、可用 Lua API 以及执行顺序。 #### a7-plugin-skywalking 用于通过 a7 CLI 配置 API7 企业版 skywalking 插件的 Skill,涵盖使用 Apache SkyWalking OAP 进行分布式追踪、采样配置、服务拓扑以及网关组作用域。 - [API7 网关 AI Agent Skill:skywalking 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-skywalking.md): 用于通过 a7 CLI 配置 API7 企业版 skywalking 插件的 Skill,涵盖使用 Apache SkyWalking OAP 进行分布式追踪、采样配置、服务拓扑以及网关组作用域。 #### a7-plugin-traffic-split 用于通过 a7 CLI 配置 API7 企业版 traffic-split 插件的 Skill,涵盖通过条件匹配规则在上游之间进行加权流量拆分,包括灰度发布、蓝绿发布、A/B 测试模式以及网关组作用域。 - [API7 网关 AI Agent Skill:traffic-split 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-traffic-split.md): 用于通过 a7 CLI 配置 API7 企业版 traffic-split 插件的 Skill,涵盖通过条件匹配规则在上游之间进行加权流量拆分,包括灰度发布、蓝绿发布、A/B 测试模式以及网关组作用域。 #### a7-plugin-wolf-rbac 用于通过 a7 CLI 配置 API7 企业版 wolf-rbac 插件的 Skill,涵盖与 Wolf RBAC 服务器集成以实现基于角色的访问控制、令牌管理、登录、用户信息、修改密码 API 端点、权限检查流程以及多应用配置。 - [API7 网关 AI Agent Skill:wolf-rbac 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-wolf-rbac.md): 用于通过 a7 CLI 配置 API7 企业版 wolf-rbac 插件的 Skill,涵盖与 Wolf RBAC 服务器集成以实现基于角色的访问控制、令牌管理、登录、用户信息、修改密码 API 端点、权限检查流程以及多应用配置。 #### a7-plugin-zipkin 用于通过 a7 CLI 配置 API7 企业版 zipkin 插件的 Skill,涵盖使用 Zipkin、Jaeger 或任何兼容 Zipkin 的采集器进行分布式追踪、B3 传播请求头、采样以及网关组作用域。 - [API7 网关 AI Agent Skill:zipkin 插件](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-plugin-zipkin.md): 用于通过 a7 CLI 配置 API7 企业版 zipkin 插件的 Skill,涵盖使用 Zipkin、Jaeger 或任何兼容 Zipkin 的采集器进行分布式追踪、B3 传播请求头、采样以及网关组作用域。 #### a7-recipe-api-versioning 使用 API7 企业版和 a7 CLI 实现 API 版本管理策略的方案 Skill,涵盖 URI 路径版本管理、基于请求头的版本管理、用于渐进式迁移的流量拆分以及版本生命周期管理。 - [API7 网关 AI Agent Skill:API 版本管理方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-api-versioning.md): 使用 API7 企业版和 a7 CLI 实现 API 版本管理策略的方案 Skill,涵盖 URI 路径版本管理、基于请求头的版本管理、用于渐进式迁移的流量拆分以及版本生命周期管理。 #### a7-recipe-blue-green 使用 a7 CLI 在 API7 企业版中实现蓝绿发布的方案 Skill,涵盖创建两个基于服务的环境、通过更新路由 service_id 切换流量、回滚流程以及限定网关组的配置同步工作流。 - [API7 网关 AI Agent Skill:蓝绿发布方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-blue-green.md): 使用 a7 CLI 在 API7 企业版中实现蓝绿发布的方案 Skill,涵盖创建两个基于服务的环境、通过更新路由 service_id 切换流量、回滚流程以及限定网关组的配置同步工作流。 #### a7-recipe-canary 使用 a7 CLI 在 API7 企业版中实现灰度发布的方案 Skill,涵盖通过 traffic-split 插件渐进式转移流量、基于请求头的灰度路由、监控检查点以及完整的发布或回滚工作流。 - [API7 网关 AI Agent Skill:灰度发布方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-canary.md): 使用 a7 CLI 在 API7 企业版中实现灰度发布的方案 Skill,涵盖通过 traffic-split 插件渐进式转移流量、基于请求头的灰度路由、监控检查点以及完整的发布或回滚工作流。 #### a7-recipe-circuit-breaker 使用 a7 CLI 在 API7 企业版中实现服务熔断模式的方案 Skill,涵盖 api-breaker 插件、不健康阈值、健康恢复、响应码分类以及与服务健康检查的集成。 - [API7 网关 AI Agent Skill:熔断方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-circuit-breaker.md): 使用 a7 CLI 在 API7 企业版中实现服务熔断模式的方案 Skill,涵盖 api-breaker 插件、不健康阈值、健康恢复、响应码分类以及与服务健康检查的集成。 #### a7-recipe-graphql-proxy 使用 API7 企业版和 a7 CLI 实现 GraphQL 代理模式的方案 Skill,涵盖基于操作的路由、按操作限流、REST 到 GraphQL 转换以及 GraphQL API 的企业级安全。 - [API7 网关 AI Agent Skill:GraphQL 代理方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-graphql-proxy.md): 使用 API7 企业版和 a7 CLI 实现 GraphQL 代理模式的方案 Skill,涵盖基于操作的路由、按操作限流、REST 到 GraphQL 转换以及 GraphQL API 的企业级安全。 #### a7-recipe-health-check 使用 a7 CLI 在 API7 企业版中配置后端健康检查的方案 Skill,涵盖主动健康检查、被动健康检查、两者组合、健康/不健康阈值以及基于服务的路由关联。 - [API7 网关 AI Agent Skill:健康检查方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-health-check.md): 使用 a7 CLI 在 API7 企业版中配置后端健康检查的方案 Skill,涵盖主动健康检查、被动健康检查、两者组合、健康/不健康阈值以及基于服务的路由关联。 #### a7-recipe-mtls 使用 a7 CLI 在 API7 企业版中配置双向 TLS(mTLS)的方案 Skill,涵盖 SSL 证书管理、到后端服务的上游 mTLS、客户端证书校验以及从客户端经 API7 企业版到上游的端到端 mTLS 配置。 - [API7 网关 AI Agent Skill:mTLS 方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-mtls.md): 使用 a7 CLI 在 API7 企业版中配置双向 TLS(mTLS)的方案 Skill,涵盖 SSL 证书管理、到后端服务的上游 mTLS、客户端证书校验以及从客户端经 API7 企业版到上游的端到端 mTLS 配置。 #### a7-recipe-multi-tenant 使用 API7 企业版和 a7 CLI 实现多租户模式的方案 Skill,涵盖网关组隔离、消费者策略、基于服务的租户路由以及基于凭证的租户访问。 - [API7 网关 AI Agent Skill:多租户方案](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-recipe-multi-tenant.md): 使用 API7 企业版和 a7 CLI 实现多租户模式的方案 Skill,涵盖网关组隔离、消费者策略、基于服务的租户路由以及基于凭证的租户访问。 #### a7-shared 使用 API7 企业版命令行工具 a7 的核心 Skill,提供项目约定、命令模式、双 API 架构和开发工作流;在处理 a7 源代码、添加新命令、编写测试或修改任何 a7 组件时加载此 Skill。 - [API7 网关 AI Agent Skill:共享 CLI 约定](https://docs.apiseven.com/api7-gateway/ai-agent-skills/a7-shared.md): 使用 API7 企业版命令行工具 a7 的核心 Skill,提供项目约定、命令模式、双 API 架构和开发工作流;在处理 a7 源代码、添加新命令、编写测试或修改任何 a7 组件时加载此 Skill。 ### ai-gateway #### get-started 在 5 分钟内配置 API7 AI 网关并代理第一个 OpenAI 请求,包含分步说明和代码示例。 - [5 分钟代理第一个大语言模型请求](https://docs.apiseven.com/api7-gateway/ai-gateway/get-started.md): 在 5 分钟内配置 API7 AI 网关并代理第一个 OpenAI 请求,包含分步说明和代码示例。 #### llm-providers - [接入 Anthropic Claude](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/anthropic.md): 通过 API7 网关路由 Anthropic Claude API 流量,集中实施安全、限流和可观测性策略。 - [集成 Azure OpenAI Service](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/azure-openai.md): 通过 API7 网关管理 Azure OpenAI Deployment,集中处理资源名称、API 版本和身份认证。 - [将流量路由到 DeepSeek 模型](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/deepseek.md): 通过 API7 网关代理 DeepSeek API 请求,集中管理身份认证、启用故障转移并监控用量。 - [接入 Google Gemini](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/google-gemini.md): 通过 API7 网关代理 Google Gemini API 请求,集中管理 API Key(API 密钥)并监控 AI 流量。 - [将流量路由到 OpenAI](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/openai.md): 通过 API7 网关代理和保护 OpenAI API 请求,集中管理身份认证、启用故障转移并监控用量。 - [接入任意 OpenAI 兼容大语言模型](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/openai-compatible.md): 通过 API7 网关代理任意 OpenAI 兼容 API,接入自托管模型、自定义端点或小众服务提供方。 - [通过 OpenRouter 接入数百种大语言模型](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/openrouter.md): 通过 API7 AI 网关接入 OpenRouter,使用一个 API 访问 200 多种大语言模型,同时保持企业级安全控制。 - [将企业 AI 流量路由到 Vertex AI](https://docs.apiseven.com/api7-gateway/ai-gateway/llm-providers/vertex-ai.md): 通过 API7 网关安全代理 Google Cloud Vertex AI 请求,支持服务账户身份认证和区域路由。 #### overview 使用 API7 AI 网关集中管理大语言模型访问,通过一个平台将流量路由到多个服务提供方、实施安全护栏并控制成本。 - [管理和保护 AI 流量](https://docs.apiseven.com/api7-gateway/ai-gateway/overview.md): 使用 API7 AI 网关集中管理大语言模型访问,通过一个平台将流量路由到多个服务提供方、实施安全护栏并控制成本。 #### use-cases - [监控 AI 流量并跟踪大语言模型成本](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/ai-observability-and-cost-tracking.md): 使用 API7 AI 网关的可观测性功能,洞察大语言模型用量、Token 消耗、延迟和成本。 - [使用 AI 重写转换 API 请求](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/ai-request-transformation.md): 在网关层使用大语言模型智能地转换、丰富或重构 API 请求与响应。 - [实施 AI 安全护栏并保护 PII](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/content-safety-and-guardrails.md): 使用 API7 AI 网关安全护栏,在请求到达大语言模型前阻止提示词注入、检测有害内容并脱敏 PII。 - [将 REST API 暴露为 AI Agent 的 MCP 工具](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/expose-apis-as-mcp-tools.md): 将现有 OpenAPI 服务转换为 MCP 兼容工具,使 AI Agent(AI 智能体)能够自动发现并调用 API。 - [通过 API7-MCP 在 AI 客户端中管理 API7 企业版](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/manage-api7-with-mcp.md): 部署 API7-MCP,让 Cursor、Claude Desktop、Cline 等 AI 客户端读取 API7 企业版资源、查看 Prometheus 指标、管理基于角色的访问控制(RBAC),并通过网关发送测试流量。 - [配置多模型路由和自动故障转移](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/multi-llm-routing-and-fallback.md): 使用加权负载均衡、自动故障转移和健康检查,在多个模型服务提供方之间路由 AI 流量。 - [实现提示词模板和装饰器](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/prompt-engineering-and-templating.md): 使用 API7 AI 网关的可复用提示词模板和自动系统提示词注入,规范大语言模型交互。 - [将 Anthropic Messages 转换为 OpenAI Chat Completions](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/protocol-conversion.md): 使用 API7 AI 网关透明地将 Anthropic Messages API 请求转换为 OpenAI Chat Completions API 格式,使团队能够通过 Anthropic SDK 使用任意 OpenAI 兼容后端。 - [在网关层实现 RAG](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/retrieval-augmented-generation.md): 使用 API7 AI 网关内置的检索增强生成(RAG),通过相关上下文提升大语言模型响应质量。 - [使用基于 Token 的限流控制 AI 成本](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/token-rate-limiting-and-quota-management.md): 实施基于 Token 的限流,防止大语言模型被滥用,并按路由和模型实例控制 AI 成本。 ### api-observability #### alert 按照本指南在 API7 企业版中创建告警策略,以便接收特定事件的通知并监控系统性能。 - [触发网关告警](https://docs.apiseven.com/api7-gateway/api-observability/alert.md): 按照本指南在 API7 企业版中创建告警策略,以便接收特定事件的通知并监控系统性能。 #### log-consumer-label-in-access-log 按照本指南在 API7 企业版的访问日志中记录消费者标签,以增强 API 的管理和安全性。 - [在访问日志中记录消费者标签](https://docs.apiseven.com/api7-gateway/api-observability/log-consumer-label-in-access-log.md): 按照本指南在 API7 企业版的访问日志中记录消费者标签,以增强 API 的管理和安全性。 #### logging 按照本指南在 API7 企业版中配置 API 流量日志记录,与各种日志平台集成以捕获详细的访问日志。 - [记录 API 流量日志](https://docs.apiseven.com/api7-gateway/api-observability/logging.md): 按照本指南在 API7 企业版中配置 API 流量日志记录,与各种日志平台集成以捕获详细的访问日志。 #### monitoring 按照本指南在 API7 企业版中监控 API 指标,利用 Prometheus 插件来有效追踪和可视化 HTTP 指标。 - [监控 API 指标](https://docs.apiseven.com/api7-gateway/api-observability/monitoring.md): 按照本指南在 API7 企业版中监控 API 指标,利用 Prometheus 插件来有效追踪和可视化 HTTP 指标。 #### tracing 按照本指南在 API7 企业版中使用 opentelemetry 插件设置追踪,实现对请求在系统中的旅程的监控。 - [追踪 API 流量](https://docs.apiseven.com/api7-gateway/api-observability/tracing.md): 按照本指南在 API7 企业版中使用 opentelemetry 插件设置追踪,实现对请求在系统中的旅程的监控。 ### best-practices #### blue-green-deployment 按照本指南在 API7 企业版中设置蓝绿发布,通过使用两个相同的环境,将应用程序更新期间的停机时间和风险降至最低。 - [配置蓝绿发布](https://docs.apiseven.com/api7-gateway/best-practices/blue-green-deployment.md): 按照本指南在 API7 企业版中设置蓝绿发布,通过使用两个相同的环境,将应用程序更新期间的停机时间和风险降至最低。 #### configure-grpc 按照本指南配置 API7 网关以代理 gRPC 流量,使你能够使用 HTTP/2 处理高性能的远程过程调用(RPC)。 - [代理 gRPC 流量](https://docs.apiseven.com/api7-gateway/best-practices/configure-grpc.md): 按照本指南配置 API7 网关以代理 gRPC 流量,使你能够使用 HTTP/2 处理高性能的远程过程调用(RPC)。 #### custom-plugin 遵循本指南在 API7 企业版中添加自定义插件,通过使用 Lua 编程定制逻辑来扩展功能和管理 API 流量。 - [添加自定义插件](https://docs.apiseven.com/api7-gateway/best-practices/custom-plugin.md): 遵循本指南在 API7 企业版中添加自定义插件,通过使用 Lua 编程定制逻辑来扩展功能和管理 API 流量。 #### dashboard-sso - [使用 LDAP 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/best-practices/dashboard-sso/ldap.md): 按照本指南在 API7 企业版中使用 LDAP 协议配置单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Auth0 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/best-practices/dashboard-sso/oidc/auth0.md): 按照本指南在 API7 企业版中使用 OIDC 协议配置基于 Auth0 的单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Microsoft Entra ID 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/best-practices/dashboard-sso/oidc/azure-ad.md): 按照本指南在 API7 企业版中使用 OIDC 协议配置基于 Microsoft Entra ID (Azure AD) 的单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Keycloak 配置控制台单点登录(SSO)](https://docs.apiseven.com/api7-gateway/best-practices/dashboard-sso/oidc/keycloak.md): 按照本指南在 API7 企业版中使用 OIDC 和 Keycloak 配置单点登录(SSO),从而简化用户身份认证并增强安全性。 - [使用 Microsoft Entra ID 和 SAML 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/best-practices/dashboard-sso/saml/azure-ad.md): 按照本指南在 API7 企业版中使用 SAML 协议配置基于 Microsoft Entra ID (Azure AD) 的单点登录 (SSO),简化用户身份验证并增强安全性。 - [使用 Okta 和 SAML 配置控制台 SSO](https://docs.apiseven.com/api7-gateway/best-practices/dashboard-sso/saml/okta.md): 按照本指南在 API7 企业版中使用 SAML 协议配置基于 Okta 的单点登录 (SSO),简化用户身份验证并在控制台中启用角色映射。 #### data-masking-access-log 了解如何在 API 网关访问日志中有效脱敏诸如电子邮件地址之类的敏感数据,以增强安全性并确保可靠的 API 管理。 - [在访问日志中脱敏敏感数据](https://docs.apiseven.com/api7-gateway/best-practices/data-masking-access-log.md): 了解如何在 API 网关访问日志中有效脱敏诸如电子邮件地址之类的敏感数据,以增强安全性并确保可靠的 API 管理。 #### design-custom-role-system 按照本指南在 API7 企业版中设计并实现自定义角色系统,授予用户细粒度的访问权限以增强安全性和数据完整性。 - [设计自定义角色系统](https://docs.apiseven.com/api7-gateway/best-practices/design-custom-role-system.md): 按照本指南在 API7 企业版中设计并实现自定义角色系统,授予用户细粒度的访问权限以增强安全性和数据完整性。 #### devops-adc 按照本指南使用 API7 声明式 CLI(ADC)声明式地管理 API7 企业版配置,轻松与版本控制系统和 CI/CD 流水线集成。 - [声明式管理 API7 企业版](https://docs.apiseven.com/api7-gateway/best-practices/devops-adc.md): 按照本指南使用 API7 声明式 CLI(ADC)声明式地管理 API7 企业版配置,轻松与版本控制系统和 CI/CD 流水线集成。 #### disable-global-plugins-conditionally 了解如何在 API7 企业版中有条件地禁用全局插件执行,使你可以根据特定要求灵活控制插件的执行。 - [有条件地禁用全局插件](https://docs.apiseven.com/api7-gateway/best-practices/disable-global-plugins-conditionally.md): 了解如何在 API7 企业版中有条件地禁用全局插件执行,使你可以根据特定要求灵活控制插件的执行。 #### forward-auth-user-info-to-upstream 在使用 OpenID Connect 或 SAML Auth 等认证插件时,你可能需要将经过身份验证的用户信息传递给上游服务。这使上游应用程序能够基于用户身份实现额外的业务逻辑,例如个性化、审计和访问控制。 - [将外部认证的用户信息转发到上游](https://docs.apiseven.com/api7-gateway/best-practices/forward-auth-user-info-to-upstream.md): 在使用 OpenID Connect 或 SAML Auth 等认证插件时,你可能需要将经过身份验证的用户信息传递给上游服务。这使上游应用程序能够基于用户身份实现额外的业务逻辑,例如个性化、审计和访问控制。 #### gateway-error-log-kubernetes-splunk 了解如何将部署在 Kubernetes 环境中的多个网关的错误日志转发至 Splunk,以进行集中式的日志管理。 - [将 Kubernetes 的错误日志转发至 Splunk](https://docs.apiseven.com/api7-gateway/best-practices/gateway-error-log-kubernetes-splunk.md): 了解如何将部署在 Kubernetes 环境中的多个网关的错误日志转发至 Splunk,以进行集中式的日志管理。 #### gateway-health-probe 按照本指南在 API7 企业版中启用健康检查探针,通过监控上游节点的健康状况来确保网关的稳定性和可靠性。 - [执行网关健康检查探针](https://docs.apiseven.com/api7-gateway/best-practices/gateway-health-probe.md): 按照本指南在 API7 企业版中启用健康检查探针,通过监控上游节点的健康状况来确保网关的稳定性和可靠性。 #### manage-token 按照本指南在 API7 企业版中实施基于 Token 的身份验证,实现与 GitOps 工作流的无缝集成并增强安全性。 - [使用 Token 集成 GitOps 工作流](https://docs.apiseven.com/api7-gateway/best-practices/manage-token.md): 按照本指南在 API7 企业版中实施基于 Token 的身份验证,实现与 GitOps 工作流的无缝集成并增强安全性。 #### plugin-development-best-practices 通过使用 apisix.core 库而非底层 OpenResty API、用 schema 校验配置、选择正确的阶段与优先级,编写正确、高性能且易维护的自定义 Lua 插件。 - [插件开发最佳实践](https://docs.apiseven.com/api7-gateway/best-practices/plugin-development-best-practices.md): 通过使用 apisix.core 库而非底层 OpenResty API、用 schema 校验配置、选择正确的阶段与优先级,编写正确、高性能且易维护的自定义 Lua 插件。 #### proxy-tcp-traffic 按照本指南配置 API7 网关以处理 TCP 和 UDP 流量,从而为 MySQL 等各种后端服务启用传输层 (四层) 代理。 - [代理 TCP 流量](https://docs.apiseven.com/api7-gateway/best-practices/proxy-tcp-traffic.md): 按照本指南配置 API7 网关以处理 TCP 和 UDP 流量,从而为 MySQL 等各种后端服务启用传输层 (四层) 代理。 #### route-priority-matching-conditions 遵循本指南使用 Ingress Controller 配置路由优先级和高级匹配条件,以实现更细粒度的 API 管理。 - [设置路由优先级和匹配条件 (Ingress Controller)](https://docs.apiseven.com/api7-gateway/best-practices/route-priority-matching-conditions.md): 遵循本指南使用 Ingress Controller 配置路由优先级和高级匹配条件,以实现更细粒度的 API 管理。 #### scim - [使用 Okta 配置 SCIM 账号同步](https://docs.apiseven.com/api7-gateway/best-practices/scim/okta.md): 按照本指南在 API7 企业版中配置基于 Okta 的 SCIM 账号同步,实现身份提供商和 API7 控制台之间的用户自动同步。 #### serverless-or-custom-plugins 对比内置的 serverless 函数插件与自定义 Lua 插件,为在 API7 网关中运行自己的 Lua 逻辑选择合适的方式。 - [Serverless 函数还是自定义插件](https://docs.apiseven.com/api7-gateway/best-practices/serverless-or-custom-plugins.md): 对比内置的 serverless 函数插件与自定义 Lua 插件,为在 API7 网关中运行自己的 Lua 逻辑选择合适的方式。 #### service-discovery 按照本指南在 API7 企业版中配置服务发现机制,以支持动态探测上游节点并增强 API 管理的灵活性。 - [使用服务发现配置上游](https://docs.apiseven.com/api7-gateway/best-practices/service-discovery.md): 按照本指南在 API7 企业版中配置服务发现机制,以支持动态探测上游节点并增强 API 管理的灵活性。 #### telemetry-compression 按照本指南配置从 API7 企业版数据面(DP)到控制面(CP)的遥测数据压缩,以提高网络性能并降低 CPU 使用率。 - [优化遥测数据传输](https://docs.apiseven.com/api7-gateway/best-practices/telemetry-compression.md): 按照本指南配置从 API7 企业版数据面(DP)到控制面(CP)的遥测数据压缩,以提高网络性能并降低 CPU 使用率。 #### upstream-ha 按照本指南在 API7 企业版中通过添加多个上游节点、修改负载均衡类型以及启用健康检查来确保上游的高可用性。 - [确保上游高可用性](https://docs.apiseven.com/api7-gateway/best-practices/upstream-ha.md): 按照本指南在 API7 企业版中通过添加多个上游节点、修改负载均衡类型以及启用健康检查来确保上游的高可用性。 #### verify-api7-image-signatures 遵循本指南使用 Cosign 验证 API7 Docker 镜像签名,确保软件供应链中镜像的真实性和完整性。 - [验证 API7 镜像签名](https://docs.apiseven.com/api7-gateway/best-practices/verify-api7-image-signatures.md): 遵循本指南使用 Cosign 验证 API7 Docker 镜像签名,确保软件供应链中镜像的真实性和完整性。 ### configure-and-manage #### benchmark-on-aws-eks 在 AWS EKS 上重现已发布的 API7 网关性能基准。演练涵盖 EKS 集群设置、三个独立节点组、Helm 安装、NGINX 上游和 wrk2 部署以及运行完整的场景套件。 - [在 AWS EKS 上运行基准](https://docs.apiseven.com/api7-gateway/configure-and-manage/benchmark-on-aws-eks.md): 在 AWS EKS 上重现已发布的 API7 网关性能基准。演练涵盖 EKS 集群设置、三个独立节点组、Helm 安装、NGINX 上游和 wrk2 部署以及运行完整的场景套件。 #### configure-control-plane API7 网关控制面的详细配置参考,涵盖控制台和 DP Manager 配置文件。 - [API7 网关控制面配置参考](https://docs.apiseven.com/api7-gateway/configure-and-manage/configure-control-plane.md): API7 网关控制面的详细配置参考,涵盖控制台和 DP Manager 配置文件。 #### configure-data-plane API7 网关数据面的详细配置参考,基于 config-default.yaml 结构。 - [API7 网关数据面配置参考](https://docs.apiseven.com/api7-gateway/configure-and-manage/configure-data-plane.md): API7 网关数据面的详细配置参考,基于 config-default.yaml 结构。 #### data-plane-resilience 为 API7 网关数据面节点配置备用存储,使其在控制面长时间中断时仍能重启并继续运行。 - [数据面弹性](https://docs.apiseven.com/api7-gateway/configure-and-manage/data-plane-resilience.md): 为 API7 网关数据面节点配置备用存储,使其在控制面长时间中断时仍能重启并继续运行。 #### deployment-scenarios - [API7 网关多可用区部署](https://docs.apiseven.com/api7-gateway/configure-and-manage/deployment-scenarios/multi-az-deployment.md): 用于跨多个可用区部署 API7 网关的配置和架构,以实现高可用性和容错能力。 - [多区域部署模式](https://docs.apiseven.com/api7-gateway/configure-and-manage/deployment-scenarios/multi-region-deployment.md): 跨多个地理区域部署 API7 网关以实现全球覆盖和灾难恢复的架构和注意事项。 #### high-availability-data-plane 设计具有多个节点、健康检查和负载均衡器故障转移的高可用 API7 网关数据面。 - [数据面高可用性](https://docs.apiseven.com/api7-gateway/configure-and-manage/high-availability-data-plane.md): 设计具有多个节点、健康检查和负载均衡器故障转移的高可用 API7 网关数据面。 #### labels 使用标签组织和筛选 API7 网关资源,通过附加到网关组、服务、路由和消费者等实体的键值元数据,按团队、环境和应用进行分类。 - [标签](https://docs.apiseven.com/api7-gateway/configure-and-manage/labels.md): 使用标签组织和筛选 API7 网关资源,通过附加到网关组、服务、路由和消费者等实体的键值元数据,按团队、环境和应用进行分类。 #### license-management 管理 API7 网关许可证,了解生产与非生产 CPU 核心数额度和许可证状态,并配置许可证文件路径以实现自动化部署。 - [许可证管理](https://docs.apiseven.com/api7-gateway/configure-and-manage/license-management.md): 管理 API7 网关许可证,了解生产与非生产 CPU 核心数额度和许可证状态,并配置许可证文件路径以实现自动化部署。 #### performance-benchmark 了解 API7 网关在 AWS EKS 和单主机环境中的性能基准结果,以及复现基准测试的方法和优化建议。 - [性能基准](https://docs.apiseven.com/api7-gateway/configure-and-manage/performance-benchmark.md): 了解 API7 网关在 AWS EKS 和单主机环境中的性能基准结果,以及复现基准测试的方法和优化建议。 #### production-best-practices 在生产中管理 API7 网关的操作最佳实践,包括 GitOps、变更管理和灾难恢复。 - [生产最佳实践](https://docs.apiseven.com/api7-gateway/configure-and-manage/production-best-practices.md): 在生产中管理 API7 网关的操作最佳实践,包括 GitOps、变更管理和灾难恢复。 #### run-in-production API7 网关的上线前检查清单和部署指南,用于确保生产环境稳定且安全。 - [在生产环境中运行](https://docs.apiseven.com/api7-gateway/configure-and-manage/run-in-production.md): API7 网关的上线前检查清单和部署指南,用于确保生产环境稳定且安全。 #### scale-data-plane 水平扩展 API7 网关数据面节点以提高吞吐量并为高可用性部署做好准备。 - [扩缩容数据面](https://docs.apiseven.com/api7-gateway/configure-and-manage/scale-data-plane.md): 水平扩展 API7 网关数据面节点以提高吞吐量并为高可用性部署做好准备。 #### shared-dict-sizing 根据部署规模为 API7 网关的指标、服务发现、开发者门户和链路追踪共享内存合理分配容量,避免内存溢出导致数据丢失。 - [共享内存容量规划](https://docs.apiseven.com/api7-gateway/configure-and-manage/shared-dict-sizing.md): 根据部署规模为 API7 网关的指标、服务发现、开发者门户和链路追踪共享内存合理分配容量,避免内存溢出导致数据丢失。 #### telemetry-opt-out 配置数据面和控制面之间的遥测数据传输,包括压缩级别以及如何禁用遥测。 - [优化遥测数据传输](https://docs.apiseven.com/api7-gateway/configure-and-manage/telemetry-opt-out.md): 配置数据面和控制面之间的遥测数据传输,包括压缩级别以及如何禁用遥测。 #### user-management 管理 API7 企业版中的用户、角色和权限策略。 - [用户管理](https://docs.apiseven.com/api7-gateway/configure-and-manage/user-management.md): 管理 API7 企业版中的用户、角色和权限策略。 ### developer-portal #### deploy - [配置开发者门户](https://docs.apiseven.com/api7-gateway/developer-portal/deploy/configure-portal.md): 配置开发者门户设置,包括公共访问、门户令牌、内置身份认证和 SCIM 预配。 - [定制开发者门户](https://docs.apiseven.com/api7-gateway/developer-portal/deploy/customize-portal.md): 使用 API7 Developer Portal Boilerplate 自定义开发者门户的品牌、主题、身份认证提供商和功能。 - [部署开发者门户](https://docs.apiseven.com/api7-gateway/developer-portal/deploy/deploy-portal.md): 在 Docker Compose 或 Kubernetes 上部署 API7 开发者门户的两个官方镜像(门户 API 后端和面向开发者的前端),并将其连接到 API7 控制面。 #### get-started 从 Docker Compose 安装包启动本地 API7 开发者门户、注册开发者,并验证对 API Hub 的访问。 - [启动本地开发者门户](https://docs.apiseven.com/api7-gateway/developer-portal/get-started.md): 从 Docker Compose 安装包启动本地 API7 开发者门户、注册开发者,并验证对 API Hub 的访问。 #### guides - [浏览 API](https://docs.apiseven.com/api7-gateway/developer-portal/guides/browse-apis.md): 在开发者门户的 API Hub 中发现和探索可用的 API 产品。 - [创建应用程序](https://docs.apiseven.com/api7-gateway/developer-portal/guides/create-application.md): 在开发者门户中创建一个应用程序来对你的 API 订阅和凭证进行分组。 - [管理凭证](https://docs.apiseven.com/api7-gateway/developer-portal/guides/manage-credentials.md): 在开发者门户中创建、查看、重新生成和删除用于对 API 请求进行身份认证的凭证。 - [管理组织](https://docs.apiseven.com/api7-gateway/developer-portal/guides/manage-organization.md): 在开发者门户中管理组织,包括邀请成员、分配角色以及在组织之间切换。 - [注册与登录](https://docs.apiseven.com/api7-gateway/developer-portal/guides/register-and-login.md): 创建开发者账户并使用电子邮件/密码、SSO 或组织邀请登录开发者门户。 - [订阅 API](https://docs.apiseven.com/api7-gateway/developer-portal/guides/subscribe-to-api.md): 为你的应用程序订阅 API 产品,以通过开发者门户获得使用 API 的访问权限。 - [调试 API](https://docs.apiseven.com/api7-gateway/developer-portal/guides/try-api.md): 使用内置的 Try It Out 功能直接从开发者门户测试 API 端点。 #### key-concepts - [API 产品](https://docs.apiseven.com/api7-gateway/developer-portal/key-concepts/api-products.md): 了解开发者门户中的 API 产品,包括产品类型、可见性设置、身份认证选项和发布生命周期。 - [应用程序](https://docs.apiseven.com/api7-gateway/developer-portal/key-concepts/applications.md): 了解开发者门户中的应用程序,以及如何按特定项目或用例对订阅和凭证进行分组。 - [凭证](https://docs.apiseven.com/api7-gateway/developer-portal/key-concepts/credentials.md): 了解开发者门户中的凭证,包括支持的身份认证类型(API Key(API 密钥)身份认证、基本身份认证和 OAuth/DCR)以及凭证生命周期管理。 - [开发者](https://docs.apiseven.com/api7-gateway/developer-portal/key-concepts/developers.md): 了解开发者门户中的开发者,包括注册方式、账户状态,以及开发者与消费者之间的区别。 - [订阅](https://docs.apiseven.com/api7-gateway/developer-portal/key-concepts/subscriptions.md): 了解开发者门户中的订阅,包括审批工作流程、状态转换和自动审批配置。 #### manage - [配置动态客户端注册(DCR)](https://docs.apiseven.com/api7-gateway/developer-portal/manage/configure-dcr.md): 配置 DCR 提供商以使开发者能够通过开发者门户注册 OAuth 2.0 客户端。 - [使用 Okta 为自定义开发者门户配置 SCIM 预配](https://docs.apiseven.com/api7-gateway/developer-portal/manage/configure-scim.md): 使用 Okta 为基于 API7 Developer Portal Boilerplate 的自定义开发者门户配置 SCIM 预配。 - [为开发者门户配置 SSO](https://docs.apiseven.com/api7-gateway/developer-portal/manage/configure-sso.md): 使用 OIDC、SAML、LDAP 或 CAS 身份提供商为开发者门户配置单点登录(SSO)。 - [管理 API 产品](https://docs.apiseven.com/api7-gateway/developer-portal/manage/manage-api-products.md): 在 Provider Portal 中创建、配置、发布和管理 API 产品,以供开发者通过开发者门户使用。 - [管理应用程序](https://docs.apiseven.com/api7-gateway/developer-portal/manage/manage-applications.md): 在开发者门户中管理开发者应用程序,包括生命周期、结构以及如何以编程方式调用开发者门户后端。 - [管理开发者](https://docs.apiseven.com/api7-gateway/developer-portal/manage/manage-developers.md): 使用 Provider Portal Admin API 和独立的开发者门户后端管理开发者账户,包括列出、创建、审批注册和删除开发者。 - [管理订阅](https://docs.apiseven.com/api7-gateway/developer-portal/manage/manage-subscriptions.md): 在 Provider Portal 中管理 API 产品订阅,包括批准、拒绝和取消订阅请求。 #### overview 了解 API7 开发者门户,这是一个供 API 提供商发布 API 产品,以及供开发者发现、订阅和使用 API 的平台。 - [开发者门户简介](https://docs.apiseven.com/api7-gateway/developer-portal/overview.md): 了解 API7 开发者门户,这是一个供 API 提供商发布 API 产品,以及供开发者发现、订阅和使用 API 的平台。 ### enterprise-features #### alerts-and-contact-points 了解 API7 网关中的告警和联系人,以及如何监控异常并及时发送通知。 - [告警和联系人](https://docs.apiseven.com/api7-gateway/enterprise-features/alerts-and-contact-points.md): 了解 API7 网关中的告警和联系人,以及如何监控异常并及时发送通知。 #### anonymous-consumers 了解 API7 网关中的匿名消费者,允许未经过身份认证的用户访问 API,同时保障系统安全。 - [匿名消费者](https://docs.apiseven.com/api7-gateway/enterprise-features/anonymous-consumers.md): 了解 API7 网关中的匿名消费者,允许未经过身份认证的用户访问 API,同时保障系统安全。 #### api-portal 了解 API7 网关中的 API 门户,为开发者提供集中访问和管理 API 的平台。 - [API 门户](https://docs.apiseven.com/api7-gateway/enterprise-features/api-portal.md): 了解 API7 网关中的 API 门户,为开发者提供集中访问和管理 API 的平台。 #### audit-logging 了解 API7 网关中的审计日志,以及如何记录用户操作和配置变更。 - [审计日志](https://docs.apiseven.com/api7-gateway/enterprise-features/audit-logging.md): 了解 API7 网关中的审计日志,以及如何记录用户操作和配置变更。 #### compliance 了解 API7 网关的合规能力,帮助组织满足监管要求并遵循安全标准。 - [合规](https://docs.apiseven.com/api7-gateway/enterprise-features/compliance.md): 了解 API7 网关的合规能力,帮助组织满足监管要求并遵循安全标准。 #### credentials 了解 API7 网关中的凭证,安全地认证用户身份,并简化凭证管理和轮换。 - [凭证](https://docs.apiseven.com/api7-gateway/enterprise-features/credentials.md): 了解 API7 网关中的凭证,安全地认证用户身份,并简化凭证管理和轮换。 #### custom-plugins 了解 API7 网关中的自定义插件,通过定制扩展满足特定业务需求。 - [自定义插件](https://docs.apiseven.com/api7-gateway/enterprise-features/custom-plugins.md): 了解 API7 网关中的自定义插件,通过定制扩展满足特定业务需求。 #### dashboard-sso 了解 API7 网关中的单点登录(SSO),使用现有凭证进行身份认证,轻松访问控制台。 - [控制台单点登录](https://docs.apiseven.com/api7-gateway/enterprise-features/dashboard-sso.md): 了解 API7 网关中的单点登录(SSO),使用现有凭证进行身份认证,轻松访问控制台。 #### gateway-groups 了解 API7 网关中的网关组,集中管理共享配置的多个 API 网关实例。 - [网关组](https://docs.apiseven.com/api7-gateway/enterprise-features/gateway-groups.md): 了解 API7 网关中的网关组,集中管理共享配置的多个 API 网关实例。 #### high-availability 了解 API7 网关中的高可用性,为关键业务应用持续提供可靠服务。 - [高可用性](https://docs.apiseven.com/api7-gateway/enterprise-features/high-availability.md): 了解 API7 网关中的高可用性,为关键业务应用持续提供可靠服务。 #### organization-and-rbac 了解 API7 网关中的组织管理和 RBAC,实现细粒度权限管理。 - [组织和 RBAC](https://docs.apiseven.com/api7-gateway/enterprise-features/organization-and-rbac.md): 了解 API7 网关中的组织管理和 RBAC,实现细粒度权限管理。 #### overview 了解 API7 网关区别于开源 Apache APISIX 的企业级特性,包括集中式管理、RBAC、审计日志和专业支持。 - [企业功能概览](https://docs.apiseven.com/api7-gateway/enterprise-features/overview.md): 了解 API7 网关区别于开源 Apache APISIX 的企业级特性,包括集中式管理、RBAC、审计日志和专业支持。 #### permission-policies-and-boundaries 了解 API7 网关中的权限策略和权限边界,定义用户访问级别,增强系统安全性。 - [权限策略和权限边界](https://docs.apiseven.com/api7-gateway/enterprise-features/permission-policies-and-boundaries.md): 了解 API7 网关中的权限策略和权限边界,定义用户访问级别,增强系统安全性。 #### secret-providers 了解 API7 网关中的密钥提供方,使用第三方工具存储敏感数据,增强系统安全性。 - [密钥提供方](https://docs.apiseven.com/api7-gateway/enterprise-features/secret-providers.md): 了解 API7 网关中的密钥提供方,使用第三方工具存储敏感数据,增强系统安全性。 #### security-hardening 了解 API7 网关中的安全加固能力,保护 API 基础设施免受威胁和漏洞影响。 - [安全加固](https://docs.apiseven.com/api7-gateway/enterprise-features/security-hardening.md): 了解 API7 网关中的安全加固能力,保护 API 基础设施免受威胁和漏洞影响。 ### getting-started #### add-gateway-group 按照本教程学习如何在 API7 企业版中新增网关组,从而实现对 API 网关实例的有效管理和组织。 - [新增网关组](https://docs.apiseven.com/api7-gateway/getting-started/add-gateway-group.md): 按照本教程学习如何在 API7 企业版中新增网关组,从而实现对 API 网关实例的有效管理和组织。 #### add-gateway-instance 按照本教程了解如何将网关实例新增到你的 API7 企业版网关组中,确保高效的路由和 API 处理。 - [新增网关实例](https://docs.apiseven.com/api7-gateway/getting-started/add-gateway-instance.md): 按照本教程了解如何将网关实例新增到你的 API7 企业版网关组中,确保高效的路由和 API 处理。 #### audit-logging 按照本教程在 API7 企业版中使用审计日志功能,实现对用户活动的详细追踪,并提升安全性和合规性。 - [使用审计日志追踪操作员活动](https://docs.apiseven.com/api7-gateway/getting-started/audit-logging.md): 按照本教程在 API7 企业版中使用审计日志功能,实现对用户活动的详细追踪,并提升安全性和合规性。 #### canary-upstream 按照本教程在 API7 企业版中配置金丝雀流量转移,通过逐步路由流量来安全地测试新的上游。 - [配置金丝雀流量转移](https://docs.apiseven.com/api7-gateway/getting-started/canary-upstream.md): 按照本教程在 API7 企业版中配置金丝雀流量转移,通过逐步路由流量来安全地测试新的上游。 #### create-custom-role 按照本教程在 API7 企业版中创建自定义角色,从而实现针对特定需求量身定制的细粒度权限管理。 - [创建自定义角色](https://docs.apiseven.com/api7-gateway/getting-started/create-custom-role.md): 按照本教程在 API7 企业版中创建自定义角色,从而实现针对特定需求量身定制的细粒度权限管理。 #### install-api7-ee 按照本教程在 Docker 上安装 API7 企业版,包括用于管理 API 网关和确保无缝设置的基本组件。 - [安装 API7 企业版](https://docs.apiseven.com/api7-gateway/getting-started/install-api7-ee.md): 按照本教程在 Docker 上安装 API7 企业版,包括用于管理 API 网关和确保无缝设置的基本组件。 #### k8s-service-discovery 按照本指南在 API7 企业版中配置 Kubernetes 服务发现,以支持动态探测 Kubernetes 集群中的上游节点。 - [配置 Kubernetes 服务发现](https://docs.apiseven.com/api7-gateway/getting-started/k8s-service-discovery.md): 按照本指南在 API7 企业版中配置 Kubernetes 服务发现,以支持动态探测 Kubernetes 集群中的上游节点。 #### launch-your-first-api 学习如何在 API7 企业版上发布并验证你的第一个 API,包括创建服务、路由,以及通过 HTTP 请求进行测试。 - [发布你的第一个 API](https://docs.apiseven.com/api7-gateway/getting-started/launch-your-first-api.md): 学习如何在 API7 企业版上发布并验证你的第一个 API,包括创建服务、路由,以及通过 HTTP 请求进行测试。 #### learn-more 了解 API7 产品系列、API7 企业版与 Apache APISIX 的关系,以及它们如何融入你的 API 管理策略。 - [深入了解 API7 产品和 APISIX](https://docs.apiseven.com/api7-gateway/getting-started/learn-more.md): 了解 API7 产品系列、API7 企业版与 Apache APISIX 的关系,以及它们如何融入你的 API 管理策略。 #### license 了解如何获取和续订 API7 企业版许可证,以确保你可以持续访问各项功能和服务。 - [续订许可证](https://docs.apiseven.com/api7-gateway/getting-started/license.md): 了解如何获取和续订 API7 企业版许可证,以确保你可以持续访问各项功能和服务。 #### management-options 比较 API7 网关控制台、Admin API、ADC、a7 CLI 和 API7-MCP,为交互式操作、自动化、GitOps 和 AI 客户端选择合适的方式。 - [管理方式](https://docs.apiseven.com/api7-gateway/getting-started/management-options.md): 比较 API7 网关控制台、Admin API、ADC、a7 CLI 和 API7-MCP,为交互式操作、自动化、GitOps 和 AI 客户端选择合适的方式。 #### overview 开始使用 API7 网关。了解平台组件、它们的协作方式,并为你的使用场景选择合适路径。 - [API7 网关概览](https://docs.apiseven.com/api7-gateway/getting-started/overview.md): 开始使用 API7 网关。了解平台组件、它们的协作方式,并为你的使用场景选择合适路径。 #### quick-start 使用 Docker Compose 在本地运行 API7 网关,并在 10 分钟内代理首个 API 请求。 - [快速开始](https://docs.apiseven.com/api7-gateway/getting-started/quick-start.md): 使用 Docker Compose 在本地运行 API7 网关,并在 10 分钟内代理首个 API 请求。 #### rbac 按照本教程在 API7 企业版中管理基于角色的访问控制(RBAC),通过角色和权限策略简化用户权限管理。 - [更新用户角色](https://docs.apiseven.com/api7-gateway/getting-started/rbac.md): 按照本教程在 API7 企业版中管理基于角色的访问控制(RBAC),通过角色和权限策略简化用户权限管理。 #### tutorial-proxying-api-requests 通过动手实践,学习代理 API 请求、使用 `key-auth` 插件添加身份认证,以及启用 `limit-count` 插件实施限流。 - [教程:通过插件代理和管理 API 请求](https://docs.apiseven.com/api7-gateway/getting-started/tutorial-proxying-api-requests.md): 通过动手实践,学习代理 API 请求、使用 `key-auth` 插件添加身份认证,以及启用 `limit-count` 插件实施限流。 ### how-to-guides #### api-security - [配置 Basic 身份认证](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/basic-auth.md): 了解如何要求客户端在 HTTP Authorization 请求头中提供标准用户名和密码来保护 API。 - [配置数据脱敏](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/data-masking.md): 使用 data-mask 插件,在请求数据写入访问日志和日志插件输出前对敏感字段进行遮盖、替换或移除,帮助满足 GDPR、HIPAA 和 PCI-DSS 要求。 - [将外部认证用户信息转发到上游](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/forward-auth-user-info.md): 将 OpenID Connect 或 SAML 路由中的已认证用户信息作为请求头或消费者名称转发到上游服务。 - [配置 HMAC 身份认证](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/hmac-auth.md): 了解如何在 API7 企业版中使用基于哈希的消息认证码(HMAC)对请求签名,从而保护 API。 - [配置 JWT 身份认证](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/jwt-auth.md): 了解如何在 API7 企业版中使用 JSON Web Token(JWT)实现无状态身份认证,以保护 API。 - [配置 Key 身份认证](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/key-auth.md): 了解如何要求客户端在请求头或查询字符串中提供唯一 API Key(API 密钥)来保护 API。 #### ops - [配置就绪和存活探针](https://docs.apiseven.com/api7-gateway/how-to-guides/ops/configure-readiness-probe.md): 为 Kubernetes、Docker 和其他非 Helm 部署中的 API7 网关数据面配置就绪和存活检查。 - [创建自定义角色](https://docs.apiseven.com/api7-gateway/how-to-guides/ops/create-custom-role.md): 通过定义权限策略、将其附加到角色并将角色分配给用户,在 API7 网关中创建自定义角色。 - [设计自定义角色体系](https://docs.apiseven.com/api7-gateway/how-to-guides/ops/design-custom-role-system.md): 通过组合角色、权限策略、标签和权限边界,在 API7 网关中设计可扩展的自定义角色体系。 - [管理网关组](https://docs.apiseven.com/api7-gateway/how-to-guides/ops/multi-gateway-group.md): 了解如何创建和管理多个网关组,以便按环境或团队组织和隔离 API 流量。 - [配置密钥管理](https://docs.apiseven.com/api7-gateway/how-to-guides/ops/secret-manager.md): 了解如何配置密钥提供方,并在 API7 企业版中引用外部密钥,避免在网关资源中硬编码敏感值。 #### overview API7 网关常见任务和工作流的实用操作指南。 - [操作指南](https://docs.apiseven.com/api7-gateway/how-to-guides/overview.md): API7 网关常见任务和工作流的实用操作指南。 #### plugin-development - [插件开发最佳实践](https://docs.apiseven.com/api7-gateway/how-to-guides/plugin-development/best-practices.md): 使用内置核心库代替底层 OpenResty API,通过 Schema 校验配置,并选择正确的阶段和优先级,编写正确、高效且易维护的自定义 Lua 插件。 - [开发自定义 Lua 插件](https://docs.apiseven.com/api7-gateway/how-to-guides/plugin-development/custom-lua-plugins.md): 了解如何为 API7 网关开发、注册和测试自定义 Lua 插件。 - [Serverless 函数还是自定义插件](https://docs.apiseven.com/api7-gateway/how-to-guides/plugin-development/serverless-or-custom-plugins.md): 比较内置 serverless-function 插件与自定义 Lua 插件,并选择适合在 API7 网关中运行自有 Lua 逻辑的方式。 #### protocol-proxy - [配置 GraphQL 代理](https://docs.apiseven.com/api7-gateway/how-to-guides/protocol-proxy/graphql-proxy.md): 了解如何通过 API7 网关代理 GraphQL API,以及何时添加支持 GraphQL 的插件进行限流和缓存。 - [配置 gRPC 代理](https://docs.apiseven.com/api7-gateway/how-to-guides/protocol-proxy/grpc-proxy.md): 了解如何配置 API7 企业版代理 gRPC 流量,包括 REST 到 gRPC 转码,以及为浏览器客户端启用 gRPC-Web 支持。 - [配置 TCP/UDP 代理](https://docs.apiseven.com/api7-gateway/how-to-guides/protocol-proxy/tcp-udp-proxy.md): 配置 API7 网关代理 TCP 和 UDP(第 4 层)流量到数据库、消息队列和自定义协议等上游服务。 - [配置 WebSocket 代理](https://docs.apiseven.com/api7-gateway/how-to-guides/protocol-proxy/websocket-proxy.md): 了解如何在 API7 企业版中为路由启用和配置 WebSocket 代理,以处理长连接和双向通信。 #### traffic-management - [实现蓝绿发布](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/blue-green-deployment.md): 使用 API7 网关实现蓝绿发布,在两个上游环境之间零停机切换流量。 - [实施灰度发布](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/canary-release.md): 了解如何使用 traffic-split 插件逐步将流量迁移到新版后端服务。 - [配置 CORS](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/cors.md): 了解如何为 API 配置跨源资源共享(CORS),允许或限制来自不同域的访问。 - [配置故障注入](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/fault-injection.md): 了解如何通过注入 HTTP 错误和响应延迟来测试应用的韧性。 - [条件式禁用全局插件](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/global-plugin-exemption.md): 使用路由标签和 _meta.filter 机制,为特定路由有条件地跳过全局插件执行。 - [配置上游健康检查](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/health-check.md): 了解如何为上游服务配置主动和被动健康检查,以确保高可用。 - [配置代理缓存](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/proxy-cache.md): 了解如何在网关处缓存响应,以提高 API 性能并降低上游负载。 - [配置代理镜像](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/proxy-mirror.md): 了解如何复制一定比例的真实生产流量并发送到辅助服务,以进行测试和验证。 - [改写代理请求](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/proxy-rewrite.md): 了解如何在将请求代理到上游服务前修改请求 URI、方法和请求头。 - [配置限流](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/rate-limiting.md): 了解如何为 API 配置简单和高级限流,以防止滥用并确保公平使用。 - [提升多网关实例下的限流精度](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/rate-limiting-accuracy.md): 理解多网关实例批量同步计数器时限流误差的来源,以及滑动窗口为何能将长期误差收敛到接近零。 - [配置响应改写](https://docs.apiseven.com/api7-gateway/how-to-guides/traffic-management/response-rewrite.md): 了解如何在向客户端返回响应之前修改状态码、响应头和响应体内容。 ### install #### deploy-high-availability 以高可用配置部署 API7 网关控制面和数据面,消除单点故障。 - [部署高可用环境](https://docs.apiseven.com/api7-gateway/install/deploy-high-availability.md): 以高可用配置部署 API7 网关控制面和数据面,消除单点故障。 #### deploy-on-kubernetes 使用 Helm 在 Kubernetes 上部署 API7 企业版,包括控制面安装、使用 mTLS 配置数据面,以及 AWS EKS、GCP GKE 和 Azure AKS 专用指南。 - [在 Kubernetes 上部署 API7 企业版](https://docs.apiseven.com/api7-gateway/install/deploy-on-kubernetes.md): 使用 Helm 在 Kubernetes 上部署 API7 企业版,包括控制面安装、使用 mTLS 配置数据面,以及 AWS EKS、GCP GKE 和 Azure AKS 专用指南。 #### deploy-on-openshift 使用正确的安全上下文约束(SCC)、服务账号和 Helm Chart 配置,在 Red Hat OpenShift 上部署 API7 网关。 - [在 OpenShift 上部署](https://docs.apiseven.com/api7-gateway/install/deploy-on-openshift.md): 使用正确的安全上下文约束(SCC)、服务账号和 Helm Chart 配置,在 Red Hat OpenShift 上部署 API7 网关。 #### deploy-with-docker-compose 使用 Docker Compose 通过在线快速安装脚本、离线部署包或可自定义的手动部署,安装完整的 API7 网关环境。 - [使用 Docker Compose 部署](https://docs.apiseven.com/api7-gateway/install/deploy-with-docker-compose.md): 使用 Docker Compose 通过在线快速安装脚本、离线部署包或可自定义的手动部署,安装完整的 API7 网关环境。 #### deploy-with-rpm 在 RHEL、Rocky Linux、AlmaLinux、CentOS 8/9 等 Red Hat 系 Linux 系统中,通过离线 RPM 包部署 API7 网关,并使用 systemd 管理控制面和数据面服务。 - [使用离线 RPM 包部署](https://docs.apiseven.com/api7-gateway/install/deploy-with-rpm.md): 在 RHEL、Rocky Linux、AlmaLinux、CentOS 8/9 等 Red Hat 系 Linux 系统中,通过离线 RPM 包部署 API7 网关,并使用 systemd 管理控制面和数据面服务。 #### installation-faq 安装过程中的常见问题和故障排查方法。 - [安装常见问题](https://docs.apiseven.com/api7-gateway/install/installation-faq.md): 安装过程中的常见问题和故障排查方法。 #### installation-packages 用于安装 API7 网关的容器镜像、Helm Chart 和 CLI 工具,包括网关、DP Manager、开发者门户和集成控制面镜像的官方 Docker Hub 仓库。 - [安装包](https://docs.apiseven.com/api7-gateway/install/installation-packages.md): 用于安装 API7 网关的容器镜像、Helm Chart 和 CLI 工具,包括网关、DP Manager、开发者门户和集成控制面镜像的官方 Docker Hub 仓库。 #### overview 比较 API7 网关在生产、评估和隔离网络环境中的 Kubernetes、Docker Compose 与安装包部署选项。 - [在本地环境安装 API7 网关](https://docs.apiseven.com/api7-gateway/install/overview.md): 比较 API7 网关在生产、评估和隔离网络环境中的 Kubernetes、Docker Compose 与安装包部署选项。 #### rpm-from-docker 当控制台尚未生成原生 RPM 数据面脚本时,可从 Docker 脚本中提取连接参数,并将 api7-gateway RPM 接入控制面。 - [从 Docker 脚本接入 RPM 数据面](https://docs.apiseven.com/api7-gateway/install/rpm-from-docker.md): 当控制台尚未生成原生 RPM 数据面脚本时,可从 Docker 脚本中提取连接参数,并将 api7-gateway RPM 接入控制面。 #### rpm-quickstart 使用 RPM 包内置的 quickstart.sh,在单台主机上快速启动 API7 网关控制面,适用于评估和概念验证(PoC)。 - [单机 RPM 快速试用](https://docs.apiseven.com/api7-gateway/install/rpm-quickstart.md): 使用 RPM 包内置的 quickstart.sh,在单台主机上快速启动 API7 网关控制面,适用于评估和概念验证(PoC)。 #### supported-versions-and-interoperability API7 网关组件和基础设施的版本兼容性矩阵。 - [支持的版本和互操作性](https://docs.apiseven.com/api7-gateway/install/supported-versions-and-interoperability.md): API7 网关组件和基础设施的版本兼容性矩阵。 #### system-requirements 安装 API7 企业版所需的硬件、操作系统和网络要求。 - [系统要求](https://docs.apiseven.com/api7-gateway/install/system-requirements.md): 安装 API7 企业版所需的硬件、操作系统和网络要求。 ### introduction 探索 API7 企业版,这是一个基于 Apache APISIX 构建的 API 网关,专为企业需求量身定制,提供全生命周期的 API 管理。 - [概览](https://docs.apiseven.com/api7-gateway/introduction.md): 探索 API7 企业版,这是一个基于 Apache APISIX 构建的 API 网关,专为企业需求量身定制,提供全生命周期的 API 管理。 #### architecture 探索 API7 企业版的架构,这是一个基于 Apache APISIX 的云原生 API 网关,具有可扩展的数据平面和控制平面,可满足企业需求。 - [架构](https://docs.apiseven.com/api7-gateway/introduction/architecture.md): 探索 API7 企业版的架构,这是一个基于 Apache APISIX 的云原生 API 网关,具有可扩展的数据平面和控制平面,可满足企业需求。 ### key-concepts #### api-portal API7 门户(API Portal)是一个集中式的在线平台,是 API 提供者与开发者之间的桥梁。 - [API 门户](https://docs.apiseven.com/api7-gateway/key-concepts/api-portal.md): API7 门户(API Portal)是一个集中式的在线平台,是 API 提供者与开发者之间的桥梁。 #### api-products 了解 API7 企业版如何通过 API 产品组织和管理 API,并向不同开发者群体提供适合其使用场景的 API 集合。 - [API 产品](https://docs.apiseven.com/api7-gateway/key-concepts/api-products.md): 了解 API7 企业版如何通过 API 产品组织和管理 API,并向不同开发者群体提供适合其使用场景的 API 集合。 #### architecture 深入了解 API7 企业版控制面与数据面解耦的架构。 - [架构](https://docs.apiseven.com/api7-gateway/key-concepts/architecture.md): 深入了解 API7 企业版控制面与数据面解耦的架构。 #### certificates 了解 API7 企业版如何使用 TLS 和 mTLS,在客户端、API 网关和后端服务之间建立安全通信。 - [证书](https://docs.apiseven.com/api7-gateway/key-concepts/certificates.md): 了解 API7 企业版如何使用 TLS 和 mTLS,在客户端、API 网关和后端服务之间建立安全通信。 #### consumers 了解 API7 企业版中的消费者如何用于身份认证、访问控制和安全的 API 请求处理。 - [消费者](https://docs.apiseven.com/api7-gateway/key-concepts/consumers.md): 了解 API7 企业版中的消费者如何用于身份认证、访问控制和安全的 API 请求处理。 #### consumers-and-credentials 使用消费者和凭证进行身份管理与身份认证。 - [消费者和凭证](https://docs.apiseven.com/api7-gateway/key-concepts/consumers-and-credentials.md): 使用消费者和凭证进行身份管理与身份认证。 #### developers 了解开发者在 API7 企业版中的角色,使他们能够通过 API 门户有效地发现、学习和集成 API。 - [开发者](https://docs.apiseven.com/api7-gateway/key-concepts/developers.md): 了解开发者在 API7 企业版中的角色,使他们能够通过 API 门户有效地发现、学习和集成 API。 #### gateway-groups 用于环境隔离和配置管理的数据面实例逻辑分组。 - [网关组](https://docs.apiseven.com/api7-gateway/key-concepts/gateway-groups.md): 用于环境隔离和配置管理的数据面实例逻辑分组。 #### overview 介绍 API7 企业版中的核心抽象和实体。 - [核心概念概览](https://docs.apiseven.com/api7-gateway/key-concepts/overview.md): 介绍 API7 企业版中的核心抽象和实体。 #### plugins 用于在 API7 网关中拦截并修改 API 流量的模块化组件。 - [插件](https://docs.apiseven.com/api7-gateway/key-concepts/plugins.md): 用于在 API7 网关中拦截并修改 API 流量的模块化组件。 #### roles-and-permission-policies 了解 API7 企业版中的角色和权限策略,实现细粒度的访问控制和用户管理,确保 API 操作的安全性。 - [角色与权限策略](https://docs.apiseven.com/api7-gateway/key-concepts/roles-and-permission-policies.md): 了解 API7 企业版中的角色和权限策略,实现细粒度的访问控制和用户管理,确保 API 操作的安全性。 #### routes 了解 API7 企业版中的路由如何匹配 HTTP 请求、执行插件并将流量转发到后端服务。 - [路由](https://docs.apiseven.com/api7-gateway/key-concepts/routes.md): 了解 API7 企业版中的路由如何匹配 HTTP 请求、执行插件并将流量转发到后端服务。 #### secrets 了解如何在 API7 企业版中使用密钥对象和提供程序安全地管理敏感信息,以增强 API 数据保护。 - [密钥](https://docs.apiseven.com/api7-gateway/key-concepts/secrets.md): 了解如何在 API7 企业版中使用密钥对象和提供程序安全地管理敏感信息,以增强 API 数据保护。 #### service-discovery API7 网关中的动态上游解析,无需硬编码 IP,即可从 Kubernetes Service、Nacos 和 Consul 注册中心自动发现后端端点。 - [服务发现](https://docs.apiseven.com/api7-gateway/key-concepts/service-discovery.md): API7 网关中的动态上游解析,无需硬编码 IP,即可从 Kubernetes Service、Nacos 和 Consul 注册中心自动发现后端端点。 #### services 了解 API7 企业版中的服务如何组织路由、上游和插件配置,以简化 API 管理。 - [服务](https://docs.apiseven.com/api7-gateway/key-concepts/services.md): 了解 API7 企业版中的服务如何组织路由、上游和插件配置,以简化 API 管理。 #### services-and-routes 了解如何使用服务与路由对 API 流量进行分组和路由。 - [服务与路由](https://docs.apiseven.com/api7-gateway/key-concepts/services-and-routes.md): 了解如何使用服务与路由对 API 流量进行分组和路由。 #### snis 了解 API7 企业版如何通过服务器名称指示(SNI)让多个主机名共享 SSL 证书,从而提升安全性和管理效率。 - [SNI](https://docs.apiseven.com/api7-gateway/key-concepts/snis.md): 了解 API7 企业版如何通过服务器名称指示(SNI)让多个主机名共享 SSL 证书,从而提升安全性和管理效率。 #### ssl-certificates 了解 API7 网关如何管理 SSL/TLS 证书和终止安全连接。 - [SSL 证书](https://docs.apiseven.com/api7-gateway/key-concepts/ssl-certificates.md): 了解 API7 网关如何管理 SSL/TLS 证书和终止安全连接。 #### stream-routes 了解 API7 网关中用于代理 TCP 和 UDP(第 4 层)流量的四层路由,包括匹配规则、支持的插件以及与 Stream 服务的关系。 - [四层路由](https://docs.apiseven.com/api7-gateway/key-concepts/stream-routes.md): 了解 API7 网关中用于代理 TCP 和 UDP(第 4 层)流量的四层路由,包括匹配规则、支持的插件以及与 Stream 服务的关系。 #### upstreams 了解 API7 企业版中的上游如何组织后端服务,实现流量转发、负载均衡和故障转移。 - [上游](https://docs.apiseven.com/api7-gateway/key-concepts/upstreams.md): 了解 API7 企业版中的上游如何组织后端服务,实现流量转发、负载均衡和故障转移。 #### upstreams-and-load-balancing 后端目标定义,包括负载均衡算法和健康检查。 - [上游与负载均衡](https://docs.apiseven.com/api7-gateway/key-concepts/upstreams-and-load-balancing.md): 后端目标定义,包括负载均衡算法和健康检查。 ### observability #### alerts 配置 API7 网关告警策略和联系人,当网关离线、证书过期或错误率超过阈值时通过邮件或 Webhook 接收通知。 - [配置告警](https://docs.apiseven.com/api7-gateway/observability/alerts.md): 配置 API7 网关告警策略和联系人,当网关离线、证书过期或错误率超过阈值时通过邮件或 Webhook 接收通知。 #### consumer-label-based-logging 在 API7 网关访问日志中包含消费者标签,以便按消费者跟踪和分析流量。 - [在访问日志中包含消费者标签](https://docs.apiseven.com/api7-gateway/observability/consumer-label-based-logging.md): 在 API7 网关访问日志中包含消费者标签,以便按消费者跟踪和分析流量。 #### debug-sessions 了解网关处理单个请求时的完整行为,包括插件执行顺序、耗时和日志。你可以按需捕获,也可以在告警触发时自动捕获。 - [使用调试会话捕获请求链路](https://docs.apiseven.com/api7-gateway/observability/debug-sessions.md): 了解网关处理单个请求时的完整行为,包括插件执行顺序、耗时和日志。你可以按需捕获,也可以在告警触发时自动捕获。 #### external-prometheus 将 API7 网关指向现有的外部 Prometheus,并从 Docker Compose 部署中移除内置实例,同时确保控制台的 Monitoring 页面持续正常工作。 - [使用现有 Prometheus](https://docs.apiseven.com/api7-gateway/observability/external-prometheus.md): 将 API7 网关指向现有的外部 Prometheus,并从 Docker Compose 部署中移除内置实例,同时确保控制台的 Monitoring 页面持续正常工作。 #### kubernetes-error-log-forwarding 使用 Splunk OpenTelemetry Collector,将 Kubernetes 中 API7 网关容器的错误日志转发到 Splunk。 - [将 Kubernetes 错误日志发送到 Splunk](https://docs.apiseven.com/api7-gateway/observability/kubernetes-error-log-forwarding.md): 使用 Splunk OpenTelemetry Collector,将 Kubernetes 中 API7 网关容器的错误日志转发到 Splunk。 #### kubernetes-log-collection 使用 OpenTelemetry Collector 或 Filebeat 在 Kubernetes 上采集 API7 网关的访问日志和错误日志,支持从容器输出采集,也支持从 Pod 内的日志文件采集。 - [在 Kubernetes 上采集网关日志](https://docs.apiseven.com/api7-gateway/observability/kubernetes-log-collection.md): 使用 OpenTelemetry Collector 或 Filebeat 在 Kubernetes 上采集 API7 网关的访问日志和错误日志,支持从容器输出采集,也支持从 Pod 内的日志文件采集。 #### logging 了解 API7 网关生成的访问日志和错误日志,配置格式与详细程度,并将日志转发到集中式日志管理系统。 - [配置集中式日志记录](https://docs.apiseven.com/api7-gateway/observability/logging.md): 了解 API7 网关生成的访问日志和错误日志,配置格式与详细程度,并将日志转发到集中式日志管理系统。 #### metrics 通过控制台内置监控页面或抓取数据面公开的 Prometheus 端点,监控 API7 网关指标。 - [监控指标](https://docs.apiseven.com/api7-gateway/observability/metrics.md): 通过控制台内置监控页面或抓取数据面公开的 Prometheus 端点,监控 API7 网关指标。 #### splunk-integration 使用 HTTP Event Collector(HEC)日志插件,将 API7 网关访问日志发送到 Splunk。 - [将访问日志发送到 Splunk](https://docs.apiseven.com/api7-gateway/observability/splunk-integration.md): 使用 HTTP Event Collector(HEC)日志插件,将 API7 网关访问日志发送到 Splunk。 #### tracing 使用 OpenTelemetry 插件在 API7 网关中配置分布式追踪、OTLP Collector、采样策略和路由跨度,以可视化请求流并分析延迟瓶颈。 - [配置分布式追踪](https://docs.apiseven.com/api7-gateway/observability/tracing.md): 使用 OpenTelemetry 插件在 API7 网关中配置分布式追踪、OTLP Collector、采样策略和路由跨度,以可视化请求流并分析延迟瓶颈。 ### overview 了解基于 Apache APISIX 构建、面向云原生环境的动态高性能 API7 网关,包括其架构、功能和部署模型。 - [API7 网关](https://docs.apiseven.com/api7-gateway/overview.md): 了解基于 Apache APISIX 构建、面向云原生环境的动态高性能 API7 网关,包括其架构、功能和部署模型。 ### reference 查找 API7 网关的 API、CLI 工具、部署配置、安全控制和配置语法参考文档。 - [参考概览](https://docs.apiseven.com/api7-gateway/reference.md): 查找 API7 网关的 API、CLI 工具、部署配置、安全控制和配置语法参考文档。 #### a7-cli 使用单独安装的 a7 CLI,以交互方式、脚本或 API7 网关 Agent Skills 管理 API7 网关组和资源。 - [a7 CLI](https://docs.apiseven.com/api7-gateway/reference/a7-cli.md): 使用单独安装的 a7 CLI,以交互方式、脚本或 API7 网关 Agent Skills 管理 API7 网关组和资源。 #### adc 使用 API 声明式 CLI(ADC)以声明式方式管理 API7 网关配置。 - [ADC 参考](https://docs.apiseven.com/api7-gateway/reference/adc.md): 使用 API 声明式 CLI(ADC)以声明式方式管理 API7 网关配置。 #### alert-template 在 API7 网关中使用预定义变量自定义告警通知,从而在告警消息和电子邮件中实现动态内容。 - [告警变量与模板](https://docs.apiseven.com/api7-gateway/reference/alert-template.md): 在 API7 网关中使用预定义变量自定义告警通知,从而在告警消息和电子邮件中实现动态内容。 #### approval-variables 使用 API7 网关审批变量和当前模板值,自定义 API 产品订阅通知邮件内容和 Webhook 消息。 - [审批通知变量与模板](https://docs.apiseven.com/api7-gateway/reference/approval-variables.md): 使用 API7 网关审批变量和当前模板值,自定义 API 产品订阅通知邮件内容和 Webhook 消息。 #### built-in-variables 了解 API7 网关中可用的内置变量,包括 NGINX、APISIX 和自定义变量,这些变量可用于路由匹配、日志自定义和插件配置。 - [内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md): 了解 API7 网关中可用的内置变量,包括 NGINX、APISIX 和自定义变量,这些变量可用于路由匹配、日志自定义和插件配置。 #### configuration 了解 API7 网关中使用的配置文件,包括用于有效管理设置的默认和用户定义文件。 - [配置文件](https://docs.apiseven.com/api7-gateway/reference/configuration.md): 了解 API7 网关中使用的配置文件,包括用于有效管理设置的默认和用户定义文件。 #### environment-variables 了解如何在 API7 网关中使用环境变量配置消费者凭证、SSL 证书和插件。 - [环境变量](https://docs.apiseven.com/api7-gateway/reference/environment-variables.md): 了解如何在 API7 网关中使用环境变量配置消费者凭证、SSL 证书和插件。 #### expressions 了解如何在 API7 网关中使用表达式进行路由匹配、请求过滤和配置中的条件逻辑。 - [API7 表达式](https://docs.apiseven.com/api7-gateway/reference/expressions.md): 了解如何在 API7 网关中使用表达式进行路由匹配、请求过滤和配置中的条件逻辑。 #### hardening 了解在 API7 网关中保护敏感信息的做法,包括存储、加密和通信实践,以防御各种威胁。 - [安全加固参考](https://docs.apiseven.com/api7-gateway/reference/hardening.md): 了解在 API7 网关中保护敏感信息的做法,包括存储、加密和通信实践,以防御各种威胁。 #### helm-chart 了解如何查看 API7 网关 Helm Chart 配置值,以及 Helm 配置值如何渲染为网关配置。 - [Helm Chart](https://docs.apiseven.com/api7-gateway/reference/helm-chart.md): 了解如何查看 API7 网关 Helm Chart 配置值,以及 Helm 配置值如何渲染为网关配置。 #### obtain-dashboard-token 在 API7 控制台中创建令牌,并将其用于 API7 网关 Admin API 和 ADC 身份认证。 - [从控制台获取令牌](https://docs.apiseven.com/api7-gateway/reference/obtain-dashboard-token.md): 在 API7 控制台中创建令牌,并将其用于 API7 网关 Admin API 和 ADC 身份认证。 #### permission-policy-action-and-resource API7 网关权限策略中所有操作和 ARN 风格资源的完整参考,按命名空间(gateway、iam、portal)组织,用于构建最小权限策略。 - [权限策略操作和资源](https://docs.apiseven.com/api7-gateway/reference/permission-policy-action-and-resource.md): API7 网关权限策略中所有操作和 ARN 风格资源的完整参考,按命名空间(gateway、iam、portal)组织,用于构建最小权限策略。 #### permission-policy-examples 可直接调整的 API7 网关权限策略示例,按访问模式、服务与插件操作、IAM 与治理以及门户管理组织。 - [权限策略示例](https://docs.apiseven.com/api7-gateway/reference/permission-policy-examples.md): 可直接调整的 API7 网关权限策略示例,按访问模式、服务与插件操作、IAM 与治理以及门户管理组织。 ### release-notes 查看 API7 网关各版本的最新更新、功能、改进和缺陷修复。 - [更新日志](https://docs.apiseven.com/api7-gateway/release-notes.md): 查看 API7 网关各版本的最新更新、功能、改进和缺陷修复。 ### scalability #### autoscale-on-kubernetes 使用 Kubernetes 的 Horizontal Pod Autoscaler(HPA)自动扩缩容 API7 网关数据面 Pod,以应对流量变化。 - [在 Kubernetes 上自动扩缩容数据面](https://docs.apiseven.com/api7-gateway/scalability/autoscale-on-kubernetes.md): 使用 Kubernetes 的 Horizontal Pod Autoscaler(HPA)自动扩缩容 API7 网关数据面 Pod,以应对流量变化。 ### security-and-compliance #### access-control-lists 使用 API7 网关的 `consumer-restriction` 插件限制 API 访问。按消费者名称、消费者组 ID、服务 ID 或路由 ID 配置允许列表和拒绝列表,实现细粒度安全控制。 - [访问控制列表(ACL)](https://docs.apiseven.com/api7-gateway/security-and-compliance/access-control-lists.md): 使用 API7 网关的 `consumer-restriction` 插件限制 API 访问。按消费者名称、消费者组 ID、服务 ID 或路由 ID 配置允许列表和拒绝列表,实现细粒度安全控制。 #### audit-logs 通过详细的审计日志跟踪 API7 控制面中的所有管理变更。了解如何查看、管理和导出审计记录,满足安全与合规要求。 - [审计日志](https://docs.apiseven.com/api7-gateway/security-and-compliance/audit-logs.md): 通过详细的审计日志跟踪 API7 控制面中的所有管理变更。了解如何查看、管理和导出审计记录,满足安全与合规要求。 #### authenticate - [客户端 mTLS 认证](https://docs.apiseven.com/api7-gateway/security-and-compliance/authenticate/client-mtls.md): 在 API7 网关上配置双向 TLS(mTLS),在允许访问 API 前使用 X.509 证书认证 API 客户端。 - [控制面与数据面之间的双向 TLS](https://docs.apiseven.com/api7-gateway/security-and-compliance/authenticate/mutual-tls-cp-dp.md): 了解 API7 网关如何使用基于 PKI 的可靠双向 TLS(mTLS)模型,保护控制面与数据面之间的所有通信。 - [为控制台配置 SCIM 预配](https://docs.apiseven.com/api7-gateway/security-and-compliance/authenticate/scim.md): 使用受支持的身份提供商,为 API7 控制台配置 SCIM 用户预配。 - [使用 Microsoft Entra ID 进行 SCIM 预配](https://docs.apiseven.com/api7-gateway/security-and-compliance/authenticate/scim-microsoft-entra-id.md): 为 API7 控制台配置 Microsoft Entra ID SCIM 预配。 - [使用 Okta 进行 SCIM 预配](https://docs.apiseven.com/api7-gateway/security-and-compliance/authenticate/scim-okta.md): 为 API7 控制台配置 Okta SCIM 预配。 - [上游 mTLS](https://docs.apiseven.com/api7-gateway/security-and-compliance/authenticate/upstream-mtls.md): 配置 API7 网关与上游服务之间的双向 TLS(mTLS),使网关向上游出示客户端证书,并可选验证上游的服务器证书。 #### ip-restrictions-control-plane 使用控制面内置 IP 允许列表限制可访问 API7 控制面(控制台和 Admin API)的客户端 IP 地址,并结合网络级控制实现纵深防御。 - [控制面 IP 限制](https://docs.apiseven.com/api7-gateway/security-and-compliance/ip-restrictions-control-plane.md): 使用控制面内置 IP 允许列表限制可访问 API7 控制面(控制台和 Admin API)的客户端 IP 地址,并结合网络级控制实现纵深防御。 #### oauth-oidc 使用现代化的令牌身份认证保护 API,并了解如何将 API7 网关与 Okta、Keycloak 等 OAuth 2.0 和 OpenID Connect(OIDC)提供商集成。 - [OAuth 2.0 和 OIDC](https://docs.apiseven.com/api7-gateway/security-and-compliance/oauth-oidc.md): 使用现代化的令牌身份认证保护 API,并了解如何将 API7 网关与 Okta、Keycloak 等 OAuth 2.0 和 OpenID Connect(OIDC)提供商集成。 #### open-source-licenses 了解 API7 网关对开源软件和许可证合规的承诺,以及所使用的主要开源组件及其许可证。 - [开源许可证](https://docs.apiseven.com/api7-gateway/security-and-compliance/open-source-licenses.md): 了解 API7 网关对开源软件和许可证合规的承诺,以及所使用的主要开源组件及其许可证。 #### overview 了解 API7 网关如何通过身份认证、授权、加密和审计等完整的安全与合规能力保护 API。 - [安全与合规概览](https://docs.apiseven.com/api7-gateway/security-and-compliance/overview.md): 了解 API7 网关如何通过身份认证、授权、加密和审计等完整的安全与合规能力保护 API。 #### permission-policies-and-boundaries 使用原生 JSON 文档格式在 API7 网关中编写权限策略。了解 `statement` 结构、允许的操作、ARN 风格资源、基于标签的条件,以及权限边界如何限制用户的最大权限范围。 - [权限策略和权限边界](https://docs.apiseven.com/api7-gateway/security-and-compliance/permission-policies-and-boundaries.md): 使用原生 JSON 文档格式在 API7 网关中编写权限策略。了解 `statement` 结构、允许的操作、ARN 风格资源、基于标签的条件,以及权限边界如何限制用户的最大权限范围。 #### role-based-access-control 使用基于角色的访问控制管理用户对 API7 网关控制面的访问。为用户分配角色、挂载权限策略,并在网关组之间实施最小权限访问。 - [基于角色的访问控制(RBAC)](https://docs.apiseven.com/api7-gateway/security-and-compliance/role-based-access-control.md): 使用基于角色的访问控制管理用户对 API7 网关控制面的访问。为用户分配角色、挂载权限策略,并在网关组之间实施最小权限访问。 #### secure-credentials 使用 API7 网关安全凭证管理保护敏感信息。了解如何管理 SSL 证书,以及如何与 HashiCorp Vault 等外部密钥管理器集成。 - [安全凭证管理](https://docs.apiseven.com/api7-gateway/security-and-compliance/secure-credentials.md): 使用 API7 网关安全凭证管理保护敏感信息。了解如何管理 SSL 证书,以及如何与 HashiCorp Vault 等外部密钥管理器集成。 #### sso-dashboard 使用单点登录(SSO)集中管理 API7 控制台用户访问。支持 OIDC、SAML、LDAP 和 CAS 协议,并可自动映射角色。 - [控制台单点登录(SSO)](https://docs.apiseven.com/api7-gateway/security-and-compliance/sso-dashboard.md): 使用单点登录(SSO)集中管理 API7 控制台用户访问。支持 OIDC、SAML、LDAP 和 CAS 协议,并可自动映射角色。 #### sso-ldap 使用 LDAP 为 API7 控制台配置单点登录(SSO),使用户能够使用现有目录服务凭证认证。 - [使用 LDAP 实现单点登录](https://docs.apiseven.com/api7-gateway/security-and-compliance/sso-ldap.md): 使用 LDAP 为 API7 控制台配置单点登录(SSO),使用户能够使用现有目录服务凭证认证。 #### sso-oidc 使用 OpenID Connect(OIDC)为 API7 控制台配置单点登录(SSO),并提供 Keycloak、Microsoft Entra ID 和 Auth0 的提供商专用配置指引。 - [使用 OIDC 配置 SSO](https://docs.apiseven.com/api7-gateway/security-and-compliance/sso-oidc.md): 使用 OpenID Connect(OIDC)为 API7 控制台配置单点登录(SSO),并提供 Keycloak、Microsoft Entra ID 和 Auth0 的提供商专用配置指引。 #### sso-saml 使用 SAML 2.0 为 API7 控制台配置单点登录(SSO),并提供 Microsoft Entra ID 和 Okta 的提供商专用配置指引。 - [使用 SAML 配置 SSO](https://docs.apiseven.com/api7-gateway/security-and-compliance/sso-saml.md): 使用 SAML 2.0 为 API7 控制台配置单点登录(SSO),并提供 Microsoft Entra ID 和 Okta 的提供商专用配置指引。 #### trust-center API7 信任中心集中提供所有安全与合规信息,包括认证、安全报告和最佳实践指南。 - [信任中心](https://docs.apiseven.com/api7-gateway/security-and-compliance/trust-center.md): API7 信任中心集中提供所有安全与合规信息,包括认证、安全报告和最佳实践指南。 #### verify-image-signatures 使用 Cosign 和基于 OIDC 的无密钥验证来验证 API7 企业版容器镜像签名,确认每个镜像均由 API7.ai 构建和签名,以保护软件供应链。 - [验证镜像签名](https://docs.apiseven.com/api7-gateway/security-and-compliance/verify-image-signatures.md): 使用 Cosign 和基于 OIDC 的无密钥验证来验证 API7 企业版容器镜像签名,确认每个镜像均由 API7.ai 构建和签名,以保护软件供应链。 #### vulnerability-scanning 了解 API7.ai 针对 API7 网关实施的安全测试和漏洞扫描实践,包括 CVE 报告和补丁流程。 - [漏洞扫描](https://docs.apiseven.com/api7-gateway/security-and-compliance/vulnerability-scanning.md): 了解 API7.ai 针对 API7 网关实施的安全测试和漏洞扫描实践,包括 CVE 报告和补丁流程。 #### web-application-firewall 了解何时将 Web 应用防火墙与 API7 网关结合使用、WAF 在安全模型中的作用,以及当前文档提供的集成方式。 - [Web 应用防火墙(WAF)](https://docs.apiseven.com/api7-gateway/security-and-compliance/web-application-firewall.md): 了解何时将 Web 应用防火墙与 API7 网关结合使用、WAF 在安全模型中的作用,以及当前文档提供的集成方式。 ### tools #### cli-tools - [CLI 工具](https://docs.apiseven.com/api7-gateway/tools/cli-tools.md) #### declarative-api - [声明式 API](https://docs.apiseven.com/api7-gateway/tools/declarative-api.md) ### troubleshooting 诊断并解决 API7 网关部署中的常见问题,包括连接问题、配置错误和性能下降。 - [API7 网关故障排查](https://docs.apiseven.com/api7-gateway/troubleshooting.md): 诊断并解决 API7 网关部署中的常见问题,包括连接问题、配置错误和性能下降。 ### upgrade-guides #### backup-and-restore 使用数据库原生工具和 ADC 备份并恢复 API7 网关控制面数据与网关组配置。 - [备份与恢复](https://docs.apiseven.com/api7-gateway/upgrade-guides/backup-and-restore.md): 使用数据库原生工具和 ADC 备份并恢复 API7 网关控制面数据与网关组配置。 #### cluster-migration 一份详细的分步指南,帮助你在零停机的情况下将 API7 网关部署迁移至新集群。 - [API 网关集群迁移](https://docs.apiseven.com/api7-gateway/upgrade-guides/cluster-migration.md): 一份详细的分步指南,帮助你在零停机的情况下将 API7 网关部署迁移至新集群。 #### dual-cluster 使用相互独立的源集群和目标集群、受控流量切换、写入协调、验证和安全回滚来升级 API7 网关。 - [双集群升级](https://docs.apiseven.com/api7-gateway/upgrade-guides/dual-cluster.md): 使用相互独立的源集群和目标集群、受控流量切换、写入协调、验证和安全回滚来升级 API7 网关。 #### in-place 在写入冻结、源控制面停机、目标控制面验证和可恢复回滚的保护下,复用现有数据库升级 API7 网关控制面。 - [控制面就地升级](https://docs.apiseven.com/api7-gateway/upgrade-guides/in-place.md): 在写入冻结、源控制面停机、目标控制面验证和可恢复回滚的保护下,复用现有数据库升级 API7 网关控制面。 #### lts-upgrades 选择从上一代 LTS 版本升级到当前 LTS 版本时受支持的 API7 网关路径和确切版本锚点。 - [选择 LTS 升级路径](https://docs.apiseven.com/api7-gateway/upgrade-guides/lts-upgrades.md): 选择从上一代 LTS 版本升级到当前 LTS 版本时受支持的 API7 网关路径和确切版本锚点。 #### rolling-upgrade 通过容量规划、灰度验证、先增后排空发布、流量检查和回滚,逐步替换 API7 网关数据面节点。 - [数据面滚动升级](https://docs.apiseven.com/api7-gateway/upgrade-guides/rolling-upgrade.md): 通过容量规划、灰度验证、先增后排空发布、流量检查和回滚,逐步替换 API7 网关数据面节点。 #### upgrade 通过确认受支持的版本路径、选择部署策略、准备备份并演练回滚,规划 API7 网关升级。 - [规划 API7 网关升级](https://docs.apiseven.com/api7-gateway/upgrade-guides/upgrade.md): 通过确认受支持的版本路径、选择部署策略、准备备份并演练回滚,规划 API7 网关升级。 #### upgrade-3.8-to-3.10 使用外部 PostgreSQL,通过 Helm 和 Kubernetes 将 API7 网关从 3.8.23 升级到 3.10.7,并完成验证和基于备份的回滚。 - [从 3.8 LTS 升级到 3.10 LTS](https://docs.apiseven.com/api7-gateway/upgrade-guides/upgrade-3.8-to-3.10.md): 使用外部 PostgreSQL,通过 Helm 和 Kubernetes 将 API7 网关从 3.8.23 升级到 3.10.7,并完成验证和基于备份的回滚。 #### upgrade-3.9-to-3.10 使用外部 PostgreSQL 15.x,通过 Helm 和 Kubernetes 将 API7 网关从 3.9.20 直接升级到 3.10.7,并完成验证和回滚。 - [从 3.9 LTS 升级到 3.10 LTS](https://docs.apiseven.com/api7-gateway/upgrade-guides/upgrade-3.9-to-3.10.md): 使用外部 PostgreSQL 15.x,通过 Helm 和 Kubernetes 将 API7 网关从 3.9.20 直接升级到 3.10.7,并完成验证和回滚。 ### version-support-policy API7 企业版版本支持生命周期、LTS 策略和升级指南。了解各版本的支持时长以及当前指定为 LTS 的版本。 - [版本支持策略](https://docs.apiseven.com/api7-gateway/version-support-policy.md): API7 企业版版本支持生命周期、LTS 策略和升级指南。了解各版本的支持时长以及当前指定为 LTS 的版本。 ## apisix ### ai-agent-skills 使用 Claude Code、Cursor 等 AI 编程代理,以自然语言配置和运维 Apache APISIX API 网关。 - [Apache APISIX AI Agent Skills](https://docs.apiseven.com/apisix/ai-agent-skills.md): 使用 Claude Code、Cursor 等 AI 编程代理,以自然语言配置和运维 Apache APISIX API 网关。 #### a6-persona-developer 面向使用 a6 CLI 在 Apache APISIX 中构建和测试 API 的开发者角色 Skill,提供 API 设计、路由配置、插件选择、测试、本地开发和 CI/CD 集成的决策框架。 - [a6-persona-developer](https://docs.apiseven.com/apisix/ai-agent-skills/a6-persona-developer.md): 面向使用 a6 CLI 在 Apache APISIX 中构建和测试 API 的开发者角色 Skill,提供 API 设计、路由配置、插件选择、测试、本地开发和 CI/CD 集成的决策框架。 #### a6-persona-operator 面向使用 a6 CLI 管理 Apache APISIX 实例的平台运维人员和 DevOps 工程师角色 Skill,涵盖部署、监控、故障排查、扩缩容、安全加固和灾难恢复等日常运维决策。 - [a6-persona-operator](https://docs.apiseven.com/apisix/ai-agent-skills/a6-persona-operator.md): 面向使用 a6 CLI 管理 Apache APISIX 实例的平台运维人员和 DevOps 工程师角色 Skill,涵盖部署、监控、故障排查、扩缩容、安全加固和灾难恢复等日常运维决策。 #### a6-plugin-ai-content-moderation 用于通过 a6 CLI 配置 Apache APISIX AWS 和阿里云 AI 内容审核的 Skill,涵盖请求与响应检查、流式传输、deny_code 以及 ai-proxy。 - [a6-plugin-ai-content-moderation](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-ai-content-moderation.md): 用于通过 a6 CLI 配置 Apache APISIX AWS 和阿里云 AI 内容审核的 Skill,涵盖请求与响应检查、流式传输、deny_code 以及 ai-proxy。 #### a6-plugin-ai-prompt-decorator 用于通过 a6 CLI 配置 Apache APISIX ai-prompt-decorator 插件的 Skill,涵盖向 LLM 请求添加系统、用户和助手消息前缀或后缀、设置对话上下文以及强制执行安全指南。 - [a6-plugin-ai-prompt-decorator](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-ai-prompt-decorator.md): 用于通过 a6 CLI 配置 Apache APISIX ai-prompt-decorator 插件的 Skill,涵盖向 LLM 请求添加系统、用户和助手消息前缀或后缀、设置对话上下文以及强制执行安全指南。 #### a6-plugin-ai-prompt-template 用于通过 a6 CLI 配置 Apache APISIX ai-prompt-template 插件的 Skill,涵盖定义带变量占位符的可复用提示词模板、强制执行提示词结构,以及与 ai-proxy 组合构建完整的 AI 网关流水线。 - [a6-plugin-ai-prompt-template](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-ai-prompt-template.md): 用于通过 a6 CLI 配置 Apache APISIX ai-prompt-template 插件的 Skill,涵盖定义带变量占位符的可复用提示词模板、强制执行提示词结构,以及与 ai-proxy 组合构建完整的 AI 网关流水线。 #### a6-plugin-ai-proxy 用于通过 a6 CLI 配置 Apache APISIX ai-proxy 插件的 Skill,涵盖向 OpenAI、Azure OpenAI、DeepSeek、Anthropic、Gemini、Vertex AI 和 Amazon Bedrock 等 LLM 服务提供方代理请求、按提供方配置身份认证、模型、流式传输和日志,以及通过 ai-proxy-multi 实现负载均衡。 - [a6-plugin-ai-proxy](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-ai-proxy.md): 用于通过 a6 CLI 配置 Apache APISIX ai-proxy 插件的 Skill,涵盖向 OpenAI、Azure OpenAI、DeepSeek、Anthropic、Gemini、Vertex AI 和 Amazon Bedrock 等 LLM 服务提供方代理请求、按提供方配置身份认证、模型、流式传输和日志,以及通过 ai-proxy-multi 实现负载均衡。 #### a6-plugin-basic-auth 用于通过 a6 CLI 配置 Apache APISIX basic-auth 插件的 Skill,涵盖路由上的 HTTP Basic Authentication、带用户名和密码的消费者凭证关联、hide_credentials、匿名消费者回退以及常见运维模式。 - [a6-plugin-basic-auth](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-basic-auth.md): 用于通过 a6 CLI 配置 Apache APISIX basic-auth 插件的 Skill,涵盖路由上的 HTTP Basic Authentication、带用户名和密码的消费者凭证关联、hide_credentials、匿名消费者回退以及常见运维模式。 #### a6-plugin-consumer-restriction 用于通过 a6 CLI 配置 Apache APISIX consumer-restriction 插件的 Skill,涵盖按消费者名称、服务 ID 或路由 ID 进行访问限制,白名单/黑名单模式以及按消费者限制 HTTP 方法。 - [a6-plugin-consumer-restriction](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-consumer-restriction.md): 用于通过 a6 CLI 配置 Apache APISIX consumer-restriction 插件的 Skill,涵盖按消费者名称、服务 ID 或路由 ID 进行访问限制,白名单/黑名单模式以及按消费者限制 HTTP 方法。 #### a6-plugin-cors 用于通过 a6 CLI 配置 Apache APISIX cors 插件的 Skill,涵盖路由上的跨域资源共享、allow_origins、allow_methods、allow_headers、凭证处理、正则来源匹配、预检缓存以及常见运维模式。 - [a6-plugin-cors](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-cors.md): 用于通过 a6 CLI 配置 Apache APISIX cors 插件的 Skill,涵盖路由上的跨域资源共享、allow_origins、allow_methods、allow_headers、凭证处理、正则来源匹配、预检缓存以及常见运维模式。 #### a6-plugin-datadog 用于通过 a6 CLI 配置 Apache APISIX datadog 插件的 Skill,涵盖通过 DogStatsD 向 Datadog 推送自定义指标、指标标签、批处理、全局 DogStatsD 服务器配置的插件元数据以及 Datadog Agent 集成。 - [a6-plugin-datadog](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-datadog.md): 用于通过 a6 CLI 配置 Apache APISIX datadog 插件的 Skill,涵盖通过 DogStatsD 向 Datadog 推送自定义指标、指标标签、批处理、全局 DogStatsD 服务器配置的插件元数据以及 Datadog Agent 集成。 #### a6-plugin-ext-plugin 用于通过 a6 CLI 配置 Apache APISIX外部插件系统(ext-plugin-pre-req、ext-plugin-post-req、ext-plugin-post-resp)的 Skill,涵盖 Plugin Runner 架构、Go/Java/Python Runner 配置、RPC 协议、优雅降级以及性能注意事项。 - [a6-plugin-ext-plugin](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-ext-plugin.md): 用于通过 a6 CLI 配置 Apache APISIX外部插件系统(ext-plugin-pre-req、ext-plugin-post-req、ext-plugin-post-resp)的 Skill,涵盖 Plugin Runner 架构、Go/Java/Python Runner 配置、RPC 协议、优雅降级以及性能注意事项。 #### a6-plugin-fault-injection 使用 a6 CLI 配置 Apache APISIX fault-injection 插件的 Skill,涵盖为混沌工程注入延迟和 HTTP 中止、按百分比采样、通过 vars 表达式条件注入,以及自定义响应头和响应体。 - [a6-plugin-fault-injection](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-fault-injection.md): 使用 a6 CLI 配置 Apache APISIX fault-injection 插件的 Skill,涵盖为混沌工程注入延迟和 HTTP 中止、按百分比采样、通过 vars 表达式条件注入,以及自定义响应头和响应体。 #### a6-plugin-grpc-transcode 用于通过 a6 CLI 配置 Apache APISIX grpc-transcode 插件的 Skill,涵盖将 RESTful HTTP 请求转换为 gRPC、proto 文件管理、用于数据类型转换的 pb_option 设置、错误详情解码以及常见运维模式。 - [a6-plugin-grpc-transcode](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-grpc-transcode.md): 用于通过 a6 CLI 配置 Apache APISIX grpc-transcode 插件的 Skill,涵盖将 RESTful HTTP 请求转换为 gRPC、proto 文件管理、用于数据类型转换的 pb_option 设置、错误详情解码以及常见运维模式。 #### a6-plugin-hmac-auth 用于通过 a6 CLI 配置 Apache APISIX hmac-auth 插件的 Skill,涵盖 HMAC 签名认证、带 key_id/secret_key 的消费者凭证关联、允许的算法、时钟偏差处理、请求体校验、签名请求头以及常见运维模式。 - [a6-plugin-hmac-auth](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-hmac-auth.md): 用于通过 a6 CLI 配置 Apache APISIX hmac-auth 插件的 Skill,涵盖 HMAC 签名认证、带 key_id/secret_key 的消费者凭证关联、允许的算法、时钟偏差处理、请求体校验、签名请求头以及常见运维模式。 #### a6-plugin-http-logger 用于通过 a6 CLI 配置 Apache APISIX http-logger 插件的 Skill,涵盖批量推送访问日志、自定义 NGINX 变量日志格式、按条件记录请求/响应体、批处理调优和外部日志系统集成。 - [a6-plugin-http-logger](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-http-logger.md): 用于通过 a6 CLI 配置 Apache APISIX http-logger 插件的 Skill,涵盖批量推送访问日志、自定义 NGINX 变量日志格式、按条件记录请求/响应体、批处理调优和外部日志系统集成。 #### a6-plugin-ip-restriction 用于通过 a6 CLI 配置 Apache APISIX ip-restriction 插件的 Skill,涵盖路由上的 IP 白名单/黑名单、CIDR 范围、IPv4/IPv6、代理后提取真实客户端 IP、自定义错误消息以及常见运维模式。 - [a6-plugin-ip-restriction](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-ip-restriction.md): 用于通过 a6 CLI 配置 Apache APISIX ip-restriction 插件的 Skill,涵盖路由上的 IP 白名单/黑名单、CIDR 范围、IPv4/IPv6、代理后提取真实客户端 IP、自定义错误消息以及常见运维模式。 #### a6-plugin-jwt-auth 用于通过 a6 CLI 配置 Apache APISIX jwt-auth 插件的 Skill,涵盖 JWT Token 认证、HS256/RS256 算法选择、消费者凭证关联、从请求头/查询参数/Cookie 查找 Token、声明处理、时钟偏差、密钥管理以及常见运维模式。 - [a6-plugin-jwt-auth](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-jwt-auth.md): 用于通过 a6 CLI 配置 Apache APISIX jwt-auth 插件的 Skill,涵盖 JWT Token 认证、HS256/RS256 算法选择、消费者凭证关联、从请求头/查询参数/Cookie 查找 Token、声明处理、时钟偏差、密钥管理以及常见运维模式。 #### a6-plugin-kafka-logger 用于通过 a6 CLI 配置 Apache APISIX kafka-logger 插件的 Skill,涵盖 Kafka 主题、Broker、SASL PLAIN/SCRAM 身份认证、自定义日志格式、Producer 调优和批处理。 - [a6-plugin-kafka-logger](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-kafka-logger.md): 用于通过 a6 CLI 配置 Apache APISIX kafka-logger 插件的 Skill,涵盖 Kafka 主题、Broker、SASL PLAIN/SCRAM 身份认证、自定义日志格式、Producer 调优和批处理。 #### a6-plugin-key-auth 用于通过 a6 CLI 配置 Apache APISIX key-auth 插件的 Skill,涵盖路由上的 API Key 认证、消费者凭证关联、从请求头/查询参数/Cookie 查找 Key、hide_credentials、匿名消费者回退以及常见运维模式。 - [a6-plugin-key-auth](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-key-auth.md): 用于通过 a6 CLI 配置 Apache APISIX key-auth 插件的 Skill,涵盖路由上的 API Key 认证、消费者凭证关联、从请求头/查询参数/Cookie 查找 Key、hide_credentials、匿名消费者回退以及常见运维模式。 #### a6-plugin-limit-count 用于通过 a6 CLI 配置 APISIX limit-count 插件的 Skill,涵盖固定与滑动窗口、Redis Sentinel、延迟同步以及共享配额。 - [a6-plugin-limit-count](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-limit-count.md): 用于通过 a6 CLI 配置 APISIX limit-count 插件的 Skill,涵盖固定与滑动窗口、Redis Sentinel、延迟同步以及共享配额。 #### a6-plugin-limit-req 用于通过 a6 CLI 配置 Apache APISIX limit-req 插件的 Skill,涵盖漏桶限流、rate/burst 配置、nodelay 行为、Key 类型、用于分布式限流的 Redis 策略、流量平滑以及与 limit-count 组合使用等常见运维模式。 - [a6-plugin-limit-req](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-limit-req.md): 用于通过 a6 CLI 配置 Apache APISIX limit-req 插件的 Skill,涵盖漏桶限流、rate/burst 配置、nodelay 行为、Key 类型、用于分布式限流的 Redis 策略、流量平滑以及与 limit-count 组合使用等常见运维模式。 #### a6-plugin-openid-connect 用于通过 a6 CLI 配置 APISIX openid-connect 插件的 Skill,涵盖授权码与 Bearer 流程、PAR、DPoP 和会话校验。 - [a6-plugin-openid-connect](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-openid-connect.md): 用于通过 a6 CLI 配置 APISIX openid-connect 插件的 Skill,涵盖授权码与 Bearer 流程、PAR、DPoP 和会话校验。 #### a6-plugin-prometheus 用于通过 a6 CLI 配置 APISIX prometheus 插件的 Skill,涵盖 HTTP、LLM 和 AI 缓存指标、延迟类型标签以及 Grafana Dashboard。 - [a6-plugin-prometheus](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-prometheus.md): 用于通过 a6 CLI 配置 APISIX prometheus 插件的 Skill,涵盖 HTTP、LLM 和 AI 缓存指标、延迟类型标签以及 Grafana Dashboard。 #### a6-plugin-proxy-rewrite 用于通过 a6 CLI 配置 Apache APISIX proxy-rewrite 插件的 Skill,涵盖将请求 URI、主机、方法、请求头和协议重写后再转发到上游,包括正则 URI 重写、请求头操作以及常见运维模式。 - [a6-plugin-proxy-rewrite](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-proxy-rewrite.md): 用于通过 a6 CLI 配置 Apache APISIX proxy-rewrite 插件的 Skill,涵盖将请求 URI、主机、方法、请求头和协议重写后再转发到上游,包括正则 URI 重写、请求头操作以及常见运维模式。 #### a6-plugin-redirect 用于通过 a6 CLI 配置 Apache APISIX redirect 插件的 Skill,涵盖 URI 重定向、HTTP 到 HTTPS 重定向、基于正则的 URI 重写、查询字符串处理以及常见运维模式。 - [a6-plugin-redirect](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-redirect.md): 用于通过 a6 CLI 配置 Apache APISIX redirect 插件的 Skill,涵盖 URI 重定向、HTTP 到 HTTPS 重定向、基于正则的 URI 重写、查询字符串处理以及常见运维模式。 #### a6-plugin-response-rewrite 用于通过 a6 CLI 配置 Apache APISIX response-rewrite 插件的 Skill,涵盖向客户端返回前重写响应状态码、请求头和响应体,包括使用 vars 条件执行、正则响应体过滤器以及常见运维模式。 - [a6-plugin-response-rewrite](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-response-rewrite.md): 用于通过 a6 CLI 配置 Apache APISIX response-rewrite 插件的 Skill,涵盖向客户端返回前重写响应状态码、请求头和响应体,包括使用 vars 条件执行、正则响应体过滤器以及常见运维模式。 #### a6-plugin-serverless 用于通过 a6 CLI 配置 Apache APISIX serverless-pre-function 和 serverless-post-function 插件的 Skill,涵盖在可配置请求阶段执行内联 Lua 函数、函数签名、闭包模式、可用 Lua API 以及执行顺序。 - [a6-plugin-serverless](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-serverless.md): 用于通过 a6 CLI 配置 Apache APISIX serverless-pre-function 和 serverless-post-function 插件的 Skill,涵盖在可配置请求阶段执行内联 Lua 函数、函数签名、闭包模式、可用 Lua API 以及执行顺序。 #### a6-plugin-skywalking 用于通过 a6 CLI 配置 Apache APISIX skywalking 插件的 Skill,涵盖使用 Apache SkyWalking OAP 进行分布式追踪、采样配置、服务拓扑以及常见运维模式。 - [a6-plugin-skywalking](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-skywalking.md): 用于通过 a6 CLI 配置 Apache APISIX skywalking 插件的 Skill,涵盖使用 Apache SkyWalking OAP 进行分布式追踪、采样配置、服务拓扑以及常见运维模式。 #### a6-plugin-traffic-split 用于通过 a6 CLI 配置 Apache APISIX traffic-split 插件的 Skill,涵盖通过条件匹配规则在上游之间进行加权流量拆分,包括灰度发布、蓝绿发布、A/B 测试模式以及常见运维模式。 - [a6-plugin-traffic-split](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-traffic-split.md): 用于通过 a6 CLI 配置 Apache APISIX traffic-split 插件的 Skill,涵盖通过条件匹配规则在上游之间进行加权流量拆分,包括灰度发布、蓝绿发布、A/B 测试模式以及常见运维模式。 #### a6-plugin-wolf-rbac 用于通过 a6 CLI 配置 Apache APISIX wolf-rbac 插件的 Skill,涵盖与 Wolf RBAC 服务器集成以实现基于角色的访问控制、Token 管理、登录/用户信息/修改密码 API 端点、权限检查流程以及多应用配置。 - [a6-plugin-wolf-rbac](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-wolf-rbac.md): 用于通过 a6 CLI 配置 Apache APISIX wolf-rbac 插件的 Skill,涵盖与 Wolf RBAC 服务器集成以实现基于角色的访问控制、Token 管理、登录/用户信息/修改密码 API 端点、权限检查流程以及多应用配置。 #### a6-plugin-zipkin 用于通过 a6 CLI 配置 Apache APISIX zipkin 插件的 Skill,涵盖使用 Zipkin、Jaeger 或任何兼容 Zipkin 的收集器进行分布式追踪、B3 传播请求头、采样以及常见运维模式。 - [a6-plugin-zipkin](https://docs.apiseven.com/apisix/ai-agent-skills/a6-plugin-zipkin.md): 用于通过 a6 CLI 配置 Apache APISIX zipkin 插件的 Skill,涵盖使用 Zipkin、Jaeger 或任何兼容 Zipkin 的收集器进行分布式追踪、B3 传播请求头、采样以及常见运维模式。 #### a6-recipe-api-versioning 使用 a6 CLI 实现 API 版本管理策略的方案 Skill,涵盖 URI 路径、请求头和查询参数版本管理,以及通过 traffic-split 和 redirect 完成渐进式迁移与版本弃用。 - [a6-recipe-api-versioning](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-api-versioning.md): 使用 a6 CLI 实现 API 版本管理策略的方案 Skill,涵盖 URI 路径、请求头和查询参数版本管理,以及通过 traffic-split 和 redirect 完成渐进式迁移与版本弃用。 #### a6-recipe-blue-green 使用 a6 CLI 实现蓝绿发布的方案 Skill,涵盖创建两套上游环境、通过路由更新或 traffic-split 即时切换流量、回滚,以及声明式配置同步。 - [a6-recipe-blue-green](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-blue-green.md): 使用 a6 CLI 实现蓝绿发布的方案 Skill,涵盖创建两套上游环境、通过路由更新或 traffic-split 即时切换流量、回滚,以及声明式配置同步。 #### a6-recipe-canary 使用 a6 CLI 在 Apache APISIX 中实现灰度发布的方案 Skill,涵盖通过 traffic-split 插件渐进式转移流量、基于请求头的灰度路由、监控检查点以及完整的发布或回滚工作流。 - [a6-recipe-canary](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-canary.md): 使用 a6 CLI 在 Apache APISIX 中实现灰度发布的方案 Skill,涵盖通过 traffic-split 插件渐进式转移流量、基于请求头的灰度路由、监控检查点以及完整的发布或回滚工作流。 #### a6-recipe-circuit-breaker 使用 a6 CLI 在 Apache APISIX 中实现服务熔断模式的方案 Skill,涵盖 api-breaker 插件、不健康阈值、健康恢复、响应码分类以及与服务健康检查的集成。 - [a6-recipe-circuit-breaker](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-circuit-breaker.md): 使用 a6 CLI 在 Apache APISIX 中实现服务熔断模式的方案 Skill,涵盖 api-breaker 插件、不健康阈值、健康恢复、响应码分类以及与服务健康检查的集成。 #### a6-recipe-graphql-proxy 使用 a6 CLI 实现 GraphQL 代理模式的方案 Skill,涵盖基于内置 GraphQL 变量的操作级路由和限流、使用 degraphql 将 REST 转换为 GraphQL,以及 GraphQL API 安全。 - [a6-recipe-graphql-proxy](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-graphql-proxy.md): 使用 a6 CLI 实现 GraphQL 代理模式的方案 Skill,涵盖基于内置 GraphQL 变量的操作级路由和限流、使用 degraphql 将 REST 转换为 GraphQL,以及 GraphQL API 安全。 #### a6-recipe-health-check 使用 a6 CLI 配置上游健康检查的方案 Skill,涵盖主动 HTTP 探测、被动响应分析、组合使用两种检查、健康/不健康阈值,以及上游节点状态监控。 - [a6-recipe-health-check](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-health-check.md): 使用 a6 CLI 配置上游健康检查的方案 Skill,涵盖主动 HTTP 探测、被动响应分析、组合使用两种检查、健康/不健康阈值,以及上游节点状态监控。 #### a6-recipe-mtls 使用 a6 CLI 配置双向 TLS(mTLS)的方案 Skill,涵盖 SSL 证书管理、连接后端服务的上游 mTLS、客户端证书校验,以及从客户端经 Apache APISIX 到上游的端到端 mTLS。 - [a6-recipe-mtls](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-mtls.md): 使用 a6 CLI 配置双向 TLS(mTLS)的方案 Skill,涵盖 SSL 证书管理、连接后端服务的上游 mTLS、客户端证书校验,以及从客户端经 Apache APISIX 到上游的端到端 mTLS。 #### a6-recipe-multi-tenant 使用 a6 CLI 在共享 Apache APISIX 网关上实现租户感知策略的方案 Skill,涵盖消费者组共享策略、基于 Host/路径/已认证消费者的路由、消费者级限流、上下文转发和声明式配置。 - [在共享网关上构建租户感知策略](https://docs.apiseven.com/apisix/ai-agent-skills/a6-recipe-multi-tenant.md): 使用 a6 CLI 在共享 Apache APISIX 网关上实现租户感知策略的方案 Skill,涵盖消费者组共享策略、基于 Host/路径/已认证消费者的路由、消费者级限流、上下文转发和声明式配置。 #### a6-shared 使用 Apache APISIX命令行工具 a6 的核心 Skill,提供项目约定、命令模式、双 API 架构和开发工作流;在处理 a6 源代码、添加新命令、编写测试或修改任何 a6 组件时加载此 Skill。 - [a6-shared](https://docs.apiseven.com/apisix/ai-agent-skills/a6-shared.md): 使用 Apache APISIX命令行工具 a6 的核心 Skill,提供项目约定、命令模式、双 API 架构和开发工作流;在处理 a6 源代码、添加新命令、编写测试或修改任何 a6 组件时加载此 Skill。 ### documentation 探索全面的 Apache APISIX 文档,涵盖安装、指南、插件以及高效 API 管理和网关功能的关键概念。 - [Apache APISIX 文档](https://docs.apiseven.com/apisix/documentation.md): 探索全面的 Apache APISIX 文档,涵盖安装、指南、插件以及高效 API 管理和网关功能的关键概念。 ### getting-started 了解如何快速安装和配置 Apache APISIX,这是一个动态且高性能的 API 网关,用于简化你的 API 生命周期管理。 - [安装 APISIX](https://docs.apiseven.com/apisix/getting-started.md): 了解如何快速安装和配置 Apache APISIX,这是一个动态且高性能的 API 网关,用于简化你的 API 生命周期管理。 #### configure-routes 了解如何在 Apache APISIX 中定义路由以管理流量、匹配客户端请求并有效地将其转发到上游服务。 - [配置路由](https://docs.apiseven.com/apisix/getting-started/configure-routes.md): 了解如何在 Apache APISIX 中定义路由以管理流量、匹配客户端请求并有效地将其转发到上游服务。 #### key-authentication 探索如何在 Apache APISIX 中配置密钥认证,通过有效管理消费者凭证来允许对你的 API 进行安全访问。 - [密钥认证](https://docs.apiseven.com/apisix/getting-started/key-authentication.md): 探索如何在 Apache APISIX 中配置密钥认证,通过有效管理消费者凭证来允许对你的 API 进行安全访问。 #### load-balancing 了解如何在 Apache APISIX 中实现负载均衡,利用各种算法在多个上游服务之间分配传入请求。 - [负载均衡](https://docs.apiseven.com/apisix/getting-started/load-balancing.md): 了解如何在 Apache APISIX 中实现负载均衡,利用各种算法在多个上游服务之间分配传入请求。 #### management-options 比较 Admin API、ADC、a6 CLI 和 APISIX-MCP,为交互式操作或自动化选择合适的 APISIX 资源管理工作流。 - [管理方式](https://docs.apiseven.com/apisix/getting-started/management-options.md): 比较 Admin API、ADC、a6 CLI 和 APISIX-MCP,为交互式操作或自动化选择合适的 APISIX 资源管理工作流。 #### rate-limiting 在 Apache APISIX 中实施限流限速,以控制流量,保护你的 API 免受滥用,并通过设置请求限制确保公平使用。 - [限流限速](https://docs.apiseven.com/apisix/getting-started/rate-limiting.md): 在 Apache APISIX 中实施限流限速,以控制流量,保护你的 API 免受滥用,并通过设置请求限制确保公平使用。 ### how-apisix-works 了解 Apache APISIX 如何从配置存储到上游选择端到端处理请求,以及路由和热更新设计如何支持数千条路由而无需重启。 - [APISIX 工作原理](https://docs.apiseven.com/apisix/how-apisix-works.md): 了解 Apache APISIX 如何从配置存储到上游选择端到端处理请求,以及路由和热更新设计如何支持数千条路由而无需重启。 ### how-to-guide #### ai-gateway - [配置提示词装饰器](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/configure-prompt-decorators.md): 了解如何配置 APISIX 提示词装饰器,在网关为 OpenAI Chat Completions 和 Responses API 请求前置或追加指令。 - [实施提示词防护栏](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/implement-prompt-guardrails.md): 探索如何在 Apache APISIX 中实施提示词防护栏,以保护用户隐私并在使用大型语言模型 (LLM) 时阻止意外的模型行为。 - [预定义提示词模板](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/pre-define-prompt-templates.md): 了解如何在 APISIX 中使用客户端提供的值、OpenAI Web 搜索和工具,为 Chat Completions 与 Responses API 配置可复用的提示词模板。 - [代理 Amazon Bedrock 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-amazon-bedrock-requests.md): 了解如何配置 APISIX 向 Amazon Bedrock 进行身份认证,并使用 ai-proxy 插件代理 Converse 和 ConverseStream 请求。 - [代理 Anthropic 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-anthropic-requests.md): 配置 Apache APISIX,使用 ai-proxy 插件将 OpenAI 兼容请求和 Anthropic 原生 Messages 请求代理到 Claude 模型。 - [代理 Azure OpenAI 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-azure-openai-requests.md): 了解如何配置 APISIX 通过 Azure OpenAI 进行身份认证,并代理流式和非流式的 Chat Completions 与 Responses API 请求。 - [代理 Gemini 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-gemini-requests.md): 了解如何配置 Apache APISIX 以使用 ai-proxy 插件代理对 Google Gemini 的请求,从而无需指定自定义端点即可通过 OpenAI 兼容 API 访问 Gemini 模型。 - [代理 OpenAI 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-openai-requests.md): 了解如何配置 APISIX 通过 OpenAI 进行身份认证,并使用 ai-proxy 插件代理 Chat Completions、Responses API 和 Embeddings 请求。 - [代理 OpenRouter 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-openrouter-requests.md): 了解如何配置 Apache APISIX 以使用 ai-proxy 插件代理对 OpenRouter 的请求,从而无需指定自定义端点即可通过 OpenAI 兼容 API 访问许多模型服务提供方。 - [代理 Vertex AI 请求](https://docs.apiseven.com/apisix/how-to-guide/ai-gateway/proxy-vertex-ai-requests.md): 了解如何配置 Apache APISIX 以使用 ai-proxy 插件代理对 Google Vertex AI 的请求,从而通过 OpenAI 兼容 API 访问 Gemini 模型。 #### authentication - [使用 Amazon Cognito 为 M2M 请求授权](https://docs.apiseven.com/apisix/how-to-guide/authentication/authorize-m2m-requests-with-amazon-cognito.md): 配置 Apache APISIX 验证 Amazon Cognito 访问 Token,并按客户端和自定义 Scope 为机器到机器 API 请求授权。 - [使用 Auth0 为 M2M 请求授权](https://docs.apiseven.com/apisix/how-to-guide/authentication/authorize-m2m-requests-with-auth0.md): 配置 Apache APISIX 验证 Auth0 访问 Token,并通过受众和 Scope 限制为机器到机器 API 请求授权。 - [使用 Microsoft Entra ID(Azure AD)为 M2M 请求授权](https://docs.apiseven.com/apisix/how-to-guide/authentication/authorize-m2m-requests-with-microsoft-entra-id.md): 配置 Apache APISIX 验证 Microsoft Entra ID 访问 Token,并使用应用角色为机器到机器 API 请求授权。 - [实施基本认证](https://docs.apiseven.com/apisix/how-to-guide/authentication/implement-basic-auth.md): 了解如何在 Apache APISIX 中设置基本认证,允许客户端使用用户名和密码组合安全地进行身份认证。 - [实施 HMAC 认证](https://docs.apiseven.com/apisix/how-to-guide/authentication/implement-hmac-auth.md): 探索在 Apache APISIX 中设置 HMAC 认证的过程,通过使用共享密钥的加密签名确确保 API 请求的安全。 - [实施 JWT 认证](https://docs.apiseven.com/apisix/how-to-guide/authentication/implement-jwt-auth.md): 了解如何在 Apache APISIX 中实施 JWT 认证,允许使用 JSON Web Token 对 API 客户端进行安全且无状态的身份认证。 - [实施密钥认证](https://docs.apiseven.com/apisix/how-to-guide/authentication/implement-key-auth.md): 了解如何在 Apache APISIX 中设置密钥认证,允许你向消费者颁发唯一的 API 密钥,以实现对 API 的有效访问控制。 - [使用 PAR 和 DPoP 保护 OIDC](https://docs.apiseven.com/apisix/how-to-guide/authentication/secure-oidc-with-par-and-dpop.md): 配置 APISIX 和 Keycloak,使用 PAR、PKCE、DPoP 绑定访问令牌和私钥 JWT 身份认证来保护 OIDC 授权码流程。 - [保护 WebSocket 流量](https://docs.apiseven.com/apisix/how-to-guide/authentication/secure-websocket-traffic.md): 了解如何在 Apache APISIX 中保护 WebSocket 流量,在初始握手期间实施身份认证机制以保护 WebSocket 连接。 - [使用 Amazon Cognito 配置 SSO](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-amazon-cognito.md): 配置 Apache APISIX 与 Amazon Cognito,通过带 PKCE 的 OpenID Connect 授权码流程实现基于浏览器的单点登录。 - [使用 Auth0 配置 SSO](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-auth0.md): 使用带 PKCE 的 OpenID Connect 授权码流程,配置 Apache APISIX 与 Auth0,实现基于浏览器的单点登录。 - [使用 Microsoft Entra ID(Azure AD)配置 SSO](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-azure-ad.md): 使用 OpenID Connect 授权码流程及 PKCE,将 Apache APISIX 配置为通过 Microsoft Entra ID 实现基于浏览器的单点登录。 - [设置 Google 单点登录](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-google.md): 配置 Apache APISIX 与 Google,使用带 PKCE 的 OpenID Connect 授权码流实现基于浏览器的单点登录。 - [设置 Keycloak 单点登录](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md): 了解如何将 Apache APISIX 与 Keycloak 集成,通过 OpenID Connect 实现安全的单点登录(SSO)身份认证流程。 - [设置 Okta 单点登录](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-okta.md): 使用带 PKCE 的 OpenID Connect 授权码流程,配置 Apache APISIX 与 Okta,实现基于浏览器的单点登录。 #### custom-plugins - [使用 Lua 创建自定义插件](https://docs.apiseven.com/apisix/how-to-guide/custom-plugins/create-plugin-in-lua.md): 了解如何为 Apache APISIX 开发自定义 Lua 插件以扩展其功能。 - [在 APISIX 中使用 Wasm 插件](https://docs.apiseven.com/apisix/how-to-guide/custom-plugins/wasm-plugins.md): 了解如何在 Apache APISIX 中实施 WebAssembly (Wasm) 插件,利用 Proxy-Wasm 规范增强功能。 #### observability - [在访问日志中记录消费者标签](https://docs.apiseven.com/apisix/how-to-guide/observability/log-consumer-label-in-access-log.md): 了解如何配置 Apache APISIX 以在访问日志中记录消费者标签,从而增强 API 管理和安全性。 - [使用 ClickHouse 记录日志](https://docs.apiseven.com/apisix/how-to-guide/observability/log-with-clickhouse.md): 了解如何配置 Apache APISIX 将访问信息记录到 ClickHouse,从而促进高效的日志管理和分析。 - [使用 Elasticsearch 记录日志](https://docs.apiseven.com/apisix/how-to-guide/observability/log-with-elasticsearch.md): 了解如何将 Apache APISIX 与 Elasticsearch 集成以收集和索引日志,并通过 ELK 技术栈提供强大的搜索和可视化能力。 - [使用 Datadog 监控 APISIX 指标](https://docs.apiseven.com/apisix/how-to-guide/observability/monitor-apisix-with-datadog.md): 探索将 Datadog 与 Apache APISIX 集成以监控指标的过程,从而增强可观测性和警报能力。 - [使用 Prometheus 监控 APISIX 指标](https://docs.apiseven.com/apisix/how-to-guide/observability/monitor-apisix-with-prometheus.md): 了解如何在 Apache APISIX 中启用 Prometheus 以收集指标,从而有效监控系统性能和健康状况。 - [使用 Zipkin 追踪请求](https://docs.apiseven.com/apisix/how-to-guide/observability/trace-with-zipkin.md): 探索如何在 Apache APISIX 中使用 Zipkin 实施请求追踪,从而实现对请求流和性能诊断的详细监控。 #### security - [在 AWS Secrets Manager 中管理密钥](https://docs.apiseven.com/apisix/how-to-guide/security/secrets-management/manage-secrets-in-aws.md): 了解如何将 AWS Secrets Manager 与 Apache APISIX 结合使用,以安全地存储和管理敏感凭证,确保持自动轮换和安全访问。 - [在 GCP Secret Manager 中管理密钥](https://docs.apiseven.com/apisix/how-to-guide/security/secrets-management/manage-secrets-in-gcp-secret-manager.md): 了解如何将 GCP Secret Manager 与 Apache APISIX 集成,以集中管理 API 密钥和密码等密钥,并提供安全检索机制。 - [在 HashiCorp Vault 中管理密钥](https://docs.apiseven.com/apisix/how-to-guide/security/secrets-management/manage-secrets-in-hashicorp-vault.md): 了解如何将 HashiCorp Vault 与 Apache APISIX 集成,以安全管理敏感信息(包括 API 密钥和密码),以及如何在应用程序中检索这些密钥。 - [与 Coraza 集成](https://docs.apiseven.com/apisix/how-to-guide/security/waf/integrate-with-coraza.md): 探索 Coraza Web 应用程序防火墙 (WAF) 与 Apache APISIX 的集成,以增强安全性,提供针对各种网络攻击的强大保护。 #### service-discovery - [与 HashiCorp Consul 集成](https://docs.apiseven.com/apisix/how-to-guide/service-discovery/consul-integration.md): 了解如何设置 HashiCorp Consul 进行服务发现,并将其与 Apache APISIX 集成,以动态路由和负载均衡微服务的流量。 - [与 Netflix Eureka 集成](https://docs.apiseven.com/apisix/how-to-guide/service-discovery/eureka-integration.md): 探索如何配置 Netflix Eureka 进行服务发现,并将其与 Apache APISIX 集成,以无缝管理服务注册和路由。 - [集成 Kubernetes 服务发现](https://docs.apiseven.com/apisix/how-to-guide/service-discovery/kubernetes-service-discovery.md): 配置 Apache APISIX 以安全地发现 Kubernetes Endpoints 或 EndpointSlices,并将请求路由到一个或多个集群中的服务。 #### traffic-management - [实施 API 版本控制](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/api-versioning.md): 了解如何在 Apache APISIX 中使用路径、查询和标头策略实施 API 版本控制,以实现更好的 API 管理。 - [条件流量管理](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/conditional-traffic-management.md): 探索如何在 Apache APISIX 中实施条件流量管理,根据请求特征(如标头或参数)启用动态路由和操作。 - [配置上游健康检查](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/health-check.md): 了解如何在 Apache APISIX 中为上游服务配置主动和被动健康检查,确保仅将请求转发到健康的服务。 - [配置客户端和 APISIX 之间的 HTTP/3 QUIC](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/http3-quic.md): 了解如何在 Apache APISIX 中配置 HTTP/3 连接,以利用 QUIC 的优势来提高性能并减少延迟。 - [代理传输层 (L4) 流量](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/proxy-transport-layer-l4-traffic.md): 探索如何配置 Apache APISIX 来处理传输层 (L4) TCP 和 UDP 流量,从而实现各种类型的网络流量的高效代理。 - [代理 WebSocket 连接](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/proxy-websocket.md): 了解如何启用 Apache APISIX 代理 WebSocket 连接,促进客户端和服务器之间的实时双向通信。 - [配置限流限速](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/rate-limiting.md): 了解如何在 Apache APISIX 中使用各种插件设置限流限速,以控制对 API 的访问并保护它们免受过多请求的影响。 - [配置客户端和 APISIX 之间的 HTTPS](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/tls-and-mtls/configure-https-between-client-and-apisix.md): 了解如何在客户端和 Apache APISIX 之间配置 HTTPS 以增强 API 安全性。 - [配置 APISIX 和上游之间的双向 TLS](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/tls-and-mtls/configure-mtls-between-apisix-and-upstream.md): 了解如何在 Apache APISIX 和上游服务之间配置双向 TLS,以增强 API 安全性。 - [配置客户端和 APISIX 之间的双向 TLS](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/tls-and-mtls/configure-mtls-between-client-and-apisix.md): 了解如何在客户端和 Apache APISIX 之间配置双向 TLS,以增强 API 安全性。 - [配置上游 HTTPS](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/tls-and-mtls/configure-upstream-https.md): 了解如何在 Apache APISIX 中连接到 HTTPS 端口上的上游服务,以确保通信安全并增强 API 安全性。 - [实施流量镜像](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/traffic-mirroring.md): 了解如何在 Apache APISIX 中设置流量镜像,允许你将传入流量复制到辅助服务进行测试或分析,而不影响主服务。 #### transformation - [将 JSON 转换为 XML](https://docs.apiseven.com/apisix/how-to-guide/transformation/convert-json-to-xml.md): 了解如何在 Apache APISIX 中使用 body-transformer 插件将 JSON 数据转换为 XML 格式,反之亦然,从而促进不同系统之间的数据交换。 - [将 HTTP 转换为 gRPC](https://docs.apiseven.com/apisix/how-to-guide/transformation/transcode-http-to-grpc.md): 了解如何在 Apache APISIX 中使用 grpc-transcode 插件在 RESTful HTTP 请求和 gRPC 请求之间进行转换,从而实现 gRPC 服务的无缝集成。 ### install #### docker 了解如何使用 Docker 安装 Apache APISIX,提供一种在容器化环境中部署和管理 API 网关的简单方法。 - [使用 Docker 安装 APISIX](https://docs.apiseven.com/apisix/install/docker.md): 了解如何使用 Docker 安装 Apache APISIX,提供一种在容器化环境中部署和管理 API 网关的简单方法。 - [构建自定义 Docker 镜像](https://docs.apiseven.com/apisix/install/docker/build-custom-images.md): 了解如何为 Apache APISIX 构建自定义 Docker 镜像,允许进行定制配置以满足你的特定部署需求。 #### kubernetes - [在 ROSA 上安装 APISIX](https://docs.apiseven.com/apisix/install/kubernetes/rosa.md): 按照步骤在 Red Hat OpenShift Service on AWS (ROSA) 上安装 Apache APISIX,这是一个用于部署 OpenShift 集群的完全托管服务。 ### key-concepts #### consumer-groups 了解 Apache APISIX 中消费者组的概念,它允许使用共享配置来管理多个消费者。 - [消费者组](https://docs.apiseven.com/apisix/key-concepts/consumer-groups.md): 了解 Apache APISIX 中消费者组的概念,它允许使用共享配置来管理多个消费者。 #### consumers 了解 Apache APISIX 中消费者的概念,它代表与 API 网关及其服务交互的用户或应用程序。 - [消费者](https://docs.apiseven.com/apisix/key-concepts/consumers.md): 了解 Apache APISIX 中消费者的概念,它代表与 API 网关及其服务交互的用户或应用程序。 #### credentials 了解 Apache APISIX 中凭证的概念,它管理消费者的身份认证配置以增强安全性和访问控制。 - [凭证](https://docs.apiseven.com/apisix/key-concepts/credentials.md): 了解 Apache APISIX 中凭证的概念,它管理消费者的身份认证配置以增强安全性和访问控制。 #### plugin-configs 了解 Apache APISIX 中插件配置的概念,它集中管理插件配置以提高 API 管理效率。 - [插件配置](https://docs.apiseven.com/apisix/key-concepts/plugin-configs.md): 了解 Apache APISIX 中插件配置的概念,它集中管理插件配置以提高 API 管理效率。 #### plugin-global-rules 了解 Apache APISIX 中全局规则的概念,它允许插件在每个传入请求上执行,以实现一致的 API 行为。 - [插件全局规则](https://docs.apiseven.com/apisix/key-concepts/plugin-global-rules.md): 了解 Apache APISIX 中全局规则的概念,它允许插件在每个传入请求上执行,以实现一致的 API 行为。 #### plugin-metadata 了解 Apache APISIX 中插件元数据的概念,它管理插件的共享配置,确保多个实例之间的一致性。 - [插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md): 了解 Apache APISIX 中插件元数据的概念,它管理插件的共享配置,确保多个实例之间的一致性。 #### plugins 了解 Apache APISIX 中插件的概念,它扩展了 API 操作中的流量管理、安全性和可观测性等功能。 - [插件](https://docs.apiseven.com/apisix/key-concepts/plugins.md): 了解 Apache APISIX 中插件的概念,它扩展了 API 操作中的流量管理、安全性和可观测性等功能。 #### protos 了解 Apache APISIX 中 Protos 的概念,它促进了服务之间的高效数据序列化和通信。 - [Protos](https://docs.apiseven.com/apisix/key-concepts/protos.md): 了解 Apache APISIX 中 Protos 的概念,它促进了服务之间的高效数据序列化和通信。 #### routes 了解 Apache APISIX 中路由的概念,它定义了通往上游服务的路径并促进了有效的流量管理。 - [路由](https://docs.apiseven.com/apisix/key-concepts/routes.md): 了解 Apache APISIX 中路由的概念,它定义了通往上游服务的路径并促进了有效的流量管理。 #### secrets 了解 Apache APISIX 中密钥管理的概念,它实现了 API 密钥等敏感信息的安全存储和管理。 - [密钥管理](https://docs.apiseven.com/apisix/key-concepts/secrets.md): 了解 Apache APISIX 中密钥管理的概念,它实现了 API 密钥等敏感信息的安全存储和管理。 #### services 了解 Apache APISIX 中服务的概念,它代表后端应用程序,并通过减少配置冗余来简化 API 管理。 - [服务](https://docs.apiseven.com/apisix/key-concepts/services.md): 了解 Apache APISIX 中服务的概念,它代表后端应用程序,并通过减少配置冗余来简化 API 管理。 #### ssl-certificates 了解 Apache APISIX 中 SSL 证书的概念,它确保客户端和 API 网关之间的安全通信。 - [SSL 证书](https://docs.apiseven.com/apisix/key-concepts/ssl-certificates.md): 了解 Apache APISIX 中 SSL 证书的概念,它确保客户端和 API 网关之间的安全通信。 #### stream-routes 了解 Apache APISIX 中四层路由的概念,它管理 TCP/UDP 流量,增强了网关对各种协议的处理能力。 - [四层路由](https://docs.apiseven.com/apisix/key-concepts/stream-routes.md): 了解 Apache APISIX 中四层路由的概念,它管理 TCP/UDP 流量,增强了网关对各种协议的处理能力。 #### upstreams 了解 Apache APISIX 中上游的概念,它管理后端服务地址以实现高效的负载均衡和服务发现。 - [上游](https://docs.apiseven.com/apisix/key-concepts/upstreams.md): 了解 Apache APISIX 中上游的概念,它管理后端服务地址以实现高效的负载均衡和服务发现。 ### migration #### nginx-to-apisix 按照指南从 NGINX 迁移到 Apache APISIX,确保平稳过渡,同时利用 API 网关的优势。 - [从 NGINX 迁移到 APISIX](https://docs.apiseven.com/apisix/migration/nginx-to-apisix.md): 按照指南从 NGINX 迁移到 Apache APISIX,确保平稳过渡,同时利用 API 网关的优势。 ### networking #### port-reference 探索 Apache APISIX 的默认端口配置,详细说明 API 网关中用于各种协议和服务的端口。 - [端口参考](https://docs.apiseven.com/apisix/networking/port-reference.md): 探索 Apache APISIX 的默认端口配置,详细说明 API 网关中用于各种协议和服务的端口。 ### production #### deployment-modes 了解 Apache APISIX 的各种部署模式,包括传统模式、解耦模式和独立模式,以优化你的 API 网关部署策略。 - [部署模式](https://docs.apiseven.com/apisix/production/deployment-modes.md): 了解 Apache APISIX 的各种部署模式,包括传统模式、解耦模式和独立模式,以优化你的 API 网关部署策略。 #### performance - [性能测试基准](https://docs.apiseven.com/apisix/production/performance/performance-testing.md): 探索对 Apache APISIX 进行性能测试的方法,确保你的 API 网关能够有效处理预期的流量负载。 #### recovery - [备份和恢复 etcd](https://docs.apiseven.com/apisix/production/recovery/etcd-backup-restore.md): 了解在 Apache APISIX 中备份和恢复 etcd 的最佳实践,确保 API 配置的数据完整性和可用性。 #### scaling - [在 AWS EC2 上自动扩缩容 APISIX 网关](https://docs.apiseven.com/apisix/production/scaling/autoscale-apisix-gateway-aws.md): 了解如何在 AWS EC2 上使用自动扩缩容组 (ASG) 自动扩缩容 APISIX 网关,以在不同的流量负载下保持一致的 API 性能。 - [自动扩展 APISIX 网关 (K8s)](https://docs.apiseven.com/apisix/production/scaling/autoscale-apisix-gateway-k8s.md): 了解如何使用水平 Pod 自动伸缩器(HPA)在 Kubernetes 上自动扩展 APISIX 网关,以在不同的流量负载下保持一致的 API 性能。 #### security - [Admin API 密钥](https://docs.apiseven.com/apisix/production/security/admin-api-key.md): 了解在 Apache APISIX 中配置 Admin API 密钥的重要性,确保对 Admin API 端点的安全访问并有效地管理权限。 - [使用密钥环加密数据](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md): 了解 Apache APISIX 中数据加密的重要性,以及如何使用密钥环保护敏感信息以增强保护。 - [IP 限制](https://docs.apiseven.com/apisix/production/security/ip-restriction.md): 了解如何在 Apache APISIX 中实施 IP 限制以控制对资源的访问,通过仅允许授权的 IP 地址来增强安全性。 - [配置 APISIX 和 etcd 之间的 mTLS](https://docs.apiseven.com/apisix/production/security/mtls/configure-mtls-between-apisix-and-etcd.md): 了解如何在 Apache APISIX 和 etcd 之间配置双向 TLS,确保这些组件之间的通信和身份认证安全。 - [配置客户端和 APISIX Admin API 之间的 mTLS](https://docs.apiseven.com/apisix/production/security/mtls/configure-mtls-between-client-and-admin-api.md): 了解如何在客户端和 Apache APISIX Admin API 之间配置双向 TLS,以增强 API 管理的安全性。 #### serve-static-resources 了解如何配置 Apache APISIX 以高效地服务静态资源,从而提高 API 的性能和资源管理。 - [服务静态资源](https://docs.apiseven.com/apisix/production/serve-static-resources.md): 了解如何配置 Apache APISIX 以高效地服务静态资源,从而提高 API 的性能和资源管理。 #### upgrade - [灰度发布](https://docs.apiseven.com/apisix/production/upgrade/canary-deployment.md): 了解 Apache APISIX 中的灰度发布策略,允许逐步推出新功能,同时将风险降至最低。 - [升级前审查变更](https://docs.apiseven.com/apisix/production/upgrade/review-changes-before-upgrade.md): 在升级到此版本前,审查可能影响现有路由、插件、指标和身份认证的 APISIX 行为变更。 ### reference #### a6-cli 了解单独安装的 a6 CLI 如何通过 Admin API 管理 Apache APISIX,以及它与其他管理工具的区别。 - [a6 CLI](https://docs.apiseven.com/apisix/reference/a6-cli.md): 了解单独安装的 a6 CLI 如何通过 Admin API 管理 Apache APISIX,以及它与其他管理工具的区别。 #### adc 使用 API 声明式 CLI(ADC)以声明方式管理 Apache APISIX 配置。 - [API 声明式 CLI(ADC)](https://docs.apiseven.com/apisix/reference/adc.md): 使用 API 声明式 CLI(ADC)以声明方式管理 Apache APISIX 配置。 #### api-standalone-usage 了解 Apache APISIX 中的 API 驱动独立模式用法,该模式将网关配置完全存储在内存中,而不是配置文件中。 - [API 驱动的独立模式](https://docs.apiseven.com/apisix/reference/api-standalone-usage.md): 了解 Apache APISIX 中的 API 驱动独立模式用法,该模式将网关配置完全存储在内存中,而不是配置文件中。 #### apisix-cli 探索 APISIX 命令行接口 (CLI),这是一个旨在轻松管理和控制 APISIX 实例的工具。 - [APISIX CLI](https://docs.apiseven.com/apisix/reference/apisix-cli.md): 探索 APISIX 命令行接口 (CLI),这是一个旨在轻松管理和控制 APISIX 实例的工具。 #### apisix-expressions 了解 APISIX 表达式,它结合了变量和运算符,用于路由匹配、请求过滤和其他功能。 - [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md): 了解 APISIX 表达式,它结合了变量和运算符,用于路由匹配、请求过滤和其他功能。 #### apisix-mcp 使用 APISIX-MCP 向兼容 MCP 的 AI 客户端和 Agent 公开 Apache APISIX 资源操作及网关测试请求。 - [APISIX 模型上下文协议(APISIX-MCP)](https://docs.apiseven.com/apisix/reference/apisix-mcp.md): 使用 APISIX-MCP 向兼容 MCP 的 AI 客户端和 Agent 公开 Apache APISIX 资源操作及网关测试请求。 #### batch-processor 了解 APISIX 如何批量处理日志和遥测条目、限制待处理任务,以及在目标变慢或不可用时控制内存使用。 - [批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md): 了解 APISIX 如何批量处理日志和遥测条目、限制待处理任务,以及在目标变慢或不可用时控制内存使用。 #### built-in-variables 探索 Apache APISIX 中的内置变量,它们提供对特定于请求的信息的访问,用于插件配置和路由。 - [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md): 探索 Apache APISIX 中的内置变量,它们提供对特定于请求的信息的访问,用于插件配置和路由。 #### configuration-files 了解 Apache APISIX 中的配置文件,详细说明如何为各种环境自定义参数。 - [配置文件](https://docs.apiseven.com/apisix/reference/configuration-files.md): 了解 Apache APISIX 中的配置文件,详细说明如何为各种环境自定义参数。 #### environment-variables 探索 Apache APISIX 中的环境变量,这些变量可以在部署期间启用可配置的设置,以增强灵活性。 - [环境变量](https://docs.apiseven.com/apisix/reference/environment-variables.md): 探索 Apache APISIX 中的环境变量,这些变量可以在部署期间启用可配置的设置,以增强灵活性。 #### file-standalone-configurations 了解 Apache APISIX 中的文件驱动独立配置,允许网关从 YAML 或 JSON 文件加载网关配置。 - [文件驱动的独立模式](https://docs.apiseven.com/apisix/reference/file-standalone-configurations.md): 了解 Apache APISIX 中的文件驱动独立配置,允许网关从 YAML 或 JSON 文件加载网关配置。 #### helm-chart 了解如何查找 Apache APISIX Helm Chart 的配置值,以及 Helm values 如何渲染为网关配置。 - [Helm Chart](https://docs.apiseven.com/apisix/reference/helm-chart.md): 了解如何查找 Apache APISIX Helm Chart 的配置值,以及 Helm values 如何渲染为网关配置。 #### plugin-common-configurations 探索 Apache APISIX 中的通用插件配置,通过 meta 属性为所有插件启用通用设置。 - [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md): 探索 Apache APISIX 中的通用插件配置,通过 meta 属性为所有插件启用通用设置。 #### router-options 了解 Apache APISIX 中的路由选项,详细说明如何调整 API 请求处理的路由行为。 - [路由选项](https://docs.apiseven.com/apisix/reference/router-options.md): 了解 Apache APISIX 中的路由选项,详细说明如何调整 API 请求处理的路由行为。 ### troubleshooting #### debug-mode 在 Apache APISIX 中启用并配置调试模式,以有效检查运行时行为,日志细节,以及故障排除问题. - [使用调试模式](https://docs.apiseven.com/apisix/troubleshooting/debug-mode.md): 在 Apache APISIX 中启用并配置调试模式,以有效检查运行时行为,日志细节,以及故障排除问题. #### set-breakpoints 了解如何使用 APISIX inspect 插件,在不重启 APISIX 或修改源代码的情况下,捕获运行中工作进程里任意 Lua 代码行的局部变量和函数闭包变量。 - [设置断点](https://docs.apiseven.com/apisix/troubleshooting/set-breakpoints.md): 了解如何使用 APISIX inspect 插件,在不重启 APISIX 或修改源代码的情况下,捕获运行中工作进程里任意 Lua 代码行的局部变量和函数闭包变量。 ## enterprise-whitepaper ### tags - [标签](https://docs.apiseven.com/enterprise-whitepaper/tags.md) #### api-7-enterprise - [16 篇文档带有标签「API7 Enterprise」](https://docs.apiseven.com/enterprise-whitepaper/tags/api-7-enterprise.md) #### api-7-whitepaper - [16 篇文档带有标签「API7 Whitepaper」](https://docs.apiseven.com/enterprise-whitepaper/tags/api-7-whitepaper.md) #### architecture - [1 篇文档带有标签「Architecture」](https://docs.apiseven.com/enterprise-whitepaper/tags/architecture.md) #### authentication - [1 篇文档带有标签「Authentication」](https://docs.apiseven.com/enterprise-whitepaper/tags/authentication.md) #### canary-release - [1 篇文档带有标签「Canary Release」](https://docs.apiseven.com/enterprise-whitepaper/tags/canary-release.md) #### log-auditing - [1 篇文档带有标签「Log Auditing」](https://docs.apiseven.com/enterprise-whitepaper/tags/log-auditing.md) #### monitoring-and-alerting - [1 篇文档带有标签「Monitoring and Alerting」](https://docs.apiseven.com/enterprise-whitepaper/tags/monitoring-and-alerting.md) #### multi-tenancy - [1 篇文档带有标签「Multi-tenancy」](https://docs.apiseven.com/enterprise-whitepaper/tags/multi-tenancy.md) #### performance - [1 篇文档带有标签「Performance」](https://docs.apiseven.com/enterprise-whitepaper/tags/performance.md) #### protocol-conversion - [1 篇文档带有标签「Protocol Conversion」](https://docs.apiseven.com/enterprise-whitepaper/tags/protocol-conversion.md) #### refined-routing - [1 篇文档带有标签「Refined Routing」](https://docs.apiseven.com/enterprise-whitepaper/tags/refined-routing.md) #### service-governance - [1 篇文档带有标签「Service Governance」](https://docs.apiseven.com/enterprise-whitepaper/tags/service-governance.md) ### architecture Data Plane - [Architecture](https://docs.apiseven.com/enterprise-whitepaper/architecture.md): Data Plane ### feature-highlights API Management - [Feature Highlights](https://docs.apiseven.com/enterprise-whitepaper/feature-highlights.md): API Management ### features API and Service Governance - [Features](https://docs.apiseven.com/enterprise-whitepaper/features.md): API and Service Governance #### authentication API7 has built-in authentication authentication plugins such as key-auth, basic-auth, jwt-auth, etc. Taking HMAC plugin as an example, API7 can work with AK/SK to encrypt the request parameters to ensure that the request has not been tampered with. - [Authentication](https://docs.apiseven.com/enterprise-whitepaper/features/authentication.md): API7 has built-in authentication authentication plugins such as key-auth, basic-auth, jwt-auth, etc. Taking HMAC plugin as an example, API7 can work with AK/SK to encrypt the request parameters to ensure that the request has not been tampered with. #### canary-release Routing is the core function of the API gateway, which is used to route and match requests passing through the API gateway and forward them to the corresponding upstream service. When the upstream service finishes processing, the result is returned to the client. If a request does not match a route, the gateway will return a 404 status code because the route has not been published to the gateway or the route is not configured. - [Canary Release](https://docs.apiseven.com/enterprise-whitepaper/features/canary-release.md): Routing is the core function of the API gateway, which is used to route and match requests passing through the API gateway and forward them to the corresponding upstream service. When the upstream service finishes processing, the result is returned to the client. If a request does not match a route, the gateway will return a 404 status code because the route has not been published to the gateway or the route is not configured. #### log-auditing API7 has a built-in log auditing module, which collects system security events, administrator operation records, system operation logs, system operation status and other kinds of information in the information system centrally, and then stores and manages them centrally in the form of logs in a unified format after normalization, filtering and consolidation, combining with rich log statistical summary and correlation analysis functions to realize comprehensive auditing of information system logs. Through post-event analysis and reporting system, administrators can easily and efficiently conduct targeted security audits on information systems; when encountering special security events or configuration failures, the log auditing system can help administrators conduct rapid configuration positioning and rollback. Only administrators with authority can perform operation rollback. - [Log Auditing](https://docs.apiseven.com/enterprise-whitepaper/features/log-auditing.md): API7 has a built-in log auditing module, which collects system security events, administrator operation records, system operation logs, system operation status and other kinds of information in the information system centrally, and then stores and manages them centrally in the form of logs in a unified format after normalization, filtering and consolidation, combining with rich log statistical summary and correlation analysis functions to realize comprehensive auditing of information system logs. Through post-event analysis and reporting system, administrators can easily and efficiently conduct targeted security audits on information systems; when encountering special security events or configuration failures, the log auditing system can help administrators conduct rapid configuration positioning and rollback. Only administrators with authority can perform operation rollback. #### monitoring-alerting API7 records the basic information and status of each request. With the help of the statistical report page in the dashboard control panel, administrators can see the status of each service call, status code distribution, number of successes, number of failures, top 95 values, top 99 values and other information. It is convenient for administrators to understand the health of the system. In addition, the data plane will regularly report the traffic processing situation, and the administrator can view the gateway operation status and other indicators, such as error rate, number of requests, status code distribution, etc., within a certain time period through the control panel. When the administrator presets the alarm rules through the control panel, if the traffic reported by the gateway matches the rules, it will trigger the preset policies, such as sending station letters, email alerts, SMS and Webhook notifications, etc. - [Monitoring and Alerting](https://docs.apiseven.com/enterprise-whitepaper/features/monitoring-alerting.md): API7 records the basic information and status of each request. With the help of the statistical report page in the dashboard control panel, administrators can see the status of each service call, status code distribution, number of successes, number of failures, top 95 values, top 99 values and other information. It is convenient for administrators to understand the health of the system. In addition, the data plane will regularly report the traffic processing situation, and the administrator can view the gateway operation status and other indicators, such as error rate, number of requests, status code distribution, etc., within a certain time period through the control panel. When the administrator presets the alarm rules through the control panel, if the traffic reported by the gateway matches the rules, it will trigger the preset policies, such as sending station letters, email alerts, SMS and Webhook notifications, etc. #### multi-tenancy API7 has a built-in workspace module, super administrators need to create multiple workspaces, then create ordinary users and assign different permissions (in the configuration of permissions, you can bind workspace and resource permissions), so that the combination of the user system and permission management can achieve different users in different workspaces, different permissions for different resources, in order to achieve fine-grained control of resources permissions. - [Multi-tenancy](https://docs.apiseven.com/enterprise-whitepaper/features/multi-tenancy.md): API7 has a built-in workspace module, super administrators need to create multiple workspaces, then create ordinary users and assign different permissions (in the configuration of permissions, you can bind workspace and resource permissions), so that the combination of the user system and permission management can achieve different users in different workspaces, different permissions for different resources, in order to achieve fine-grained control of resources permissions. #### performance API7 adopts excellent performance solutions in all aspects from route matching, JSONSchema validation, and plugin operation. - [Performance](https://docs.apiseven.com/enterprise-whitepaper/features/performance.md): API7 adopts excellent performance solutions in all aspects from route matching, JSONSchema validation, and plugin operation. #### plugins API7 has more than 60 built-in common plugins, covering authentication, security protection, traffic control, analysis and monitoring, request/response conversion and many other categories. Some popular plugins are listed in the chart below. - [Plugins](https://docs.apiseven.com/enterprise-whitepaper/features/plugins.md): API7 has more than 60 built-in common plugins, covering authentication, security protection, traffic control, analysis and monitoring, request/response conversion and many other categories. Some popular plugins are listed in the chart below. #### protocol-conversion API7 exposes RESTful APIs uniformly to the outside world, which can be set by administrators in the control panel. These APIs correspond to microservices/upstream services in the enterprise and support proxies for protocols such as Dubbo, gRPC, WebServices, MQTT, etc., in addition to common HTTP services. - [Protocol Conversion](https://docs.apiseven.com/enterprise-whitepaper/features/protocol-conversion.md): API7 exposes RESTful APIs uniformly to the outside world, which can be set by administrators in the control panel. These APIs correspond to microservices/upstream services in the enterprise and support proxies for protocols such as Dubbo, gRPC, WebServices, MQTT, etc., in addition to common HTTP services. #### refined-routing API7 will triage the matched requests according to the preset weights and parameters. - [Refined Routing](https://docs.apiseven.com/enterprise-whitepaper/features/refined-routing.md): API7 will triage the matched requests according to the preset weights and parameters. #### service-governance API7 has built-in service governance features such as flow and rate limiting, service meltdown, IP blacklist and whitelist, and fault isolation. - [Service Governance](https://docs.apiseven.com/enterprise-whitepaper/features/service-governance.md): API7 has built-in service governance features such as flow and rate limiting, service meltdown, IP blacklist and whitelist, and fault isolation. ### highlights API7 Highlights - [Highlights](https://docs.apiseven.com/enterprise-whitepaper/highlights.md): API7 Highlights ### introduction API7.ai's API Gateway product (hereinafter referred to as API7) is built based on Apache APISIX, a top-level project of the Apache Software Foundation. API7 consists of 3 components: API Gateway, ManagerAPI and Dashboard Control Panel. - [Overview](https://docs.apiseven.com/enterprise-whitepaper/introduction.md): API7.ai's API Gateway product (hereinafter referred to as API7) is built based on Apache APISIX, a top-level project of the Apache Software Foundation. API7 consists of 3 components: API Gateway, ManagerAPI and Dashboard Control Panel. ### modules API7 mainly contains the following functional modules: - [Modules](https://docs.apiseven.com/enterprise-whitepaper/modules.md): API7 mainly contains the following functional modules: ## ingress-controller ### apply-plugins-to-l4-routes 了解如何通过配置并验证 L4RoutePolicy,将 APISIX Stream 插件挂载到 Gateway API TCPRoute、UDPRoute 和 TLSRoute 资源。 - [为四层路由应用插件](https://docs.apiseven.com/ingress-controller/apply-plugins-to-l4-routes.md): 了解如何通过配置并验证 L4RoutePolicy,将 APISIX Stream 插件挂载到 Gateway API TCPRoute、UDPRoute 和 TLSRoute 资源。 ### canary-releases 了解如何通过协调工作负载、加权路由、分析、提升和回滚,使用 APISIX 或 API7 Ingress Controller 规划金丝雀发布。 - [金丝雀发布](https://docs.apiseven.com/ingress-controller/canary-releases.md): 了解如何通过协调工作负载、加权路由、分析、提升和回滚,使用 APISIX 或 API7 Ingress Controller 规划金丝雀发布。 #### argo-rollouts 配置 Argo Rollouts,通过 HTTPRoute 或 ApisixRoute 转移 APISIX 或 API7 Gateway 流量,并提升、分析和中止发布。 - [使用 Argo Rollouts 进行金丝雀发布](https://docs.apiseven.com/ingress-controller/canary-releases/argo-rollouts.md): 配置 Argo Rollouts,通过 HTTPRoute 或 ApisixRoute 转移 APISIX 或 API7 Gateway 流量,并提升、分析和中止发布。 #### flagger 使用 Flagger 和 APISIX 指标,通过 Gateway API HTTPRoute 或 ApisixRoute 资源自动执行金丝雀分析、提升和回滚。 - [使用 Flagger 自动执行金丝雀发布](https://docs.apiseven.com/ingress-controller/canary-releases/flagger.md): 使用 Flagger 和 APISIX 指标,通过 Gateway API HTTPRoute 或 ApisixRoute 资源自动执行金丝雀分析、提升和回滚。 ### common-use-cases 了解网关插件生态支持的常见使用场景,以及如何通过 Ingress Controller 配置这些插件。 - [常见使用场景](https://docs.apiseven.com/ingress-controller/common-use-cases.md): 了解网关插件生态支持的常见使用场景,以及如何通过 Ingress Controller 配置这些插件。 ### configure-upstream-health-checks 了解如何通过 APISIX 或 API7 Ingress Controller 配置上游健康检查。 - [配置上游健康检查](https://docs.apiseven.com/ingress-controller/configure-upstream-health-checks.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置上游健康检查。 ### custom-plugins #### lua 了解如何在 Kubernetes 环境中将 Lua 自定义插件加载到网关,并通过 APISIX 或 API7 Ingress Controller 将插件应用到路由。 - [部署 Lua 自定义插件](https://docs.apiseven.com/ingress-controller/custom-plugins/lua.md): 了解如何在 Kubernetes 环境中将 Lua 自定义插件加载到网关,并通过 APISIX 或 API7 Ingress Controller 将插件应用到路由。 #### wasm 了解如何在 Kubernetes 环境中将 Wasm 自定义插件加载到网关,并通过 APISIX Ingress Controller 将插件应用到路由。 - [部署 Wasm 插件](https://docs.apiseven.com/ingress-controller/custom-plugins/wasm.md): 了解如何在 Kubernetes 环境中将 Wasm 自定义插件加载到网关,并通过 APISIX Ingress Controller 将插件应用到路由。 ### detect-upstream-protocol-appprotocol 了解如何通过 APISIX 或 API7 Ingress Controller 根据 appProtocol 的值自动配置上游协议。 - [使用 appProtocol 检测上游协议](https://docs.apiseven.com/ingress-controller/detect-upstream-protocol-appprotocol.md): 了解如何通过 APISIX 或 API7 Ingress Controller 根据 appProtocol 的值自动配置上游协议。 ### documentation 阅读 API7 与 APISIX Ingress Controller 文档,了解安装、操作指南、故障排查,以及通过 Ingress、Gateway API 和 APISIX CRD 动态管理网关流量的参考信息。 - [Ingress Controller 文档](https://docs.apiseven.com/ingress-controller/documentation.md): 阅读 API7 与 APISIX Ingress Controller 文档,了解安装、操作指南、故障排查,以及通过 Ingress、Gateway API 和 APISIX CRD 动态管理网关流量的参考信息。 ### high-availability 配置 APISIX 或 API7 Ingress Controller 的副本、部署位置、领导者选举和故障转移验证,实现高可用部署。 - [高可用](https://docs.apiseven.com/ingress-controller/high-availability.md): 配置 APISIX 或 API7 Ingress Controller 的副本、部署位置、领导者选举和故障转移验证,实现高可用部署。 ### installation #### gitops 规划 APISIX 或 API7 Ingress Controller 的 GitOps 部署,包括仓库结构、资源所有权、CRD 和凭证。 - [为 GitOps 做准备](https://docs.apiseven.com/ingress-controller/installation/gitops.md): 规划 APISIX 或 API7 Ingress Controller 的 GitOps 部署,包括仓库结构、资源所有权、CRD 和凭证。 - [使用 Argo CD 管理](https://docs.apiseven.com/ingress-controller/installation/gitops/argo-cd.md): 使用 Argo CD 安装 APISIX 或 API7 Ingress Controller,并采用稳定的 Webhook 证书、明确的 CRD 所有权和安全协调策略。 - [使用 Flux 管理](https://docs.apiseven.com/ingress-controller/installation/gitops/flux.md): 使用 Flux 和 HelmRelease 资源安装 APISIX 或 API7 Ingress Controller,并配置明确的 CRD 策略、漂移检测和验证。 #### openshift 按照本指南在 OpenShift 集群上部署 API7 Ingress Controller,确保为你的环境进行正确配置和设置。 - [在 OpenShift 上安装 API7 Ingress Controller](https://docs.apiseven.com/ingress-controller/installation/openshift.md): 按照本指南在 OpenShift 集群上部署 API7 Ingress Controller,确保为你的环境进行正确配置和设置。 ### production #### cross-namespace 使用 APISIX 或 API7 Ingress Controller 为路由、后端、TLS Secret 和 Consumer 凭证配置安全的跨命名空间引用。 - [配置跨命名空间引用](https://docs.apiseven.com/ingress-controller/production/cross-namespace.md): 使用 APISIX 或 API7 Ingress Controller 为路由、后端、TLS Secret 和 Consumer 凭证配置安全的跨命名空间引用。 #### gateway-api-access-control 了解如何使用 Kubernetes RBAC,在平台团队与应用团队之间安全委派 APISIX 或 API7 Ingress Controller 的 Gateway API 资源管理权限。 - [使用 Kubernetes RBAC 委派 Gateway API 访问权限](https://docs.apiseven.com/ingress-controller/production/gateway-api-access-control.md): 了解如何使用 Kubernetes RBAC,在平台团队与应用团队之间安全委派 APISIX 或 API7 Ingress Controller 的 Gateway API 资源管理权限。 #### upgrade 更新 CRD、审查兼容性变更并验证流量,将 APISIX 或 API7 Ingress Controller 从 2.1.0 升级到 2.2.0。 - [升级 Ingress Controller](https://docs.apiseven.com/ingress-controller/production/upgrade.md): 更新 CRD、审查兼容性变更并验证流量,将 APISIX 或 API7 Ingress Controller 从 2.1.0 升级到 2.2.0。 ### proxy-grpc-traffic 了解如何通过 APISIX 或 API7 Ingress Controller 配置路由以代理 gRPC 流量。 - [代理 gRPC 流量](https://docs.apiseven.com/ingress-controller/proxy-grpc-traffic.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置路由以代理 gRPC 流量。 ### proxy-requests-to-a-service 了解如何通过 Ingress Controller 创建路由,将请求代理到示例 HTTP 上游服务并验证路由结果。 - [将请求代理到服务](https://docs.apiseven.com/ingress-controller/proxy-requests-to-a-service.md): 了解如何通过 Ingress Controller 创建路由,将请求代理到示例 HTTP 上游服务并验证路由结果。 ### proxy-tcp-traffic 了解如何通过 APISIX 或 API7 Ingress Controller 按端口代理 TCP 流量。 - [按端口代理 TCP 流量](https://docs.apiseven.com/ingress-controller/proxy-tcp-traffic.md): 了解如何通过 APISIX 或 API7 Ingress Controller 按端口代理 TCP 流量。 ### proxy-tcp-traffic-over-tls 了解如何通过 APISIX 或 API7 Ingress Controller 基于 SNI 配置路由以代理 TLS 上的 TCP 流量。 - [通过 SNI 代理 TLS 上的 TCP 流量](https://docs.apiseven.com/ingress-controller/proxy-tcp-traffic-over-tls.md): 了解如何通过 APISIX 或 API7 Ingress Controller 基于 SNI 配置路由以代理 TLS 上的 TCP 流量。 ### proxy-to-external-services 了解如何通过 APISIX 或 API7 Ingress Controller 将请求代理到 Kubernetes 集群外部托管的服务。 - [将请求代理到外部服务](https://docs.apiseven.com/ingress-controller/proxy-to-external-services.md): 了解如何通过 APISIX 或 API7 Ingress Controller 将请求代理到 Kubernetes 集群外部托管的服务。 ### proxy-to-weighted-backends 了解如何通过 APISIX 或 API7 Ingress Controller 配置加权路由,将流量分发到多个上游服务。 - [将请求代理到加权后端](https://docs.apiseven.com/ingress-controller/proxy-to-weighted-backends.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置加权路由,将流量分发到多个上游服务。 ### proxy-udp-traffic 了解如何通过 APISIX 或 API7 Ingress Controller 按端口代理 UDP 流量。 - [按端口代理 UDP 流量](https://docs.apiseven.com/ingress-controller/proxy-udp-traffic.md): 了解如何通过 APISIX 或 API7 Ingress Controller 按端口代理 UDP 流量。 ### proxy-websocket-connection 使用 HTTPRoute 或 ApisixRoute 资源配置 APISIX 或 API7 Ingress Controller 代理 WebSocket 连接。 - [代理 WebSocket 连接](https://docs.apiseven.com/ingress-controller/proxy-websocket-connection.md): 使用 HTTPRoute 或 ApisixRoute 资源配置 APISIX 或 API7 Ingress Controller 代理 WebSocket 连接。 ### reference #### annotations 了解注解如何扩展 Ingress Controller 中 Kubernetes Ingress 和 IngressClass 资源的功能,以配置路由、安全和网关行为。 - [注解](https://docs.apiseven.com/ingress-controller/reference/annotations.md): 了解注解如何扩展 Ingress Controller 中 Kubernetes Ingress 和 IngressClass 资源的功能,以配置路由、安全和网关行为。 #### configuration-file 配置 APISIX 或 API7 Ingress Controller 的日志、领导者选举、指标、同步、Gateway API 和 Webhook 设置。 - [配置文件](https://docs.apiseven.com/ingress-controller/reference/configuration-file.md): 配置 APISIX 或 API7 Ingress Controller 的日志、领导者选举、指标、同步、Gateway API 和 Webhook 设置。 #### crd-reference 探索 Ingress Controller 支持的自定义资源定义 (CRD) 的详细参考文档。 - [自定义资源定义 API 参考](https://docs.apiseven.com/ingress-controller/reference/crd-reference.md): 探索 Ingress Controller 支持的自定义资源定义 (CRD) 的详细参考文档。 #### examples 探索展示 Ingress Controller 资源配置的各种示例,帮助你根据自身环境有效调整设置。 - [配置示例](https://docs.apiseven.com/ingress-controller/reference/examples.md): 探索展示 Ingress Controller 资源配置的各种示例,帮助你根据自身环境有效调整设置。 #### helm-charts 了解用于部署 APISIX 和 API7 Ingress Controller 的 Helm Chart,包括它们的工作方式以及可配置 Chart values 的参考位置。 - [Helm Chart](https://docs.apiseven.com/ingress-controller/reference/helm-charts.md): 了解用于部署 APISIX 和 API7 Ingress Controller 的 Helm Chart,包括它们的工作方式以及可配置 Chart values 的参考位置。 #### ingress-and-gateway-api-support 了解 Ingress Controller 支持的 Gateway API 和 Ingress 资源及其当前功能。 - [Ingress 和 Gateway API 支持](https://docs.apiseven.com/ingress-controller/reference/ingress-and-gateway-api-support.md): 了解 Ingress Controller 支持的 Gateway API 和 Ingress 资源及其当前功能。 ### release-notes 查看 APISIX 和 API7 Ingress Controller 各版本的共有及产品特有变更、升级要求、兼容性信息与重要修复。 - [发布说明](https://docs.apiseven.com/ingress-controller/release-notes.md): 查看 APISIX 和 API7 Ingress Controller 各版本的共有及产品特有变更、升级要求、兼容性信息与重要修复。 ### set-up-ingress-controller-and-gateway 了解如何快速部署和配置 API7 Ingress Controller 或 APISIX Ingress Controller,用于管理 Kubernetes 入站流量。 - [设置 Ingress Controller 和网关](https://docs.apiseven.com/ingress-controller/set-up-ingress-controller-and-gateway.md): 了解如何快速部署和配置 API7 Ingress Controller 或 APISIX Ingress Controller,用于管理 Kubernetes 入站流量。 ### tls-and-mtls #### configure-downstream-https 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关接收来自客户端的 HTTPS 流量。 - [配置客户端与网关之间的 HTTPS](https://docs.apiseven.com/ingress-controller/tls-and-mtls/configure-downstream-https.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关接收来自客户端的 HTTPS 流量。 #### configure-downstream-mtls 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关,要求客户端使用双向 TLS(mTLS)。 - [配置客户端与网关之间的 mTLS](https://docs.apiseven.com/ingress-controller/tls-and-mtls/configure-downstream-mtls.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关,要求客户端使用双向 TLS(mTLS)。 #### configure-upstream-mtls 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关通过双向 TLS(mTLS)将流量转发到上游服务。 - [配置网关与上游之间的 mTLS](https://docs.apiseven.com/ingress-controller/tls-and-mtls/configure-upstream-mtls.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关通过双向 TLS(mTLS)将流量转发到上游服务。 #### proxy-to-https-upstream 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关通过 HTTPS 将流量转发到上游服务。 - [将请求代理到 HTTPS 上游服务](https://docs.apiseven.com/ingress-controller/tls-and-mtls/proxy-to-https-upstream.md): 了解如何通过 APISIX 或 API7 Ingress Controller 配置网关通过 HTTPS 将流量转发到上游服务。 ### troubleshooting #### admission-webhook 了解准入 Webhook 在应用 Ingress Controller 资源时可能返回的错误和警告消息,以及如何解决这些问题。 - [了解准入 Webhook](https://docs.apiseven.com/ingress-controller/troubleshooting/admission-webhook.md): 了解准入 Webhook 在应用 Ingress Controller 资源时可能返回的错误和警告消息,以及如何解决这些问题。 #### common-issues 了解如何识别和解决 APISIX 或 API7 Ingress Controller 中的常见问题。 - [常见问题与解决方案](https://docs.apiseven.com/ingress-controller/troubleshooting/common-issues.md): 了解如何识别和解决 APISIX 或 API7 Ingress Controller 中的常见问题。 #### configuration-synchronization 了解如何检查并排查 APISIX 或 API7 Ingress Controller 中的配置转换与同步问题。 - [排查 Manifest 转换与同步问题](https://docs.apiseven.com/ingress-controller/troubleshooting/configuration-synchronization.md): 了解如何检查并排查 APISIX 或 API7 Ingress Controller 中的配置转换与同步问题。 #### gateway-debug-mode 了解如何在 Kubernetes 环境中启用网关调试模式,以便排查和观察网关运行时行为。 - [启用网关调试模式](https://docs.apiseven.com/ingress-controller/troubleshooting/gateway-debug-mode.md): 了解如何在 Kubernetes 环境中启用网关调试模式,以便排查和观察网关运行时行为。 ## portal ### next #### demo This page is used for API7 Portal Documentation's Next version. It is rendered in docs.api7.ai/portal/next/blank - [Blank](https://docs.apiseven.com/portal/next/demo.md): This page is used for API7 Portal Documentation's Next version. It is rendered in docs.api7.ai/portal/next/blank ### tags - [标签](https://docs.apiseven.com/portal/tags.md) #### api-7-portal - [1 篇文档带有标签「API7 Portal」](https://docs.apiseven.com/portal/tags/api-7-portal.md) ### background-information #### how-api7-portal-works - [api7-portal-architecture](https://docs.apiseven.com/portal/background-information/how-api7-portal-works/api7-portal-architecture.md) - [integrate-with-api-management-platform](https://docs.apiseven.com/portal/background-information/how-api7-portal-works/integrate-with-api-management-platform.md) - [network-resiliency-and-availability](https://docs.apiseven.com/portal/background-information/how-api7-portal-works/network-resiliency-and-availability.md) ### get-started #### developer - [analyze-api-usage](https://docs.apiseven.com/portal/get-started/developer/analyze-api-usage.md) - [call-subscribed-api](https://docs.apiseven.com/portal/get-started/developer/call-subscribed-api.md) - [discover-api](https://docs.apiseven.com/portal/get-started/developer/discover-api.md) - [get-developer-account](https://docs.apiseven.com/portal/get-started/developer/get-developer-account.md) - [manage-api-key](https://docs.apiseven.com/portal/get-started/developer/manage-api-key.md) - [subscribe-api-product](https://docs.apiseven.com/portal/get-started/developer/subscribe-api-product.md) #### provider - [access-developer-portal](https://docs.apiseven.com/portal/get-started/provider/access-developer-portal.md) - [analyze-api-usage](https://docs.apiseven.com/portal/get-started/provider/analyze-api-usage.md) - [get-provider-account](https://docs.apiseven.com/portal/get-started/provider/get-provider-account.md) - [manage-api-subscription](https://docs.apiseven.com/portal/get-started/provider/manage-api-subscription.md) - [publish-api-product](https://docs.apiseven.com/portal/get-started/provider/publish-api-product.md) ### how-to-guides #### security - [api7-portal-authentication](https://docs.apiseven.com/portal/how-to-guides/security/api7-portal-authentication.md) ### introduction 什么是 API7 Portal - [概览](https://docs.apiseven.com/portal/introduction.md): 什么是 API7 Portal --- # Full Documentation Content [跳到主要内容](#__docusaurus_skipToContent_fallback) Toggle Menu []()[![Logo](https://static.apiseven.com/202108/1640917868852-37633689-5279-48d6-a13a-189054e4d15b.png)](https://www.apiseven.com/) [Get Started](https://apiseven.feishu.cn/share/base/form/shrcnP2ryU7GwkaOIavHTggzBef) 产品 [API7 API 网关企业版](https://www.apiseven.com/enterprise)[Apache APISIX vs API7 企业版](https://www.apiseven.com/apisix-vs-enterprise)[API7 Portal](https://www.apiseven.com/portal) 解决方案 [本地部署升级混合云部署](https://www.apiseven.com/solutions/on-prem-to-hybrid-cloud)[单体架构升级微服务架构](https://www.apiseven.com/solutions/monolith-to-microservices)[可观测性](https://www.apiseven.com/solutions/observability)[零信任安全](https://www.apiseven.com/solutions/zero-trust-security)[虚拟机升级 Kubernetes](https://www.apiseven.com/solutions/vm-to-kubernetes) [客户案例](https://www.apiseven.com/customers) 开源项目 [Apache APISIX](http://apisix.apache.org/)[Apache APISIX Ingress Controller](https://github.com/apache/apisix-ingress-controller) 相关资源 [API7 企业版文档](https://docs.apiseven.com/api7-gateway/overview)[Apache APISIX 文档](https://docs.apiseven.com/apisix/documentation.md)[API 网关插件中心](https://docs.apiseven.com/hub.md)[白皮书](https://static.apiseven.com/202202/API7-WhitePaper.pdf)[Ingress Controller 文档](https://docs.apiseven.com/ingress-controller/documentation.md)[Apache APISIX vs NGINX](https://www.apiseven.com/apisix-vs-nginx)[Apache APISIX vs Kong](https://www.apiseven.com/apisix-vs-kong)[APISIX 商业支持](https://api7.ai/apache-apisix-enterprise-support) [技术博客](https://www.apiseven.com/blog) [Request Demo](https://apiseven.feishu.cn/share/base/form/shrcnP2ryU7GwkaOIavHTggzBef) [API7](#)[![Logo](https://static.apiseven.com/202108/1640917868852-37633689-5279-48d6-a13a-189054e4d15b.png)](https://www.apiseven.com/) * 产品 [* API7 API 网关企业版 可部署于任何系统和云平台的 API 管理平台](https://www.apiseven.com/enterprise) [- Apache APISIX vs API7 企业版 开源 API 网关和企业版 API 网关的对比](https://www.apiseven.com/apisix-vs-enterprise) [* API7 Portal 以安全便捷的方式对内外部开放 API,管控并可视化分析 API 的调用关系和调用量](https://www.apiseven.com/portal) * 解决方案 [* 本地部署升级混合云部署 高效管理和保护多云、混合云环境中的 API](https://www.apiseven.com/solutions/on-prem-to-hybrid-cloud) [- 单体架构升级微服务架构 提高业务服务可扩展性、弹性,降低风险和故障范围,实现团队效率提升](https://www.apiseven.com/solutions/monolith-to-microservices) [* 可观测性 通过可视化监控和异常检测提高系统可用性和性能](https://www.apiseven.com/solutions/observability) [- 零信任安全 在所有服务中实施零信任安全以简化安全防护](https://www.apiseven.com/solutions/zero-trust-security) [* 虚拟机升级 Kubernetes 降低运营成本并轻松管理数千服务](https://www.apiseven.com/solutions/vm-to-kubernetes) * [客户案例](https://www.apiseven.com/customers) * 开源项目 [* Apache APISIX 高性能、可扩展的微服务 API 网关](http://apisix.apache.org/) [- Apache APISIX Ingress Controller 基于 Apache APISIX 并集成 Kubernetes 集群管理能力,支持申明式动态配置入口流量的分发规则](https://github.com/apache/apisix-ingress-controller) * 相关资源 [* API7 企业版文档 查看 API7 API 网关企业版详细指南,助力企业高效集成与管理 API](https://docs.apiseven.com/api7-gateway/overview) [- Apache APISIX 文档 采用 Apache 2.0 许可证、功能丰富、高性能的 API 网关](https://docs.apiseven.com/apisix/documentation.md) [* API 网关插件中心 探索强大的插件,扩展 Apache APISIX 的能力,实现无缝的 API 管理](https://docs.apiseven.com/hub.md) [- 白皮书 阅读 API7 网关技术白皮书,了解更多功能与性能报告](https://static.apiseven.com/202202/API7-WhitePaper.pdf) [* Ingress Controller 文档 了解 API7 与 APISIX Ingress Controller 的安装、操作指南和参考信息](https://docs.apiseven.com/ingress-controller/documentation.md) [- Apache APISIX vs NGINX 动态配置、多环境管理、全生命周期 API 管理](https://www.apiseven.com/apisix-vs-nginx) [* Apache APISIX vs Kong 极致性能、高可用、稳定、开发者友好](https://www.apiseven.com/apisix-vs-kong) [- APISIX 商业支持 了解 Apache APISIX 的商业支持和企业级方案](https://api7.ai/apache-apisix-enterprise-support) * [技术博客](https://www.apiseven.com/blog) [申请试用](https://apiseven.feishu.cn/share/base/form/shrcnP2ryU7GwkaOIavHTggzBef) [](https://docs.apiseven.com/)[APISIX API 网关](https://docs.apiseven.com/apisix/documentation.md)[API7 网关](https://docs.apiseven.com/api7-gateway/overview.md)[AISIX AI 网关](https://docs.apiseven.com/ai-gateway/.md)[Ingress Controller](https://docs.apiseven.com/ingress-controller/documentation.md)[API 网关插件中心](https://docs.apiseven.com/hub.md) ![](https://static.api7.ai/uploads/2025/03/10/CYPjJmOl_bg-title-bg.avif) # 欢迎来到 API 网关插件中心 ![](https://static.api7.ai/uploads/2025/03/13/BrEQKYAn_plugin.avif) 探索强大的插件,扩展 Apache APISIX 的能力,实现无缝的 API 管理 [插件概览](https://docs.apiseven.com/apisix/key-concepts/plugins.md)|[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) ## AI[#](#ai) [![AI Aliyun Content Moderation](https://static.api7.ai/uploads/2025/03/13/tcMjtNjI_ai-aliyun-content-moderation.png)](https://docs.apiseven.com/hub/ai-aliyun-content-moderation.md) #### [AI Aliyun Content Moderation](https://docs.apiseven.com/hub/ai-aliyun-content-moderation.md) [AI Aliyun Content Moderation 插件集成阿里云内容安全服务,在 AI 网关代理 LLM 请求时实时检测提示词输入风险,自动拦截超过安全阈值的请求,保障 AI 应用合规。](https://docs.apiseven.com/hub/ai-aliyun-content-moderation.md) [![AI AWS Content Moderation](https://static.api7.ai/uploads/2025/03/13/86ShT776_ai-aws-content-moderation.png)](https://docs.apiseven.com/hub/ai-aws-content-moderation.md) #### [AI AWS Content Moderation](https://docs.apiseven.com/hub/ai-aws-content-moderation.md) [AI AWS Content Moderation 插件集成 AWS Comprehend,在 AI 网关代理 LLM 请求时检测提示词毒性内容,自动拦截超过阈值的有害请求,保障 AI 应用安全合规。](https://docs.apiseven.com/hub/ai-aws-content-moderation.md) [![AI Cache](https://static.api7.ai/uploads/2024/03/11/ZWCmMDim_proxy-cache.png)](https://docs.apiseven.com/hub/ai-cache.md) #### [AI Cache](https://docs.apiseven.com/hub/ai-cache.md) [ai-cache 插件将完全匹配和语义相似的 LLM 响应存储在 Redis 中,从而降低响应延迟并减少重复的上游模型调用。](https://docs.apiseven.com/hub/ai-cache.md) [![AI Lakera Guard](https://static.api7.ai/uploads/2025/03/13/8v3RKxEA_ai-prompt-guard.png)](https://docs.apiseven.com/hub/ai-lakera-guard.md) #### [AI Lakera Guard](https://docs.apiseven.com/hub/ai-lakera-guard.md) [ai-lakera-guard 插件通过 Lakera Guard API 筛查 AI 流量,检测请求和 LLM 响应中的提示词注入及其他不安全内容。](https://docs.apiseven.com/hub/ai-lakera-guard.md) [![AI Prompt Decorator](https://static.api7.ai/uploads/2024/10/10/D9oM81AC_ai-prompt-decorator.png)](https://docs.apiseven.com/hub/ai-prompt-decorator.md) #### [AI Prompt Decorator](https://docs.apiseven.com/hub/ai-prompt-decorator.md) [AI Prompt Decorator 插件在 AI 网关层为 LLM 请求的用户提示词自动添加前缀和后缀,无需修改客户端代码即可统一注入系统指令,简化 AI API 管理与内容生成流程。](https://docs.apiseven.com/hub/ai-prompt-decorator.md) [![AI Prompt Guard](https://static.api7.ai/uploads/2025/03/13/8v3RKxEA_ai-prompt-guard.png)](https://docs.apiseven.com/hub/ai-prompt-guard.md) #### [AI Prompt Guard](https://docs.apiseven.com/hub/ai-prompt-guard.md) [AI Prompt Guard 插件通过允许/拒绝模式在 AI 网关层过滤 LLM 提示词,支持检查最新消息或完整对话历史,有效防止提示词注入攻击,保障 AI 应用安全。](https://docs.apiseven.com/hub/ai-prompt-guard.md) [![AI Prompt Template](https://static.api7.ai/uploads/2024/10/09/nmOsFCYK_ai-prompt-template.png)](https://docs.apiseven.com/hub/ai-prompt-template.md) #### [AI Prompt Template](https://docs.apiseven.com/hub/ai-prompt-template.md) [AI Prompt Template 插件为 AI 网关提供预配置提示词模板,支持以填空方式让客户端传入变量,统一规范发送给 LLM 的请求格式,简化 AI API 管理与集成。](https://docs.apiseven.com/hub/ai-prompt-template.md) [![AI Proxy](https://static.api7.ai/uploads/2024/10/10/hj8UBb3W_ai-proxy.png)](https://docs.apiseven.com/hub/ai-proxy.md) #### [AI Proxy](https://docs.apiseven.com/hub/ai-proxy.md) [AI Proxy 插件将 API 网关请求转换为 OpenAI、DeepSeek、Anthropic、Gemini 等 LLM 所需格式,支持多模型统一接入,并可在访问日志中记录 Token 用量和首字节响应时间。](https://docs.apiseven.com/hub/ai-proxy.md) [![AI Proxy Multi](https://static.api7.ai/uploads/2025/03/05/0Dzb0DI3_ai-proxy-multi.png)](https://docs.apiseven.com/hub/ai-proxy-multi.md) #### [AI Proxy Multi](https://docs.apiseven.com/hub/ai-proxy-multi.md) [ai-proxy-multi 插件通过负载均衡、重试、故障转移和健康检查扩展 ai-proxy 的能力,简化与 OpenAI、DeepSeek 及其他 OpenAI 兼容 API 的集成。](https://docs.apiseven.com/hub/ai-proxy-multi.md) [![AI RAG](https://static.api7.ai/uploads/2024/10/24/qoiBcXyS_ai-rag.png)](https://docs.apiseven.com/hub/ai-rag.md) #### [AI RAG](https://docs.apiseven.com/hub/ai-rag.md) [AI RAG 插件在代理 LLM 请求之前,使用 Azure OpenAI 嵌入和 Azure AI Search 检索上下文。](https://docs.apiseven.com/hub/ai-rag.md) [![AI Rate Limiting](https://static.api7.ai/uploads/2025/03/05/CJqBH5Rp_ai-rate-limiting.png)](https://docs.apiseven.com/hub/ai-rate-limiting.md) #### [AI Rate Limiting](https://docs.apiseven.com/hub/ai-rate-limiting.md) [AI Rate Limiting 插件专为 AI 网关设计,基于 Token 用量对 LLM API 请求进行速率限制,有效控制 AI 服务成本,防止资源滥用,保障 AI API 的稳定可用性。](https://docs.apiseven.com/hub/ai-rate-limiting.md) [![AI Request Rewrite](https://static.api7.ai/uploads/2025/04/07/bbcNos7x_ai-request-rewrite.png)](https://docs.apiseven.com/hub/ai-request-rewrite.md) #### [AI Request Rewrite](https://docs.apiseven.com/hub/ai-request-rewrite.md) [AI Request Rewrite 插件在 API 网关层动态改写发往 LLM 的请求参数,支持修改模型、温度等配置,实现请求的灵活路由与转换,简化 AI 服务的统一管理。](https://docs.apiseven.com/hub/ai-request-rewrite.md) [![OpenAPI to MCP](https://static.api7.ai/uploads/2025/09/22/rxyJgPnj_tmp-icon.png)企业版](https://docs.apiseven.com/hub/openapi-to-mcp.md) #### [OpenAPI to MCP](https://docs.apiseven.com/hub/openapi-to-mcp.md) [OpenAPI to MCP 插件将 OpenAPI 规范自动转换为 MCP(Model Context Protocol)工具,使 AI Agent 能够通过 API 网关直接调用 REST API,加速 AI 应用与 API 的集成。](https://docs.apiseven.com/hub/openapi-to-mcp.md) ## 流量管理[#](#traffic-management) [![GraphQL Limit Count](https://static.api7.ai/uploads/2023/10/18/4qPNgRwS_test_2.8.png)](https://docs.apiseven.com/hub/graphql-limit-count.md) #### [GraphQL Limit Count](https://docs.apiseven.com/hub/graphql-limit-count.md) [graphql-limit-count 插件使用固定窗口限制 GraphQL 文档的累计成本,默认以选择集深度作为度量。](https://docs.apiseven.com/hub/graphql-limit-count.md) [![GraphQL Proxy Cache](https://static.api7.ai/uploads/2023/10/18/T9HdQS9U_test_2.6.png)](https://docs.apiseven.com/hub/graphql-proxy-cache.md) #### [GraphQL Proxy Cache](https://docs.apiseven.com/hub/graphql-proxy-cache.md) [GraphQL Proxy Cache 插件在 Apache APISIX 层缓存 GraphQL 查询响应,减少对后端 GraphQL 服务的重复请求,显著提升 API 响应速度,降低后端服务负载。](https://docs.apiseven.com/hub/graphql-proxy-cache.md) [![Limit Conn](https://static.api7.ai/uploads/2024/12/12/2OJrqIVM_limit-conn.png)](https://docs.apiseven.com/hub/limit-conn.md) #### [Limit Conn](https://docs.apiseven.com/hub/limit-conn.md) [Limit Conn 插件基于并发连接数对 Apache APISIX 路由进行限流,防止后端服务因连接数过多而过载,保障 API 网关在高并发场景下的稳定性和服务质量。](https://docs.apiseven.com/hub/limit-conn.md) [![Limit Count](https://static.api7.ai/uploads/2023/10/27/wLA7vu2k_limit-count.png)](https://docs.apiseven.com/hub/limit-count.md) #### [Limit Count](https://docs.apiseven.com/hub/limit-count.md) [Limit Count 插件使用固定窗口算法对 Apache APISIX 路由进行请求速率限制,在指定时间窗口内限制请求次数,超出配额的请求将被拒绝,保护 API 网关后端服务。](https://docs.apiseven.com/hub/limit-count.md) [![Limit Count Advanced](https://static.api7.ai/uploads/2024/10/31/QdYZeJh7_limit-count-advanced.png)企业版](https://docs.apiseven.com/hub/limit-count-advanced.md) #### [Limit Count Advanced](https://docs.apiseven.com/hub/limit-count-advanced.md) [Limit Count Advanced 插件提供企业级 API 速率限制能力,支持多维度限流策略和共享计数器,在 Apache APISIX 网关层实现精细化的请求频率控制与流量管理。](https://docs.apiseven.com/hub/limit-count-advanced.md) [![Limit Req](https://static.api7.ai/uploads/2023/11/01/2CZt13jD_limit-req.png)](https://docs.apiseven.com/hub/limit-req.md) #### [Limit Req](https://docs.apiseven.com/hub/limit-req.md) [Limit Req 插件使用漏桶算法对 Apache APISIX 路由进行请求速率平滑限流,有效防止流量突刺对后端服务造成冲击,保障 API 网关的平稳运行和服务稳定性。](https://docs.apiseven.com/hub/limit-req.md) [![OAS Validator](https://static.api7.ai/uploads/2023/11/08/Fu3KAzpq_oas-validator.png)](https://docs.apiseven.com/hub/oas-validator.md) #### [OAS Validator](https://docs.apiseven.com/hub/oas-validator.md) [OAS Validator 插件在请求转发到上游服务前,根据 OpenAPI 规范校验传入的 HTTP 请求。](https://docs.apiseven.com/hub/oas-validator.md) [![Proxy Buffering](https://static.api7.ai/uploads/2023/10/25/03goqJor_proxy_buffering.png)](https://docs.apiseven.com/hub/proxy-buffering.md) #### [Proxy Buffering](https://docs.apiseven.com/hub/proxy-buffering.md) [Proxy Buffering 插件控制 Apache APISIX 对上游响应的缓冲行为,支持在网关层缓存响应数据后再转发给客户端,优化大响应体的传输性能和客户端体验。](https://docs.apiseven.com/hub/proxy-buffering.md) [![Proxy Cache](https://static.api7.ai/uploads/2024/03/11/ZWCmMDim_proxy-cache.png)](https://docs.apiseven.com/hub/proxy-cache.md) #### [Proxy Cache](https://docs.apiseven.com/hub/proxy-cache.md) [Proxy Cache 插件在 Apache APISIX 网关层缓存上游 API 响应,支持磁盘和内存两种缓存模式,显著减少后端请求压力,提升 API 响应速度和整体服务性能。](https://docs.apiseven.com/hub/proxy-cache.md) [![Proxy Mirror](https://static.api7.ai/uploads/2024/01/29/Hxr9HkkD_proxy-mirror.png)](https://docs.apiseven.com/hub/proxy-mirror.md) #### [Proxy Mirror](https://docs.apiseven.com/hub/proxy-mirror.md) [Proxy Mirror 插件将 Apache APISIX 的 API 请求实时镜像到指定目标服务,用于流量复制、灰度测试和线上问题复现,在不影响正常流量的情况下进行 API 调试。](https://docs.apiseven.com/hub/proxy-mirror.md) [![Request ID](https://static.api7.ai/uploads/2024/12/09/1U8hV11N_request-id.png)](https://docs.apiseven.com/hub/request-id.md) #### [Request ID](https://docs.apiseven.com/hub/request-id.md) [Request ID 插件为每个经过 Apache APISIX 的 API 请求自动生成唯一标识符,并添加到请求头中,便于分布式系统中的请求追踪、日志关联和问题排查。](https://docs.apiseven.com/hub/request-id.md) [![Request Validation](https://static.api7.ai/uploads/2023/12/07/bzStlCLK_request-validation.png)](https://docs.apiseven.com/hub/request-validation.md) #### [Request Validation](https://docs.apiseven.com/hub/request-validation.md) [Request Validation 插件在 Apache APISIX 网关层根据 JSON Schema 验证 API 请求的参数和请求体,在请求到达后端前过滤非法数据,提升 API 安全性和数据质量。](https://docs.apiseven.com/hub/request-validation.md) [![Traffic Label](https://static.api7.ai/uploads/2023/10/18/IRDVY9sk_test_2.10.png)](https://docs.apiseven.com/hub/traffic-label.md) #### [Traffic Label](https://docs.apiseven.com/hub/traffic-label.md) [Traffic Label 插件对请求表达式求值,并通过加权方式修改请求头,以实现基于条件的流量管理。](https://docs.apiseven.com/hub/traffic-label.md) [![Traffic Split](https://static.api7.ai/uploads/2023/11/01/tYpqD1OB_traffic-split.png)](https://docs.apiseven.com/hub/traffic-split.md) #### [Traffic Split](https://docs.apiseven.com/hub/traffic-split.md) [Traffic Split 插件在 Apache APISIX 中实现按比例的流量分割,支持灰度发布、蓝绿部署和 A/B 测试,通过 API 网关层的流量控制降低新版本发布风险。](https://docs.apiseven.com/hub/traffic-split.md) [![Workflow](https://static.api7.ai/uploads/2024/03/05/CTQ2O8NF_workflow.png)](https://docs.apiseven.com/hub/workflow.md) #### [Workflow](https://docs.apiseven.com/hub/workflow.md) [Workflow 插件允许在 Apache APISIX 中定义多步骤的请求处理工作流,支持条件判断和动作编排,实现复杂的 API 网关流量治理逻辑,无需编写自定义插件代码。](https://docs.apiseven.com/hub/workflow.md) ## 流量处理与转换[#](#transformation) [![Attach Consumer Label](https://static.api7.ai/uploads/2024/09/14/dNILru0T_update-icon-bcg.jpeg)](https://docs.apiseven.com/hub/attach-consumer-label.md) #### [Attach Consumer Label](https://docs.apiseven.com/hub/attach-consumer-label.md) [Attach Consumer Label 插件为经过身份认证的消费者请求自动附加标签,便于在 Apache APISIX 中实现基于消费者属性的精细化流量管理、监控和访问控制策略。](https://docs.apiseven.com/hub/attach-consumer-label.md) [![Body Transformer](https://static.api7.ai/uploads/2023/11/07/e7rKZFn9_body-transformer.png)](https://docs.apiseven.com/hub/body-transformer.md) #### [Body Transformer](https://docs.apiseven.com/hub/body-transformer.md) [Body Transformer 插件在 API 网关层对请求和响应的消息体进行格式转换,支持 JSON 与 XML 互转及自定义模板,实现不同系统间的数据格式无缝对接。](https://docs.apiseven.com/hub/body-transformer.md) [![DeGraphQL](https://static.api7.ai/uploads/2023/12/06/kms6zvcY_degraphql.png)](https://docs.apiseven.com/hub/degraphql.md) #### [DeGraphQL](https://docs.apiseven.com/hub/degraphql.md) [DeGraphQL 插件将 RESTful API 请求转换为 GraphQL 查询,让客户端无需了解 GraphQL 语法即可访问 GraphQL 后端,通过 API 网关实现 REST 到 GraphQL 的无缝桥接。](https://docs.apiseven.com/hub/degraphql.md) [![Exit Transformer](https://static.api7.ai/uploads/2024/10/25/R6XnlT7J_exit-transformer.png)](https://docs.apiseven.com/hub/exit-transformer.md) #### [Exit Transformer](https://docs.apiseven.com/hub/exit-transformer.md) [Exit Transformer 插件可在 APISIX 向客户端发送响应前,自定义由网关插件或缺失路由生成的响应。](https://docs.apiseven.com/hub/exit-transformer.md) [![Fault Injection](https://static.api7.ai/uploads/2025/01/22/m6b1DCku_fault-injection.png)](https://docs.apiseven.com/hub/fault-injection.md) #### [Fault Injection](https://docs.apiseven.com/hub/fault-injection.md) [Fault Injection 插件在 Apache APISIX 中模拟 API 故障场景,支持注入延迟和自定义错误响应,用于混沌工程测试,验证微服务架构在 API 网关层的容错能力。](https://docs.apiseven.com/hub/fault-injection.md) [![gRPC Transcode](https://static.api7.ai/uploads/2024/02/21/3uzsq5N4_grpc-transcode.png)](https://docs.apiseven.com/hub/grpc-transcode.md) #### [gRPC Transcode](https://docs.apiseven.com/hub/grpc-transcode.md) [gRPC Transcode 插件将 HTTP/JSON 请求转换为 gRPC 协议,让 RESTful 客户端无缝访问 gRPC 后端服务,通过 Apache APISIX 实现 REST 与 gRPC 的协议桥接。](https://docs.apiseven.com/hub/grpc-transcode.md) [![gRPC Web](https://static.api7.ai/uploads/2026/01/06/al39Dafe_gRPC-web.png)](https://docs.apiseven.com/hub/grpc-web.md) #### [gRPC Web](https://docs.apiseven.com/hub/grpc-web.md) [gRPC Web 插件使 Apache APISIX 支持 gRPC-Web 协议,让浏览器端应用能够直接调用 gRPC 后端服务,解决 Web 客户端与 gRPC 服务之间的协议兼容问题。](https://docs.apiseven.com/hub/grpc-web.md) [![Mocking](https://static.api7.ai/uploads/2025/01/24/WttCR3KD_mocking.png)](https://docs.apiseven.com/hub/mocking.md) #### [Mocking](https://docs.apiseven.com/hub/mocking.md) [Mocking 插件在 Apache APISIX 网关层返回预设的模拟响应,无需启动后端服务即可进行 API 开发和测试,加速前后端并行开发,提升 API 开发效率。](https://docs.apiseven.com/hub/mocking.md) [![Proxy Rewrite](https://static.api7.ai/uploads/2023/10/18/yCccWhP0_test_2.11.png)](https://docs.apiseven.com/hub/proxy-rewrite.md) #### [Proxy Rewrite](https://docs.apiseven.com/hub/proxy-rewrite.md) [Proxy Rewrite 插件在 Apache APISIX 转发请求前修改请求的 URI、请求头和请求方法,实现 API 网关层的路由重写与请求改造,支持灵活的 API 路由策略配置。](https://docs.apiseven.com/hub/proxy-rewrite.md) [![Response Rewrite](https://static.api7.ai/uploads/2023/10/25/Nm2E852J_rr.png)](https://docs.apiseven.com/hub/response-rewrite.md) #### [Response Rewrite](https://docs.apiseven.com/hub/response-rewrite.md) [Response Rewrite 插件在 Apache APISIX 返回响应前修改响应状态码、响应头和响应体,实现 API 网关层的响应格式统一化,无需修改后端服务即可调整 API 输出。](https://docs.apiseven.com/hub/response-rewrite.md) [![SOAP](https://static.api7.ai/uploads/2023/10/18/V3vWj7A6_test_2.2.png)企业版](https://docs.apiseven.com/hub/soap.md) #### [SOAP](https://docs.apiseven.com/hub/soap.md) [SOAP 插件使 Apache APISIX 支持将 RESTful 请求转换为 SOAP 协议请求,让现代 API 客户端无缝访问传统 SOAP Web 服务,通过 API 网关实现新旧系统的协议桥接。](https://docs.apiseven.com/hub/soap.md) ## 认证[#](#authentication) [![Authz Keycloak](https://static.api7.ai/uploads/2023/12/08/pqqgJ2YO_keycloak-authz.png)](https://docs.apiseven.com/hub/authz-keycloak.md) #### [Authz Keycloak](https://docs.apiseven.com/hub/authz-keycloak.md) [Authz Keycloak 插件将 Apache APISIX 与 Keycloak 授权服务集成,支持基于策略的细粒度访问控制,为 API 网关提供企业级的身份与访问管理(IAM)能力。](https://docs.apiseven.com/hub/authz-keycloak.md) [![Basic Auth](https://static.api7.ai/uploads/2024/08/23/YwSkGnhY_basic-auth.png)](https://docs.apiseven.com/hub/basic-auth.md) #### [Basic Auth](https://docs.apiseven.com/hub/basic-auth.md) [Basic Auth 插件为 Apache APISIX 路由添加 HTTP 基本访问认证,要求客户端提供用户名和密码才能访问上游资源,快速为 API 网关启用简单身份认证保护。](https://docs.apiseven.com/hub/basic-auth.md) [![DingTalk Auth](https://static.api7.ai/uploads/2026/03/09/DTrdaKDT_dingtalk-auth.webp)企业版](https://docs.apiseven.com/hub/dingtalk-auth.md) #### [DingTalk Auth](https://docs.apiseven.com/hub/dingtalk-auth.md) [dingtalk-auth 插件提供了钉钉 OAuth 2.0 身份认证能力,验证客户端请求中携带的免登录授权码并获取用户信息,适用于钉钉企业内部应用的访问控制场景。](https://docs.apiseven.com/hub/dingtalk-auth.md) [![Feishu Auth](https://static.api7.ai/uploads/2026/02/12/Sojj8e7c_feishu-auth.png)企业版](https://docs.apiseven.com/hub/feishu-auth.md) #### [Feishu Auth](https://docs.apiseven.com/hub/feishu-auth.md) [feishu-auth 插件支持飞书 OAuth 2.0 身份认证,允许客户端在访问上游资源前通过飞书账号完成认证,增强 API 安全性。](https://docs.apiseven.com/hub/feishu-auth.md) [![Forward Auth](https://static.api7.ai/uploads/2024/04/29/UNSKKKqr_forward-auth.png)](https://docs.apiseven.com/hub/forward-auth.md) #### [Forward Auth](https://docs.apiseven.com/hub/forward-auth.md) [Forward Auth 插件将 Apache APISIX 的认证请求转发到外部认证服务,支持与任意 OAuth2、JWT 或自定义认证系统集成,实现 API 网关层的灵活外部鉴权。](https://docs.apiseven.com/hub/forward-auth.md) [![HMAC Auth](https://static.api7.ai/uploads/2024/09/03/xG9Vqxl5_hmac-auth.png)](https://docs.apiseven.com/hub/hmac-auth.md) #### [HMAC Auth](https://docs.apiseven.com/hub/hmac-auth.md) [HMAC Auth 插件为 Apache APISIX 提供基于 HMAC 签名的 API 身份认证,通过验证请求签名确保请求完整性和来源可信,为 API 网关提供防篡改的安全认证机制。](https://docs.apiseven.com/hub/hmac-auth.md) [![JWE Decrypt](https://static.api7.ai/uploads/2024/01/15/8AkaEKui_jwe-icon.png)](https://docs.apiseven.com/hub/jwe-decrypt.md) #### [JWE Decrypt](https://docs.apiseven.com/hub/jwe-decrypt.md) [JWE Decrypt 插件解密 JWE 紧凑序列化 Token,并在配置的请求头中转发明文。](https://docs.apiseven.com/hub/jwe-decrypt.md) [![JWT Auth](https://static.api7.ai/uploads/2024/03/20/3Dw978og_jwt-auth.png)](https://docs.apiseven.com/hub/jwt-auth.md) #### [JWT Auth](https://docs.apiseven.com/hub/jwt-auth.md) [JWT Auth 插件为 Apache APISIX 提供基于 JSON Web Token 的 API 身份认证,支持 HS256、RS256 等多种签名算法,在 API 网关层实现无状态的安全身份认证。](https://docs.apiseven.com/hub/jwt-auth.md) [![Key Auth](https://static.api7.ai/uploads/2024/03/20/DRWFmK4D_key-auth.png)](https://docs.apiseven.com/hub/key-auth.md) #### [Key Auth](https://docs.apiseven.com/hub/key-auth.md) [Key Auth 插件为 Apache APISIX 提供基于 API Key 的身份认证,支持通过请求头或查询参数传递密钥,快速为 API 网关启用简单高效的 API 密钥认证保护。](https://docs.apiseven.com/hub/key-auth.md) [![LDAP Auth Advanced](https://static.api7.ai/uploads/2024/08/23/YwSkGnhY_basic-auth.png)](https://docs.apiseven.com/hub/ldap-auth-advanced.md) #### [LDAP Auth Advanced](https://docs.apiseven.com/hub/ldap-auth-advanced.md) [LDAP Auth Advanced 插件对接 OpenLDAP、Active Directory 等 LDAP 目录完成客户端认证,并可把认证到的目录用户映射为消费者,使目录身份能够复用消费者级插件、限流与用量统计。](https://docs.apiseven.com/hub/ldap-auth-advanced.md) [![Multi Auth](https://static.api7.ai/uploads/2024/01/15/d4Lo3cix_multi-auth.png)](https://docs.apiseven.com/hub/multi-auth.md) #### [Multi Auth](https://docs.apiseven.com/hub/multi-auth.md) [Multi Auth 插件允许在 Apache APISIX 路由上同时配置多种认证方式,按顺序尝试各认证插件,灵活支持多种客户端认证机制,提升 API 网关的认证兼容性。](https://docs.apiseven.com/hub/multi-auth.md) [![OPA](https://static.api7.ai/uploads/2024/08/23/BdRXak7x_opa.png)](https://docs.apiseven.com/hub/opa.md) #### [OPA](https://docs.apiseven.com/hub/opa.md) [OPA 插件将 Apache APISIX 与 Open Policy Agent 集成,在 API 网关层实现基于策略的细粒度授权决策,支持复杂的访问控制逻辑,满足企业级合规要求。](https://docs.apiseven.com/hub/opa.md) [![OpenID Connect](https://static.api7.ai/uploads/2023/11/15/TdzRQl8n_oidc.png)](https://docs.apiseven.com/hub/openid-connect.md) #### [OpenID Connect](https://docs.apiseven.com/hub/openid-connect.md) [OpenID Connect 插件为 Apache APISIX 提供标准的 OIDC 身份认证,支持与 Keycloak、Okta、Auth0 等身份提供商集成,在 API 网关层实现企业级单点登录(SSO)。](https://docs.apiseven.com/hub/openid-connect.md) [![SAML Auth](https://static.api7.ai/uploads/2024/08/23/pYpD0ncp_saml-auth.png)](https://docs.apiseven.com/hub/saml-auth.md) #### [SAML Auth](https://docs.apiseven.com/hub/saml-auth.md) [SAML Auth 插件为 Apache APISIX 提供基于 SAML 2.0 协议的身份认证,支持与企业 IdP(身份提供商)集成,在 API 网关层实现企业级联合身份认证与单点登录。](https://docs.apiseven.com/hub/saml-auth.md) ## 安全[#](#security) [![ACL](https://static.api7.ai/uploads/2024/02/04/dnlZbDhq_acl.png)](https://docs.apiseven.com/hub/acl.md) #### [ACL](https://docs.apiseven.com/hub/acl.md) [ACL(访问控制列表)插件通过验证用户是否在允许列表中,精细控制对 Apache APISIX 上游资源的访问权限,为企业级 API 网关提供强大的授权管理能力。](https://docs.apiseven.com/hub/acl.md) [![Chaitin WAF](https://static.api7.ai/uploads/2025/09/08/8mi7erpW_chaitin-waf.png)](https://docs.apiseven.com/hub/chaitin-waf.md) #### [Chaitin WAF](https://docs.apiseven.com/hub/chaitin-waf.md) [Chaitin WAF 插件将长亭科技 Web 应用防火墙集成到 Apache APISIX,在 API 网关层实时检测并拦截 SQL 注入、XSS 等 Web 攻击,为 API 提供企业级安全防护。](https://docs.apiseven.com/hub/chaitin-waf.md) [![Consumer Restriction](https://static.api7.ai/uploads/2024/03/23/2Or0rpNg_consumer-restriction.png)](https://docs.apiseven.com/hub/consumer-restriction.md) #### [Consumer Restriction](https://docs.apiseven.com/hub/consumer-restriction.md) [Consumer Restriction 插件基于消费者身份对 Apache APISIX 路由访问进行精细控制,支持白名单和黑名单模式,实现 API 网关层的消费者级别访问授权管理。](https://docs.apiseven.com/hub/consumer-restriction.md) [![CORS](https://static.api7.ai/uploads/2024/02/01/VGYw3KjS_20240201-095424.jpeg)](https://docs.apiseven.com/hub/cors.md) #### [CORS](https://docs.apiseven.com/hub/cors.md) [CORS 插件为 Apache APISIX 路由启用跨源资源共享(CORS),支持灵活配置允许的来源、方法和请求头,解决前端跨域问题,提升 API 的可访问性与兼容性。](https://docs.apiseven.com/hub/cors.md) [![Data Mask](https://static.api7.ai/uploads/2024/04/01/2JlB10Xi_data-mask.png)](https://docs.apiseven.com/hub/data-mask.md) #### [Data Mask](https://docs.apiseven.com/hub/data-mask.md) [Data Mask 插件在 Apache APISIX 日志记录前对敏感字段进行脱敏处理,支持自定义掩码规则,保护用户隐私数据,帮助 API 网关满足数据安全合规要求。](https://docs.apiseven.com/hub/data-mask.md) [![IP Restriction](https://static.api7.ai/uploads/2024/02/28/0WSO7GZL_ip-res.png)](https://docs.apiseven.com/hub/ip-restriction.md) #### [IP Restriction](https://docs.apiseven.com/hub/ip-restriction.md) [IP Restriction 插件基于客户端 IP 地址对 Apache APISIX 路由进行访问控制,支持 IP 白名单和黑名单配置,快速实现 API 网关层的网络访问限制与安全防护。](https://docs.apiseven.com/hub/ip-restriction.md) [![MCP Tools ACL](https://static.api7.ai/uploads/2024/02/04/dnlZbDhq_acl.png)企业版](https://docs.apiseven.com/hub/mcp-tools-acl.md) #### [MCP Tools ACL](https://docs.apiseven.com/hub/mcp-tools-acl.md) [mcp-tools-acl 插件为 openapi-to-mcp 路由上的 MCP 工具调用提供基于消费者的访问控制,支持基于规则的白名单和黑名单模式,并可通过表达式条件进行条件匹配。](https://docs.apiseven.com/hub/mcp-tools-acl.md) [![UA Restriction](https://static.api7.ai/uploads/2024/02/29/Y0qfz6CT_ua-restriction.png)](https://docs.apiseven.com/hub/ua-restriction.md) #### [UA Restriction](https://docs.apiseven.com/hub/ua-restriction.md) [UA Restriction 插件基于 User-Agent 请求头对 Apache APISIX 路由进行访问控制,支持白名单和黑名单配置,有效阻止爬虫或未授权客户端访问 API 网关资源。](https://docs.apiseven.com/hub/ua-restriction.md) ## 可观测性[#](#observability) [![ClickHouse Logger](https://static.api7.ai/uploads/2023/12/19/HYDN4Dmw_clickhouse.png)](https://docs.apiseven.com/hub/clickhouse-logger.md) #### [ClickHouse Logger](https://docs.apiseven.com/hub/clickhouse-logger.md) [clickhouse-logger 插件将请求和响应日志分批推送到 ClickHouse 数据库,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/clickhouse-logger.md) [![Datadog](https://static.api7.ai/uploads/2024/01/18/s7gmob0S_datadog.png)](https://docs.apiseven.com/hub/datadog.md) #### [Datadog](https://docs.apiseven.com/hub/datadog.md) [datadog 插件与 Datadog 集成,将指标分批发送到 DogStatsD,以改进 API 监控和性能跟踪。](https://docs.apiseven.com/hub/datadog.md) [![Elasticsearch Logger](https://static.api7.ai/uploads/2025/01/13/9VsL3UBH_sukBLfk2_elasticsearch-logger.png)](https://docs.apiseven.com/hub/elasticsearch-logger.md) #### [Elasticsearch Logger](https://docs.apiseven.com/hub/elasticsearch-logger.md) [elasticsearch-logger 插件将请求和响应日志分批推送到 Elasticsearch,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/elasticsearch-logger.md) [![Error Log Collect](/img/plugins/error-log-collect.png)企业版](https://docs.apiseven.com/hub/error-log-collect.md) #### [Error Log Collect](https://docs.apiseven.com/hub/error-log-collect.md) [Error Log Collect 插件捕获处理指定请求时产生的错误日志,包括所配置日志级别通常会丢弃的低级别日志,并将其写入网关错误日志,便于针对性调试。](https://docs.apiseven.com/hub/error-log-collect.md) [![Error Log Logger](https://static.apiseven.com/uploads/2025/01/26/9gRLjv8N_error-log-logger.png)](https://docs.apiseven.com/hub/error-log-logger.md) #### [Error Log Logger](https://docs.apiseven.com/hub/error-log-logger.md) [Error Log Logger 插件将 Apache APISIX 产生的错误日志推送到远程日志服务,支持集中化错误日志管理,帮助运维团队及时发现和处理 API 网关的异常情况。](https://docs.apiseven.com/hub/error-log-logger.md) [![Google Cloud Logging](https://static.apiseven.com/uploads/2025/02/06/4qDGkFhw_google-cloud.png)](https://docs.apiseven.com/hub/google-cloud-logging.md) #### [Google Cloud Logging](https://docs.apiseven.com/hub/google-cloud-logging.md) [google-cloud-logging 插件将请求和响应日志分批推送到 Google Cloud Logging Service,并支持自定义日志格式。](https://docs.apiseven.com/hub/google-cloud-logging.md) [![HTTP Logger](https://static.api7.ai/uploads/2025/01/20/XhSZolpi_http-logger.png)](https://docs.apiseven.com/hub/http-logger.md) #### [HTTP Logger](https://docs.apiseven.com/hub/http-logger.md) [http-logger 插件将请求和响应日志作为 JSON 对象分批推送到 HTTP(S) 服务器,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/http-logger.md) [![Kafka Logger](https://static.api7.ai/uploads/2025/01/20/ipzxNV6T_kafka-logger.png)](https://docs.apiseven.com/hub/kafka-logger.md) #### [Kafka Logger](https://docs.apiseven.com/hub/kafka-logger.md) [kafka-logger 插件将请求和响应日志作为 JSON 对象分批推送到 Apache Kafka 集群,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/kafka-logger.md) [![Loki Logger](https://static.api7.ai/uploads/2024/12/27/YXMsoZns_output-2.png)](https://docs.apiseven.com/hub/loki-logger.md) #### [Loki Logger](https://docs.apiseven.com/hub/loki-logger.md) [loki-logger 插件通过 Loki HTTP API 将请求和响应日志作为 JSON 对象分批发送到 Grafana Loki,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/loki-logger.md) [![OpenTelemetry](https://static.api7.ai/uploads/2024/02/17/TIoDf61O_otel-icon.png)](https://docs.apiseven.com/hub/opentelemetry.md) #### [OpenTelemetry](https://docs.apiseven.com/hub/opentelemetry.md) [OpenTelemetry 插件将 Apache APISIX 的请求追踪数据上报到 OpenTelemetry Collector,支持与 Jaeger、Zipkin 等后端集成,实现 API 网关的分布式追踪。](https://docs.apiseven.com/hub/opentelemetry.md) [![Prometheus](https://static.api7.ai/uploads/2023/10/18/Ep8zNIyd_test_2.5.png)](https://docs.apiseven.com/hub/prometheus.md) #### [Prometheus](https://docs.apiseven.com/hub/prometheus.md) [Prometheus 插件与 Prometheus 集成,用于收集指标和持续监控,从而增强 API 可观测性。](https://docs.apiseven.com/hub/prometheus.md) [![RocketMQ Logger](https://static.api7.ai/uploads/2023/12/18/JKMT7TOw_rocketmq.png)](https://docs.apiseven.com/hub/rocketmq-logger.md) #### [RocketMQ Logger](https://docs.apiseven.com/hub/rocketmq-logger.md) [rocketmq-logger 插件将请求和响应日志作为 JSON 对象分批推送到 RocketMQ 集群,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/rocketmq-logger.md) [![SkyWalking](https://static.api7.ai/uploads/2025/01/15/JGYsNvMp_SkyWalking.png)](https://docs.apiseven.com/hub/skywalking.md) #### [SkyWalking](https://docs.apiseven.com/hub/skywalking.md) [SkyWalking 插件将 Apache APISIX 的分布式追踪数据上报到 Apache SkyWalking,实现 API 网关与微服务全链路追踪,帮助团队快速定位性能瓶颈和故障根因。](https://docs.apiseven.com/hub/skywalking.md) [![SkyWalking Logger](https://static.api7.ai/uploads/2025/01/20/bRD2lASg_SkyWalking-logger.png)](https://docs.apiseven.com/hub/skywalking-logger.md) #### [SkyWalking Logger](https://docs.apiseven.com/hub/skywalking-logger.md) [skywalking-logger 插件将请求和响应日志作为 JSON 对象分批推送到 SkyWalking OAP 服务器,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/skywalking-logger.md) [![Splunk HEC Logging](https://static.api7.ai/uploads/2024/11/28/wFKN9wIR_output.png)](https://docs.apiseven.com/hub/splunk-hec-logging.md) #### [Splunk HEC Logging](https://docs.apiseven.com/hub/splunk-hec-logging.md) [splunk-hec-logging 插件将请求和响应上下文信息序列化为 Splunk Event Data 格式,再分批推送到 Splunk HTTP Event Collector(HEC),并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/splunk-hec-logging.md) [![Syslog](https://static.api7.ai/uploads/2024/03/01/wq96rSoX_Syslog.png)](https://docs.apiseven.com/hub/syslog.md) #### [Syslog](https://docs.apiseven.com/hub/syslog.md) [syslog 插件将请求和响应日志作为 JSON 对象分批推送到 syslog 服务器,并支持自定义日志格式,以增强数据管理能力。](https://docs.apiseven.com/hub/syslog.md) [![Zipkin](https://static.api7.ai/uploads/2024/01/23/K5z0SiCS_zipkin-white.png)](https://docs.apiseven.com/hub/zipkin.md) #### [Zipkin](https://docs.apiseven.com/hub/zipkin.md) [Zipkin 插件将 Apache APISIX 的分布式追踪数据上报到 Zipkin,支持与 Zipkin 兼容的追踪后端集成,为 API 网关提供请求链路追踪能力,助力微服务性能分析。](https://docs.apiseven.com/hub/zipkin.md) ## 通用[#](#general) [![Error Page](https://static.api7.ai/uploads/2024/03/15/yh6VviFP_error-page.png)](https://docs.apiseven.com/hub/error-page.md) #### [Error Page](https://docs.apiseven.com/hub/error-page.md) [Error Page 插件可自定义网关生成的 404、500、502 和 503 响应,但不会修改上游服务返回的响应。](https://docs.apiseven.com/hub/error-page.md) [![Public API](https://static.api7.ai/uploads/2024/01/26/OJVqobOZ_public-api.png)](https://docs.apiseven.com/hub/public-api.md) #### [Public API](https://docs.apiseven.com/hub/public-api.md) [Public API 插件将 Apache APISIX 内部 API(如自定义插件接口)暴露为公开可访问的端点,支持为内部服务创建公共 API 路由,扩展 API 网关的服务暴露能力。](https://docs.apiseven.com/hub/public-api.md) [![Real IP](https://static.api7.ai/uploads/2023/11/01/fi20fydE_real-ip.png)](https://docs.apiseven.com/hub/real-ip.md) #### [Real IP](https://docs.apiseven.com/hub/real-ip.md) [Real IP 插件从请求头(如 X-Forwarded-For)中提取真实客户端 IP 地址,替换 Apache APISIX 获取到的代理 IP,确保 API 网关后端服务获取准确的客户端来源信息。](https://docs.apiseven.com/hub/real-ip.md) ## 无服务器[#](#serverless) [![AWS Lambda](https://static.api7.ai/uploads/2024/04/26/FjXGfhOO_aws-lambda.png)](https://docs.apiseven.com/hub/aws-lambda.md) #### [AWS Lambda](https://docs.apiseven.com/hub/aws-lambda.md) [AWS Lambda 插件将 Apache APISIX 与 AWS Lambda 无服务器函数集成,支持将 API 请求直接代理到 Lambda 函数,实现 Serverless 架构下的 API 网关统一管理。](https://docs.apiseven.com/hub/aws-lambda.md) [![Serverless Functions](https://static.api7.ai/uploads/2024/05/09/2NzjIiNI_serverless-funcs.png)](https://docs.apiseven.com/hub/serverless-functions.md) #### [Serverless Functions](https://docs.apiseven.com/hub/serverless-functions.md) [Serverless Functions 插件允许在 Apache APISIX 的请求处理阶段动态执行自定义 Lua 函数,无需重启网关即可扩展 API 网关功能,实现灵活的 Serverless 逻辑处理。](https://docs.apiseven.com/hub/serverless-functions.md) ## 其他协议[#](#other-protocols) [![MQTT Proxy](https://static.api7.ai/uploads/2024/09/19/4S2PT5Bc_mqtt.png)](https://docs.apiseven.com/hub/mqtt-proxy.md) #### [MQTT Proxy](https://docs.apiseven.com/hub/mqtt-proxy.md) [MQTT Proxy 插件使 Apache APISIX 支持 MQTT 协议代理,将物联网设备的 MQTT 消息路由到对应的后端 Broker,实现 API 网关对 IoT 设备的统一接入与管理。](https://docs.apiseven.com/hub/mqtt-proxy.md) 产品 * [API7 企业版Hot](https://www.apiseven.com/enterprise) * [API7 PortalNew](https://www.apiseven.com/portal) 开源项目 * [Apache APISIX](http://apisix.apache.org/) * [Apache APISIX Ingress Controller](https://github.com/apache/apisix-ingress-controller) 相关资源 * [用户案例](https://www.apiseven.com/usercases) * [技术博客](https://www.apiseven.com/blog) * [API7 企业版文档](https://docs.apiseven.com/api7-gateway/overview) * [白皮书](https://static.apiseven.com/202202/API7-WhitePaper.pdf) * [隐私政策](https://www.apiseven.com/privacy_policy) 支流科技 * [关于我们](https://www.apiseven.com/about) * [工作机会](https://www.apiseven.com/careers) * [合作伙伴](https://www.apiseven.com/partners) * [新闻报道](https://www.apiseven.com/news) 友情链接 * [Apifox](https://www.apifox.cn/) 邮件订阅 订阅 API7.ai 邮件列表,及时获得产品最新动态与相关资源。 <请输入你的邮箱>立即订阅 [![Logo](https://static.apiseven.com/202108/1640917868852-37633689-5279-48d6-a13a-189054e4d15b.png)](https://www.apiseven.com/) * [Twitter](https://twitter.com/ApacheAPISIX) * [YouTube](https://www.youtube.com/channel/UCgPD18cMhOg5rmPVnQhAC8g) * [Github](https://github.com/apache/apisix) [隐私政策](https://www.apiseven.com/privacy_policy) [粤ICP备19060840号](https://beian.miit.gov.cn/#/Integrated/index) 版权所有 © 2026 深圳支流科技有限公司 保留一切权利 --- # acl `acl` 插件用于根据发起请求的用户是否在访问控制列表(ACL)中,允许或拒绝对上游资源的访问。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下使用 `acl` 插件。 ### 通过检查消费者标签控制访问[​](#通过检查消费者标签控制访问 "通过检查消费者标签控制访问的直接链接") 以下示例展示了如何在成功认证后,根据消费者(Consumer)标签控制访问权限。 * Admin API * ADC * Ingress Controller 创建两个消费者 `john` 和 `jane`,并为他们分别配置所属组织和项目的标签: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john", "labels": { "org": "[\"opensource\",\"apache\"]", "project": "[\"tomcat\",\"web-server\",\"http,server\"]" } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jane", "labels": { "org": "apache", "project": "gateway,apisix,web-server" } }' ``` 为 `john` 和 `jane` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 提示 消费者标签可以通过以下两种方式配置: 1. 逗号分隔的字符串值,例如 `{"project": "gateway,apisix"}` 2. 转义的字符串数组,例如 `{"project": "[\"gateway\",\"apisix\"]"}` 创建一个启用了 `key-auth` 的路由,并配置 `acl` 插件: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "acl-route", "uri": "/get", "plugins": { "key-auth": {}, "acl": { "allow_labels": { "org": ["opensource"] } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 仅允许 `org` 标签值为 `opensource` 的消费者访问上游资源。 创建消费者 `john` 和 `jane`,分别配置标签、凭证,并创建启用了 `key-auth` 和 `acl` 插件的路由: adc.yaml ``` consumers: - username: john labels: org: "[\"opensource\",\"apache\"]" project: "[\"tomcat\",\"web-server\",\"http,server\"]" credentials: - name: cred-john-key-auth type: key-auth config: key: john-key - username: jane labels: org: "apache" project: "gateway,apisix,web-server" credentials: - name: cred-jane-key-auth type: key-auth config: key: jane-key services: - name: acl-service routes: - name: acl-route uris: - /get plugins: key-auth: {} acl: allow_labels: org: - opensource upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 消费者标签可以使用两种方式配置:逗号分隔的字符串值(如 `"apache"`),或转义后的字符串数组(如 `"[\"opensource\",\"apache\"]"`)。 ❷ 仅允许 `org` 标签值为 `opensource` 的消费者访问上游资源。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建两个带标签的消费者,并通过 `HTTPRoute` 引用的 `PluginConfig` 挂载 `acl` 插件: acl-gateway-api.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john labels: org: opensource spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane labels: org: apache spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: acl-plugin-config spec: plugins: - name: key-auth config: {} - name: acl config: allow_labels: org: - opensource --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: acl-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: acl-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f acl-gateway-api.yaml ``` 创建两个带标签的消费者,并通过 `ApisixRoute` 应用 `acl` 插件: acl-apisix-crd.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john labels: org: opensource spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane labels: org: apache spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: acl-route spec: ingressClassName: apisix http: - name: acl match: paths: - /get backends: - serviceName: httpbin servicePort: 80 plugins: - name: key-auth config: {} - name: acl config: allow_labels: org: - opensource ``` 将配置应用到集群: ``` kubectl apply -f acl-apisix-crd.yaml ``` 以消费者 `jane` 的身份发送请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key' ``` 你应该会收到 `HTTP/1.1 403 Forbidden` 响应,因为消费者 `jane` 没有配置访问该路由所需的标签。 以消费者 `john` 的身份发送请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key' ``` 你应该会收到 `HTTP/1.1 200 OK` 响应,因为消费者 `john` 配置了访问该路由所需的标签。 ### 通过检查外部身份提供商的用户信息控制访问[​](#通过检查外部身份提供商的用户信息控制访问 "通过检查外部身份提供商的用户信息控制访问的直接链接") 以下示例展示了在通过外部身份提供商成功认证后,如何根据用户标签控制访问。具体来说,本示例使用 Keycloak 和用户组作为标签。 按照 [使用 Keycloak 设置 SSO 指南](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md) 中的步骤创建 realm、client 和用户。 进入 **Groups** 并创建两个新组:`apisix` 和 `opensource`: ![Keycloak 用户组页面,树中显示 apisix 和 opensource 组,并突出显示 New 按钮](https://static.api7.ai/uploads/2024/02/05/n4M3Id6L_new-group.png) 要将用户添加到组,请点击用户并进入 **Groups** 选项卡。依次选择每个组并点击 **join**: ![Keycloak 管理界面:将用户添加到一个或多个组](https://static.api7.ai/uploads/2024/02/05/vaBSVk5U_add-membership.png) 要在从 Keycloak 请求用户信息时包含组成员资格,请进入 client 并转到 **Mappers** 选项卡。创建一个新的 mapper: ![Keycloak 中 apisix-quickstart-client 的 Clients Mappers 选项卡,尚未配置 mapper,并突出显示 Create 按钮](https://static.api7.ai/uploads/2024/02/05/GTGLRwc9_tHUb4QIw_create-mapper.png) 填写 protocol mapper 的名称,选择 **Group Membership** 作为 mapper 类型,使用 `groups` 作为 token claim 名称,然后点击 **Save**: ![Keycloak Create Protocol Mapper 表单,其中 Name 设置为 apisix-acl,Mapper Type 设置为 Group Membership,Token Claim Name 设置为 groups](https://static.api7.ai/uploads/2024/02/05/A5ABZSmE_protocol-mapper.png) 要验证请求用户信息时是否可见该属性,首先从 Keycloak 获取访问令牌(access token): ``` OIDC_USER=quickstart-user OIDC_PASSWORD=quickstart-user-pass OIDC_CLIENT_ID=apisix-quickstart-client OIDC_CLIENT_SECRET=bi9NFscFT4k0ljaRzQWlJWthrlygUn3x # 替换为你的客户端密钥 curl "http://$KEYCLOAK_IP:8080/realms/quickstart-realm/protocol/openid-connect/token" -X POST \ -d 'grant_type=password' \ -d 'client_id='$OIDC_CLIENT_ID'' \ -d 'client_secret='$OIDC_CLIENT_SECRET'' \ -d 'username='$OIDC_USER'' \ -d 'password='$OIDC_PASSWORD'' ``` 将访问令牌保存到名为 `ACCESS_TOKEN` 的环境变量中,并使用该令牌向 Keycloak 用户信息端点发送请求: ``` curl "http://$KEYCLOAK_IP:8080/realms/quickstart-realm/protocol/openid-connect/userinfo" -H "Authorization: Bearer $ACCESS_TOKEN" ``` 你应该会看到类似以下的响应: ``` { "sub":"4310e97c-d4c3-479b-bbbd-8c66120e6cee", "email_verified":false, "groups":["/apisix", "/opensource"], "preferred_username":"quickstart-user" } ``` 假设你只想允许 `groups` 属性包含 `/apisix` 值的用户访问上游资源。 创建一个包含 [`openid-connect`](https://docs.apiseven.com/hub/openid-connect.md) 和 `acl` 插件的路由: * Admin API * ADC * Ingress Controller ``` KEYCLOAK_IP=192.168.1.81 # 请替换为你的主机 IP OIDC_DISCOVERY=http://${KEYCLOAK_IP}:8080/realms/quickstart-realm/.well-known/openid-configuration curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <= 23.0.0`。 接下来,从 `/userinfo` 端点请求用户访问令牌和用户信息,类似于[上一个示例](#%E9%80%9A%E8%BF%87%E6%A3%80%E6%9F%A5%E5%A4%96%E9%83%A8%E8%BA%AB%E4%BB%BD%E6%8F%90%E4%BE%9B%E5%95%86%E7%9A%84%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF%E6%8E%A7%E5%88%B6%E8%AE%BF%E9%97%AE)。你应该会看到 Keycloak 返回类似以下的用户信息: ``` { "sub": "f62086ef-29e1-4401-8609-451a2d724bd7", "email_verified": false, "acl_labels": { "nested": { "groups": [ "/apisix", "/opensource" ] } }, "preferred_username": "quickstart-user" } ``` 在 API7 中,创建一个带有 [`openid-connect`](https://docs.apiseven.com/hub/openid-connect.md) 的路由以通过 Keycloak 进行认证,并配置 `acl` 插件: * Admin API * ADC * Ingress Controller ``` KEYCLOAK_IP=192.168.1.81 # 请替换为你的主机 IP OIDC_DISCOVERY=http://${KEYCLOAK_IP}:8080/realms/quickstart-realm/.well-known/openid-configuration curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < ## 演示[​](#演示 "演示的直接链接") 以下演示展示了如何在 API7 企业版控制台中完成[审查请求内容毒性示例](#%E5%AE%A1%E6%A0%B8%E8%AF%B7%E6%B1%82%E5%86%85%E5%AE%B9%E6%AF%92%E6%80%A7):你可以审查请求内容是否含有毒性,并自定义拒绝状态码和消息。 ## 按请求格式处理[​](#按请求格式处理 "按请求格式处理的直接链接") 该插件使用各协议的原生内容结构审核 Chat Completions、Responses API、Embeddings、Anthropic Messages 和 Bedrock Converse 请求。 网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式: * Bedrock Converse 要求 URI 以 `/converse` 结尾且包含 `messages` 数组。 * Anthropic Messages 要求 URI 以 `/v1/messages` 结尾。 * Responses API 要求 URI 以 `/v1/responses` 结尾且包含 `input` 字段。 * Chat Completions 使用 `messages` 数组。 * 当前面的规则均不匹配时,Embeddings 使用 `input`。 * 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。 | 请求格式 | 可审核的内容 | | ------------------ | ------------------------------------ | | Bedrock Converse | `system` 和 `messages` 中的文本。 | | Anthropic Messages | `messages` 中的文本。 | | Responses API | `instructions` 和 `input` 中的文本。 | | Chat Completions | `messages` 中的文本。 | | Embeddings | `input` 中的字符串或字符串数组。 | | 其他 JSON(透传) | 不提取请求格式特定文本。 | APISIX 会审核表中列出的所有已提取内容。API7 企业版 3.9.16 或 3.10.3 起支持按角色选择内容,默认审核最近一轮用户消息。使用 `request_check_roles` 选择用户、工具或系统内容,使用 `request_check_mode` 选择最近一轮或所有匹配轮次。 按角色选择内容时,选择系统角色即可审核 Anthropic 顶层 `system` 提示词。当请求格式使用独立的工具角色或条目表示工具输出时,插件可以审核工具结果。Anthropic Messages 和 Bedrock Converse 将工具结果嵌套在用户消息中,因此仅选择工具角色时不会提取这些结果。 要审核支持范围内尽可能广的请求内容,请在插件配置中选择所有可用角色和全部轮次: ``` { "request_check_roles": ["user", "tool", "system"], "request_check_mode": "all" } ``` 此配置会扫描检测到的协议为这些角色暴露的所有文本,但不会恢复为原始请求体审核:嵌套的 Anthropic 和 Bedrock 工具结果仍属于用户内容,而不是独立的 `tool` 消息;不支持的非 AI 结构则遵循 `fail_mode`。 如果 Responses 内容被拒绝,插件会以 Responses API 格式返回配置的消息。流式请求会收到以 `response.completed` 结尾的类型化服务器发送事件。 Embeddings 没有对话角色或轮次。启用按角色选择后,其 `input` 由用户角色选中。被拒绝的请求会收到 OpenAI 风格的错误响应。 如果向阿里云发起的审核请求失败,插件会记录错误,并在没有审核结论的情况下放行内容。`fail_mode` 只控制不支持的请求格式或非 AI 请求,不会让阿里云服务故障转为故障关闭。当该插件作为强制执行控制时,请监控内容审核错误和阿里云服务可用性。 ## 示例[​](#示例 "示例的直接链接") 以下示例将使用 OpenAI 作为上游模型服务提供方。 在开始之前,请创建一个 [OpenAI 账号](https://openai.com) 并获取 [API Key](https://openai.com/blog/openai-api)。如果你使用其他模型服务提供方,请参考该提供方的文档获取 API Key。 此外,请创建一个 [阿里云账号](https://www.aliyun.com),开通内容安全增强版服务,并获取 endpoint、region ID、access key ID 和 access key secret。 你可以选择将这些信息保存到环境变量中: ``` # 替换为你的数据 export OPENAI_API_KEY=YOUR_OPENAI_API_KEY export ALIYUN_ENDPOINT=https://green-cip.cn-shanghai.aliyuncs.com export ALIYUN_REGION_ID=cn-shanghai export ALIYUN_ACCESS_KEY_ID=YOUR_ALIYUN_ACCESS_KEY_ID export ALIYUN_ACCESS_KEY_SECRET=YOUR_ALIYUN_ACCESS_KEY_SECRET ``` ### 审核请求内容毒性[​](#审核请求内容毒性 "审核请求内容毒性的直接链接") 以下示例演示了如何使用该插件审查请求内容的毒性,并自定义拒绝状态码和消息。 * Admin API * ADC * Ingress Controller 使用 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 插件创建一个通往 LLM 聊天完成端点的路由,并在 `ai-aliyun-content-moderation` 插件中配置集成详情以及拒绝代码和消息: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <
## 按请求格式处理[​](#按请求格式处理 "按请求格式处理的直接链接") 在 APISIX 中,该插件通过将完整的序列化 JSON 请求体发送到 Amazon Comprehend 来审核请求。它不会从检测到的请求格式中提取文本,被拒绝的请求会收到通用 HTTP 400 错误。 API7 企业版 3.9.16 或 3.10.3 起增加了按请求格式提取文本和生成拒绝响应的能力。网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式: * Bedrock Converse 要求 URI 以 `/converse` 结尾且包含 `messages` 数组。 * Anthropic Messages 要求 URI 以 `/v1/messages` 结尾。 * Responses API 要求 URI 以 `/v1/responses` 结尾且包含 `input` 字段。 * Chat Completions 使用 `messages` 数组。 * 当前面的规则均不匹配时,Embeddings 使用 `input`。 * 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。 插件随后审核以下内容: | 请求格式 | 审核的文本 | | ------------------ | ------------------------------------------------- | | Bedrock Converse | `system` 和 `messages` 中的文本。 | | Anthropic Messages | `messages` 中的文本,不包含顶层 `system` 提示词。 | | Responses API | `input` 和 `instructions` 中的文本。 | | Chat Completions | `messages` 中所有条目的文本。 | | Embeddings | `input` 中的字符串或字符串数组。 | | 其他 JSON(透传) | 不提取请求格式特定文本。 | 在 API7 企业版中,被拒绝的请求会以检测到的请求格式返回响应,状态码由 `deny_code` 配置。响应包含配置的 `deny_message`;如果未配置,则返回超过阈值的原因。 流式 Chat Completions、Responses API 和 Anthropic Messages 拒绝响应使用各自协议的 SSE 格式。Bedrock ConverseStream 拒绝响应使用非流式 Converse 响应体,而不是 AWS 事件流帧。 ## 示例[​](#示例 "示例的直接链接") 以下示例将使用 OpenAI 作为上游模型服务提供方。 在开始之前,请创建一个 [OpenAI 账号](https://openai.com) 并获取 [API Key](https://openai.com/blog/openai-api)。如果你使用其他模型服务提供方,请参考该提供方的文档获取 API Key。 此外,请为 APISIX 创建 [AWS IAM 用户访问密钥](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) 以访问 [AWS Comprehend](https://aws.amazon.com/comprehend/)。 你可以选择将这些密钥保存到环境变量中: ``` # 替换为你的密钥 export OPENAI_API_KEY=YOUR_OPENAI_API_KEY export AWS_ACCESS_KEY=YOUR_AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY ``` ### 审核亵渎内容[​](#审核亵渎内容 "审核亵渎内容的直接链接") 以下示例演示了如何使用该插件审核提示词中的亵渎内容等级。 * Admin API * ADC * Ingress Controller 使用 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 插件创建一个通往 LLM 聊天完成端点的路由,并在 `ai-aws-content-moderation` 中配置允许的亵渎等级: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <", "object": "chat.completion", "model": "gpt-4", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "request body exceeds PROFANITY threshold" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 } } ``` 向该路由发送另一个请求,请求体中包含一个正常的问题: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { "role": "user", "content": "What is 1+1?" } ] }' ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并看到模型输出: ``` { ..., "model": "gpt-4-0613", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "1+1 equals 2.", "refusal": null }, "logprobs": null, "finish_reason": "stop" } ], ... } ``` ### 审核整体毒性[​](#审核整体毒性 "审核整体毒性的直接链接") 以下示例演示了除了审核单个类别外,如何使用该插件审核提示词中的整体毒性等级。 * Admin API * ADC * Ingress Controller 使用 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 插件创建一个通往 LLM 聊天完成端点的路由,并在 `ai-aws-content-moderation` 中配置允许的亵渎和整体毒性等级: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <", "object": "chat.completion", "model": "gpt-4", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "request body exceeds toxicity threshold" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 } } ``` 向该路由发送另一个请求,请求体中不包含任何亵渎词汇: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { "role": "user", "content": "What is 1+1?" } ] }' ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并看到模型输出: ``` { ..., "model": "gpt-4-0613", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "1+1 equals 2.", "refusal": null }, "logprobs": null, "finish_reason": "stop" } ], ... } ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 该插件支持使用 `env://` 前缀从环境变量引用敏感参数值,也支持使用 `secret://` 前缀从密钥管理器(例如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv))引用敏感参数值。有关更多信息,请参阅[插件中的环境变量](https://docs.apiseven.com/apisix/reference/environment-variables.md#plugins)和[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * comprehend object 必填 *** [AWS Comprehend](https://aws.amazon.com/comprehend) 配置。 * access\_key\_id string 必填 *** AWS Access Key ID。 * secret\_access\_key string 必填 *** AWS Secret Access Key。该值在存储到 etcd 前会使用 AES 加密。 * region string 必填 *** AWS 区域。 * endpoint string *** AWS Comprehend 服务端点。未设置时,默认为 `https://comprehend.{region}.amazonaws.com`。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,启用 TLS 证书验证。 * moderation\_categories object *** 审核类别及其对应阈值的键值对。 在每一对中,键应该是 `PROFANITY`(亵渎)、`HATE_SPEECH`(仇恨言论)、`INSULT`(侮辱)、`HARASSMENT_OR_ABUSE`(骚扰或滥用)、`SEXUAL`(色情)或 `VIOLENCE_OR_THREAT`(暴力或威胁)之一;阈值应该在 0 到 1 之间(包含 0 和 1)。 * moderation\_threshold number 默认值:`0.5` 有效值: 介于 0 和 1 之间(含边界值) *** 整体毒性阈值。值越高意味着允许的毒性内容越多。 此选项不同于 `moderation_categories` 中的单个类别阈值。例如,如果 `moderation_categories` 将 `PROFANITY` 阈值设置为 `0.5`,而请求的 `PROFANITY` 分数为 `0.1`,该请求不会超过类别阈值。但是,如果请求的 `SEXUAL` 或 `VIOLENCE_OR_THREAT` 等其他类别超过 `moderation_threshold`,请求将被拒绝。 * check\_request boolean 默认值:`true` *** 如果为 true,则审核请求内容。 自 API7 企业版 3.9.16 和 3.10.3 以及 APISIX 3.18.0 起可用。 * deny\_code integer 默认值:`200` 有效值: 介于 200 和 599 之间(含边界值) *** 在响应头发送前拒绝被标记流量时返回的 HTTP 状态码。默认的 `200` 会返回与服务提供方兼容的拒绝响应;设置为 `4xx` 值可将内容审查结果暴露为 HTTP 错误。流式传输开始后无法再更改状态码。 自 API7 企业版 3.9.16 和 3.10.3 以及 APISIX 3.18.0 起可用。 * deny\_message string *** 请求或响应内容被拒绝时返回的消息。未设置时,插件返回超过阈值的原因。 自 API7 企业版 3.9.16 和 3.10.3 以及 APISIX 3.18.0 起可用。 * fail\_mode string 默认值:`skip` 有效值: `skip`、`warn` 或 `error` *** 当插件收到无法审查的请求时的行为,例如绑定到 Consumer 的非 AI 流量,或未经过 AI Proxy 的请求。取值为 `skip` 时,请求会未经检查直接放行。取值为 `warn` 时,请求会未经检查放行并记录 warning 日志。取值为 `error` 时,插件会使用适用的 HTTP 400 或 500 响应拒绝请求。以上任何结果都不表示内容审查成功。 自 API7 企业版 3.9.14 和 APISIX 3.18.0 起可用。 * request\_check\_roles array\[string] 默认值:`["user", "tool", "system", "assistant"]` 有效值: `user`、`assistant`、`system` 或 `tool` *** 请求侧需要审查的消息角色。`user`、`tool` 和 `assistant` 遵循 `request_check_mode`;`system` 在每次请求时都会被检查,因为其内容可能受到恶意工具调用参数的影响。`assistant` 消息是客户端提供的会话历史,因此默认也会被审查。 选中 `system` 时同时覆盖 `developer` 角色的消息——`developer` 是 OpenAI 在较新模型和 Responses API 中用来替代 `system` 的角色,没有单独的 `developer` 取值。 工具结果的审查适用于把工具输出表示为独立 `tool` 角色或条目的 OpenAI 兼容格式。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * request\_check\_mode string 默认值:`all` 有效值: `all` 或 `last` *** 所选角色中哪些消息会被审查。取值为 `all` 时,所选角色的每条消息都会被检查;取值为 `last` 时,只检查所选角色消息中最后一段连续的消息。`system` 角色不受该选项影响,只要被选中就始终检查。 同时选择 `assistant` 与 `last` 会扩大被视为「最后一段」的范围,因为 assistant 轮次不再作为该段的结束。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * request\_check\_length\_limit integer 默认值:`1000` 有效值: 4 到 1024 之间(含) *** 每个 Amazon Comprehend 文本分段中请求内容的最大字节数。超长内容会被切分到多个分段,从而完整审查而不是被截断。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * check\_response boolean 默认值:`false` *** 如果为 true,则在审查请求之外同时审查 LLM 响应内容。非流式响应会在返回客户端前完成审查;如果 Amazon Comprehend 无法评分,则以 HTTP 500 关闭失败。流式响应按 `stream_check_mode` 审查;字节发送后,如果服务提供方失败,插件会记录错误,并在没有审查结论的情况下放行剩余响应流。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * response\_check\_length\_limit integer 默认值:`1000` 有效值: 4 到 1024 之间(含) *** 每个 Amazon Comprehend 文本分段中响应内容的最大字节数。超长内容会被切分到多个分段。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * stream\_check\_mode string 默认值:`final_packet` 有效值: `final_packet` 或 `realtime` *** 启用 `check_response` 后,流式响应的审查方式。取值为 `final_packet` 时,对拼装完成的响应审查一次,并在最后一个分片上标注风险等级;取值为 `realtime` 时,在响应流式转发过程中分批审查,一旦某批命中,流的剩余部分会被替换为拒绝消息。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * stream\_check\_cache\_size integer 默认值:`128` 有效值: 大于或等于 1 *** 在 `realtime` 模式下,每个审查批次累积的最大字符数。取值越小越早发现有害内容,代价是审查调用次数增加。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * stream\_check\_interval number 默认值:`3` 有效值: 大于或等于 0.1 *** 在 `realtime` 模式下,两次批量检查之间的间隔秒数。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * timeout integer 默认值:`10000` 有效值: 大于或等于 1 *** 请求 Amazon Comprehend 的超时时间,单位为毫秒。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * keepalive boolean 默认值:`true` *** 如果为 true,则保持与 Amazon Comprehend 的连接存活,使同一请求内的多次审查调用复用该连接,而不是每次都重新建立。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 连接池中与 Amazon Comprehend 的连接在空闲多久后被关闭,单位为毫秒。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 --- # ai-cache `ai-cache` 插件会缓存 LLM 服务的响应,使重复请求直接从缓存返回,而不再次调用上游模型。这可以降低重复提示词的响应延迟,并减少上游 Token 用量。 该插件支持精确匹配缓存:仅当规范化后的请求与此前缓存的某个请求完全相同时,才会复用其响应。它还可以启用语义缓存层,在精确匹配未命中后通过 RediSearch 比较提示词向量嵌入。 ## 按请求格式处理[​](#按请求格式处理 "按请求格式处理的直接链接") 插件会将检测到的不同请求格式保存在不同的缓存条目中。 网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式: * Bedrock Converse 要求 URI 以 `/converse` 结尾且包含 `messages` 数组。 * Anthropic Messages 要求 URI 以 `/v1/messages` 结尾。 * Responses API 要求 URI 以 `/v1/responses` 结尾且包含 `input` 字段。 * Chat Completions 使用 `messages` 数组。 * 当前面的规则均不匹配时,Embeddings 使用 `input`。 * 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。 | 请求格式 | 精确匹配缓存 | 语义缓存 | | ------------------ | ------------ | -------- | | Bedrock Converse | 支持 | 绕过 | | Anthropic Messages | 支持 | 绕过 | | Responses API | 支持 | 绕过 | | Chat Completions | 支持 | 支持 | | Embeddings | 支持 | 绕过 | | 其他 JSON(透传) | 支持 | 绕过 | 精确匹配缓存自 API7 企业版 3.9.16、3.10.2 以及 APISIX 3.18.0 起可用。 语义缓存和流式响应缓存自 API7 企业版 3.9.16、3.10.3 以及 APISIX 3.18.0 起可用。 ## 工作原理[​](#工作原理 "工作原理的直接链接") `ai-cache` 插件必须与同一路由上的 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 或 [`ai-proxy-multi`](https://docs.apiseven.com/hub/ai-proxy-multi.md) 插件一起使用,因为它缓存的是这些插件所代理的 LLM 流量。 对于每个请求,插件会根据检测到的请求格式、请求体以及所选 AI 实例的配置计算缓存键。自 API7 企业版 3.9.20 和 3.10.7 起,`passthrough` 协议下的缓存键还包含客户端的请求方法、路径和查询字符串。该协议会把这三者原样代理出去,因此由它们决定上游端点。缓存键的作用域由 `cache_key` 配置。精确缓存条目存储在 Redis 中,并具有可配置的存活时间。 对于 Chat Completions 请求,语义缓存会在精确缓存未命中后运行。插件对配置的提示词窗口生成向量嵌入,并在 RediSearch 向量索引中查询足够相似的缓存响应。 插件会将 `X-AI-Cache-Status` 响应头设置为以下值之一: * `HIT`:找到有效的缓存响应并直接返回,不调用上游。`X-AI-Cache-Age` 头会以秒为单位报告该缓存条目的存活时长。语义命中还会返回 `X-AI-Cache-Similarity`。 * `MISS`:未找到缓存响应。请求被代理到上游,且大小在 `max_cache_body_size` 以内的成功响应(`HTTP 200`)会被缓存以供后续请求使用。 * `BYPASS`:此请求跳过缓存,例如因为它匹配了某条 `bypass_on` 规则、未选中任何 AI 实例,或响应无法安全捕获。 完整的 SSE 流式响应可以被缓存,并使用其流式内容类型重放。只有当插件收到客户端协议的终止事件后,流式响应才会被缓存,例如 OpenAI Chat Completions 的 `[DONE]`、Anthropic Messages 的 `message_stop`,或 OpenAI Responses API 的 `response.completed`。被中断或因限制而截断的流式响应不会被缓存。流式请求和非流式请求使用不同的缓存条目;缓存的流式响应会立即重放,而不会保留原始 Token 的时间间隔。使用其他帧格式的流(例如 Bedrock ConverseStream 的 AWS 事件流格式)会绕过缓存。 警告 缓存的提示词和响应可能包含敏感数据。请限制对 Redis 的访问,选择合适的缓存存活时间;如果缓存响应不应在不同消费者或请求上下文之间共享,请使用 `cache_key.include_consumer` 或 `cache_key.include_vars`。 ## 示例[​](#示例 "示例的直接链接") 以下示例使用 OpenAI 作为上游 LLM 服务,并使用一个 Redis 实例来存储缓存。在开始之前,请创建一个 [OpenAI 账号](https://openai.com) 和 [API Key](https://openai.com/blog/openai-api),并确保网关能够访问到一个 Redis 实例。你可以选择将密钥保存到环境变量中: ``` export OPENAI_API_KEY=YOUR_OPENAI_API_KEY # 替换为你的 API Key ``` 如果你使用其他模型服务提供方,请参考该提供方的文档获取 API Key。 ### 缓存 LLM 响应[​](#缓存-llm-响应 "缓存 LLM 响应的直接链接") 以下示例演示如何将 `ai-cache` 与 `ai-proxy` 配合配置,使重复的相同请求由 Redis 提供响应。 * Admin API * ADC * Ingress Controller 创建一个使用 `ai-proxy` 代理到 OpenAI、并使用 `ai-cache` 缓存响应的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < ## 演示[​](#演示 "演示的直接链接") 以下演示展示了如何在 API7 企业版控制台中完成[配置允许和拒绝模式示例](#%E5%AE%9E%E7%8E%B0%E5%85%81%E8%AE%B8%E5%92%8C%E6%8B%92%E7%BB%9D%E6%A8%A1%E5%BC%8F):你可以同时定义允许模式和拒绝模式来验证用户提示词,并了解允许模式如何优先生效。 ## 按请求格式处理[​](#按请求格式处理 "按请求格式处理的直接链接") 该插件使用各协议的原生内容结构检查 Chat Completions、Responses API、Embeddings、Anthropic Messages 和 Bedrock Converse 请求。 网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式: * Bedrock Converse 要求 URI 以 `/converse` 结尾且包含 `messages` 数组。 * Anthropic Messages 要求 URI 以 `/v1/messages` 结尾。 * Responses API 要求 URI 以 `/v1/responses` 结尾且包含 `input` 字段。 * Chat Completions 使用 `messages` 数组。 * 当前面的规则均不匹配时,Embeddings 使用 `input`。 * 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。 默认情况下,插件检查最近的用户内容。使用 `match_all_roles` 包含其他角色,使用 `match_all_conversation_history` 包含更早的消息。 | 请求格式 | 检查的内容 | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Bedrock Converse | 根据角色和对话历史设置检查 `system` 和 `messages` 中的内容。 | | Anthropic Messages | 根据角色和对话历史设置检查顶层 `system` 提示词和 `messages` 中的内容。 | | Responses API | 检查 `input` 中的用户内容。启用 `match_all_roles` 后,还会检查 `instructions` 以及 `input` 中分配给其他角色的内容。对话历史设置不适用,因为 `instructions` 和 `input` 是并列字段。 | | Chat Completions | 根据角色和对话历史设置检查 `messages` 中的内容。 | | Embeddings | 检查 `input` 中的字符串,并将其视为用户内容。不检查输入字符串数组。 | | 其他 JSON(透传) | 不作为受支持的 AI 请求格式进行检查。 | ## 示例[​](#示例 "示例的直接链接") 以下示例将使用 OpenAI 作为上游模型服务提供方。在开始之前,请创建一个 [OpenAI 账号](https://openai.com) 并获取 [API Key](https://openai.com/blog/openai-api)。你可以选择将密钥保存到环境变量中,如下所示: ``` export OPENAI_API_KEY=YOUR_OPENAI_API_KEY # 替换为你的 API Key ``` 如果你使用其他模型服务提供方,请参考该提供方的文档获取 API Key。 ### 实现允许和拒绝模式[​](#实现允许和拒绝模式 "实现允许和拒绝模式的直接链接") 以下示例演示了如何使用 `ai-prompt-guard` 插件通过定义允许和拒绝模式来验证用户提示词,并理解允许模式的优先级。 定义允许和拒绝模式。你可以选择将它们保存到环境变量中以便更容易转义: ``` # 允许美元金额 export ALLOW_PATTERN_1='\\$?\\(?\\d{1,3}(,\\d{3})*(\\.\\d{1,2})?\\)?' # 拒绝美国号码格式的电话号码 export DENY_PATTERN_1='(\\([0-9]{3}\\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}' ``` * Admin API * ADC * Ingress Controller 创建一个使用 `ai-proxy` 代理到 OpenAI 并使用 `ai-prompt-guard` 检查输入提示词的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- </` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 向该路由发送一个 POST 请求,请求体中包含系统提示词和示例用户问题: adc.yaml ``` services: - name: vertex-ai-service routes: - name: vertex-ai-route uris: - /anything methods: - POST plugins: ai-proxy: provider: vertex-ai auth: gcp: service_account_json: "${GCP_SA_JSON}" provider_conf: project_id: api7-vertex region: us-central1 options: model: google/gemini-2.5-flash ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ 将模型服务提供方指定为 `vertex-ai`。 ❷ 替换为你的 JSON 凭证。请确保该值为经过 JSON 转义的字符串。 ❸ 替换为你的 Vertex AI 项目 ID 和区域。 ❹ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 * Gateway API * APISIX CRD vertex-ai-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ai-proxy-plugin-config spec: plugins: - name: ai-proxy config: provider: vertex-ai auth: gcp: service_account_json: '{"type":"service_account","project_id":"api7-vertex","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----","client_email":"api7-docs@api7-vertex.iam.gserviceaccount.com","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/api7-docs%40api7-vertex.iam.gserviceaccount.com","universe_domain":"googleapis.com"}' provider_conf: project_id: api7-vertex region: us-central1 options: model: google/gemini-2.5-flash --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: vertex-ai-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ai-proxy-plugin-config ``` 将配置应用到集群: ``` kubectl apply -f vertex-ai-ic.yaml ``` ❶ 将模型服务提供方指定为 `vertex-ai`。 ❷ 替换为你的 JSON 凭证。请确保该值为经过 JSON 转义的字符串。 ❸ 替换为你的 Vertex AI 项目 ID 和区域。 ❹ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 vertex-ai-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: vertex-ai-route spec: ingressClassName: apisix http: - name: vertex-ai-route match: paths: - /anything methods: - POST plugins: - name: ai-proxy enable: true config: provider: vertex-ai auth: gcp: service_account_json: '{"type":"service_account","project_id":"api7-vertex","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----","client_email":"api7-docs@api7-vertex.iam.gserviceaccount.com","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/api7-docs%40api7-vertex.iam.gserviceaccount.com","universe_domain":"googleapis.com"}' provider_conf: project_id: api7-vertex region: us-central1 options: model: google/gemini-2.5-flash ``` 将配置应用到集群: ``` kubectl apply -f vertex-ai-ic.yaml ``` ❶ 将模型服务提供方指定为 `vertex-ai`。 ❷ 替换为你的 JSON 凭证。请确保该值为经过 JSON 转义的字符串。 ❸ 替换为你的 Vertex AI 项目 ID 和区域。 ❹ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 发送一个 POST 请求到该路由,请求体中包含系统提示词和一个示例用户问题: ``` curl "http://127.0.0.1:9080/anything" -X POST \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { "role": "user", "content": "What is 1+1?" } ] }' ``` 你应该会收到类似以下的响应: ``` { "choices": [ { "message": { "role": "assistant", "content": "1 + 1 = 2\n" }, "index": 0, "logprobs": null, "finish_reason": "stop" } ], "usage": { "completion_tokens": 8, "extra_properties": { "google": { "traffic_type": "ON_DEMAND" } }, "total_tokens": 19, "prompt_tokens": 11 }, "object": "chat.completion", "model": "google/gemini-2.5-flash", ... } ``` ### 代理到 Vertex AI 向量嵌入模型[​](#代理到-vertex-ai-向量嵌入模��型 "代理到 Vertex AI 向量嵌入模型的直接链接") 以下示例演示了如何配置 `ai-proxy` 插件,使用 GCP 服务账号认证将请求代理到 Vertex AI 向量嵌入模型。本示例仅适用于 API7 企业版 3.9.2 及更高版本,不适用于 Apache APISIX。 在继续之前: * [启用 Vertex AI](https://docs.cloud.google.com/vertex-ai/docs/featurestore/setup) 并为 GCP 项目启用结算。 * 按照[服务账号凭证](https://developers.google.com/workspace/guides/create-credentials#service-account)文档在 GCP 中创建服务账号,为该账号分配“Vertex AI User”角色,并获取 JSON 格式的账号凭证。 凭证文件应类似如下: credentials.json ``` { "type": "service_account", "project_id": "api7-vertex", "private_key_id": "...", "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n", "client_email": "api7-docs@api7-vertex.iam.gserviceaccount.com", "client_id": "....", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/api7-docs%40api7-vertex.iam.gserviceaccount.com", "universe_domain": "googleapis.com" } ``` 你可以选择将该 JSON 保存到环境变量中: ``` export GCP_SA_JSON="$(cat credentials.json)" ``` * Admin API * ADC * Ingress Controller 创建一个路由并按如下方式配置 `ai-proxy` 插件: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < export AWS_SECRET_ACCESS_KEY= ``` 创建一个路由,并为 Bedrock 配置 `ai-proxy` 插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < -n -f values.yaml ``` 现在,如果你按照 [代理到 OpenAI 示例](#%E4%BB%A3%E7%90%86%E5%88%B0-openai) 创建一个路由。发送如下请求: ``` curl "http://127.0.0.1:9080/anything" -X POST \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-3.5", "messages": [ { "role": "system", "content": "You are a mathematician" }, { "role": "user", "content": "What is 1+1?" } ] }' ``` 由于 `ai-proxy` 中的模型是 `gpt-4`,因此请求将被转发到 GPT-4 模型,你将收到类似以下的响应: ``` { ..., "model": "gpt-4-0613", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "1+1 equals 2.", "refusal": null, "annotations": [] }, "logprobs": null, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 23, "completion_tokens": 8, "total_tokens": 31, "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 }, ... }, "service_tier": "default", "system_fingerprint": null } ``` 在网关的访问日志中,你应该会看到类似于以下的日志条目: ``` 192.168.215.1 - - [29/Aug/2025:09:54:16 +0000] 127.0.0.1:9080 "POST /anything HTTP/1.1" 200 808 2.670 "-" "curl/8.6.0" - - 2670 "http://127.0.0.1:9080" "6526bf5c961b6e6bb8cfcb66486f02dc" "ai_chat" "2670" "gpt-4" "gpt-3.5" "23" "8" "31" "false" "false" "0" "" "0" "0" "0" ``` 该访问日志条目显示:APISIX 上游响应时间为 `2.670` 秒,请求类型为 `ai_chat`,首 Token 时间为 `2670` 毫秒,请求转发到的 LLM 模型为 `gpt-4`,请求中的 LLM 模型为 `gpt-3.5`,提示词 Token 用量为 `23`,补全 Token 用量为 `8`,Token 总用量为 `31`;该请求为非流式请求,没有工具调用,请求中未提供工具,也没有终端用户标识符、提示词缓存 Token 或推理 Token。 ### 将请求日志发送到日志记录器[​](#将请求日志发送到日志记录器 "将请求日志发送到日志记录器的直接链接") 以下示例演示了如何记录请求和请求信息(包括 LLM 模型、令牌和负载),并将它们推送到日志记录器。在继续之前,你应该先设置一个日志记录器,例如 Kafka。有关更多信息,请参阅 [`kafka-logger`](https://docs.apiseven.com/hub/kafka-logger.md)。 * Admin API * ADC * Ingress Controller 创建一条通往 LLM 服务的路由,并按如下方式配置日志记录详情: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < ## 演示[​](#演示 "演示的直接链接") 以下演示展示了[配置实例优先级和速率限制示例](#%E9%85%8D%E7%BD%AE%E5%AE%9E%E4%BE%8B%E4%BC%98%E5%85%88%E7%BA%A7%E5%92%8C%E9%80%9F%E7%8E%87%E9%99%90%E5%88%B6)。它展示了如何在 API7 企业版中使用控制台配置两个具有不同优先级的模型,并对优先级较高的实例应用速率限制。在将 `fallback_strategy` 设置为 `["rate_limiting"]` 的情况下,一旦高优先级实例的速率限制配额用完,插件应继续将请求转发到低优先级实例。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何针对不同场景配置 `ai-proxy-multi`。 ### 实例间负载均衡[​](#实例间负载均衡 "实例间负载均衡的直接链接") 以下示例配置两个模型进行负载均衡,将 80% 的流量转发到一个实例,20% 转发到另一个实例。如果首次尝试在两秒内返回 `429` 或 `5xx`,插件还会重试另一个实例。`max_retries` 和 `retry_on_failure_within_ms` 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 为了演示和更易于区分,你将配置一个 OpenAI 实例和一个 DeepSeek 实例作为上游 LLM 服务。 创建路由如下,并根据需要更新你的模型服务提供方、模型、API Key 和端点: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <" options: model: gpt-4.1 - name: openai-responses-secondary provider: openai weight: 1 auth: header: Authorization: "Bearer " options: model: gpt-4.1-mini --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ai-proxy-multi-responses-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /v1/responses method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ai-proxy-multi-responses-plugin-config ``` 将配置应用到集群: ``` kubectl apply -f ai-proxy-multi-ic.yaml ``` ai-proxy-multi-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ai-proxy-multi-responses-route spec: ingressClassName: apisix http: - name: ai-proxy-multi-responses-route match: paths: - /v1/responses methods: - POST plugins: - name: ai-proxy-multi enable: true config: instances: - name: openai-responses-primary provider: openai weight: 1 auth: header: Authorization: "Bearer " options: model: gpt-4.1 - name: openai-responses-secondary provider: openai weight: 1 auth: header: Authorization: "Bearer " options: model: gpt-4.1-mini ``` 将配置应用到集群: ``` kubectl apply -f ai-proxy-multi-ic.yaml ``` 使用 OpenAI Responses API 格式发送请求: ``` curl "http://127.0.0.1:9080/v1/responses" -X POST \ -H "Content-Type: application/json" \ -d '{ "input": "Write one sentence about API gateways." }' ``` 请求会被转发到已配置的某个 OpenAI 实例,并以 Responses API 格式返回响应。 ### 按语义相似度路由[​](#按语义相似度路由 "按语义相似度路由的直接链接") `semantic` 负载均衡算法通过比较请求提示词与分配给各实例的示例语句来选择实例。此功能自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 导出向量嵌入请求和 LLM 请求所需的 API Key: ``` export EMBEDDING_API_KEY="" export LLM_API_KEY="" ``` 创建一条路由,分别配置适用于编程、翻译和通用提示词的实例。当所有得分均未达到配置的阈值,或向量嵌入请求失败时,也会使用通用实例作为后备实例: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <` 格式指定通过 Google AI Studio 使用的 Gemini 模型名称。 ❹ 将提供商配置为 `vertex-ai`,以访问 Vertex AI Gemini。 ❺ 替换为你的 JSON 凭证。确保它是一个 JSON 转义字符串。 ❻ 替换为你的 Vertex AI 项目 ID 和区域。 ❼ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 adc.yaml ``` services: - name: ai-proxy-multi-service routes: - name: ai-proxy-multi-route uris: - /anything methods: - POST plugins: ai-proxy-multi: fallback_strategy: - rate_limiting instances: - name: gemini-instance provider: gemini weight: 7 auth: header: Authorization: "Bearer ${GEMINI_API_KEY}" options: model: gemini-2.5-flash - name: vertex-ai-instance provider: vertex-ai weight: 3 auth: gcp: service_account_json: "${GCP_SA_JSON}" provider_conf: project_id: api7-vertex region: us-central1 options: model: google/gemini-2.5-flash ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ 将提供商配置为 `gemini`,以访问 Google AI Studio Gemini。 ❷ 在 `Authorization` 请求头中替换为你的 Gemini API Key。 ❸ 以 `` 格式指定通过 Google AI Studio 使用的 Gemini 模型名称。 ❹ 将提供商配置为 `vertex-ai`,以访问 Vertex AI Gemini。 ❺ 替换为你的 JSON 凭证。确保它是一个 JSON 转义字符串。 ❻ 替换为你的 Vertex AI 项目 ID 和区域。 ❼ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 * Gateway API * APISIX CRD ai-proxy-multi-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ai-proxy-multi-plugin-config spec: plugins: - name: ai-proxy-multi config: fallback_strategy: - rate_limiting instances: - name: gemini-instance provider: gemini weight: 7 auth: header: Authorization: "Bearer YOUR_GEMINI_API_KEY" options: model: gemini-2.5-flash - name: vertex-ai-instance provider: vertex-ai weight: 3 auth: gcp: service_account_json: '{"type":"service_account","project_id":"api7-vertex","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----","client_email":"api7-docs@api7-vertex.iam.gserviceaccount.com","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/api7-docs%40api7-vertex.iam.gserviceaccount.com","universe_domain":"googleapis.com"}' provider_conf: project_id: api7-vertex region: us-central1 options: model: google/gemini-2.5-flash --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ai-proxy-multi-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ai-proxy-multi-plugin-config ``` 将配置应用到集群: ``` kubectl apply -f ai-proxy-multi-ic.yaml ``` ❶ 将提供商配置为 `gemini`,以访问 Google AI Studio Gemini。 ❷ 在 `Authorization` 请求头中替换为你的 Gemini API Key。 ❸ 以 `` 格式指定通过 Google AI Studio 使用的 Gemini 模型名称。 ❹ 将提供商配置为 `vertex-ai`,以访问 Vertex AI Gemini。 ❺ 替换为你的 JSON 凭证。确保它是一个 JSON 转义字符串。 ❻ 替换为你的 Vertex AI 项目 ID 和区域。 ❼ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 ai-proxy-multi-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ai-proxy-multi-route spec: ingressClassName: apisix http: - name: ai-proxy-multi-route match: paths: - /anything methods: - POST plugins: - name: ai-proxy-multi enable: true config: fallback_strategy: - rate_limiting instances: - name: gemini-instance provider: gemini weight: 7 auth: header: Authorization: "Bearer YOUR_GEMINI_API_KEY" options: model: gemini-2.5-flash - name: vertex-ai-instance provider: vertex-ai weight: 3 auth: gcp: service_account_json: '{"type":"service_account","project_id":"api7-vertex","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----","client_email":"api7-docs@api7-vertex.iam.gserviceaccount.com","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/api7-docs%40api7-vertex.iam.gserviceaccount.com","universe_domain":"googleapis.com"}' provider_conf: project_id: api7-vertex region: us-central1 options: model: google/gemini-2.5-flash ``` 将配置应用到集群: ``` kubectl apply -f ai-proxy-multi-ic.yaml ``` ❶ 将提供商配置为 `gemini`,以访问 Google AI Studio Gemini。 ❷ 在 `Authorization` 请求头中替换为你的 Gemini API Key。 ❸ 以 `` 格式指定通过 Google AI Studio 使用的 Gemini 模型名称。 ❹ 将提供商配置为 `vertex-ai`,以访问 Vertex AI Gemini。 ❺ 替换为你的 JSON 凭证。确保它是一个 JSON 转义字符串。 ❻ 替换为你的 Vertex AI 项目 ID 和区域。 ❼ 以 `/` 格式指定通过 Vertex AI 使用的 Gemini 模型名称。 向该路由发送 10 个 POST 请求,以查看负载均衡分布: ``` studio_count=0 vertex_count=0 for i in {1..10}; do model=$(curl -s "http://127.0.0.1:9080/anything" -X POST \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { "role": "user", "content": "What is 1+1?" } ] }' | jq -r '.model') if [[ "$model" == "gemini-2.5-flash" ]]; then ((studio_count++)) elif [[ "$model" == "google/gemini-2.5-flash" ]]; then ((vertex_count++)) fi done echo "Google AI Studio Gemini responses: $studio_count" echo "Vertex AI Gemini responses: $vertex_count" ``` 你应该看到类似于以下的响应: ``` Google AI Studio Gemini responses: 7 Vertex AI Gemini responses: 3 ``` ### 配置实例优先级和速率限制[​](#配置实例优先级和速率限制 "配置实例优先级和速率限制的直接链接") 以下示例展示了如何配置两个具有不同优先级的模型,并对优先级较高的实例应用速率限制。在 `fallback_strategy` 设置为 `["rate_limiting"]` 的情况下,一旦高优先级实例的速率限制配额耗尽,插件应继续将请求转发给低优先级实例。 创建路由如下,并根据需要更新你的模型服务提供方、模型、API Key 和端点: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < -n -f values.yaml ``` 接下来,按照之前的示例创建一个带有 `ai-proxy-multi` 插件的路由并发送请求。例如,如果你发送如下请求: ``` curl "http://127.0.0.1:9080/anything" -X POST \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-3.5", "messages": [ { "role": "system", "content": "You are a mathematician" }, { "role": "user", "content": "What is 1+1?" } ] }' ``` 如果 `ai-proxy-multi` 中的 LLM 实例模型是 `gpt-4`,那么请求将被转发到 GPT-4 模型,你将收到类似于以下的响应: ``` { ..., "model": "gpt-4-0613", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "1+1 equals 2.", "refusal": null, "annotations": [] }, "logprobs": null, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 23, "completion_tokens": 8, "total_tokens": 31, "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 }, ... }, "service_tier": "default", "system_fingerprint": null } ``` 在网关的访问日志中,你应该会看到类似于以下的日志条目: ``` 192.168.215.1 - - [29/Aug/2025:09:54:16 +0000] 127.0.0.1:9080 "POST /anything HTTP/1.1" 200 808 2.670 "-" "curl/8.6.0" - - 2670 "http://127.0.0.1:9080" "6526bf5c961b6e6bb8cfcb66486f02dc" "ai_chat" "2670" "gpt-4" "gpt-3.5" "23" "8" "31" "false" "false" "0" "" "0" "0" "0" ``` 该访问日志条目显示:APISIX 上游响应时间为 `2.670` 秒,请求类型为 `ai_chat`,首 Token 时间为 `2670` 毫秒,请求转发到的 LLM 模型为 `gpt-4`,请求中的 LLM 模型为 `gpt-3.5`,提示词 Token 用量为 `23`,补全 Token 用量为 `8`,Token 总用量为 `31`;该请求为非流式请求,没有工具调用,请求中未提供工具,也没有终端用户标识符、提示词缓存 Token 或推理 Token。 ### 将请求日志发送到日志记录器[​](#将请求日志发送到日志记录器 "将请求日志发送到日志记录器的直接链接") 以下示例演示了如何记录请求和请求信息(包括 LLM 模型、令牌和负载),并将它们推送到日志记录器。在继续之前,你应该先设置一个日志记录器,例如 Kafka。有关更多信息,请参阅 [`kafka-logger`](https://docs.apiseven.com/hub/kafka-logger.md)。 创建到你的 LLM 服务的路由,并如下配置日志记录详细信息: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < -n --all -o yaml > values.yaml ``` 新增或更新以下值: values.yaml ``` apisix: pluginAttrs: ai-proxy: http_client: lua-resty-http ``` 然后使用当前 APISIX release 对应的 Chart 应用该 values 文件: ``` helm upgrade apisix/apisix -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * fallback\_strategy string or array 有效值: 字符串:`instance_health_and_rate_limiting`、`http_429` 或 `http_5xx`
数组:`rate_limiting`、`http_429` 和 `http_5xx` 的任意组合 *** 回退策略。选项 `instance_health_and_rate_limiting` 是为向后兼容保留的,功能上与 `rate_limiting` 相同。 当设置为 `rate_limiting` 或 `instance_health_and_rate_limiting` 时,如果当前实例的配额已用完,请求将转发到下一个实例(无论优先级如何)。当设置为 `http_429` 时,如果某个实例返回状态码 429,则请求会在其他实例上重试。当设置为 `http_5xx` 时,如果某个实例返回 5xx 状态码,则请求会在其他实例上重试。如果所有实例都失败,插件将返回最后一个上游状态码、响应体和 `Content-Type`。 当未设置时,如果高优先级实例的 Token 用尽,插件不会将请求转发到低优先级实例。 * max\_retries integer 有效值: 大于或等于 0 *** 初始请求失败后的最大回退重试次数。该配置限制单个请求最多尝试多少个额外实例,避免耗尽所有已配置的实例。仅在与 `fallback_strategy` 一起使用时生效。当未设置时,没有明确上限,插件会一直重试,直到某个实例成功或所有实例都已尝试。自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * retry\_on\_failure\_within\_ms integer 有效值: 大于或等于 1 *** 仅当上游在此毫秒数内失败时才回退到另一个实例。快速失败(例如连接错误以及快速返回的 429 或 5xx 响应)会被重试,而耗时超过该值的慢速失败会直接返回给客户端,以避免总等待时间翻倍。仅在与 `fallback_strategy` 一起使用时生效。当未设置时,无论失败尝试耗时多久,插件都会重试。自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * fallback\_http\_statuses array\[integer] 有效值: 每项介于 400 与 599 之间,且不重复 *** 除 `fallback_strategy` 中的 `http_429` 与 `http_5xx` 之外,还有哪些上游 HTTP 状态码会让请求回退到另一个实例。适用于表示该实例自身的凭据或配额有问题、而非请求本身有问题的状态码,例如密钥过期的 `401` 或账号被禁用的 `403`,使请求转由其他实例重试而不是直接返回给客户端。仅在配置了 `fallback_strategy` 时生效。在 API7 企业版 3.9.x 系列中自 3.9.19 起可用,在 3.10.x 系列中自 3.10.6 起可用。 * balancer object *** 负载均衡配置。 * algorithm string 默认值:`roundrobin` 有效值: `roundrobin`、`chash` 或 `semantic` *** 负载均衡算法。设置为 `roundrobin` 时,使用加权轮询算法。设置为 `chash` 时,使用一致性哈希算法。设置为 `semantic` 时,选择 `examples` 与提示词语义最接近的实例,相关配置位于 `semantic_opts` 下。 `semantic` 算法不参与健康检查、`fallback_strategy` 和 `max_retries`:所选实例的上游失败会直接返回客户端;只有在没有实例达到阈值或嵌入请求失败时,该算法才会回落。 `semantic` 自 API7 企业版 3.9.x 系列的 3.9.18 版本起可用,3.10.x 系列自 3.10.5 版本起可用;在 APISIX 中自 3.18.0 版本起可用。 * hash\_on string 默认值:`vars` 有效值: `vars`、`header`、`cookie`、`consumer` 或 `vars_combinations` *** 当 `type` 为 `chash` 时使用。支持基于[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)、请求头、Cookie、消费者或[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)的组合进行哈希。 * key string *** 当 `type` 为 `chash` 时使用。当 `hash_on` 设置为 `header` 或 `cookie` 时,`key` 为必填。当 `hash_on` 设置为 `consumer` 时,`key` 不是必需的,因为消费者名称将自动用作键。 * semantic\_opts object *** `semantic` 负载均衡算法的配置。当 `balancer.algorithm` 为 `semantic` 时必填,其它情况下会被忽略。 自 API7 企业版 3.9.x 系列的 3.9.18 版本起可用,3.10.x 系列自 3.10.5 版本起可用;在 APISIX 中自 3.18.0 版本起可用。 * embeddings object 必填 *** 用于把提示词和各实例的 `examples` 转换为向量的嵌入服务。每次请求都会对提示词做嵌入,因此该服务位于请求路径上。 * provider string 必填 有效值: `openai` 或 `azure-openai` *** 嵌入服务提供商。 * model string 必填 *** 嵌入模型名称,例如 `text-embedding-3-small`。 * endpoint string *** 嵌入 API 端点。对 `openai` 为可选,默认使用其公共 API;对 `azure-openai` 为必填,且必须是完整 URL,例如 `https://{resource}.openai.azure.com/openai/deployments/{deployment}/embeddings?api-version={version}`。 * auth object 必填 *** 嵌入服务的认证信息,通过请求头或查询参数携带。 * header object *** 以请求头形式发送给嵌入服务的键值对。 * query object *** 以查询参数形式发送给嵌入服务的键值对。 * timeout integer 默认值:`3000` 有效值: 大于或等于 1 *** 嵌入请求的超时时间,单位为毫秒。由于提示词是同步嵌入的,该值决定了嵌入服务变慢时每个请求最多额外增加的延迟。超时后请求会被路由到 fallback 实例,而不是直接失败。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则校验嵌入服务的 TLS 证书。 * threshold number 默认值:`0` 有效值: -1 到 1 之间(含) *** 实例被选中所需达到的全局最小余弦相似度。实例自身的 `threshold` 会覆盖该值。默认值 `0` 几乎接受任何提示词,因此只有把阈值设为大于 `0` 时才可能走到 fallback 实例。 * fallback string *** 当没有实例达到阈值或嵌入请求失败时,请求路由到的实例名称。该实例同样参与正常排名,因此也需要配置自己的 `examples`。未设置时默认使用第一个实例。 * debugging boolean 默认值:`false` *** 如果为 true,则通过 `X-AI-Semantic-Scores` 和 `X-AI-Semantic-Picked-Instance` 响应头返回各实例的相似度得分与路由结果。该选项用于调优 `examples` 和阈值,不建议在生产流量上开启。 * instances array\[object] 必填 *** LLM 实例配置。 * name string 必填 *** LLM 服务实例的名称。 * examples array\[string] 有效值: 1 到 64 个元素 *** 用于表示该实例所处理意图的示例语句。每条示例会被嵌入为各自的参考向量,语义负载均衡算法会把请求路由到示例与提示词最相似的那个实例。 当 `balancer.algorithm` 为 `semantic` 时,每个实例都必须配置该字段,包括 `semantic_opts.fallback` 指定的实例;其它算法会忽略该字段。 自 API7 企业版 3.9.x 系列的 3.9.18 版本起可用,3.10.x 系列自 3.10.5 版本起可用;在 APISIX 中自 3.18.0 版本起可用。 * threshold number 有效值: -1 到 1 之间(含) *** 语义负载均衡算法选中该实例所需的最小余弦相似度,会覆盖该实例上的 `semantic_opts.threshold`。 自 API7 企业版 3.9.x 系列的 3.9.18 版本起可用,3.10.x 系列自 3.10.5 版本起可用;在 APISIX 中自 3.18.0 版本起可用。 * provider string 必填 有效值: `openai`、`deepseek`、`azure-openai`、`aimlapi`、`gemini`、`vertex-ai`、`anthropic`、`openrouter`、`bedrock`、`openai-compatible` *** LLM 模型服务提供方。 当设置为 `openai` 时,插件会将检测到的 Chat Completions、Responses API 和 Embeddings 请求发送到对应的 OpenAI 端点。 当设置为 `deepseek` 时,插件会将请求代理到 `https://api.deepseek.com/chat/completions`。 当设置为 `gemini`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将请求代理到 `https://generativelanguage.googleapis.com/v1beta/openai/chat/completions`。如果要将请求代理到向量嵌入模型,应在 `override` 中配置向量嵌入模型端点。 当设置为 `vertex-ai`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将请求代理到 Google Cloud Vertex AI。对于聊天补全,插件会将请求代理到 `https://{region}-aiplatform.googleapis.com/v1beta1/projects/{project_id}/locations/{region}/endpoints/openapi/chat/completions`。对于向量嵌入,插件会将请求代理到 `https://{region}-aiplatform.googleapis.com/v1/projects/{project_id}/locations/{region}/publishers/google/models/{model}:predict`。这些端点要求在 `provider_conf` 中配置 `project_id` 和 `region`;也可以配置 `override` 使用自定义端点。 当设置为 `anthropic`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将检测到的 Chat Completions 请求发送到 `https://api.anthropic.com/v1/chat/completions`,并将原生 Anthropic Messages 请求发送到 `https://api.anthropic.com/v1/messages`。 当设置为 `openrouter`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将请求代理到 `https://openrouter.ai/api/v1/chat/completions`。 当设置为 `bedrock`(自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用)时,插件使用 Converse API 将请求代理到 AWS Bedrock。 当设置为 `aimlapi`(自 APISIX 3.14.0 和 API7 企业版 3.8.17 起可用)时,插件使用 OpenAI 兼容驱动并将请求代理到 `https://api.aimlapi.com/v1/chat/completions`。 当设置为 `openai-compatible` 时,插件会将请求代理到 `override` 中配置的自定义端点。 当设置为 `azure-openai` 时,插件同样会将请求代理到 `override` 中配置的自定义端点,并从用户请求中移除 `model` 参数。 * priority integer 默认值:`0` *** 负载均衡中 LLM 实例的优先级。`priority` 优先于 `weight`。 * weight integer 必填 有效值: 大于或等于 0 *** 负载均衡中 LLM 实例的权重。 * auth object 必填 *** 认证配置。 * header object *** 认证请求头。`header` 和 `query` 至少需配置其中之一。你可以配置额外的自定义请求头,这些请求头将被转发到上游 LLM 服务。 * query object *** 认证查询参数。`header` 和 `query` 至少需配置其中之一。 * gcp object *** Vertex AI 的 GCP 服务账号认证。自 API7 企业版 3.9.2 和 APISIX 3.17.0 起可用。 * service\_account\_json string *** 用于认证的 GCP 服务账号 JSON 内容。可以通过此参数配置,或通过设置 `GCP_SERVICE_ACCOUNT` 环境变量配置。 * max\_ttl integer *** GCP 访问令牌缓存的最大 TTL,单位为秒。 * expire\_early\_secs integer 默认值:`60` *** 访问令牌在其实际过期时间之前提前过期的时间(秒)。这可以防止在活跃请求期间令牌过期的边缘情况。 * aws object *** AWS IAM 凭证,用于 SigV4 签名。当 `provider` 为 `bedrock` 时必填(对于 Bedrock,`auth.aws` 即可满足认证需求,无需配置 `auth.header`/`auth.query`)。自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用。 * access\_key\_id string 必填 *** AWS IAM Access Key ID。 * secret\_access\_key string 必填 *** AWS IAM Secret Access Key。 * session\_token string *** 临时凭证(例如来自 STS AssumeRole)的 AWS 会话令牌。 * options object *** 模型配置。 除了 `model`,你还可以配置其他参数,这些参数将在请求体中转发到上游 LLM 服务。例如,如果你使用 OpenAI 或 DeepSeek,可以配置其他参数,如 `max_tokens`、`temperature`、`top_p` 和 `stream`。有关更多可用选项,请参阅你的模型服务提供方的 API 文档。 * model string *** LLM 模型的名称,例如 `gpt-4` 或 `gpt-3.5`。有关更多可用模型,请参阅你的模型服务提供方的 API 文档。 * provider\_conf object *** 服务提供方专属配置。当 `provider` 为 `bedrock` 时必填;当 `provider` 为 `vertex-ai` 时,需配置 `provider_conf` 或 `override.endpoint`。 自 API7 企业版 3.9.2 和 APISIX 3.17.0 起可用。 * project\_id string *** Vertex AI 的 Google Cloud 项目 ID。 * region string 必填 *** 云区域。对于 `vertex-ai`,这是 GCP 区域;对于 `bedrock`,这是 AWS 区域(例如 `us-east-1`)。 * override object *** 覆盖设置。 * endpoint string *** 用于替换根据检测到的请求协议所选端点的 LLM 模型服务提供方端点。 * llm\_options object *** 面向服务提供方的 LLM 选项覆盖。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * max\_tokens integer *** 输出 Token 的最大数量。网关会根据目标服务提供方自动映射到正确的字段名,例如 OpenAI Chat 使用 `max_completion_tokens`,OpenAI Responses API 使用 `max_output_tokens`,并覆盖客户端传入的值。 * request\_body object *** 按目标协议覆盖请求体。键可以是 `openai-chat`、`openai-responses`、`openai-embeddings`、`anthropic-messages`、`bedrock-converse` 和 `passthrough` 等目标协议名称。值是会深度合并到发送请求体中的部分请求体。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * request\_body\_force\_override boolean 默认值:`false` *** 为 `false`(默认值)时,客户端请求体字段优先,`request_body` 只填充缺失字段。为 `true` 时,`request_body` 中的值会覆盖客户端字段。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * checks object *** 健康检查配置。 请注意,目前 OpenAI 和 DeepSeek 没有提供官方的健康检查端点。你在 `openai-compatible` 服务提供方下配置的其他 LLM 服务可能有可用的健康检查端点。 * active object 必填 *** 主动健康检查配置。 * type string 默认值:`http` 有效值: `http`、`https` 或 `tcp` *** 健康检查连接类型。 * timeout number 默认值:`1` *** 健康检查超时时间,单位为秒。 * concurrency integer 默认值:`10` *** 同时检查的上游节点数量。 * host string *** HTTP 主机。 * port integer 有效值: 介于 1 和 65535 之间(含边界值) *** HTTP 端口。 * http\_path string 默认值:`/` *** HTTP 探测请求的路径。 * http\_method string 默认值:`GET` 有效值: `CONNECT`、`DELETE`、`GET`、`HEAD`、`OPTIONS`、`PATCH`、`POST`、`PURGE`、`PUT` 或 `TRACE` *** 主动健康检查探测请求的 HTTP 方法。在 API7 企业版以及 APISIX 3.18.0 及更高版本中可用。 * http\_req\_body string *** 主动健康检查探测请求中发送的请求体。当 `http_method` 设置为 `POST` 时非常有用。默认为空字符串。在 API7 企业版以及 APISIX 3.18.0 及更高版本中可用。 * https\_verify\_certificate boolean 默认值:`true` *** 如果为 true,则验证节点的 TLS 证书。 * healthy object *** 健康节点配置。 * interval integer 默认值:`1` *** 检查健康节点的时间间隔,单位为秒。 * http\_statuses array\[integer] 默认值:`[200,302]` 有效值: 介于 200 和 599 之间的状态码(含边界值) *** 定义健康节点的 HTTP 状态码数组。 * successes integer 默认值:`2` 有效值: 介于 1 和 254 之间(含边界值) *** 定义健康节点所需的成功探测次数。 * req\_headers array\[string] *** 健康检查探测请求中发送的额外 HTTP 头列表,格式为 `"Header: Value"`。 * unhealthy object *** 不健康节点配置。 * interval integer 默认值:`1` *** 检查不健康节点的时间间隔,单位为秒。 * http\_statuses array\[integer] 默认值:`[429,404,500,501,502,503,504,505]` 有效值: 介于 200 和 599 之间的状态码(含边界值) *** 定义不健康节点的 HTTP 状态码数组。 * http\_failures integer 默认值:`5` 有效值: 介于 1 和 254 之间(含边界值) *** 定义不健康节点所需的 HTTP 失败次数。 * tcp\_failures integer 默认值:`2` 有效值: 介于 1 和 254 之间(含边界值) *** 定义不健康节点所需的 TCP 失败次数。 * timeouts integer 默认值:`3` 有效值: 介于 1 和 254 之间(含边界值) *** 定义不健康节点所需的探测超时次数。 * logging object *** 日志配置。该配置适用于访问日志和发送到日志插件的日志,不影响错误日志。 * summaries boolean 默认值:`false` *** 如果为 true,则向日志条目添加 `llm_summary` 对象,其中包含模型、延迟和 Token 用量。在 API7 企业版 3.9.18、3.10.5 以及 APISIX 3.18.0 中,可用时该摘要还包含流状态、工具数量及使用情况、最终用户 ID、缓存读取与创建 Token 数、推理 Token 数和内容风险级别。 * payloads boolean 默认值:`false` *** 如果为 true,则记录请求和响应的负载。 * timeout integer 默认值:`30000` 有效值: 介于 1 和 600000 之间(含边界值) *** 对 LLM 服务进行每次连接、发送或阻塞读取操作的超时时间,单位为毫秒。该配置不限制流式响应的总持续时间;如需限制总持续时间,请使用 `max_stream_duration_ms`。 * max\_req\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** 插件读入内存的最大请求体大小,单位为字节。超过该大小的请求将以 HTTP 413 拒绝。该配置可防止大请求体导致的无限内存缓冲。默认值为 67108864 字节(64 MiB)。自 API7 企业版 3.9.x 版本线的 3.9.14、3.10.x 版本线的 3.10.1,以及 APISIX 3.17.0 起可用。 * max\_stream\_duration\_ms integer 有效值: 大于或等于 1 *** 流式 AI 响应允许占用的最长实际时间(毫秒)。该限制为可选配置。达到限制时,网关会关闭连接;若已开始输出,响应流会直接结束,不会附带 `[DONE]`、`message_stop` 或 `response.completed` 等协议终止标记。限制在两次上游读取之间执行,因此最后一个数据块可能超过配置的时长。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * max\_response\_bytes integer 有效值: 大于或等于 1 *** 单个流式或非流式 AI 响应从上游读取的最大总字节数。该限制为可选配置,并在两次上游读取之间检查,因此最后一个数据块可能超过限制。如果输出开始前超过限制,网关返回 `502 Bad Gateway`;输出开始后超过限制,网关直接关闭响应流且不发送协议终止标记。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * streaming\_flush\_interval\_ms integer 默认值:`10` 有效值: 大于或等于 0 *** 流式响应的后台刷新间隔,单位为毫秒。正值会定期刷新缓冲输出,以便在上游突发发送 Token 时限制客户端延迟。设置为 0 时同步刷新每个数据块。自 API7 企业版 3.9.13 和 APISIX 3.17.0 起可用。 * keepalive boolean 默认值:`true` *** 如果为 true,则在请求 LLM 服务时保持连接活跃。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 请求 LLM 服务时的 Keepalive 超时时间(毫秒)。 * keepalive\_pool integer 默认值:`30` 有效值: 大于或等于 1 *** 连接 LLM 服务时的 Keepalive 连接池大小。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则验证 LLM 服务的证书。 --- # 协议参考 `ai-proxy` 和 `ai-proxy-multi` 插件使用相同的请求协议检测与转换流程。该流程会先识别客户端格式,再将请求路由到已配置的服务提供方或所选实例。 有关插件专用配置,请参阅 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 和 [`ai-proxy-multi`](https://docs.apiseven.com/hub/ai-proxy-multi.md)。 ## 请求协议检测[​](#request-protocol-detection "请求协议检测的直接链接") 插件会先识别客户端协议,再将其与所选服务提供方或实例支持的协议进行匹配。以下检测规则适用于两个插件。 ### 请求要求[​](#请求要求 "请求要求的直接链接") 如果请求包含 `Content-Type`,其值必须为 `application/json`。如果省略该请求头,插件会将请求体视为 JSON。在选择服务提供方或实例前,插件会拒绝不支持的内容类型和无效请求体。 请求体不能超过 `max_req_body_size`,默认值为 67,108,864 字节。超过此限制的请求会收到 HTTP 413 响应。在 API7 网关中,此配置自 3.9.x 版本线的 3.9.14 和 3.10.x 版本线的 3.10.1 起可用;在 APISIX 3.17.0 及更高版本中可用。 ### 检测顺序[​](#检测顺序 "检测顺序的直接链接") 插件按以下顺序检查规则: | 客户端协议 | 请求体信号 | 路径要求 | | ----------------------- | ------------------------------------------ | --------------------------------------------- | | Bedrock Converse | 请求体包含 `messages` 数组。 | 路径以 `/converse` 结尾;允许自定义前缀。 | | Anthropic Messages | 请求体是 JSON 对象。 | 路径以 `/v1/messages` 结尾;允许自定义前缀。 | | OpenAI Responses | 请求体包含 `input`。 | 路径以 `/v1/responses` 结尾;允许自定义前缀。 | | OpenAI Chat Completions | 请求体包含 `messages` 数组。 | 路由匹配的任意路径。 | | OpenAI Embeddings | 请求体包含 `input`,且前面的规则均不匹配。 | 路由匹配的任意路径。 | 路径特定规则会先于仅基于请求体的规则执行,从而避免将包含 `messages` 的 Bedrock Converse 和 Anthropic Messages 请求识别为 Chat Completions。Responses 和 Embeddings 请求都使用 `input`,因此包含 `input` 但不包含 `messages` 的请求会被识别为 Embeddings,除非其路径以 `/v1/responses` 结尾。 其他任何非空 JSON 对象都会按透传处理。只要请求转换未改变请求体,此模式会保留原始请求路径,并可以复用原始请求体。服务提供方身份认证和 `override.endpoint` 仍然生效。空请求体或无效请求体会被拒绝。 透传模式不会向下游 AI 感知插件提供 AI 协议模型,因此不会执行用量提取、提示词装饰或模板处理、内容审核文本提取以及协议转换。 ### 检测后处理[​](#检测后处理 "检测后处理的直接链接") 对于已命名的协议,如果所选服务提供方支持该协议,插件会直接使用检测到的协议而不执行转换。否则,插件会查找已注册的转换器,将请求转换为服务提供方支持的协议。如果既没有原生支持,也没有兼容的转换器,请求会被拒绝。 检测到的协议和请求体决定日志插件将 `request_type` 记录为 `ai_stream` 还是 `ai_chat`。响应解析则根据上游响应的内容类型区分流式与非流式响应。 ## 请求覆盖优先级[​](#request-override-precedence "请求覆盖优先级的直接链接") 最终插件配置使用 `override.llm_options.max_tokens` 进行服务提供方感知的 Token 限制映射。服务提供方先将该值映射到目标协议预期的字段,再应用匹配的 `override.request_body` 对象。 请求体对象采用递归合并;数组和标量直接替换,不会合并。`request_body_force_override: false` 时客户端字段优先,覆盖配置只补充缺失字段;设为 `true` 时覆盖值优先并替换同名客户端字段。请求体键使用完成协议转换后的目标协议名称,例如 `openai-chat`、`anthropic-messages` 或 `bedrock-converse`。 ## 失败响应[​](#failure-responses "失败响应的直接链接") | 条件 | 客户端可见行为 | | ----------------------------------------- | ------------------------------ | | 请求体超过 `max_req_body_size` | `413 Request Entity Too Large` | | 在收到可用响应前,LLM 连接或读取超时 | `504 Gateway Timeout` | | 流式转换器无法按所选格式解析响应 | `502 Bad Gateway` | | `ai-request-rewrite` 收到没有请求体的请求 | `400 Bad Request` | 如果在流式输出开始后达到响应限制,网关会关闭下游响应流。已发送的字节无法替换为新的 HTTP 错误响应。 ## Anthropic 到 OpenAI 的转换[​](#anthropic-to-openai-conversion "Anthropic 到 OpenAI 的转换的直接链接") Anthropic Messages 客户端可以通过 `ai-proxy` 或 `ai-proxy-multi` 向支持 OpenAI Chat Completions 的后端发送请求。插件会将客户端请求转换为 OpenAI 格式,并将后端响应转换为 Anthropic 格式。此转换只支持 Anthropic Messages API 的一部分:保留部分字段、转换其他字段,并丢弃不支持的字段。 ### 何时执行转换[​](#何时执行转换 "何时执行转换的直接链接") 当请求路径以 `/v1/messages` 结尾且请求体是 JSON 对象时,插件会将其识别为 Anthropic Messages 请求。如果所选服务提供方支持 Anthropic Messages,请求会直接使用该协议而不进行转换。如果服务提供方支持的是 OpenAI Chat Completions,共享转换器会转换请求和响应。 不支持相反的客户端/后端组合:OpenAI Chat Completions 客户端不能使用此转换器调用 Anthropic Messages 后端。 对于 `ai-proxy-multi`,是否需要转换由所选实例决定。[转换配置示例](https://docs.apiseven.com/hub/ai-proxy.md#convert-anthropic-requests-to-openai-compatible-backend)使用 `ai-proxy`;有关多实例配置,请参阅 [`ai-proxy-multi`](https://docs.apiseven.com/hub/ai-proxy-multi.md)。 ### 请求转换[​](#请求转换 "请求转换的��直接链接") 转换后的请求体根据允许列表构建。下表汇总转换器会读取的 Anthropic 输入。无法识别的字段会在请求到达后端前被丢弃。 #### 请求字段[​](#请求字段 "请求字段的直接链接") | Anthropic 字段 | OpenAI 字段 | 行为 | | --------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | `model` | 转发;但如果路由通过 `options.model` 固定模型,则不转发。 | | `max_tokens` | `max_completion_tokens` | 重命名。 | | `stop_sequences` | `stop` | 重命名。 | | `temperature`、`top_p` | 同名字段 | 转发。 | | `stream` | `stream`,以及 `stream_options.include_usage` | 插件设置 `stream_options.include_usage`,使流中包含用量信息。 | | `system` | 位于消息开头且 `role: system` 的消息 | 文本块会拼接成一个字符串。 | | `tools[]`(自定义工具) | `tools[].function` | 如果工具名称包含 `[a-zA-Z0-9_-]` 以外的字符,或长度超过 64 个字符,则会改写为符合 OpenAI 命名规则的名称;响应中会恢复原名称。 | | `tool_choice` | `tool_choice` | 转换:`{"type": "auto"}` 变为 `"auto"`,`{"type": "any"}` 变为 `"required"`,`{"type": "none"}` 变为 `"none"`,`{"type": "tool", "name": "..."}` 变为指定该函数的对象。 | | `tool_choice.disable_parallel_tool_use` | `parallel_tool_calls: false` | 转换。 | | `thinking` | `reasoning_effort` | 近似转换。连续的 `budget_tokens` 值会映射到一个离散的推理强度级别;阈值取决于版本。 | | `output_config.effort` | `reasoning_effort` | 当 `thinking.type` 为 `adaptive` 时使用。不同版本支持情况不同,请参阅[版本兼容性](#release-compatibility)。 | | `output_format`、`output_config.format` | `response_format` | 不同版本支持情况不同,请参阅[版本兼容性](#release-compatibility)。 | | `metadata.user_id` | `user` | 重命名。 | | `service_tier` | `service_tier` | 转发。 | #### 消息内容[​](#消息内容 "消息内容的直接链接") | Anthropic 内容 | OpenAI 等效形式 | 行为 | | --------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------- | | 字符串形式的 `messages[].content` | 内容相同的字符串形式 `messages[].content` | 转发。 | | `text` | 文本内容部分或纯字符串 | 具体形式取决于版本,请参阅[版本兼容性](#release-compatibility)。 | | 使用 Base64 源的 `image` | 使用 `data:` URL 的 `image_url` | 转换。后端模型是否接受图片输入因模型而异。 | | 使用 URL 源的 `image` | 使用相同 URL 的 `image_url` | 原样转发。 | | 使用 Base64 源的 `document` | 使用 `data:` URL 的 `image_url` | 近似转换。文档字节会放入 OpenAI Schema 定义为图片的字段中,因此后端是否接受不在该 Schema 的保证范围内。 | | `tool_use` | 包含 `tool_calls` 的助手消息 | 转换。消息历史中的工具名称处理取决于版本,请参阅[版本兼容性](#release-compatibility)。 | | `tool_result` | `role: tool` 的消息 | 转换。其与普通文本的相对顺序取决于版本,请参阅[版本兼容性](#release-compatibility)。 | #### 丢弃的字段[​](#丢弃的字段 "丢弃的字段的直接链接") 后端不会收到以下字段,响应中也不会提示字段已被移除: | Anthropic 字段 | 丢弃原因 | | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `top_k` | OpenAI Chat Completions 没有等效参数。 | | `cache_control` | 没有等效字段;转换后的请求不包含缓存指令。 | | `citations` | 转换器在两个方向都不映射引用。 | | 消息历史中的 `thinking` 和 `redacted_thinking` 块 | OpenAI Chat Completions 没有等效字段;同一助手消息中的普通文本会保留。 | | Anthropic 内置工具(`computer_`、`bash_`、`text_editor_`、`web_search`、`code_execution_`) | 转换器没有这些工具的映射。 | #### 请求头[​](#请求头 "请求头的直接链接") 如果请求包含 `x-api-key` 请求头但不包含 `Authorization` 请求头,转换器会将该 Key 作为 Bearer Token 放入 `Authorization`。它会移除原始 `x-api-key` 请求头,以及名称以 `anthropic-` 或 `x-stainless-` 开头的请求头。 ### 响应转换[​](#响应转换 "响应转换的直接链接") 转换器只读取 `choices[0]` 中的补全字段;其他 OpenAI choice 会被丢弃。顶层 `usage` 和 `error` 字段会单独映射。 | OpenAI 响应字段 | Anthropic 响应 | 行为 | | -------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `message.content` | `text` 内容块 | 转换。 | | `message.reasoning_content` 或 `message.reasoning` | `thinking` 内容块 | 后端返回非空字符串时转换。非流式块的签名为空,请参阅[已知限制](#known-limitations)。 | | `message.tool_calls` | `tool_use` 内容块 | 转换。如果原始名称可用,会恢复经过规范化的工具名称。 | | `finish_reason` | `stop_reason` | `stop` 和 `content_filter` 变为 `end_turn`;`length` 变为 `max_tokens`;`tool_calls` 和 `function_call` 变为 `tool_use`。其他值默认为 `end_turn`。 | | `usage` | `input_tokens`、`output_tokens` 和可用的缓存 Token 字段 | `prompt_tokens` 变为 `input_tokens`,`completion_tokens` 变为 `output_tokens`。如果缓存详情可用,会从 `input_tokens` 中扣除缓存的提示词 Token,并报告为 `cache_read_input_tokens`;如果提供了 `cache_creation_input_tokens`,也会包含该字段。 | | `error` | Anthropic 错误对象 | 正常解析的上游响应体包含错误对象时转换。HTTP 429、5xx 和传输错误可能绕过此转换。 | 对于流式响应,转换器会为 OpenAI 文本、推理和工具调用增量发出 Anthropic 消息及内容块事件。初始 `message_start` 中的用量值为零;最终 Token 用量在 `message_delta` 中发出。如果后端在受支持的用量块中提供缓存 Token 字段,也可以包含这些字段。报告流式用量的客户端应读取最终事件,且不应假设缓存 Token 字段一定存在。 ### 版本兼容性[​](#release-compatibility "版本兼容性的直接链接") API7 网关 3.9.x 和 3.10.x 会分别接收修复。请查看实际运行版本所在的列。 | 行为 | API7 网关 3.9.x | API7 网关 3.10.x | APISIX | | ------------------------------------------------------------------------------------ | ----------------- | ----------------- | --------------- | | 所有工具都被丢弃时,移除失去关联的 `tool_choice` | 3.9.16 及更高版本 | 3.10.2 及更高版本 | 3.17.0 中不支持 | | 后端工具调用格式错误时降级处理,而不是使响应失败 | 3.9.16 及更高版本 | 3.10.2 及更高版本 | 3.17.0 中不支持 | | 将 `message_start.content` 序列化为数组 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | 识别 Anthropic 当前的结构化输出形式 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | `thinking.type: adaptive` 使用 `output_config.effort` | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | `thinking.budget_tokens` 使用下述四级映射 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | 将仅含一个文本块的用户消息作为内容数组发送,并把包含多个文本块的助手消息拼接为字符串 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | 消息历史中的工具名称与声明的工具保持一致地改写 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | `tool_result` 消息放在同一用户消息的普通文本之前 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | | 用户消息同时包含 `tool_result` 时保留媒体内容 | 3.9.16 及更高版本 | 3.10.3 及更高版本 | 3.17.0 中不支持 | 这些版本差异会影响结构化输出、消息内容、推理强度和工具历史,具体如下。 #### 结构化输出[​](#结构化输出 "结构化输出的直接链接") API7 网关 3.9.15 及更早版本、API7 网关 3.10.0 至 3.10.2,以及 APISIX 3.17.0,只能识别转换器过去预期的形式:`output_config` 或 `output_format` 包含 `type: json_schema` 及 `json_schema` 字段,或者包含 `type: json` 或 `type: json_object`。 Anthropic 当前会把 Schema 放在 `output_format.schema` 或 `output_config.format` 中。API7 网关 3.9.x 从 3.9.16 起识别这种形式;3.10.x 从 3.10.3 起识别。这些版本会规范化 Schema,并发送启用严格模式的 `response_format`。在更早版本中,后端不会收到 `response_format`,客户端也不会收到错误。 #### 消息内容形式[​](#消息内容形式 "消息内容形式的直接链接") 在早于该项变更的版本中,只包含一个文本块的用户消息会以纯字符串发送;包含多个文本块的助手消息会以内容数组发送。只接受其中一种形式的后端,在升级前后会表现不同。 #### 推理强度[​](#推理强度 "推理强度的直接链接") 不同版本使用不同的 `budget_tokens` 映射。较早的映射适用于 APISIX 3.17.0,以及 API7 网关对应版本线中早于 3.9.16 或 3.10.3 的版本。较新的映射分别从 API7 网关 3.9.16 和 3.10.3 起适用。 | `budget_tokens` | 较早版本 | 较新版本 | | --------------- | -------- | --------- | | 小于 1024 | `low` | `minimal` | | 1024 至 2047 | `low` | `low` | | 2048 至 4095 | `low` | `medium` | | 4096 至 16383 | `medium` | `high` | | 16384 或更高 | `high` | `high` | | 未提供 | `medium` | `minimal` | #### 工具历史[​](#工具历史 "工具历史的直接链接") 在较早版本中,消息历史里的 `tool_use` 名称不会按照相应的已声明工具名称改写。同一用户消息中的普通文本也可能先于 `tool_result` 消息发送,并且该消息中的媒体内容会被丢弃。严格的后端可能会拒绝名称或顺序不匹配。API7 网关 3.9.16 及更高版本和 API7 网关 3.10.3 及更高版本会一致地改写历史名称、优先放置工具消息并保留媒体内容。 ### 已知限制[​](#known-limitations "已知限制的直接链接") 以下限制可能会影响所有受支持版本中的转换请求和响应。 #### 流式传输可能在没有终止事件的情况下结束[​](#流式传输可能在没有终止事件的情况下结束 "流式传输可能在没有终止事件的情况下结束的直接链接") 如果后端关闭流时没有发送格式正确、分隔完整的最后一帧,插件不会发出结尾的 `message_delta` 和 `message_stop` 事件。依赖 `message_stop` 的客户端可能无限等待,或将该流视为不完整。上述所有版本都会受到影响。请设置客户端超时,并将流意外结束视为失败。 #### 转换后的 `thinking` 块不包含有效签名[​](#转换后的-thinking-块不包含有效签名 "转换后的-thinking-块不包含有效签名的直接链接") 对于非流式响应,插件会将该块的 `signature` 设置为空字符串;对于流式响应,插件会发出不含签名的 thinking 增量。要求有效签名的客户端无法将任一转换形式作为已签名的 Anthropic thinking 块重放。如果后端把推理内容嵌入普通消息内容,响应中的推理会显示为可见文本。 #### 错误响应不一定采用 Anthropic 格式[​](#错误响应不一定采用-anthropic-格式 "错误响应不一定采用 Anthropic 格式的直接链接") HTTP 429、5xx 和传输超时响应可能绕过响应转换。客户端应做好接收不符合 Anthropic 错误 Schema 的上游或网关错误响应体的准备。 #### 不验证后端能力[​](#不验证后端能力 "不验证后端能力的直接链接") 插件会转换请求,但不会检查后端模型是否支持转换结果。后端可能返回 HTTP 200,却静默忽略某项能力,例如丢弃图片、忽略 `response_format` 或不返回工具调用。 不同模型的后端行为不同,同一模型名称的不同日期快照也可能不同。请验证计划使用的具体模型,不要根据某个后端笼统推断。 ### 验证后端兼容性[​](#验证后端兼容性 "验证后端兼容性的直接链接") 请针对每个后端模型测试以下转换输入,因为即使原始 Anthropic 请求有效,后端仍可能拒绝它们: * **指定名称的 `tool_choice`。** 转换器会输出指定函数的对象或 `"required"`。有些后端在模型进行推理时只接受 `"auto"`。如果后端拒绝转换后的形式,请从客户端发送 `{"type": "auto"}`。 * **`thinking` 与较小的 `max_tokens` 同时使用。** `thinking` 会变为 `reasoning_effort`,可能使后端预留推理预算。如果该预算超过转换后的 `max_completion_tokens`,后端会拒绝请求。启用 `thinking` 时请提高 `max_tokens`。 * **`document` 块。** 转换器只能将其作为图片提供给后端。无法读取它的模型可能会生成虚构内容,而不是报告错误。 * **混合文本、媒体和 `tool_result` 内容。** 较早版本可能会把普通文本放在转换后的工具消息之前,并丢弃同一用户消息中的媒体内容。如果后端验证工具消息顺序,请测试这种形式,或升级到会先放置工具消息并保留媒体内容的版本。 ## 相关配置[​](#相关配置 "相关配置的直接链接") * [配置 `ai-proxy` 转换 Anthropic 请求](https://docs.apiseven.com/hub/ai-proxy.md#convert-anthropic-requests-to-openai-compatible-backend)。 * [配置原生 Anthropic Messages 透传](https://docs.apiseven.com/hub/ai-proxy.md#native-anthropic-messages-api-pass-through)。 * [配置 `ai-proxy-multi`](https://docs.apiseven.com/hub/ai-proxy-multi.md)。 * [使用 API7 网关转换 Anthropic Messages](https://docs.apiseven.com/api7-gateway/ai-gateway/use-cases/protocol-conversion.md)。 --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * provider string 必填 有效值: `openai`、`deepseek`、`azure-openai`、`aimlapi`、`gemini`、`vertex-ai`、`anthropic`、`openrouter`、`bedrock`、`openai-compatible` *** LLM 模型服务提供方。 当设置为 `openai` 时,插件会将检测到的 Chat Completions、Responses API 和 Embeddings 请求发送到对应的 OpenAI 端点。 当设置为 `deepseek` 时,插件会将请求代理到 `https://api.deepseek.com/chat/completions`。 当设置为 `gemini`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将请求代理到 `https://generativelanguage.googleapis.com/v1beta/openai/chat/completions`。如果要将请求代理到向量嵌入模型,应在 `override` 中配置向量嵌入模型端点。 当设置为 `vertex-ai`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将请求代理到 Google Cloud Vertex AI。对于聊天补全,插件会将请求代理到 `https://{region}-aiplatform.googleapis.com/v1beta1/projects/{project_id}/locations/{region}/endpoints/openapi/chat/completions`。对于向量嵌入,插件会将请求代理到 `https://{region}-aiplatform.googleapis.com/v1/projects/{project_id}/locations/{region}/publishers/google/models/{model}:predict`。这些端点要求在 `provider_conf` 中配置 `project_id` 和 `region`;也可以配置 `override` 使用自定义端点。 当设置为 `anthropic`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将检测到的 Chat Completions 请求发送到 `https://api.anthropic.com/v1/chat/completions`,并将原生 Anthropic Messages 请求发送到 `https://api.anthropic.com/v1/messages`。 当设置为 `openrouter`(自 APISIX 3.15.0 和 API7 企业版 3.9.2 起可用)时,插件会将请求代理到 `https://openrouter.ai/api/v1/chat/completions`。 当设置为 `bedrock`(自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用)时,插件使用 [Converse API](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html) 将请求代理到 AWS Bedrock。需要在 `auth.aws` 中配置 IAM 凭证,并在 `provider_conf.region` 中配置 AWS 区域。当请求体中的 `stream` 设置为 `true` 时,支持非流式和流式(ConverseStream)响应。 当设置为 `aimlapi`(自 APISIX 3.14.0 和 API7 企业版 3.8.17 起可用)时,插件使用 OpenAI 兼容驱动并将请求代理到 `https://api.aimlapi.com/v1/chat/completions`。 当设置为 `openai-compatible` 时,插件会将请求代理到 `override` 中配置的自定义端点。 当设置为 `azure-openai` 时,插件同样会将请求代理到 `override` 中配置的自定义端点,并从用户请求中移除 `model` 参数。 * auth object 必填 *** 认证配置。 * header object *** 身份认证请求头。 * query object *** 认证查询参数。 * gcp object *** Vertex AI 的 GCP 服务账号认证。自 API7 企业版 3.9.2 和 APISIX 3.17.0 起可用。 * service\_account\_json string *** 用于认证的 GCP 服务账号 JSON 内容。可以使用此参数配置,也可以通过设置 `GCP_SERVICE_ACCOUNT` 环境变量来配置。 * max\_ttl integer *** GCP 访问令牌缓存的最大 TTL(秒)。 * expire\_early\_secs integer 默认值:`60` *** 在实际过期时间之前使访问令牌过期的秒数。这可以防止在活动请求期间令牌过期的边缘情况。 * aws object *** AWS IAM 凭证,用于 SigV4 签名。当 `provider` 为 `bedrock` 时必填(对于 Bedrock,`auth.aws` 即可满足认证需求,无需配置 `auth.header`/`auth.query`)。自 API7 Enterprise 3.9.12 和 APISIX 3.17.0 起可用。 * access\_key\_id string 必填 *** AWS IAM 访问密钥 ID。 * secret\_access\_key string 必填 *** AWS IAM 秘密访问密钥。 * session\_token string *** AWS 临时凭证的会话令牌(例如来自 STS AssumeRole)。 * options object *** 模型配置。 除了 `model` 之外,你还可以配置其他参数,它们将在请求体中转发到上游 LLM 服务。例如,如果你使用 OpenAI,你可以配置 `temperature`、`top_p` 和 `stream` 等附加参数。更多可用选项请参见你的模型服务提供方的 API 文档。 * model string *** LLM 模型名称,例如 `gpt-4` 或 `gpt-3.5`。更多可用模型请参见你的模型服务提供方 API 文档。 * provider\_conf object *** 提供商特定配置。当 `provider` 为 `bedrock` 时必填;当 `provider` 为 `vertex-ai` 时,需配置 `provider_conf` 或 `override.endpoint`。 自 API7 企业版 3.9.2 和 APISIX 3.17.0 起可用。 * project\_id string *** Google Cloud Project ID。当 `provider` 为 `vertex-ai` 时必填。 * region string 必填 *** 云区域。对于 `vertex-ai`,为 GCP 区域。对于 `bedrock`,为 AWS 区域(如 `us-east-1`)。 * override object *** 覆盖设置。 * endpoint string *** 模型服务提供方端点。当 `provider` 为 `openai-compatible` 时必填。 * llm\_options object *** 感知提供商的 LLM 选项覆盖。自 API7 Enterprise 版本 3.9.10 和 APISIX 3.17.0 起可用。 * max\_tokens integer *** 最大输出 token 数。网关自动将此值映射为目标提供商的正确字段名(例如 OpenAI Chat 的 `max_completion_tokens`,OpenAI Responses API 的 `max_output_tokens`)。始终强制覆盖客户端值。 * request\_body object *** 按目标协议的请求体覆盖。键为目标协议名称(`openai-chat`、`openai-responses`、`openai-embeddings`、`anthropic-messages`、`bedrock-converse`、`passthrough`);值为部分请求体,深度合并到发出的请求体中(对象递归合并,数组和标量整体替换)。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * request\_body\_force\_override boolean 默认值:`false` *** 当为 `false`(默认)时,客户端请求体字段优先,`request_body` 覆盖值仅填充缺失字段。当为 `true` 时,`request_body` 覆盖值强制覆盖客户端字段。自 API7 Enterprise 版本 3.9.10 和 APISIX 3.17.0 起可用。 * logging object *** 日志配置。该配置适用于访问日志和发送到日志插件的日志,不影响错误日志。 * summaries boolean 默认值:`false` *** 如果为 true,在日志条目中添加 `llm_summary` 对象,其中包含模型、延迟和 Token 用量。在 API7 企业版 3.9.18 和 3.10.5,以及 APISIX 3.18.0 中,该摘要还会在可用时包含流式状态、工具数量和用量、终端用户 ID、缓存读取和创建 Token、推理 Token,以及内容风险等级。 * payloads boolean 默认值:`false` *** 如果为 true,记录请求和响应 Payload。 * timeout integer 默认值:`30000` 有效值: 介于 1 和 600000 之间(含边界值) *** 连接、发送或阻塞读取 LLM 服务时,每次操作的超时时间(毫秒)。它不限制流式响应的总时长;如需设置总时长限制,请使用 `max_stream_duration_ms`。 * max\_req\_body\_size integer 默认值:`67108864` *** 插件读取到内存中的最大请求体大小,单位为字节(默认 67108864 字节,即 64 MiB)。请求体大于此限制时将以 HTTP 413 被拒绝,从而避免大请求体造成无限制内存缓冲。自 API7 企业版 3.9.x 版本线的 3.9.14、3.10.x 版本线的 3.10.1,以及 APISIX 3.17.0 起可用。 * keepalive boolean 默认值:`true` *** 如果为 true,在请求 LLM 服务时保持连接活动。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 请求 LLM 服务时的 Keepalive 超时时间(毫秒)。 * keepalive\_pool integer 默认值:`30` 有效值: 大于或等于 1 *** 连接 LLM 服务时的 Keepalive 连接池大小。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,验证 LLM 服务的证书。 * max\_stream\_duration\_ms integer *** 流式 AI 响应允许占用的最长实际时间(毫秒)。该限制为可选配置。达到限制时,网关会关闭连接;若已开始输出,响应流会直接结束,不会附带 `[DONE]`、`message_stop` 或 `response.completed` 等协议终止标记。限制在两次上游读取之间执行,因此最后一个数据块可能超过配置的时长。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * max\_response\_bytes integer *** 单个流式或非流式 AI 响应从上游读取的最大总字节数。该限制为可选配置,并在两次上游读取之间检查,因此最后一个数据块可能超过限制。如果输出开始前超过限制,网关返回 `502 Bad Gateway`;输出开始后超过限制,网关直接关闭响应流且不发送协议终止标记。自 API7 企业版 3.9.10 和 APISIX 3.17.0 起可用。 * streaming\_flush\_interval\_ms integer 默认值:`10` *** 流式响应的后台 flush 间隔,单位为毫秒。正整数会启动后台线程周期性 flush 输出,用于在上游一次性突发多个 token 时限制客户端侧延迟。设置为 0 时禁用后台线程,并对每个 chunk 执行同步 inline flush。自 API7 企业版 3.9.13 和 APISIX 3.17.0 起可用。 --- # ai-rag `ai-rag` 插件实现检索增强生成(RAG)请求流程中的检索步骤。它根据请求生成嵌入并执行向量搜索,然后将检索到的内容添加到协议对应的 LLM 输入中,移除 `ai_rag` 对象后再代理请求。 当前实现使用 [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) 生成嵌入,并使用 [Azure AI Search](https://azure.microsoft.com/en-us/products/ai-services/ai-search) 执行向量搜索。请在同一请求流程中使用 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 插件,将增强后的请求代理到 LLM 服务提供方。该插件不会创建或填充搜索索引;通过 APISIX 发送请求之前,请先准备好索引及其内容。
## 按请求格式处理[​](#按请求格式处理 "按请求格式处理的直接链接") 该插件使用各协议的原生提示词结构丰富 Chat Completions、Responses API、Anthropic Messages 和 Bedrock Converse 请求。 网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式: * Bedrock Converse 要求 URI 以 `/converse` 结尾且包含 `messages` 数组。 * Anthropic Messages 要求 URI 以 `/v1/messages` 结尾。 * Responses API 要求 URI 以 `/v1/responses` 结尾且包含 `input` 字段。 * Chat Completions 使用 `messages` 数组。 * 当前面的规则均不匹配时,Embeddings 使用 `input`。 * 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。 | 请求格式 | 上下文增强方式 | | ------------------ | --------------------------------------------------------------------------------- | | Bedrock Converse | 将检索到的上下文作为用户消息追加到 `messages`。 | | Anthropic Messages | 将检索到的上下文作为用户消息追加到 `messages`。 | | Responses API | 将检索到的上下文追加到 `input`。 | | Chat Completions | 将检索到的上下文作为用户消息追加到 `messages`。 | | Embeddings | 不增强请求。嵌套的 `ai_rag.embeddings` 对象用于配置内部检索所使用的向量嵌入输入。 | | 其他 JSON(透传) | 不增强请求。 | ## 验证上游 TLS[​](#verify-upstream-tls "验证上游 TLS的直接链接") 自 API7 企业版 3.9.10 和 APISIX 3.17.0 起,调用嵌入服务和向量搜索服务时,`ssl_verify` 默认值为 `true`。生产环境启用插件前,应为两个端点配置可信证书链。仅在临时迁移或开发场景中,才可将 `ssl_verify` 设置为 `false` 以连接使用不受信任证书的端点。 ## 示例[​](#示例 "示例的直接链接") 要跟随示例进行操作,请先创建一个 [Azure 账户](https://portal.azure.com) 并完成以下步骤: * 在 [Azure AI Foundry](https://oai.azure.com/portal) 中部署一个生成式对话模型(如 `gpt-4o`)和一个嵌入模型(如 `text-embedding-3-large`)。获取 API Key 和模型端点。 * 按照 [Azure 的示例](https://github.com/Azure/azure-search-vector-samples/blob/main/demo-python/code/basic-vector-workflow/azure-search-vector-python-sample.ipynb) 使用 Python 在 [Azure AI Search](https://azure.microsoft.com/en-us/products/ai-services/ai-search) 中准备向量搜索。该示例将创建一个名为 `vectest` 的搜索索引,并包含所需的架构,同时上传包含 108 条各类 Azure 服务描述的[示例数据](https://github.com/Azure/azure-search-vector-samples/blob/main/data/text-sample.json),以便根据 `title` 和 `content` 生成嵌入 `titleVector` 和 `contentVector`。在 Python 中执行向量搜索之前,请完成所有设置。 * 在 [Azure AI Search](https://azure.microsoft.com/en-us/products/ai-services/ai-search) 中,[获取 Azure 向量搜索 API Key 和搜索服务端点](https://learn.microsoft.com/en-us/azure/search/search-get-started-vector?tabs=api-key#retrieve-resource-information)。 将 API Key 和端点保存到环境变量中: ``` # 替换为你的配置值 export AZ_OPENAI_DOMAIN=https://your-openai-resource.openai.azure.com export AZ_OPENAI_API_KEY=your-azure-openai-api-key export AZ_CHAT_ENDPOINT=${AZ_OPENAI_DOMAIN}/openai/deployments/gpt-4o/chat/completions?api-version=2024-02-15-preview export AZ_EMBEDDING_MODEL=text-embedding-3-large export AZ_EMBEDDINGS_ENDPOINT=${AZ_OPENAI_DOMAIN}/openai/deployments/${AZ_EMBEDDING_MODEL}/embeddings?api-version=2023-05-15 export AZ_AI_SEARCH_SVC_DOMAIN=https://your-search-service.search.windows.net export AZ_AI_SEARCH_KEY=your-azure-ai-search-api-key export AZ_AI_SEARCH_INDEX=vectest export AZ_AI_SEARCH_ENDPOINT=${AZ_AI_SEARCH_SVC_DOMAIN}/indexes/${AZ_AI_SEARCH_INDEX}/docs/search?api-version=2024-07-01 ``` ### 集成 Azure 以生成 RAG 增强响应[​](#集成-azure-以生成-rag-增强响应 "集成 Azure 以生成 RAG 增强响应的直接链接") 以下示例演示了如何使用 [`ai-proxy`](https://docs.apiseven.com/hub/ai-proxy.md) 插件代理请求到 Azure OpenAI 大语言模型,并使用 `ai-rag` 插件生成嵌入并执行向量搜索,以增强大语言模型的响应。 * Admin API * ADC * Ingress Controller 创建路由如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. ``` 4. 验证集群节点: ``` docker exec -it redis-node-7000 redis-cli -c -a redis-cluster-password -p 7000 cluster nodes ``` 预期输出应类似于以下内容: ``` node-id-1 172.XX.0.2:7000@17000 myself,master - 0 0 1 connected 0-5460 node-id-2 172.XX.0.3:7001@17001 master - 0 0 2 connected 5461-10922 node-id-3 172.XX.0.4:7002@17002 master - 0 0 3 connected 10923-16383 node-id-4 172.XX.0.5:7003@17003 slave node-id-1 0 0 1 connected node-id-5 172.XX.0.6:7004@17004 slave node-id-2 0 0 2 connected node-id-6 172.XX.0.7:7005@17005 slave node-id-3 0 0 3 connected ``` 5. 检查集群健康状况(可选): ``` docker exec redis-node-7000 redis-cli -c -a redis-cluster-password -p 7000 cluster info ``` 你应该看到以下响应: ``` cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_known_nodes:6 cluster_size:3 ... ``` 为 Redis 集群创建 Kubernetes 清单: redis-cluster.yaml ``` apiVersion: apps/v1 kind: StatefulSet metadata: namespace: aic name: redis-cluster spec: serviceName: redis-cluster replicas: 6 selector: matchLabels: app: redis-cluster template: metadata: labels: app: redis-cluster spec: containers: - name: redis image: redis:7.2-alpine ports: - containerPort: 6379 name: client - containerPort: 16379 name: gossip command: - redis-server - --cluster-enabled - "yes" - --cluster-config-file - nodes.conf - --cluster-node-timeout - "5000" - --appendonly - "yes" - --requirepass - redis-cluster-password - --masterauth - redis-cluster-password volumeMounts: - name: data mountPath: /data volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 1Gi --- apiVersion: v1 kind: Service metadata: namespace: aic name: redis-cluster spec: clusterIP: None selector: app: redis-cluster ports: - port: 6379 name: client - port: 16379 name: gossip ``` 应用该清单: ``` kubectl apply -f redis-cluster.yaml ``` 等待所有 Pod 就绪,然后初始化集群: ``` kubectl exec -n aic redis-cluster-0 -- redis-cli \ --cluster create \ $(for i in 0 1 2 3 4 5; do \ echo -n "$(kubectl get pod -n aic redis-cluster-$i -o jsonpath='{.status.podIP}'):6379 "; \ done) \ --cluster-replicas 1 \ --cluster-yes \ -a redis-cluster-password ``` #### 创建路由并配置速率限制[​](#创建路由并配置速率限制-1 "创建路由并配置速率限制的直接链接") 在网关组中创建一个具有以下配置的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- </dev/null | grep -v "^$" || echo "No related keys found" done ``` 你应该看到类似以下的输出: ``` Checking node redis-node-7000: No related keys found Checking node redis-node-7001: No related keys found Checking node redis-node-7002: plugin-ai-rate-limitingroute&service&::: Checking node redis-node-7003: plugin-ai-rate-limitingroute&service&::: Checking node redis-node-7004: No related keys found Checking node redis-node-7005: No related keys found ``` ### 使用 Redis Sentinel 在网关节点之间共享配额[​](#使用-redis-sentinel-在网关节点之间共享配额 "使用 Redis Sentinel 在网关节点之间共享配额的直接链接") 此示例适用于 API7 企业版 3.9.2 及更高版本。它不适用于 APISIX,因为尚不支持 `policy` 功能。 如果需要自动故障转移和高可用,但不需要数据分区,请使用 Redis Sentinel。此模式管理起来更简单,适用于大多数高可用场景。 确保你的 Redis 实例运行在 [Sentinel 模式](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/)。 #### 先决条件[​](#先决条件-2 "先决条件的直接链接") * Docker * Kubernetes 1. 创建一个 Docker 网络: ``` docker network create redis-sentinel-network ``` 确保你的网关实例在与 Redis Sentinel 集群相同的网络中运行。 2. 启动一个 Redis 主节点: ``` docker run -d --name redis-master --network redis-sentinel-network \ -p 6379:6379 \ redis:7.2-alpine \ redis-server --requirepass StrongP@ss123 --appendonly yes ``` 3. 启动 Sentinel 副本节点: ``` for i in 1 2; do PORT=$((6380 + i - 1)) docker run -d --name redis-slave-$i --network redis-sentinel-network \ -p $PORT:6379 \ redis:7.2-alpine \ redis-server --slaveof redis-master 6379 \ --requirepass StrongP@ss123 \ --masterauth StrongP@ss123 \ --appendonly yes done ``` 4. 获取主节点 IP 地址以进行下一步: ``` MASTER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-master) echo "Redis master node IP: $MASTER_IP" ``` 5. 启动 Sentinel 集群并将 `$MASTER_IP` 替换为你的主节点 IP: ``` for i in 1 2 3; do docker run -d --name redis-sentinel-$i --network redis-sentinel-network -p $((26378+i-1)):26379 \ redis:7.2-alpine \ sh -c " cat << 'EOF' > /sentinel.conf port 26379 sentinel monitor mymaster $MASTER_IP 6379 2 sentinel auth-pass mymaster StrongP@ss123 requirepass admin-password sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 10000 sentinel parallel-syncs mymaster 1 protected-mode no EOF redis-sentinel /sentinel.conf " done echo "✅ Sentinel cluster started successfully." ``` 你可以看到以下响应: ``` Starting redis-sentinel-1 (port:26379)... eb9efacb629d0cfdfaa48856f42ba8c67642baa79f1589df5b251c11d3ec6e1a Starting redis-sentinel-2 (port:26380)... 7f23f4b6e63c9b6be4c5e1903a244f078d481952a1465a9650c743ea2ee4600f Starting redis-sentinel-3 (port:26381)... 1df087502124e3903df7ae665ef597bf735669c5ce3f9d87696c4acd82526626 ✅ Sentinel cluster started successfully. ``` 6. 确认 Sentinel 环境运行正常: ``` echo "Waiting for Sentinel cluster establishment (10 seconds)..." sleep 10 echo -e "\nVerifying Sentinel cluster status:" for i in 1 2 3; do echo "--- Sentinel $i status ---" if docker ps | grep -q "redis-sentinel-$i"; then echo "Container: ✅ Running" docker exec redis-sentinel-$i redis-cli -p 26379 SENTINEL master mymaster 2>&1 | grep -E "(flags|num-slaves|num-other-sentinels)" else echo "Container: ❌ Not running (run 'docker logs redis-sentinel-$i' to check)" fi echo "-----------------------------------" done ``` 你可以看到以下响应: ``` Verifying Sentinel cluster status: --- Sentinel 1 status --- Container: ✅ Running --- Sentinel 2 status --- Container: ✅ Running --- Sentinel 3 status --- Container: ✅ Running ``` 7. 获取 Sentinel IP 地址以进行插件配置: ``` echo -e "Getting Sentinel container IP addresses:" for i in 1 2 3; do IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-sentinel-$i) echo " redis-sentinel-$i : $IP" done ``` 你可以看到以下响应: ``` Getting Sentinel container IP addresses: redis-sentinel-1 : 172.22.0.4 redis-sentinel-2 : 172.22.0.5 redis-sentinel-3 : 172.22.0.6 ``` 8. 进行详细的状态检查: ``` echo "Checking detailed Sentinel cluster status..." for i in 1 2 3; do echo "--- Sentinel $i detailed info ---" docker exec redis-sentinel-$i redis-cli -p 26379 SENTINEL masters echo "-----------------------------------" done ``` 你可以看到以下响应: ``` Checking detailed Sentinel cluster status... === Sentinel 1 Details === name: mymaster ip: 172.22.0.2 port: 6379 runid: ${YOUR_RUN_ID} flags: master link-pending-commands: 0 link-refcount: 1 last-ping-sent: 0 last-ok-ping-reply: 113 last-ping-reply: 113 down-after-milliseconds: 5000 info-refresh: 6979 role-reported: master role-reported-time: 107360 config-epoch: 0 num-slaves: 1 num-other-sentinels: 2 quorum: 2 failover-timeout: 10000 parallel-syncs: 1 ... ``` 为 Redis 主节点、副本和 Sentinel 集群创建 Kubernetes 清单: redis-sentinel.yaml ``` apiVersion: v1 kind: ConfigMap metadata: namespace: aic name: redis-sentinel-config data: sentinel.conf: | port 26379 sentinel monitor mymaster redis-master.aic.svc 6379 2 sentinel auth-pass mymaster StrongP@ss123 requirepass admin-password sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 10000 sentinel parallel-syncs mymaster 1 protected-mode no --- apiVersion: apps/v1 kind: StatefulSet metadata: namespace: aic name: redis-master spec: serviceName: redis-master replicas: 1 selector: matchLabels: app: redis-master template: metadata: labels: app: redis-master spec: containers: - name: redis image: redis:7.2-alpine ports: - containerPort: 6379 command: - redis-server - --requirepass - StrongP@ss123 - --appendonly - "yes" --- apiVersion: v1 kind: Service metadata: namespace: aic name: redis-master spec: clusterIP: None selector: app: redis-master ports: - port: 6379 --- apiVersion: apps/v1 kind: StatefulSet metadata: namespace: aic name: redis-replica spec: serviceName: redis-replica replicas: 2 selector: matchLabels: app: redis-replica template: metadata: labels: app: redis-replica spec: containers: - name: redis image: redis:7.2-alpine ports: - containerPort: 6379 command: - redis-server - --slaveof - redis-master.aic.svc - "6379" - --requirepass - StrongP@ss123 - --masterauth - StrongP@ss123 - --appendonly - "yes" --- apiVersion: v1 kind: Service metadata: namespace: aic name: redis-replica spec: clusterIP: None selector: app: redis-replica ports: - port: 6379 --- apiVersion: apps/v1 kind: StatefulSet metadata: namespace: aic name: redis-sentinel spec: serviceName: redis-sentinel replicas: 3 selector: matchLabels: app: redis-sentinel template: metadata: labels: app: redis-sentinel spec: containers: - name: sentinel image: redis:7.2-alpine ports: - containerPort: 26379 command: - redis-sentinel - /etc/sentinel/sentinel.conf volumeMounts: - name: sentinel-config mountPath: /etc/sentinel volumes: - name: sentinel-config configMap: name: redis-sentinel-config --- apiVersion: v1 kind: Service metadata: namespace: aic name: redis-sentinel spec: clusterIP: None selector: app: redis-sentinel ports: - port: 26379 ``` 应用该清单: ``` kubectl apply -f redis-sentinel.yaml ``` 等待所有 Pod 就绪: ``` kubectl wait --for=condition=Ready pod -l app=redis-sentinel -n aic --timeout=120s ``` #### 创建路由并配置速率限制[​](#创建路由并配置速率限制-2 "创建路由并配置速率限制的直接链接") 在网关组中创建一个具有以下配置的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <设置 `rules` 后,响应头改用前缀。有关详细信息,请参阅 `rules.header_prefix`。 - limit\_strategy string 默认值:`total_tokens` 有效值: `total_tokens`、`prompt_tokens`、`completion_tokens` 或 `expression` *** 应用速率限制的 Token 类型。`total_tokens`、`prompt_tokens` 和 `completion_tokens` 值在每个模型响应中返回,其中 `total_tokens` 是 `prompt_tokens` 和 `completion_tokens` 的总和。 当设置为 `expression` 时,使用 `cost_expr` 中定义的自定义 Lua 算术表达式计算限速成本。自 API7 企业版 3.9.8 和 APISIX 3.17.0 起可用。 - cost\_expr string 有效值: 任意非空字符串(必须是有效的 Lua 算术表达式) *** 用于动态 Token 成本计算的 Lua 算术表达式。变量从 LLM 提供者的原始 usage 响应字段注入(如 `input_tokens`、`output_tokens`、`cache_creation_input_tokens`)。缺失的变量默认为 `0`。仅允许 math 函数(`abs`、`ceil`、`floor`、`max`、`min`)和算术运算符。表达式语法在配置时校验。当 `limit_strategy` 为 `expression` 时必填,其他情况下不得设置。 示例:`input_tokens + cache_creation_input_tokens` 根据 Anthropic Claude 的缓存感知 Token 用量计算成本。 自 API7 企业版 3.9.8 和 APISIX 3.17.0 起可用。 - instances array\[object] *** LLM 实例速率限制配置。 * name string 必填 *** LLM 服务实例的名称。 * limit integer | string 必填 有效值: 大于 0 *** 指定时间间隔内允许消耗的最大 Token 数量。 在 API7 企业版(自 3.8.17 起)和 APISIX(自 3.16.0 起)中,此参数还支持字符串类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。较早的 APISIX 版本仅支持整数类型。 * time\_window integer | string 必填 有效值: 大于 0 *** 对应于速率限制 `limit` 的时间间隔,以秒为单位。 在 API7 企业版(自 3.8.17 起)和 APISIX(自 3.16.0 起)中,此参数还支持字符串类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。较早的 APISIX 版本仅支持整数类型。 - rejected\_code integer 默认值:`503` 有效值: 介于 200 和 599 之间(含边界值) *** 当请求超过配额被拒绝时返回的 HTTP 状态码。 - rejected\_msg string 有效值: 任意非空字符串 *** 当请求超过配额被拒绝时返回的响应体。 - policy string 默认值:`local` 有效值: `local`、`redis`、`redis-cluster` 或 `redis-sentinel` *** 速率限制计数器的策略。API7 网关要求配置此字段;不使用 Redis 时请设置为 `local`。APISIX 在省略此字段时使用 `local`。 Redis 后端策略自 API7 企业版 3.8.19 和 APISIX 3.18.0 起可用。 设置为 `local` 以将计数器存储在本地内存中。 设置为 `redis` 以将计数器存储在 Redis 实例上。 设置为 `redis-cluster` 以将计数器存储在 Redis 集群中。 设置为 `redis-sentinel` 以将计数器存储在由 Redis Sentinel 管理的 Redis 主节点上,这通过在故障情况下自动将副本提升为主节点来确保高可用性。Redis Sentinel 在不使用 Redis Cluster 时为 Redis 提供高可用性。 - redis\_host string *** Redis 节点的地址。当 `policy` 为 `redis` 时必填。 - redis\_port integer 默认值:`6379` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 时 Redis 节点的端口。 - redis\_username string *** 如果使用 Redis ACL,则为 Redis 用户名。如果使用传统身份认证方法 `requirepass`,请仅配置 `redis_password`。当 `policy` 为 `redis` 时使用;在 API7 企业版 3.10.5 和 APISIX 3.18.0 中,也可与 `redis-sentinel` 一起使用。 - redis\_password string *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 节点的密码;在 API7 企业版 3.10.5 和 APISIX 3.18.0 中,也可与 `redis-sentinel` 一起使用。 在 API7 网关 3.10.x 系列的 3.10.2 及更高版本,以及 3.9.x 系列的 3.9.16 及更高版本中,该值在保存到数据库前会使用 AES256 加密。 在 APISIX 3.18.0 及更高版本中,该值在存储到 etcd 前会使用 AES 加密。 - redis\_database integer 默认值:`0` 有效值: 大于或等于 0 *** 当 `policy` 为 `redis` 或 `redis-sentinel` 时 Redis 中的数据库编号。 - redis\_ssl boolean 默认值:`false` *** 如果为 true,则当 `policy` 为 `redis` 时使用 SSL 连接到 Redis。 - redis\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则当 `policy` 为 `redis` 时验证服务器 SSL 证书。 - redis\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 超时值(以毫秒为单位)。 - redis\_cluster\_nodes array\[string] *** Redis 集群节点列表,至少包含两个地址。当 `policy` 为 `redis-cluster` 时必填。 - redis\_cluster\_name string *** Redis 集群的名称。当 `policy` 为 `redis-cluster` 时必填。 - redis\_cluster\_ssl boolean 默认值:`false` *** 如果为 true,则当 `policy` 为 `redis-cluster` 时使用 SSL 连接到 Redis 集群。 - redis\_cluster\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则当 `policy` 为 `redis-cluster` 时验证服务器 SSL 证书。 - redis\_sentinels array\[object] *** Redis Sentinel 节点(主机和端口)的数组。当 `policy` 为 `redis-sentinel` 时必填。 - redis\_master\_name string *** Sentinel 监控的 Redis 主组名称。当 `policy` 为 `redis-sentinel` 时必填。 - redis\_role string 默认值:`master` 有效值: `master` 或 `slave` *** 要连接的 Redis 节点角色。当 `policy` 为 `redis-sentinel` 时可配置。设置为 `master` 连接到当前 Redis 主节点,设置为 `slave` 连接到 Redis 副本。 - redis\_connect\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 建立 Redis 节点连接的超时时间(以毫秒为单位)。当 `policy` 为 `redis-sentinel` 时可配置。 - redis\_read\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 从 Redis 节点读取数据的超时时间(以毫秒为单位)。当 `policy` 为 `redis-sentinel` 时可配置。 - redis\_keepalive\_timeout integer 默认值:`` `redis` 或 `redis-cluster` 为 `10000`;`redis-sentinel` 为 `60000` `` 有效值: 对 `redis` 和 `redis-cluster` 大于或等于 1000;对 `redis-sentinel` 大于或等于 1 *** 空闲 Redis 连接在连接池中保持存活、超过后关闭的时间(毫秒)。在 APISIX 3.18.0 中,所有 Redis 后端策略都会使用此字段。在 API7 企业版中,`redis-sentinel` 使用此字段;`redis` 和 `redis-cluster` 自 3.9.x 系列的 3.9.16 以及 3.10.x 系列的 3.10.3 起支持此字段。 - redis\_keepalive\_pool integer 默认值:`100` 有效值: 大于或等于 1 *** 保活连接池中空闲 Redis 连接的最大数量。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。自 API7 企业版 3.9.x 系列的 3.9.16、3.10.x 系列的 3.10.3 以及 APISIX 3.18.0 起可用。 - sentinel\_username string *** 用于 Redis Sentinel 实例认证的用户名。当 `policy` 为 `redis-sentinel` 时可配置。 - sentinel\_password string *** 用于向 Redis Sentinel 实例进行身份认证的密码。当 `policy` 为 `redis-sentinel` 时可配置。 在 API7 网关 3.10.x 系列的 3.10.2 及更高版本,以及 3.9.x 系列的 3.9.16 及更高版本中,该值在保存到数据库前会使用 AES256 加密。 在 APISIX 3.18.0 及更高版本中,该值在存储到 etcd 前会使用 AES 加密。 - allow\_degradation boolean 默认值:`false` *** 如果为 true,则当插件或其依赖项不可用时,允许网关继续处理请求而不使用该插件。 自 API7 企业版 3.8.19 和 APISIX 3.18.0 起可用。 - rules array\[object] *** 按顺序应用的一组速率限制规则。 自 API7 企业版 3.8.17 和 APISIX 3.16.0 起可用。 * count integer | string 必填 有效值: 大于 0 *** 指定时间间隔内允许消耗的最大 Token 数量。 此参数还支持字符串数据类型,并允许使用以美元符号(`$`)为前缀的 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * time\_window integer | string 必填 有效值: 大于 0 *** 对应于速率限制 `count` 的时间间隔,以秒为单位。 此参数还支持字符串数据类型,并允许使用以美元符号(`$`)为前缀的 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * key string 必填 *** 用于对请求计数的键。如果配置的键不存在,则不会执行该规则。 `key` 被解释为变量。变量无需以美元符号(`$`)作为前缀。有关可用变量,请参阅[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * header\_prefix string *** 所有速率限制响应头的前缀。自 API7 企业版 3.8.19 和 APISIX 3.17.0 起可用。 配置后,前缀将插入到头名称中的 `X-AI-` 之后。例如,将 `header_prefix` 设置为 `test`,则头变为 `X-AI-Test-RateLimit-Limit`、`X-AI-Test-RateLimit-Remaining` 和 `X-AI-Test-RateLimit-Reset`。 如果未配置,则使用规则在规则数组中的索引作为前缀。例如,第一个规则的头将是 `X-AI-1-RateLimit-Limit`、`X-AI-1-RateLimit-Remaining` 和 `X-AI-1-RateLimit-Reset`。 --- # ai-request-rewrite `ai-request-rewrite` 插件处理客户端请求的方式是:在将请求中继到上游服务之前,先将其转发给 LLM 服务进行转换。这使得能够进行 LLM 驱动的修改,例如数据编辑、内容丰富或重新格式化。该插件支持与 OpenAI、DeepSeek、Gemini、Vertex AI、Anthropic、OpenRouter 以及其他 OpenAI 兼容的 API 集成。 用于重写的 LLM 调用与客户端的请求格式相互独立。使用 `openai` 提供方时,插件会根据配置的提示词和原始请求体构造一个非流式 Chat Completions 请求;它不会将客户端请求分类为 AI 协议,也不会按 AI 协议代理该请求。该内部请求携带插件配置的服务提供方凭证,不会转发客户端请求头。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `ai-request-rewrite`。 这些示例将使用 OpenAI 作为 LLM 服务。要继续操作,请获取 OpenAI [API Key](https://openai.com/blog/openai-api) 并将其保存到环境变量中: ``` export OPENAI_API_KEY=YOUR_OPENAI_API_KEY # 替换为你的 API Key ``` ### 编辑敏感信息[​](#编辑敏感信息 "编辑敏感信息的直接链接") 以下示例展示了如何使用 `ai-request-rewrite` 插件在请求到达上游服务之前编辑敏感信息。 * Admin API * ADC * Ingress Controller 创建一个路由并按如下方式配置 `ai-request-rewrite` 插件: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < Authorization Scopes 标签页](https://static.api7.ai/uploads/2024/01/06/bVHhiALe_auth-scope.png) 创建 URI 为 `/anything`、作用域为 `access` 的资源 `httpbin-anything`: ![列出 Default Resource 且突出显示 Create 按钮的 Keycloak 客户端 Authorization > Resources 标签页](https://static.api7.ai/uploads/2024/01/06/15DJ9HAU_create-resource.png) 创建要求 `httpbin-access` 的客户端作用域策略 `access-client-scope-policy`: ![列出 Default Policy 且突出显示 Create Policy 下拉菜单的 Keycloak 客户端 Authorization > Policies 标签页](https://static.api7.ai/uploads/2024/01/06/7UtT3cF6_create-policy.png) 创建基于作用域的权限 `access-scope-perm`,该权限使用 `access` 作用域和 `access-client-scope-policy`: ![在 Keycloak 中添加基于作用域的权限](https://static.api7.ai/uploads/2024/01/12/Y0vlk1Tj_add-scope-permission.png) 将 `httpbin-access` 添加到 `apisix-quickstart-client` 的默认客户端作用域: ![将客户端作用域关联到 Keycloak 客户端](https://static.api7.ai/uploads/2024/01/06/sJKUMUcP_add-client-scope.png) 创建名为 `quickstart-user` 的用户: ![保存新的 Keycloak 用户](https://static.api7.ai/uploads/2024/01/12/3fUQOFWg_save-user.png) 将密码设置为 `quickstart-user-pass`,并关闭 **Temporary**: ![为 Keycloak 用户设置密码](https://static.api7.ai/uploads/2024/01/12/aoabcBbC_set-password.png) 点击 **Clients** > `apisix-quickstart-client` > **Credentials**,并从 **Secret** 中复制客户端密钥: ![显示已生成客户端 Secret 的 Keycloak 客户端 Credentials 标签页](https://static.api7.ai/uploads/2024/01/12/3VqiXdf9_client-secret.png) 将 OIDC Client ID 和 Secret 保存到环境变量: ``` OIDC_CLIENT_ID=apisix-quickstart-client OIDC_CLIENT_SECRET=replace-with-your-client-secret ``` 提示 如果 APISIX 在 Kubernetes 中运行,请确保插件配置和 Token 请求始终使用相同的 Keycloak 主机名。否则,Token 签发者与配置的授权端点不匹配时,Keycloak 可能会拒绝 Bearer Token。 #### 请求访问令牌 (Access Token)[​](#请求访问令牌-access-token "请求访问令牌 (Access Token)的直接链接") 从 Keycloak 请求访问令牌,并将其保存到 `ACCESS_TOKEN`: * Docker * Kubernetes ``` ACCESS_TOKEN=$(curl -sS "$KEYCLOAK_URL/realms/quickstart-realm/protocol/openid-connect/token" \ -d 'grant_type=client_credentials' \ -d 'client_id='$OIDC_CLIENT_ID'' \ -d 'client_secret='$OIDC_CLIENT_SECRET'' | jq -r '.access_token') ``` 在 Keycloak Pod 内执行令牌请求,并将结果保存到 `ACCESS_TOKEN`: ``` ACCESS_TOKEN=$(kubectl exec -n aic deploy/keycloak -- env OIDC_CLIENT_SECRET="$OIDC_CLIENT_SECRET" sh -lc 'curl -sS "http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token" \ -d grant_type=client_credentials \ -d client_id=apisix-quickstart-client \ -d client_secret="$OIDC_CLIENT_SECRET"' | jq -r '.access_token') ``` ### 使用延迟加载路径和资源注册端点[​](#使用延迟加载路径和资源注册端点 "使用延迟加载路径和资源注册端点的直接链接") 以下示例演示了如何配置 `authz-keycloak` 插件,使其使用资源注册端点将请求 URI 动态解析为一个或多个资源,而不是使用静态权限。 * Admin API * ADC * Ingress Controller 创建一个路由 `authz-keycloak-route` 如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < 信息 Amazon API Gateway 支持两种类型的 RESTful API:HTTP API 和 REST API。只有 REST API 提供 API 密钥和 IAM 作为安全措施。 你现在应该被重定向回 Lambda 界面。要查找 API 密钥和网关 API 端点,请转到 Lambda 函数的 **Configuration** 选项卡,在 **Triggers** 下,你可以找到 API 网关的详细信息: ![AWS 控制台显示 API Gateway 端点 URL 和生成的 API 密钥](https://static.api7.ai/uploads/2024/04/25/6bjpeNIb_api-gateway-info.png) 最后,在 APISIX 中创建一个带有你的网关端点和 API 密钥的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "aws-lambda-route", "uri": "/aws-lambda", "plugins": { "aws-lambda": { "function_uri": "https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource", "authorization": { "apikey": "YOUR_API_GATEWAY_API_KEY" }, "ssl_verify": false } } }' ``` adc.yaml ``` services: - name: aws-lambda-service routes: - name: aws-lambda-route uris: - /aws-lambda plugins: aws-lambda: function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource authorization: apikey: YOUR_API_GATEWAY_API_KEY ssl_verify: false ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD aws-lambda-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: aws-lambda-plugin-config spec: plugins: - name: aws-lambda config: function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource authorization: apikey: YOUR_API_GATEWAY_API_KEY ssl_verify: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: aws-lambda-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /aws-lambda filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: aws-lambda-plugin-config ``` aws-lambda-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: aws-lambda-route spec: ingressClassName: apisix http: - name: aws-lambda-route match: paths: - /aws-lambda plugins: - name: aws-lambda enable: true config: function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource authorization: apikey: YOUR_API_GATEWAY_API_KEY ssl_verify: false ``` 应用配置: ``` kubectl apply -f aws-lambda-ic.yaml ``` 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/aws-lambda" ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并包含以下消息: ``` "Hello from Lambda!" ``` 如果你的 API 密钥无效,你应该收到 `HTTP/1.1 403 Forbidden` 响应。 ### 转发请求到 Amazon API Gateway 子路径[​](#转发请求到-amazon-api-gateway-子路径 "转发请求到 Amazon API Gateway 子路径的直接链接") 以下示例演示了如何将请求转发到 Amazon API Gateway API 的子路径,并配置 API 以触发 Lambda 函数的执行。 请先按照[上一个示例](#%E4%BD%BF%E7%94%A8-api-%E5%AF%86%E9%92%A5%E5%AE%89%E5%85%A8%E9%9B%86%E6%88%90-amazon-api-gateway)设置 API 网关。 要创建子路径,请转到 Lambda 函数的 **Configuration** 选项卡,在 **Triggers** 下,点击 API 网关: ![AWS Lambda 控制台:打开函数的 API Gateway 集成](https://static.api7.ai/uploads/2024/04/26/5Twffgyr_click-into-adjusted.png) 接下来,选择 **Create resource** 以创建子路径: ![AWS API Gateway Resources 页面,并突出显示 Create resource 按钮](https://static.api7.ai/uploads/2024/04/26/hXlnuVwk_create-resource.png) 输入子路径信息并完成创建: ![完成资源创建](https://static.api7.ai/uploads/2024/04/26/7t1yiWjl_create-resource-2.png) 重定向回主网关控制台后,你应该能看到新创建的路径。选择 **Create method** 为路径配置 HTTP 方法及关联的操作: ![AWS API Gateway Resources 页面显示 /api7-docs 资源,并突出显示 Create method 按钮](https://static.api7.ai/uploads/2024/04/26/3rZZJy3e_create-method.png) 在下拉菜单中选择允许的 HTTP 方法。为了演示目的,本例继续使用相同的 Lambda 函数作为请求路径时的触发操作: ![创建方法和 Lambda 函数](https://static.api7.ai/uploads/2024/04/26/vni7yS2q_create%20method%202.png) 完成方法创建。重定向回主网关控制台后,点击 **Deploy API** 以部署路径和方法更改: ![AWS API Gateway 方法执行视图,显示从客户端经由方法和集成请求到 Lambda 集成的流程,并突出显示 Deploy API 按钮](https://static.api7.ai/uploads/2024/04/26/2vrqnVPB_deploy-api.png) 最后,在 APISIX 中创建一个带有你的网关端点和 API 密钥的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "aws-lambda-route", "uri": "/aws-lambda/*", "plugins": { "aws-lambda": { "function_uri": "https://your-api-id.execute-api.us-west-2.amazonaws.com/default", "authorization": { "apikey": "YOUR_API_GATEWAY_API_KEY" }, "ssl_verify": false } } }' ``` adc.yaml ``` services: - name: aws-lambda-service routes: - name: aws-lambda-route uris: - /aws-lambda/* plugins: aws-lambda: function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default authorization: apikey: YOUR_API_GATEWAY_API_KEY ssl_verify: false ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD aws-lambda-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: aws-lambda-plugin-config spec: plugins: - name: aws-lambda config: function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default authorization: apikey: YOUR_API_GATEWAY_API_KEY ssl_verify: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: aws-lambda-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /aws-lambda/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: aws-lambda-plugin-config ``` aws-lambda-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: aws-lambda-route spec: ingressClassName: apisix http: - name: aws-lambda-route match: paths: - /aws-lambda/* plugins: - name: aws-lambda enable: true config: function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default authorization: apikey: YOUR_API_GATEWAY_API_KEY ssl_verify: false ``` 应用配置: ``` kubectl apply -f aws-lambda-ic.yaml ``` ❶ 匹配 `/aws-lambda/` 的所有子路径 ❷ 对于 Admin API、ADC 和 APISIX CRD 示例,通配符 `*` 匹配的子路径将追加到 `function_uri` 末尾。在 Gateway API 示例中,`PathPrefix` 匹配 `/aws-lambda/` 下的请求,因此转发的请求路径会接在已配置的 `function_uri` 前缀之后。 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/aws-lambda/api7-docs" ``` APISIX 会将请求转发到 `https://your-api-id.execute-api.us-west-2.amazonaws.com/default/api7-docs`,你应该会收到包含以下消息的 `HTTP/1.1 200 OK` 响应: ``` "Hello from Lambda!" ``` 如果你的 API 密钥无效或请求的路径未关联任何方法,你应该收到 `HTTP/1.1 403 Forbidden` 响应。 --- ## 属性[​](#属性 "属性的直接链接") ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * function\_uri string 必填 *** 触发 Lambda 函数的 AWS Lambda 函数 URL 或 AWS API Gateway 端点。 * authorization object *** 用于在 AWS 上进行身份认证和授权以调用 Lambda 函数的凭证。 * apikey string *** 选择 API Key 作为安全机制时 REST API Gateway 使用的 API Key。API7 网关会在静态存储时使用 AES 加密该值;当启用 `apisix.data_encryption.enable_encrypt_fields` 时,APISIX 会在将其存储到 etcd 前加密。 * iam object *** 使用 [AWS Signature Version 4](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html) 进行身份认证和授权的 IAM 凭证。 * accesskey string *** IAM 用户访问密钥。API7 网关会在静态存储时使用 AES 加密该值;当启用 `apisix.data_encryption.enable_encrypt_fields` 时,APISIX 会在将其存储到 etcd 前加密。 * secretkey string *** IAM 用户秘密访问密钥。API7 网关会在静态存储时使用 AES 加密该值;当启用 `apisix.data_encryption.enable_encrypt_fields` 时,APISIX 会在将其存储到 etcd 前加密。 * aws\_region string 默认值:`us-east-1` *** AWS 区域。 * service string 默认值:`execute-api` *** 接收请求的服务。 要与 AWS API Gateway 集成以执行 API,请将服务设置为 `execute-api` 以用于 HTTP 触发器。 要直接与 Lambda 函数集成,请将服务设置为 `lambda`。 * timeout integer 默认值:`3000` 有效值: 大于或等于 100 *** 代理请求超时时间(以毫秒为单位)。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则执行 SSL 验证。 * keepalive boolean 默认值:`true` *** 如果为 true,则保持连接活动以便重用。 * keepalive\_pool integer 默认值:`5` 有效值: 大于或等于 1 *** 连接池中保持活动的空闲连接数。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 连接保持空闲而不关闭的时间(以毫秒为单位)。 * max\_req\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** 发送到 AWS Lambda 前读取的请求体最大字节数。超过该大小的请求体会以 `400 Bad Request` 被拒绝。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 --- # basic-auth `basic-auth` 插件为 [消费者 (Consumers)](https://docs.apiseven.com/apisix/key-concepts/consumers.md) 添加 [基本访问认证 (Basic Access Authentication)](https://en.wikipedia.org/wiki/Basic_access_authentication),以便他们在访问上游资源之前进行身份认证。 消费者成功通过身份认证后,APISIX 会在将请求代理到上游服务之前添加额外的请求头,例如 `X-Consumer-Username`、`X-Credential-Identifier`;如果配置了消费者自定义请求头,也会一并添加。上游服务可以据此区分消费者并执行额外逻辑。如果这些值不可用,则不会添加相应的请求头。 关于 X-Consumer-Username 使用 Ingress Controller 配置消费者时,消费者名称会生成为 `namespace_consumername` 格式。因此,`X-Consumer-Username` 请求头也会采用此格式,而不只是 `consumername`。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下使用 `basic-auth` 插件。 ### 在路由上实现基本认证[​](#在路由上实现基本认证 "在路由上实现基本认证的直接链接") 以下示例展示了如何在路由上实现基本认证。 * Admin API * ADC * Ingress Controller 创建一个消费者 `johndoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "johndoe" }' ``` 为该消费者创建 `basic-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-basic-auth", "plugins": { "basic-auth": { "username": "johndoe", "password": "john-key" } } }' ``` 创建一个启用 `basic-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `basic-auth` 凭证的消费者,以及一个配置了 `basic-auth` 插件的路由: adc.yaml ``` consumers: - username: johndoe credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `basic-auth` 凭证的消费者,以及一个配置了 `basic-auth` 插件的路由: * Gateway API * APISIX CRD basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-cred config: username: johndoe password: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: basicAuth: value: username: johndoe password: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` #### 使用有效密钥进行验证[​](#使用有效密钥进行验证 "��使用有效密钥进行验证的直接链接") 使用有效密钥发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` 你应该会看到类似以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Authorization": "Basic am9obmRvZTpqb2huLWtleQ==", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66e5107c-5bb3e24f2de5baf733aec1cc", "X-Consumer-Username": "johndoe", "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "origin": "192.168.65.1, 205.198.122.37", "url": "http://127.0.0.1/anything" } ``` #### 使用无效密钥进行验证[​](#使用无效密钥进行验证 "使用无效密钥进行验证的直接链接") 使用无效密钥发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-password ``` 你应该会看到包含以下内容的 `HTTP/1.1 401 Unauthorized` 响应: ``` {"message":"Invalid user authorization"} ``` #### 未提供密钥进行验证[​](#未提供密钥进行验证 "未提供密钥进行验证的直接链接") 未提供密钥发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会看到包含以下内容的 `HTTP/1.1 401 Unauthorized` 响应: ``` {"message":"Missing authorization in request"} ``` ### 向上游隐藏认证信息[​](#向上游隐藏认证信息 "向上游隐藏认证信息的直接链接") 以下示例演示了如何通过配置 `hide_credentials`,防止将客户端凭证(`Authorization` 请求头)发送到上游服务。使用 APISIX 时,包含客户端凭证的 `Authorization` 请求头默认会转发到上游服务,这在某些情况下可能带来安全风险,因此应考虑按本示例更新 `hide_credentials`。 * Admin API * ADC * Ingress Controller 创建一个消费者 `johndoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "johndoe" }' ``` 为该消费者创建 `basic-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-basic-auth", "plugins": { "basic-auth": { "username": "johndoe", "password": "john-key" } } }' ``` #### 不隐藏凭证[​](#不隐藏凭证 "不隐藏凭证的直接链接") 创建一个启用 `basic-auth` 的路由,并将 `hide_credentials` 配置为 `false`(这是默认配置): ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": { "hide_credentials": false } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `basic-auth` 凭证的消费者,以及一个配置了 `basic-auth` 插件的路由: adc.yaml ``` consumers: - username: johndoe credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: hide_credentials: false upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `basic-auth` 凭证的消费者,以及一个配置了 `basic-auth` 插件的路由: * Gateway API * APISIX CRD basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-cred config: username: johndoe password: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false hide_credentials: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: basicAuth: value: username: johndoe password: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true config: hide_credentials: false ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` 使用有效密钥发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` 你应该会看到包含以下内容的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Authorization": "Basic am9obmRvZTpqb2huLWtleQ==", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66cc2195-22bd5f401b13480e63c498c6", "X-Consumer-Username": "johndoe", "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "GET", "origin": "192.168.65.1, 43.228.226.23", "url": "http://127.0.0.1/anything" } ``` 注意,上游服务可以看到经过 Base64 编码的凭证。 提示 你也可以通过 `Authorization` 请求头传递经过 Base64 编码的凭证,如下所示: ``` curl -i "http://127.0.0.1:9080/anything" -H "Authorization: Basic am9obmRvZTpqb2huLWtleQ==" ``` #### 隐藏凭证[​](#隐藏凭证 "隐藏凭证的直接链接") * Admin API * ADC * Ingress Controller 将插件的 `hide_credentials` 更新为 `true`: ``` curl "http://127.0.0.1:9180/apisix/admin/routes/basic-auth-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "basic-auth": { "hide_credentials": true } } }' ``` 更新路由配置: adc.yaml ``` # 其他配置 # ... services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: hide_credentials: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `PluginConfig`,将 `hide_credentials` 设置为 `true`: basic-auth-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false hide_credentials: true ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` 更新 `ApisixRoute`,将 `hide_credentials` 设置为 `true`: basic-auth-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true config: hide_credentials: true ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` 使用有效密钥发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` 你应该会看到包含以下内容的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66cc21a7-4f6ac87946e25f325167d53a", "X-Consumer-Username": "johndoe", "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "GET", "origin": "192.168.65.1, 43.228.226.23", "url": "http://127.0.0.1/anything" } ``` 注意,凭证不再对上游服务可见。 ### 将消费者自定义 ID 添加到请求头[​](#将消费者自定义-id-添加到请求头 "将消费者自定义 ID 添加到请求头的直接链接") 以下示例展示了如何将消费者自定义 ID 添加到已认证请求的 `Consumer-Custom-Id` 请求头中,以便按需实现额外逻辑。 * Admin API * ADC * Ingress Controller 创建一个带有自定义 ID 标签的消费者 `johndoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "johndoe", "labels": { "custom_id": "495aec6a" } }' ``` 为该消费者创建 `basic-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-basic-auth", "plugins": { "basic-auth": { "username": "johndoe", "password": "john-key" } } }' ``` 创建一个启用 `basic-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `basic-auth` 凭证的消费者,以及一个启用了 `basic-auth` 插件的路由: adc.yaml ``` consumers: - username: johndoe labels: custom_id: "495aec6a" credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `basic-auth` 凭证的消费者,以及一个启用了 `basic-auth` 插件的路由: * Gateway API * APISIX CRD basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe labels: custom_id: "495aec6a" spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-key config: username: johndoe password: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe labels: custom_id: "495aec6a" spec: ingressClassName: apisix authParameter: basicAuth: value: username: johndoe password: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true config: _meta: disable: false ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` 要进行验证,请使用有效密钥向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` 你应该会看到类似以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Authorization": "Basic am9obmRvZTpqb2huLWtleQ==", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66ea8d64-33df89052ae198a706e18c2a", "X-Consumer-Username": "aic_johndoe", "X-Consumer-Custom-Id": "495aec6a", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "GET", "origin": "192.168.65.1, 205.198.122.37", "url": "http://127.0.0.1/anything" } ``` 如果你想将更多消费者自定义请求头添加到已认证请求中,请参阅 [`attach-consumer-label`](https://docs.apiseven.com/hub/attach-consumer-label.md) 插件。 ### 针对匿名消费者的速率限制[​](#针对匿名消费者的速率限制 "针对匿名消费者的速率限制的直接链接") 以下示例展示了如何针对普通消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者无需认证,但配额较少。 * Admin API * ADC * Ingress Controller 创建一个普通消费者 `johndoe`,并配置 `limit-count` 插件,允许在 30 秒窗口内有 3 次配额: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "johndoe", "plugins": { "limit-count": { "count": 3, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 为消费者 `johndoe` 创建 `basic-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-basic-auth", "plugins": { "basic-auth": { "username": "johndoe", "password": "john-key" } } }' ``` 创建一个匿名用户 `anonymous`,并配置 `limit-count` 插件,允许在 30 秒窗口内有 1 次配额: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "anonymous", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 创建一个路由并配置 `basic-auth` 插件,允许匿名消费者 `anonymous` 绕过认证: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": { "anonymous_consumer": "anonymous" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: adc.yaml ``` consumers: - username: johndoe plugins: limit-count: count: 3 time_window: 30 rejected_code: 429 policy: local credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key - username: anonymous plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 policy: local services: - name: anonymous-rate-limit-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: anonymous_consumer: anonymous upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-key config: username: johndoe password: john-key plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: anonymous spec: gatewayRef: name: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: anonymous_consumer: aic_anonymous # namespace_consumername --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: basic-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: basicAuth: value: username: johndoe password: john-key plugins: - name: limit-count enable: true config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: anonymous spec: ingressClassName: apisix plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true config: anonymous_consumer: aic_anonymous ``` 将配置应用到集群: ``` kubectl apply -f basic-auth-ic.yaml ``` 要进行验证,请使用 `johndoe` 的密钥连续发送 5 个请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -u johndoe:john-key -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示在 5 个请求中,有 3 个请求成功(状态码 `200`),而其他请求被拒绝(状态码 `429`)。 ``` 200: 3, 429: 2 ``` 发送 5 个匿名请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示只有一个请求成功: ``` 200: 1, 429: 4 ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 ### 凭据[​](#凭据 "凭据的直接链接") 以下是可在[凭据](https://docs.apiseven.com/apisix/key-concepts/credentials.md)上配置的插件属性。 * username string 必填 *** 消费者的唯一基本认证用户名。 * password string 必填 *** 消费者的基本认证密码。 自 API7 企业版 3.9.20 和 3.10.7 起,密码不能为空,且允许包含冒号。按照 RFC 7617 的定义,解码后凭据中第一个冒号之后的全部内容都是密码。解码后的凭据在比对前仍会去掉两部分中的所有空白字符,因此含空格的密码无法使用。 密码在存储到 etcd 之前会使用 AES 进行加密。你也可以将其存储在环境变量中并使用 `$env://` 前缀引用,或者存储在密钥管理器(如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv))中并使用 `$secret://` 前缀引用。更多信息请参见[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 解析结果为空的 `$env://` 或 `$secret://` 引用仍然可以通过配置校验,因为引用是在请求时才解析的。自 API7 企业版 3.9.20 和 3.10.7 起,网关在这种情况下按失败关闭处理,该消费者的所有请求都会被拒绝并返回 `HTTP 401`,同时记录一条 warning 日志。 ### 路由或服务[​](#路由或服务 "路由或服务的直接链接") 以下是可用于 [路由 (Routes)](https://docs.apiseven.com/apisix/key-concepts/routes.md) 或 [服务 (Services)](https://docs.apiseven.com/apisix/key-concepts/services.md) 配置的插件属性。 * hide\_credentials boolean 默认值:`false` *** 如果为 `true`,则不将 `Authorization` 请求头传递给上游服务。 * anonymous\_consumer string *** 匿名消费者名称。如果配置,则允许匿名用户绕过认证。更多详细信息,请参见 [针对匿名消费者的速率限制](https://docs.apiseven.com/hub/basic-auth.md#针对匿名消费者的速率限制)。 * realm string 默认值:`basic` *** 因身份认证失败而返回 `401 Unauthorized` 响应时,[`WWW-Authenticate`](https://datatracker.ietf.org/doc/html/rfc7235#section-4.1) 响应头中的 Realm。例如: * 如果 `realm` 设置为 `basic-auth`,401 响应将包含以下响应头: ``` WWW-Authenticate: Basic realm="basic-auth" ``` * 如果未配置 `realm`,401 响应将包含以下响应头: ``` WWW-Authenticate: Basic realm="basic" ``` 此参数在 API7 企业版 3.9.2 及更高版本,以及 Apache APISIX 3.15.0 及更高版本中可用。 --- # body-transformer `body-transformer` 插件执行基于模板的转换,将请求和/或响应体从一种格式转换为另一种格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `body-transformer`。 转换模板使用 [lua-resty-template](https://github.com/bungle/lua-resty-template) 语法。有关详细信息,请参阅[模板语法](https://github.com/bungle/lua-resty-template#template-syntax)。 你还可以使用辅助函数 `_escape_json()` 和 `_escape_xml()` 来转义双引号等特殊字符,使用 `_body` 访问请求体,使用 `_ctx` 访问上下文变量。 在所有情况下,你应确保转换模板是一个有效的 JSON 字符串。 ### 在 JSON 和 XML SOAP 之间转换[​](#在-json-和-xml-soap-之间转换 "在 JSON 和 XML SOAP 之间转换的直接链接") 以下示例演示了如何在与 SOAP 上游服务一起工作时,将请求体从 JSON 转换为 XML,并将响应体从 XML 转换为 JSON。 启动示例 SOAP 服务: ``` cd /tmp git clone https://github.com/spring-guides/gs-producing-web-service.git cd gs-producing-web-service/complete ./mvnw spring-boot:run ``` 创建请求和响应转换模板: ``` req_template=$(cat < {{_escape_xml(name)}} EOF ) rsp_template=$(cat < {{_escape_xml(name)}} input_format: json response: template: | {% if Envelope.Body.Fault == nil then %} { "status":"{{_ctx.var.status}}", "currency":"{{Envelope.Body.getCountryResponse.country.currency}}", "population":{{Envelope.Body.getCountryResponse.country.population}}, "capital":"{{Envelope.Body.getCountryResponse.country.capital}}", "name":"{{Envelope.Body.getCountryResponse.country.name}}" } {% else %} { "message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*}, "code":"{{Envelope.Body.Fault.faultcode}}" {% if Envelope.Body.Fault.faultactor ~= nil then %} , "actor":"{{Envelope.Body.Fault.faultactor}}" {% end %} } {% end %} input_format: xml proxy-rewrite: headers: set: Content-Type: text/xml upstream: type: roundrobin nodes: - host: host.docker.internal port: 8080 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: soap-route.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: json-xml-plugin spec: plugins: - name: body-transformer config: request: template: | {{_escape_xml(name)}} input_format: json response: template: | {% if Envelope.Body.Fault == nil then %} { "status":"{{_ctx.var.status}}", "currency":"{{Envelope.Body.getCountryResponse.country.currency}}", "population":{{Envelope.Body.getCountryResponse.country.population}}, "capital":"{{Envelope.Body.getCountryResponse.country.capital}}", "name":"{{Envelope.Body.getCountryResponse.country.name}}" } {% else %} { "message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*}, "code":"{{Envelope.Body.Fault.faultcode}}" {% if Envelope.Body.Fault.faultactor ~= nil then %} , "actor":"{{Envelope.Body.Fault.faultactor}}" {% end %} } {% end %} input_format: xml - name: proxy-rewrite config: headers: set: Content-Type: text/xml --- apiVersion: v1 kind: Service metadata: namespace: aic name: ws-external-domain spec: type: ExternalName externalName: host.docker.internal --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-transformer-route spec: parentRefs: - name: apisix rules: - matches: - method: POST path: type: Exact value: /services filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: json-xml-plugin backendRefs: - name: ws-external-domain port: 8080 ``` 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: soap-route.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-transformer-route spec: ingressClassName: apisix http: - name: body-transformer-route match: paths: - /services methods: - POST plugins: - name: body-transformer enable: true config: request: template: | {{_escape_xml(name)}} input_format: json response: template: | {% if Envelope.Body.Fault == nil then %} { "status":"{{_ctx.var.status}}", "currency":"{{Envelope.Body.getCountryResponse.country.currency}}", "population":{{Envelope.Body.getCountryResponse.country.population}}, "capital":"{{Envelope.Body.getCountryResponse.country.capital}}", "name":"{{Envelope.Body.getCountryResponse.country.name}}" } {% else %} { "message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*}, "code":"{{Envelope.Body.Fault.faultcode}}" {% if Envelope.Body.Fault.faultactor ~= nil then %} , "actor":"{{Envelope.Body.Fault.faultactor}}" {% end %} } {% end %} input_format: xml - name: proxy-rewrite enable: true config: headers: set: Content-Type: text/xml upstreams: - name: ws-external-domain --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: ws-external-domain spec: externalNodes: - type: Domain name: host.docker.internal port: 8080 ``` 将配置应用到集群: ``` kubectl apply -f soap-route.yaml ``` ❶ 将请求输入格式设置为 JSON,以便插件在内部应用 JSON 解码器。 ❷ 将响应输入格式设置为 XML,以便插件在内部应用 XML 解码器。 ❸ 将 `Content-Type` 头设置为 `text/xml`,以便上游服务正确响应。 ❹ SOAP 服务的地址。APISIX 在 Docker 中运行时,`host.docker.internal` 解析到宿主机;如果采用其他方式运行 APISIX,请替换为实际地址。 提示 如果调整复杂的文本文件使其成为有效的转换模板比较麻烦,你可以使用 base64 工具对文件进行编码,如下所示: ``` "body-transformer": { "request": { "template": "'"$(base64 -w0 /path/to/request_template_file)"'" }, "response": { "template": "'"$(base64 -w0 /path/to/response_template_file)"'" } } ``` 发送带有有效 JSON 体的请求: ``` curl "http://127.0.0.1:9080/services" -X POST -d '{"name": "Spain"}' ``` 请求中发送的 JSON 体将在转发到上游 SOAP 服务之前转换为 XML,响应体将从 XML 转换回 JSON。 你应该看到类似于以下的响应: ``` { "status": "200", "currency": "EUR", "population": 46704314, "capital": "Madrid", "name": "Spain" } ``` ### 修改请求体[​](#修改请求体 "修改请求体的直接链接") 以下示例演示了如何动态修改请求体。 * Admin API * ADC * Ingress Controller 创建一个带有 `body-transformer` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "body-transformer-route", "uri": "/anything", "plugins": { "body-transformer": { "request": { "template": "{\"foo\":\"{{name .. \" world\"}}\",\"bar\":{{age+10}}}" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个带有 `body-transformer` 的路由: adc.yaml ``` services: - name: body-transformer-service routes: - name: body-transformer-route uris: - /anything plugins: body-transformer: request: template: "{\"foo\":\"{{name .. \" world\"}}\",\"bar\":{{age+10}}}" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: body-transformer-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: body-transformer-plugin-config spec: plugins: - name: body-transformer config: request: template: "{\"foo\":\"{{name .. \" world\"}}\",\"bar\":{{age+10}}}" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-transformer-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: body-transformer-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: body-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-transformer-route spec: ingressClassName: apisix http: - name: body-transformer-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: body-transformer enable: true config: request: template: "{\"foo\":\"{{name .. \" world\"}}\",\"bar\":{{age+10}}}" ``` 将配置应用到集群: ``` kubectl apply -f body-transformer-ic.yaml ``` ❶ 设置一个模板,将 "world" 追加到 name,并将 10 加到 age,然后将它们分别设置为 "foo" 和 "bar" 的值。 发送请求到路由: ``` curl "http://127.0.0.1:9080/anything" -X POST \ -H "Content-Type: application/json" \ -d '{"name":"hello","age":20}' \ -i ``` 你应该看到以下响应: ``` { "args": {}, "data": "{\"foo\":\"hello world\",\"bar\":30}", ... "json": { "bar": 30, "foo": "hello world" }, "method": "POST", ... } ``` ### 使用变量生成请求体[​](#使用变量生成请求体 "使用变量生成请求体的直接链接") 以下示例演示了如何使用 `ctx` 上下文变量动态生成请求体。 * Admin API * ADC * Ingress Controller 创建一个带有 `body-transformer` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "body-transformer-route", "uri": "/anything", "plugins": { "body-transformer": { "request": { "template": "{\"foo\":\"{{_ctx.var.arg_name .. \" world\"}}\"}" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个带有 `body-transformer` 的路由: adc.yaml ``` services: - name: body-transformer-service routes: - name: body-transformer-route uris: - /anything plugins: body-transformer: request: template: "{\"foo\":\"{{_ctx.var.arg_name .. \" world\"}}\"}" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: body-transformer-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: body-transformer-plugin-config spec: plugins: - name: body-transformer config: request: template: "{\"foo\":\"{{_ctx.var.arg_name .. \" world\"}}\"}" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-transformer-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: body-transformer-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: body-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-transformer-route spec: ingressClassName: apisix http: - name: body-transformer-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: body-transformer enable: true config: request: template: "{\"foo\":\"{{_ctx.var.arg_name .. \" world\"}}\"}" ``` 将配置应用到集群: ``` kubectl apply -f body-transformer-ic.yaml ``` ❶ 设置一个模板,使用 [NGINX 变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md#nginx-%E5%8F%98%E9%87%8F) `arg_name` 访问请求参数。 发送带有 `name` 参数的请求到路由: ``` curl -i "http://127.0.0.1:9080/anything?name=hello" ``` 你应该看到像这样的响应: ``` { "args": { "name": "hello" }, ..., "json": { "foo": "hello world" }, ... } ``` ### 将请求体从 YAML 转换为 JSON[​](#将请求体从-yaml-转换为-json "将请求体从 YAML 转换为 JSON的直接链接") 以下示例演示了如何将请求体从 YAML 转换为 JSON。 创建请求转换模板: ``` req_template=$(cat < 18 then context._multipart:set_simple("status", "adult") else context._multipart:set_simple("status", "minor") end local body = context._multipart:tostring() %}{* body *} EOF ) ``` * Admin API * ADC * Ingress Controller 创建一个带有 `body-transformer` 的路由如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < 18 then context._multipart:set_simple("status", "adult") else context._multipart:set_simple("status", "minor") end local body = context._multipart:tostring() %}{* body *} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: body-transformer-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: body-transformer-plugin-config spec: plugins: - name: body-transformer config: request: input_format: multipart template: | {% if tonumber(context.age) > 18 then context._multipart:set_simple("status", "adult") else context._multipart:set_simple("status", "minor") end local body = context._multipart:tostring() %}{* body *} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-transformer-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: body-transformer-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 创建一个启用了 `body-transformer` 插件的路由 Kubernetes 清单文件: body-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-transformer-route spec: ingressClassName: apisix http: - name: body-transformer-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: body-transformer enable: true config: request: input_format: multipart template: | {% if tonumber(context.age) > 18 then context._multipart:set_simple("status", "adult") else context._multipart:set_simple("status", "minor") end local body = context._multipart:tostring() %}{* body *} ``` 将配置应用到集群: ``` kubectl apply -f body-transformer-ic.yaml ``` ❶ 将 `input_format` 设置为 `multipart`。 ❷ 设置为之前创建的请求模板。 发送一个 multipart POST 请求到路由: ``` curl -X POST \ -F "name=john" \ -F "age=10" \ "http://127.0.0.1:9080/anything" ``` 你应该看到类似于以下的响应: ``` { "args": {}, "data": "", "files": {}, "form": { "age": "10", "name": "john", "status": "minor" }, "headers": { "Accept": "*/*", "Content-Length": "361", "Content-Type": "multipart/form-data; boundary=------------------------qtPjk4c8ZjmGOXNKzhqnOP", ... }, ... } ``` ### 基于消费者身份转换响应体[​](#基于消费者身份转换响应体 "基于消费者身份转换响应体的直接链接") 以下示例演示了如何根据不同的消费者身份自定义响应体转换。该示例展示了如何向不同的消费者返回不同的响应格式,同时过滤敏感字段并重命名属性。 创建响应转换模板,该模板根据消费者身份应用不同的转换: ``` rsp_template=$(cat < ## 响应头[​](#响应头 "响应头的直接链接") 根据 `append_waf_resp_header` 和 `append_waf_debug_header` 的配置,插件可以添加以下响应头: | 响应头 | 描述 | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `X-APISIX-CHAITIN-WAF` | 指示 APISIX 是否将请求转发给 WAF 服务器。
• `yes`: 请求已转发给 WAF 服务器。
• `no`: 请求未转发给 WAF 服务器。
• `unhealthy`: 请求匹配配置的规则,但没有可用的 WAF 服务。
• `err`: 插件执行期间发生错误。`X-APISIX-CHAITIN-WAF-ERROR` 头也包含详细信息。
• `waf-err`: 与 WAF 服务器交互时出错。`X-APISIX-CHAITIN-WAF-ERROR` 头也包含详细信息。
• `timeout`: 对 WAF 服务器的请求超时。 | | `X-APISIX-CHAITIN-WAF-TIME` | 请求到 Chaitin WAF 服务器的往返时间 (RTT)(毫秒),包括网络延迟和 WAF 服务器处理时间。 | | `X-APISIX-CHAITIN-WAF-STATUS` | WAF 服务器返回给 APISIX 的状态码。 | | `X-APISIX-CHAITIN-WAF-ACTION` | WAF 服务器返回给 APISIX 的动作。
• `pass`: 请求被 WAF 服务允许。
• `reject`: 请求被 WAF 服务阻止。 | | `X-APISIX-CHAITIN-WAF-ERROR` | 调试头。包含 WAF 错误消息。 | | `X-APISIX-CHAITIN-WAF-SERVER` | 调试头。指示选择了哪个 WAF 服务器。 | ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `chaitin-waf` 插件。 在继续之前,请确保你已安装 [Chaitin WAF (SafeLine)](https://docs.waf.chaitin.com/en/GetStarted/Deploy)。 ### 在路由上阻止恶意请求[​](#在路由上阻止恶意请求 "在路由上阻止恶意请求的直接链接") 以下示例演示了如何与 Chaitin WAF 集成以保护路由上的流量,立即拒绝恶意请求。 * Admin API * ADC * Ingress Controller 使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)配置 Chaitin WAF 连接详细信息(相应地更新地址): ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "nodes": [ { "host": "172.22.222.5", "port": 8000 } ] }' ``` 创建一个路由并在路由上启用 `chaitin-waf` 以阻止被识别为恶意的请求: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "chaitin-waf-route", "uri": "/anything", "plugins": { "chaitin-waf": { "mode": "block", "append_waf_resp_header": true, "append_waf_debug_header": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 将 `mode` 设置为 `block` 以阻止被识别为恶意的请求。 ❷ 将 `append_waf_resp_header` 设置为 `true` 以包含与 WAF 相关的标准响应头。 ❸ 将 `append_waf_debug_header` 设置为 `true` 以包含与 WAF 相关的调试响应头。 adc.yaml ``` plugin_metadata: chaitin-waf: nodes: - host: "172.22.222.5" port: 8000 services: - name: chaitin-waf-service routes: - name: chaitin-waf-route uris: - /anything plugins: chaitin-waf: mode: block append_waf_resp_header: true append_waf_debug_header: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ `nodes`:Chaitin WAF 服务地址列表。请更新 `host` 和 `port`,使其与 Chaitin WAF(雷池)部署一致。 ❷ 将 `mode` 设置为 `block`,阻止被识别为恶意的请求。 ❸ 将 `append_waf_resp_header` 设置为 `true`,以包含 WAF 相关标准响应头。 ❹ 将 `append_waf_debug_header` 设置为 `true`,以包含 WAF 相关调试响应头。 更新 `GatewayProxy` 清单以配置插件元数据。如果 Chaitin WAF 安装在集群外的主机上,请使用该主机的 IP 地址。在大多数部署中,请将 Chaitin WAF 公开为集群内可访问的 `Service`、IP 地址或 DNS 名称,也可以改用节点或 `LoadBalancer` 地址。 gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 你的控制面连接配置 pluginMetadata: chaitin-waf: nodes: - host: "172.22.222.5" port: 8000 ``` ❶ `nodes`:Chaitin WAF 服务地址列表。请更新 `host` 和 `port`,使其与 Chaitin WAF(雷池)部署一致。 * Gateway API * APISIX CRD 创建启用了 `chaitin-waf` 的路由以阻止恶意请求: chaitin-waf-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: chaitin-waf-plugin-config spec: plugins: - name: chaitin-waf config: mode: block append_waf_resp_header: true append_waf_debug_header: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: chaitin-waf-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: chaitin-waf-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yaml ``` 创建启用了 `chaitin-waf` 的路由以阻止恶意请求: chaitin-waf-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: chaitin-waf-route spec: ingressClassName: apisix http: - name: chaitin-waf-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: chaitin-waf enable: true config: mode: block append_waf_resp_header: true append_waf_debug_header: true ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yaml ``` ❷ 将 `mode` 设置为 `block`,阻止被识别为恶意的请求。 ❸ 将 `append_waf_resp_header` 设置为 `true`,以包含 WAF 相关标准响应头。 ❹ 将 `append_waf_debug_header` 设置为 `true`,以包含 WAF 相关调试响应头。 向路由发送标准请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 向路由发送带有 SQL 注入的请求: ``` curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1' ``` 你应该看到类似以下的 `HTTP/1.1 403 Forbidden` 响应: ``` ... X-APISIX-CHAITIN-WAF-STATUS: 403 X-APISIX-CHAITIN-WAF-ACTION: reject X-APISIX-CHAITIN-WAF-SERVER: 172.22.222.5 X-APISIX-CHAITIN-WAF: yes X-APISIX-CHAITIN-WAF-TIME: 3 ... {"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "276be6457d8447a4bf1f792501dfba6c"} ``` ### 监控恶意意图请求[​](#监控恶意意图请求 "监控恶意意图请求的直接链接") 此示例展示了如何与 Chaitin WAF 集成以监控所有带有 `chaitin-waf` 的路由而不拒绝,并在特定路由上拒绝潜在的恶意请求。 * Admin API * ADC * Ingress Controller 使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)配置 Chaitin WAF 连接详细信息(相应地更新地址)并配置模式: ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "nodes": [ { "host": "172.22.222.5", "port": 8000 } ], "mode": "monitor" }' ``` ❶ 在插件元数据中将 `mode` 设置为 `monitor`。如果未在路由上指定 `mode`,这将适用于所有 `chaitin-waf` 插件实例。 创建一个路由并在路由上启用 `chaitin-waf` 而不做任何配置: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "chaitin-waf-route", "uri": "/anything", "plugins": { "chaitin-waf": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` plugin_metadata: chaitin-waf: nodes: - host: "172.22.222.5" port: 8000 mode: monitor services: - name: chaitin-waf-service routes: - name: chaitin-waf-route uris: - /anything plugins: chaitin-waf: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ `nodes`:Chaitin WAF 服务地址列表。请更新 `host` 和 `port`,使其与 Chaitin WAF(雷池)部署一致。 ❷ 在插件元数据中将 `mode` 设置为 `monitor`。如果路由上未指定 `mode`,此配置将应用于所有 `chaitin-waf` 插件实例。 更新 `GatewayProxy` 清单以配置插件元数据。如果 Chaitin WAF 安装在集群外的主机上,请使用该主机的 IP 地址。在大多数部署中,请将 Chaitin WAF 公开为集群内可访问的 `Service`、IP 地址或 DNS 名称,也可以改用节点或 `LoadBalancer` 地址。 gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 你的控制面连接配置 pluginMetadata: chaitin-waf: nodes: - host: "172.22.222.5" port: 8000 mode: monitor ``` ❶ 在插件元数据中将 `mode` 设置为 `monitor`。如果未在路由上指定 `mode`,这将适用于所有 `chaitin-waf` 插件实例。 * Gateway API * APISIX CRD 创建一个启用了 `chaitin-waf`、但未设置任何插件级配置的路由,使其继承插件元数据中的 `monitor` 模式: chaitin-waf-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: chaitin-waf-plugin-config spec: plugins: - name: chaitin-waf config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: chaitin-waf-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: chaitin-waf-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yaml ``` 要覆盖 `monitor` 模式并在路由上阻止恶意请求,请更新 `PluginConfig`,将 `mode` 设置为 `block`: chaitin-waf-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: chaitin-waf-plugin-config spec: plugins: - name: chaitin-waf config: mode: block ``` 将更新后的配置应用到集群: ``` kubectl apply -f chaitin-waf-ic.yaml ``` 创建一个启用了 `chaitin-waf`、但未设置任何插件级配置的路由,使其继承插件元数据中的 `monitor` 模式: chaitin-waf-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: chaitin-waf-route spec: ingressClassName: apisix http: - name: chaitin-waf-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: chaitin-waf enable: true config: {} ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f chaitin-waf-ic.yaml ``` 要覆盖 `monitor` 模式并在路由上阻止恶意请求,请更新 `ApisixRoute`,将 `mode` 设置为 `block`: chaitin-waf-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: chaitin-waf-route spec: ingressClassName: apisix http: - name: chaitin-waf-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: chaitin-waf enable: true config: mode: block ``` 将更新后的配置应用到集群: ``` kubectl apply -f chaitin-waf-ic.yaml ``` 向路由发送标准请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 向路由发送带有 SQL 注入的请求: ``` curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1' ``` 你应该同样收到 `HTTP/1.1 200 OK` 响应,因为请求在 `monitor` 模式下未被阻止,但在日志条目中观察到以下内容: ``` 2025/09/09 11:44:08 [warn] 115#115: *31683 [lua] chaitin-waf.lua:385: do_access(): chaitin-waf monitor mode: request would have been rejected, event_id: 49bed20603e242f9be5ba6f1744bba4b, client: 172.20.0.1, server: _, request: "POST /anything HTTP/1.1", host: "127.0.0.1:9080" ``` 如果你在路由上显式配置 `mode`,它将优先于插件元数据中的配置。例如,如果你创建一个如下路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "chaitin-waf-route", "uri": "/anything", "plugins": { "chaitin-waf": { "mode": "block" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` plugin_metadata: chaitin-waf: nodes: - host: "172.22.222.5" port: 8000 mode: monitor services: - name: chaitin-waf-service routes: - name: chaitin-waf-route uris: - /anything plugins: chaitin-waf: mode: block upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `PluginConfig`,将 `mode` 设置为 `block`: chaitin-waf-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: chaitin-waf-plugin-config spec: plugins: - name: chaitin-waf config: mode: block ``` 将更新后的配置应用到集群: ``` kubectl apply -f chaitin-waf-ic.yaml ``` 更新 `ApisixRoute`,将 `mode` 设置为 `block`: chaitin-waf-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: chaitin-waf-route spec: ingressClassName: apisix http: - name: chaitin-waf-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: chaitin-waf enable: true config: mode: block ``` 将更新后的配置应用到集群: ``` kubectl apply -f chaitin-waf-ic.yaml ``` 向路由发送标准请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 向路由发送带有 SQL 注入的请求: ``` curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1' ``` 你应该看到类似以下的 `HTTP/1.1 403 Forbidden` 响应: ``` ... X-APISIX-CHAITIN-WAF-STATUS: 403 X-APISIX-CHAITIN-WAF-ACTION: reject X-APISIX-CHAITIN-WAF: yes X-APISIX-CHAITIN-WAF-TIME: 3 ... {"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "c3eb25eaa7ae4c0d82eb8ceebf3600d0"} ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * mode string 默认值:`block` 有效值: `off`、`monitor` 或 `block` *** 确定插件对匹配请求的行为模式。 在 `off` 模式下,跳过 WAF 检查。在 `monitor` 模式下,记录潜在威胁的请求但不阻止。在 `block` 模式下,具有威胁的请求将按照 WAF 服务的决定被阻止。 * match array\[object] *** 匹配规则数组。插件使用这些规则来决定是否对请求执行 WAF 检查。如果列表为空,则处理所有请求。 * vars array\[array] *** 一个或多个匹配条件数组,格式为 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md),用于有条件地执行插件。 * append\_waf\_resp\_header boolean 默认值:`true` *** 如果为 true,则添加响应头 `X-APISIX-CHAITIN-WAF`、`X-APISIX-CHAITIN-WAF-TIME`、`X-APISIX-CHAITIN-WAF-ACTION` 和 `X-APISIX-CHAITIN-WAF-STATUS`。 * append\_waf\_debug\_header boolean 默认值:`false` *** 如果为 true,则在响应中添加调试头 `X-APISIX-CHAITIN-WAF-ERROR` 和 `X-APISIX-CHAITIN-WAF-SERVER`。仅当 `append_waf_resp_header` 为 `true` 时有效。 * config object *** Chaitin WAF 服务配置。指定时,这些设置会覆盖相应的元数据默认值。 * connect\_timeout integer 默认值:`1000` *** 到 WAF 服务的连接超时时间,单位为毫秒。 * send\_timeout integer 默认值:`1000` *** 向 WAF 服务发送数据的超时时间,单位为毫秒。 * read\_timeout integer 默认值:`1000` *** 从 WAF 服务接收数据的读取超时时间,单位为毫秒。 * req\_body\_size integer 默认值:`1024` *** 允许的最大请求体大小,单位为 KB。 * keepalive\_size integer 默认值:`256` *** 可以并发维护的到 WAF 检测服务的最大空闲连接数。 * keepalive\_timeout integer 默认值:`60000` *** WAF 服务的空闲连接超时时间,单位为毫秒。 * real\_client\_ip boolean 默认值:`true` *** 如果为 true,则使用网关已解析的客户端 IP,其中包括受信任代理和 Real IP 配置的影响。如果为 false,则使用连接的直接对端地址。插件不会直接读取客户端提供的转发请求头。 * log\_resp boolean *** 如果为 true,在响应已经返回给客户端之后,除请求外还把响应一并上报给 WAF 检测服务。该上报仅供参考,不会阻断也不会修改响应。API7 企业版 3.9.20 和 3.10.7 起可用。 * resp\_body\_size integer *** 上报的响应体最大大小,单位为 KB。设置为 `0` 表示只上报响应头。仅当 `log_resp` 为 true 时生效。API7 企业版 3.9.20 和 3.10.7 起可用。 * extra\_ignored\_content\_types string *** 以逗号分隔的额外响应 content type 列表,在内置忽略列表之外。命中的响应完全不会上报给 WAF 检测服务,响应头也不会上报。仅当 `log_resp` 为 true 时生效。API7 企业版 3.9.20 和 3.10.7 起可用。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * nodes array\[object] 必填 *** Chaitin WAF 服务的地址数组。 * host string 必填 *** Chaitin WAF 服务地址。支持 IPv4、IPv6、Unix Socket 等。 * port integer 默认值:`80` *** Chaitin WAF 服务端口。 * mode string 默认值:`block` *** 确定插件对匹配请求的行为模式。 在 `off` 模式下,跳过 WAF 检查。在 `monitor` 模式下,记录潜在威胁的请求但不阻止。在 `block` 模式下,具有威胁的请求将按照 WAF 服务的决定被阻止。 * config object *** Chaitin WAF 服务配置。 * connect\_timeout integer 默认值:`1000` *** 到 WAF 服务的连接超时时间,单位为毫秒。 * send\_timeout integer 默认值:`1000` *** 向 WAF 服务发送数据的超时时间,单位为毫秒。 * read\_timeout integer 默认值:`1000` *** 从 WAF 服务接收数据的读取超时时间,单位为毫秒。 * req\_body\_size integer 默认值:`1024` *** 允许的最大请求体大小,单位为 KB。 * keepalive\_size integer 默认值:`256` *** 可以并发维护的到 WAF 检测服务的最大空闲连接数。 * keepalive\_timeout integer 默认值:`60000` *** WAF 服务的空闲连接超时时间,单位为毫秒。 * real\_client\_ip boolean 默认值:`true` *** 如果为 true,则使用网关已解析的客户端 IP,其中包括受信任代理和 Real IP 配置的影响。如果为 false,则使用连接的直接对端地址。插件不会直接读取客户端提供的转发请求头。 * log\_resp boolean 默认值:`false` *** 如果为 true,在响应已经返回给客户端之后,除请求外还把响应一并上报给 WAF 检测服务。该上报仅供参考,不会阻断也不会修改响应。API7 企业版 3.9.20 和 3.10.7 起可用。 * resp\_body\_size integer 默认值:`4` *** 上报的响应体最大大小,单位为 KB。设置为 `0` 表示只上报响应头。仅当 `log_resp` 为 true 时生效。API7 企业版 3.9.20 和 3.10.7 起可用。 * extra\_ignored\_content\_types string *** 以逗号分隔的额外响应 content type 列表,在内置忽略列表之外。命中的响应完全不会上报给 WAF 检测服务,响应头也不会上报。仅当 `log_resp` 为 true 时生效。API7 企业版 3.9.20 和 3.10.7 起可用。 --- # clickhouse-logger `clickhouse-logger` 插件将请求和响应日志以批处理的方式推送到 ClickHouse 数据库,并支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `clickhouse-logger` 插件。 要按照示例操作,请启动一个用户名为 `default` 且密码为空的 ClickHouse 服务器示例: * Docker * Kubernetes ``` docker run -d -p 8123:8123 -p 9000:9000 -p 9009:9009 --name clickhouse-server clickhouse/clickhouse-server ``` 为 ClickHouse Deployment 创建 Kubernetes 清单文件: clickhouse-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: clickhouse-server spec: replicas: 1 selector: matchLabels: app: clickhouse-server template: metadata: labels: app: clickhouse-server spec: containers: - name: clickhouse-server image: clickhouse/clickhouse-server ports: - containerPort: 8123 - containerPort: 9000 - containerPort: 9009 ``` 为 ClickHouse Service 创建 Kubernetes 清单文件: clickhouse-service.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: clickhouse-server spec: selector: app: clickhouse-server ports: - name: http port: 8123 targetPort: 8123 - name: native port: 9000 targetPort: 9000 type: ClusterIP ``` 应用清单: ``` kubectl apply -f clickhouse-deployment.yaml -f clickhouse-service.yaml ``` ### 使用默认日志格式记录日志[​](#使用默认日志格式记录日志 "使用默认日志格式记录日志的直接链接") 以下示例展示了如何使用默认日志格式记录日志。 在 ClickHouse 数据库中创建一个名为 `default_logs` 的表,其列对应于你的日志格式: * Docker * Kubernetes ``` curl "http://127.0.0.1:8123" -X POST -d ' CREATE TABLE default.default_logs ( host String, client_ip String, route_id String, service_id String, start_time String, latency String, upstream_latency String, apisix_latency String, consumer String, request String, response String, server String, PRIMARY KEY(`start_time`) ) ENGINE = MergeTree() ' --user default: ``` ``` kubectl exec -n aic deploy/clickhouse-server -- clickhouse-client --query " CREATE TABLE default.default_logs ( host String, client_ip String, route_id String, service_id String, start_time String, latency String, upstream_latency String, apisix_latency String, consumer String, request String, response String, server String, PRIMARY KEY(start_time) ) ENGINE = MergeTree() " ``` 创建一个启用 `clickhouse-logger` 的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "clickhouse-logger-route", "uri": "/get", "plugins": { "clickhouse-logger": { "user": "default", "password": "", "database": "default", "logtable": "default_logs", "endpoint_addrs": ["http://127.0.0.1:8123"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: clickhouse-logger-route plugins: clickhouse-logger: user: default password: "" database: default logtable: default_logs endpoint_addrs: - "http://127.0.0.1:8123" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD clickhouse-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: clickhouse-logger-plugin-config spec: plugins: - name: clickhouse-logger config: user: default password: "" database: default logtable: default_logs endpoint_addrs: - "http://clickhouse-server.aic.svc:8123" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: clickhouse-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: clickhouse-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` clickhouse-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: clickhouse-logger-route spec: ingressClassName: apisix http: - name: clickhouse-logger-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: clickhouse-logger config: user: default password: "" database: default logtable: default_logs endpoint_addrs: - "http://clickhouse-server.aic.svc:8123" ``` 应用配置: ``` kubectl apply -f clickhouse-logger-ic.yaml ``` 向路由发送请求以生成日志条目: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该会看到一个 `HTTP/1.1 200 OK` 响应。 向 ClickHouse 发送请求以查看日志条目: ``` echo 'SELECT * FROM default.default_logs FORMAT Pretty' | curl "http://127.0.0.1:8123/?" -d @- ``` 你应该会看到类似以下的日志条目: ``` ┏━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ host ┃ client_ip ┃ route_id ┃ service_id ┃ start_time ┃ latency ┃ upstream_latency ┃ apisix_latency ┃ consumer ┃ request ┃ response ┃ server ┃ ┡━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ │ 172.19.0.1 │ clickhouse-logger-route │ │ 1703026935235 │ 481.00018501282 │ 473 │ 8.0001850128174 │ │ {"method":"GET","uri":"/get","headers":{"host":"127.0.0.1:9080","user-agent":"curl/7.29.0","accept":"*/*"},"url":"http://127.0.0.1:9080/get","querystring":{},"size":81} │ {"headers":{"access-control-allow-credentials":"true","access-control-allow-origin":"*","content-type":"application/json","content-length":"299","date":"Tue,19 Dec 2023 23:02:15 GMT","connection":"close","server":"APISIX/3.8.0"},"status":200,"size":526} │ {"hostname":"85cf6f06914e","version":"3.8.0"} │ └──────┴────────────┴─────────────────────────┴────────────┴───────────────┴─────────────────┴──────────────────┴─────────────────┴──────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────┘ ``` ### 通过插件元数据自定义日志格式[​](#通过插件元数据自定义日志格式 "通过插件元数据自定义日志格式的直接链接") 以下示例展示了如何使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)自定义日志格式。 在 ClickHouse 数据库中创建一个名为 `custom_logs` 的表,其列对应于你的自定义日志格式: * Docker * Kubernetes ``` curl "http://127.0.0.1:8123" -X POST -d ' CREATE TABLE default.custom_logs ( host String, client_ip String, route_id String, service_id String, `@timestamp` String, PRIMARY KEY(`@timestamp`) ) ENGINE = MergeTree() ' --user default: ``` ``` kubectl exec -n aic deploy/clickhouse-server -- clickhouse-client --query " CREATE TABLE default.custom_logs ( host String, client_ip String, route_id String, service_id String, \`@timestamp\` String, PRIMARY KEY(\`@timestamp\`) ) ENGINE = MergeTree() " ``` 创建一个启用 `clickhouse-logger` 插件的路由,用于将指定格式的日志转发到 ClickHouse: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "clickhouse-logger-route", "uri": "/get", "plugins": { "clickhouse-logger": { "user": "default", "password": "", "database": "default", "logtable": "custom_logs", "endpoint_addrs": ["http://127.0.0.1:8123"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: clickhouse-logger-route plugins: clickhouse-logger: user: default password: "" database: default logtable: custom_logs endpoint_addrs: - "http://127.0.0.1:8123" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD clickhouse-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: clickhouse-logger-plugin-config spec: plugins: - name: clickhouse-logger config: user: default password: "" database: default logtable: custom_logs endpoint_addrs: - "http://clickhouse-server.aic.svc:8123" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: clickhouse-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: clickhouse-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` clickhouse-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: clickhouse-logger-route spec: ingressClassName: apisix http: - name: clickhouse-logger-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: clickhouse-logger config: user: default password: "" database: default logtable: custom_logs endpoint_addrs: - "http://clickhouse-server.aic.svc:8123" ``` 应用配置: ``` kubectl apply -f clickhouse-logger-ic.yaml ``` 配置 `clickhouse-logger` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/clickhouse-logger" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "log_format": { "host": "$host", "client_ip": "$remote_addr", "route_id": "$route_id", "service_id": "$service_id", "@timestamp": "$time_iso8601" } }' ``` adc.yaml ``` plugin_metadata: - name: clickhouse-logger log_format: host: "$host" client_ip: "$remote_addr" route_id: "$route_id" service_id: "$service_id" "@timestamp": "$time_iso8601" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` clickhouse-logger-metadata.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: service: name: apisix-admin port: 9180 auth: type: AdminKey adminKey: value: edd1c9f034335f136f87ad84b625c8f1 pluginMetadata: clickhouse-logger: log_format: host: "$host" client_ip: "$remote_addr" route_id: "$route_id" service_id: "$service_id" "@timestamp": "$time_iso8601" ``` 应用配置: ``` kubectl apply -f clickhouse-logger-metadata.yaml ``` 向路由发送请求以生成日志条目: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该会看到一个 `HTTP/1.1 200 OK` 响应。 向 ClickHouse 发送请求以查看日志条目: ``` echo 'SELECT * FROM default.custom_logs FORMAT Pretty' | curl "http://127.0.0.1:8123/?" -d @- ``` 你应该会看到类似以下的日志条目: ``` ┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ host ┃ client_ip ┃ route_id ┃ service_id ┃ @timestamp ┃ ┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 127.0.0.1 │ 172.19.0.1 │ clickhouse-logger-route │ │ 2023-12-19T23:25:43+00:00 │ └───────────┴────────────┴─────────────────────────┴────────────┴───────────────────────────┘ ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * endpoint\_addr string *** 已废弃,请改用 `endpoint_addrs`。ClickHouse 端点。`endpoint_addr` 和 `endpoint_addrs` 二选一配置。 * endpoint\_addrs array *** ClickHouse 端点。`endpoint_addrs` 和已废弃的 `endpoint_addr` 二选一配置。 * database string 必填 *** 存储日志的数据库名称。 * logtable string 必填 *** 存储日志的表名称。 * user string 必填 *** ClickHouse 用户名。 从 APISIX 3.16.0 起,支持使用 `$ENV://` 前缀引用环境变量中的值,或使用 `$secret://` 前缀引用密钥管理器中的值。有关更多信息,请参阅[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * password string 必填 *** ClickHouse 密码。 该值在存储到 etcd 前会使用 AES 加密。 从 APISIX 3.16.0 起,支持使用 `$ENV://` 前缀引用环境变量中的值,或使用 `$secret://` 前缀引用密钥管理器中的值。有关更多信息,请参阅[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * timeout integer 默认值:`3` 有效值: 大于 0 *** 发送请求后的连接保持时间。 * ssl\_verify boolean 默认值:`true` *** 如果设置为 true,验证 SSL。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 你也可以通过配置[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)来全局配置日志格式,这将对所有 `clickhouse-logger` 插件实例生效。如果单个插件实例配置的日志格式与插件元数据中配置的日志格式不同,则单个插件实例的配置优先级更高。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/clickhouse-logger.md#通过插件元数据自定义日志格式)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * include\_req\_body boolean 默认值:`false` *** 如果设置为 true,在日志中包含请求体。注意:如果请求体过大导致无法保存在内存中,由于 NGINX 的限制,它可能无法被记录。 * include\_req\_body\_expr array\[array] *** 一个包含一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。当 `include_req_body` 为 true 时使用。只有当此处配置的表达式求值为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果设置为 true,在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 一个包含一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。当 `include_resp_body` 为 true 时使用。只有当此处配置的表达式求值为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * name string 默认值:`clickhouse-logger` *** 批处理器的唯一标识符。如果你使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称将导出在 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每一批次允许的最大日志条目数。一旦达到该数值,批次将被发送到日志服务。将此参数设置为 1 意味着立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(以秒为单位)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 批次中最旧条目在发送到日志服务之前允许保留的最长时间(以秒为单位)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(以秒为单位)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 在丢弃日志条目之前允许的最大失败重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # consumer-restriction `consumer-restriction` 插件支持基于消费者名称、路由 ID、服务 ID 或消费者组 ID 的访问控制。 该插件需要与认证插件一起工作,例如 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 和 [`jwt-auth`](https://docs.apiseven.com/hub/jwt-auth.md),这意味着你的用例中应始终至少创建一个[消费者](https://docs.apiseven.com/apisix/key-concepts/consumers.md)。有关详细信息,请参阅下面的示例。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `consumer-restriction` 插件。 虽然示例使用 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 作为身份认证方法,但你可以根据需要轻松调整为其他身份认证插件。 ### 基于消费者限制访问[​](#基于消费者限制访问 "基于消费者限制访问的直接链接") 以下示例演示了如何在路由上使用 `consumer-restriction` 插件,通过消费者名称限制消费者访问,其中消费者通过 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 进行身份认证。 * Admin API * ADC * Ingress Controller 创建一个消费者 `JohnDoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "JohnDoe" }' ``` 为消费者创建 `key-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/JohnDoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建第二个消费者 `JaneDoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "JaneDoe" }' ``` 为消费者创建 `key-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/JaneDoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 接下来,创建一个启用了密钥身份认证的路由,并配置 `consumer-restriction` 仅允许消费者 `JaneDoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "consumer-restricted-route", "uri": "/get", "plugins": { "key-auth": {}, "consumer-restriction": { "whitelist": ["JaneDoe"] } }, "upstream" : { "nodes": { "httpbin.org":1 } } }' ``` adc.yaml ``` consumers: - username: JohnDoe credentials: - name: cred-john-key-auth type: key-auth config: key: john-key - username: JaneDoe credentials: - name: cred-jane-key-auth type: key-auth config: key: jane-key services: - name: consumer-restriction-service routes: - name: consumer-restricted-route uris: - /get plugins: key-auth: {} consumer-restriction: whitelist: - "JaneDoe" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` Ingress Controller 中的消费者名称格式 使用 API7 Ingress Controller 配置消费者时,消费者名称将以 `namespace_consumername` 格式生成。例如,`aic` 命名空间中名为 `janedoe` 的消费者会变为 `aic_janedoe`。请在 `consumer-restriction` 的 `whitelist` 或 `blacklist` 中使用此格式。 * Gateway API * APISIX CRD consumer-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: key-auth name: john-key-auth config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: janedoe spec: gatewayRef: name: apisix credentials: - type: key-auth name: jane-key-auth config: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: consumer-restriction-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: consumer-restriction config: whitelist: - "aic_janedoe" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: consumer-restriction-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: consumer-restriction-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` consumer-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: janedoe spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: consumer-restriction-route spec: ingressClassName: apisix http: - name: consumer-restriction-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: key-auth enable: true - name: consumer-restriction enable: true config: whitelist: - "aic_janedoe" ``` 将配置应用到集群: ``` kubectl apply -f consumer-restriction-ic.yaml ``` 以消费者 `JohnDoe` 身份向路由发送请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key' ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应,并包含以下消息: ``` {"message":"The consumer_name is forbidden."} ``` 以消费者 `JaneDoe` 身份向路由发送另一个请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key' ``` 你应该收到 `HTTP/1.1 200 OK` 响应,表明消费者访问被允许。 ### 基于消费者和 HTTP 方法限制访问[​](#基于消费者和-http-方法限制访问 "基于消费者和 HTTP 方法限制访问的直接链接") 以下示例演示了如何在路由上使用 `consumer-restriction` 插件,通过消费者名称和 HTTP 方法限制消费者访问,其中消费者通过 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 进行身份认证。 * Admin API * ADC * Ingress Controller 创建一个消费者 `JohnDoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "JohnDoe" }' ``` 为消费者创建 `key-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/JohnDoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建第二个消费者 `JaneDoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "JaneDoe" }' ``` 为消费者创建 `key-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/JaneDoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 接下来,创建一个启用了密钥身份认证的路由,并使用 `consumer-restriction` 仅允许消费者使用配置的 HTTP 方法: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "consumer-restricted-route", "uri": "/anything", "plugins": { "key-auth": {}, "consumer-restriction": { "allowed_by_methods":[ { "user": "JohnDoe", "methods": ["GET"] }, { "user": "JaneDoe", "methods": ["POST"] } ] } }, "upstream" : { "nodes": { "httpbin.org":1 } } }' ``` adc.yaml ``` consumers: - username: JohnDoe credentials: - name: cred-john-key-auth type: key-auth config: key: john-key - username: JaneDoe credentials: - name: cred-jane-key-auth type: key-auth config: key: jane-key services: - name: consumer-restriction-service routes: - name: consumer-restricted-route uris: - /anything plugins: key-auth: {} consumer-restriction: allowed_by_methods: - user: "JohnDoe" methods: - "GET" - user: "JaneDoe" methods: - "POST" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD consumer-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: key-auth name: john-key-auth config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: janedoe spec: gatewayRef: name: apisix credentials: - type: key-auth name: jane-key-auth config: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: consumer-restriction-methods-config spec: plugins: - name: key-auth config: _meta: disable: false - name: consumer-restriction config: allowed_by_methods: - user: "aic_johndoe" methods: - "GET" - user: "aic_janedoe" methods: - "POST" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: consumer-restriction-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: consumer-restriction-methods-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f consumer-restriction-ic.yaml ``` consumer-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: janedoe spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: consumer-restriction-route spec: ingressClassName: apisix http: - name: consumer-restriction-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: key-auth enable: true - name: consumer-restriction enable: true config: allowed_by_methods: - user: "aic_johndoe" methods: - "GET" - user: "aic_janedoe" methods: - "POST" ``` 将配置应用到集群: ``` kubectl apply -f consumer-restriction-ic.yaml ``` 以消费者 `JohnDoe` 身份向路由发送 POST 请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -H 'apikey: john-key' ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应,并包含以下消息: ``` {"message":"The consumer_name is forbidden."} ``` 现在,以消费者 `JohnDoe` 身份向路由发送 GET 请求: ``` curl -i "http://127.0.0.1:9080/anything" -X GET -H 'apikey: john-key' ``` 你应该收到 `HTTP/1.1 200 OK` 响应,表明消费者访问被允许。 你还可以通过以消费者 `JaneDoe` 身份发送请求来验证配置,并观察行为是否与路由上的 `consumer-restriction` 插件配置相符。 ### 基于服务 ID 限制访问[​](#基于服务-id-限制访问 "基于服务 ID 限制访问的直接链接") 以下示例演示了如何使用 `consumer-restriction` 插件基于服务 ID 限制消费者访问,其中消费者通过 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 进行身份认证。 * Admin API * ADC * Ingress Controller 创建两个示例服务: ``` curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "srv-1", "upstream": { "type": "roundrobin", "nodes": { "httpbin.org":1 } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "srv-2", "upstream": { "type": "roundrobin", "nodes": { "mock.api7.ai":1 } } }' ``` 接下来,创建一个带有 `key-auth` 的消费者,并配置 `consumer-restriction` 仅允许 `srv-1` 服务: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "JohnDoe", "plugins": { "key-auth": { "key": "john-key" }, "consumer-restriction": { "type": "service_id", "whitelist": ["srv-1"] } } }' ``` 最后,创建两个路由,每个路由属于之前创建的服务之一: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "srv-1-route", "uri": "/anything", "service_id": "srv-1" }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "srv-2-route", "uri": "/srv-2", "service_id": "srv-2" }' ``` adc.yaml ``` consumers: - username: JohnDoe plugins: key-auth: key: john-key consumer-restriction: type: service_id whitelist: - "srv-1" services: - name: srv-1 routes: - name: srv-1-route uris: - /anything upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 - name: srv-2 routes: - name: srv-2-route uris: - /srv-2 upstream: type: roundrobin nodes: - host: mock.api7.ai port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` Ingress Controller 中的服务 ID 格式 使用 API7 Ingress Controller 配置路由时,APISIX 服务 ID 会自动生成为 `{namespace}_{routeName}_{ruleIndex}` 的哈希值。这些 ID 难以预先确定,建议改用基于消费者名称的限制方式。 向 `srv-1` 服务中的路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -H 'apikey: john-key' ``` 你应该收到 `HTTP/1.1 200 OK` 响应,表明消费者访问被允许。 向 `srv-2` 服务中的路由发送请求: ``` curl -i "http://127.0.0.1:9080/srv-2" -H 'apikey: john-key' ``` 你应该收到 `HTTP/1.1 401 Unauthorized` 响应,并包含以下消息: ``` {"message":"The request is rejected, please check the service_id for this request"} ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * type string 默认值:`consumer_name` 有效值: `consumer_name`、`consumer_group_id`、`service_id` 或 `route_id` *** 限制依据的键类型。 * whitelist array\[string] *** 白名单对象列表。 应至少配置 `whitelist`、`blacklist` 和 `allowed_by_methods` 中的一个。如果全部配置,优先级为 `blacklist` > `whitelist` > `allowed_by_methods`。 * blacklist array\[string] *** 黑名单对象列表。 应至少配置 `whitelist`、`blacklist` 和 `allowed_by_methods` 中的一个。如果全部配置,优先级为 `blacklist` > `whitelist` > `allowed_by_methods`。 * allowed\_by\_methods array\[object] *** 消费者名称及其对应的允许 HTTP 方法的键值对列表。 应至少配置 `whitelist`、`blacklist` 和 `allowed_by_methods` 中的一个。如果全部配置,优先级为 `blacklist` > `whitelist` > `allowed_by_methods`。 * user string *** 消费者用户名。 * methods array\[string] 有效值: `GET`、`POST`、`PUT`、`DELETE`、`PATCH`、`HEAD`、`OPTIONS`、`CONNECT`、`TRACE`、`PURGE` 方法的任意组合 *** 消费者允许的 HTTP 方法列表。 * rejected\_code integer 默认值:`403` 有效值: 大于或等于 200 *** 请求被拒绝时返回的 HTTP 状态码。 * rejected\_msg string *** 请求被拒绝时返回的错误消息。 --- # cors `cors` 插件允许你启用[跨源资源共享 (CORS)](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS)。CORS 是一种基于 HTTP 头的机制,允许服务器指定除自身以外的任何来源(域、协议或端口),并指示浏览器允许加载来自这些来源的资源。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下使用 `cors` 插件配置路由。 ### 为路由启用 CORS[​](#为路由启用-cors "为路由启用 CORS的直接链接") 以下示例展示了如何在路由上启用 CORS,以允许从来源列表加载资源。 * Admin API * ADC * Ingress Controller 创建一个带有 `cors` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cors-route", "uri": "/anything", "plugins": { "cors": { "allow_origins": "http://sub.domain.com,http://sub2.domain.com", "allow_methods": "GET,POST", "allow_headers": "headr1,headr2", "expose_headers": "ex-headr1,ex-headr2", "max_age": 50, "allow_credential": true } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: cors-service routes: - name: cors-route uris: - /anything plugins: cors: allow_origins: "http://sub.domain.com,http://sub2.domain.com" allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_credential: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD cors-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: cors-plugin-config spec: plugins: - name: cors config: allow_origins: "http://sub.domain.com,http://sub2.domain.com" allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_credential: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: cors-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: cors-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f cors-ic.yaml ``` cors-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: cors-route spec: ingressClassName: apisix http: - name: cors-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: cors enable: true config: allow_origins: "http://sub.domain.com,http://sub2.domain.com" allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_credential: true ``` 将配置应用到集群: ``` kubectl apply -f cors-ic.yaml ``` ❶ `allow_origins`: 配置允许的来源,用逗号分隔。要允许所有来源,请将其设置为 `*`。 ❷ `max_age`: 配置结果缓存的最大时间(以秒为单位)。 ❸ `allow_credential`: 设置为 `true` 以允许随请求发送凭据(cookie、HTTP 身份认证和客户端 SSL 证书)。如果将其设置为 true,则不能将 `*` 用于其他 cors 属性。 使用允许的来源向路由发送 HEAD 请求: ``` curl "http://127.0.0.1:9080/anything" -H "Origin: http://sub2.domain.com" -I ``` 你应该收到 `HTTP/1.1 200 OK` 响应并观察到 CORS 头: ``` ... Access-Control-Allow-Origin: http://sub2.domain.com Access-Control-Allow-Credentials: true Server: APISIX/3.8.0 Vary: Origin Access-Control-Allow-Methods: GET,POST Access-Control-Max-Age: 50 Access-Control-Expose-Headers: ex-headr1,ex-headr2 Access-Control-Allow-Headers: headr1,headr2 ``` 使用未允许的来源向路由发送 HEAD 请求: ``` curl "http://127.0.0.1:9080/anything" -H "Origin: http://sub3.domain.com" -I ``` 你应该收到 `HTTP/1.1 200 OK` 响应,没有任何 CORS 头: ``` ... Server: APISIX/3.8.0 Vary: Origin ``` ### 使用正则匹配来源[​](#使用正则匹配来源 "使用正则匹配来源的直接链接") 以下示例演示了如何使用 `allow_origins_by_regex` 字段通过正则表达式匹配 `allow_origins` 中的来源。 * Admin API * ADC * Ingress Controller 创建一个带有 `cors` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cors-route", "uri": "/anything", "plugins": { "cors": { "allow_methods": "GET,POST", "allow_headers": "headr1,headr2", "expose_headers": "ex-headr1,ex-headr2", "max_age": 50, "allow_origins_by_regex": [ ".*\\.test.com$" ] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: cors-service routes: - name: cors-route uris: - /anything plugins: cors: allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_origins_by_regex: - ".*\\.test.com$" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD cors-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: cors-regex-plugin-config spec: plugins: - name: cors config: allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_origins_by_regex: - ".*\\.test.com$" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: cors-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: cors-regex-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f cors-ic.yaml ``` cors-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: cors-route spec: ingressClassName: apisix http: - name: cors-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: cors enable: true config: allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_origins_by_regex: - ".*\\.test.com$" ``` 将配置应用到集群: ``` kubectl apply -f cors-ic.yaml ``` ❶ `allow_origins_by_regex`: 使用正则表达式允许来源。如果与 `allow_origins` 一起使用,则 `allow_origins` 将被忽略。 使用允许的来源向路由发送 HEAD 请求: ``` curl "http://127.0.0.1:9080/anything" -H "Origin: http://a.test.com" -I ``` 你应该收到 `HTTP/1.1 200 OK` 响应并观察到 CORS 头: ``` ... Access-Control-Allow-Origin: http://a.test.com Access-Control-Allow-Credentials: true Server: APISIX/3.8.0 Access-Control-Allow-Methods: GET,POST Access-Control-Max-Age: 50 Access-Control-Expose-Headers: ex-headr1,ex-headr2 Access-Control-Allow-Headers: headr1,headr2 ``` 你也可以尝试使用无效的来源发出请求: ``` curl "http://127.0.0.1:9080/anything" -H "Origin: http://a.test2.com" -I ``` 你应该收到 `HTTP/1.1 200 OK` 响应,没有任何 CORS 头: ``` ... Server: APISIX/3.8.0 Vary: Origin ``` ### 在插件元数据中配置来源[​](#在插件元数据中配置来源 "在插件元数据中配置来源的直接链接") 以下示例演示了如何在[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)中配置来源,并在 `cors` 插件中将其引用为允许的来源。 * Admin API * ADC * Ingress Controller 为 `cors` 插件配置插件元数据: ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/cors" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "allow_origins": { "key_1": "https://domain.com", "key_2": "https://sub.domain.com,https://sub2.domain.com", "key_3": "*" } }' ``` ❶ `allow_origins` : 键和允许来源的映射。键将用于匹配路由中的来源。 使用 `allow_origins_by_metadata` 创建一个带有 `cors` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cors-route", "uri": "/anything", "plugins": { "cors": { "allow_methods": "GET,POST", "allow_headers": "headr1,headr2", "expose_headers": "ex-headr1,ex-headr2", "max_age": 50, "allow_origins_by_metadata": ["key_1"] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` ❶ `allow_origins_by_metadata`: 元数据中用于匹配来源的键。 adc.yaml ``` plugin_metadata: cors: allow_origins: key_1: "https://domain.com" key_2: "https://sub.domain.com,https://sub2.domain.com" key_3: "*" services: - name: cors-service routes: - name: cors-route uris: - /anything plugins: cors: allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_origins_by_metadata: - "key_1" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 更新 `GatewayProxy` 清单以配置插件元数据: gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 你的控制面连接配置 pluginMetadata: cors: allow_origins: key_1: "https://domain.com" key_2: "https://sub.domain.com,https://sub2.domain.com" key_3: "*" ``` ❶ `allow_origins`:由键和允许的源组成的映射。该键用于匹配路由中的源。 * Gateway API * APISIX CRD 创建配置了 `allow_origins_by_metadata` 的路由: cors-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: cors-metadata-plugin-config spec: plugins: - name: cors config: allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_origins_by_metadata: - "key_1" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: cors-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: cors-metadata-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 创建配置了 `allow_origins_by_metadata` 的路由: cors-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: cors-route spec: ingressClassName: apisix http: - name: cors-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: cors enable: true config: allow_methods: "GET,POST" allow_headers: "headr1,headr2" expose_headers: "ex-headr1,ex-headr2" max_age: 50 allow_origins_by_metadata: - "key_1" ``` ❶ `allow_origins_by_metadata`: 元数据中用于匹配来源的键。 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f cors-ic.yaml ``` 使用允许的来源向路由发送 HEAD 请求: ``` curl "http://127.0.0.1:9080/anything" -H "Origin: https://domain.com" -I ``` 你应该收到 `HTTP/1.1 200 OK` 响应并观察到 CORS 头: ``` ... Access-Control-Allow-Origin: https://domain.com Access-Control-Allow-Credentials: true Server: APISIX/3.8.0 Access-Control-Allow-Methods: GET,POST Access-Control-Max-Age: 50 Access-Control-Expose-Headers: ex-headr1,ex-headr2 Access-Control-Allow-Headers: headr1,headr2 ``` 使用无效的来源发送另一个请求: ``` curl "http://127.0.0.1:9080/anything" -H "Origin: http://a.test2.com" -I ``` 你应该收到 `HTTP/1.1 200 OK` 响应,没有任何 CORS 头: ``` ... Server: APISIX/3.8.0 Vary: Origin ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * allow\_origins string 默认值:`*` *** 允许 CORS 的来源,用逗号分隔的字符串。 如果 `allow_credential` 设置为 `true`,你可以通过将该字段配置为 `**` 来强制允许所有来源的 CORS,但敏感数据(如身份认证令牌或 cookie)可能会暴露给任何恶意网站。 你还可以使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)在全局范围内配置允许来源,这会配置所有 `cors` 插件实例的允许来源。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/cors.md#在插件元数据中配置来源)。 * allow\_methods string 默认值:`*` *** 允许 CORS 的 HTTP 请求方法,用逗号分隔的字符串。 如果 `allow_credential` 设置为 `true`,你可以通过将该字段配置为 `**` 来强制允许所有方法的 CORS,但恶意行为者可以使用 HTTP 方法(如 `PUT` 或 `DELETE`)对共享资源进行意外修改并构成安全威胁。 * allow\_headers string 默认值:`*` *** 允许在请求中使用的 HTTP 头,用逗号分隔的字符串。 如果 `allow_credential` 设置为 `true`,你可以通过将该字段配置为 `**` 来强制允许所有请求头的 CORS,但这可能会允许向服务器发送恶意头。 * expose\_headers string *** 应该在响应跨源请求时提供的 HTTP 头,用逗号分隔的字符串。 * max\_age integer 默认值:`5` *** [预检请求](https://developer.mozilla.org/zh-CN/docs/Glossary/Preflight_request)结果可以缓存的最大时间(以秒为单位)。如果时间在此限制内,浏览器将检查缓存的结果。要禁用缓存,请将 `max_age` 设置为 `-1`。 请注意,允许的最大值取决于浏览器。有关更多详细信息,请参阅 [`Access-Control-Max-Age`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Max-Age#指令)。 * allow\_credential boolean *** 如果为 true,则允许请求包含凭据,例如 cookie。根据 CORS 规范,当 `allow_credential` 设置为 true 时,不能将 `*` 用于其他 CORS 属性。 要允许所有来源,请将该字段设置为 `**`。这可能会允许敏感的用户数据(如身份认证令牌或 cookie)暴露给恶意行为者。 * allow\_origins\_by\_regex array\[string] *** 用于匹配允许 CORS 的来源的正则表达式。配置后,仅允许此范围内的域,并且 `allow_origins` 中的任何配置都将被忽略。 例如,`['.*.test.com$']` 可以匹配 `test.com` 的所有子域。 * allow\_origins\_by\_metadata array\[string] *** 引用插件元数据中设置的 `allow_origins` 来启用 CORS 的来源。例如,如果在插件元数据中设置了 `allow_origins: {'EXAMPLE': 'https://example.com'}`,则可以使用 `['EXAMPLE']` 来允许来源 `https://example.com` 的 CORS。 * timing\_allow\_origins string *** 允许访问资源计时信息的来源,用逗号分隔的字符串。有关更多详细信息,请参阅 [`Timing-Allow-Origin`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin)。 * timing\_allow\_origins\_by\_regex array\[string] *** 用于匹配允许访问资源计时信息的来源的正则表达式。配置后,仅允许匹配正则表达式的域,并且 `timing_allow_origins` 中的任何配置都将被忽略。 例如,`['.*.test.com']` 可以匹配 `test.com` 的所有子域。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * allow\_origins object *** 允许 CORS 的命名来源映射,其中每个键都是由 `allow_origins_by_metadata` 引用的标识符,每个值都是对应的来源字符串。 例如,`{'EXAMPLE': 'https://example.com'}` 为来源 `https://example.com` 定义了键 `EXAMPLE`。 如果 `allow_credential` 设置为 `true`,可以将映射值设置为 `**`,以强制允许所有来源的 CORS,但身份认证令牌或 Cookie 等敏感数据可能会暴露给恶意网站。 --- # data-mask `data-mask` 插件在使用日志记录插件时,会屏蔽请求头、请求体和 URL 查询中的敏感信息。请注意,它不会修改实际的请求或响应流量。 要对网关访问日志中的敏感信息进行脱敏,请参阅[配置数据脱敏](https://docs.apiseven.com/api7-gateway/how-to-guides/api-security/data-masking.md)。 关于插件执行顺序 该插件可以在路由、服务或全局插件上配置。但是,请注意[全局插件始终在路由或服务级插件之前执行](https://docs.apiseven.com/apisix/key-concepts/plugins.md#plugins-execution-order),因此数据屏蔽可能会在日志记录之后发生。 例如,如果全局配置了日志记录插件,而 `data-mask` 应用于路由级别,则请求将在屏蔽发生之前被记录,敏感数据将以明文形式出现。 为了确保预期的行为,建议在同一级别配置两个插件: 1. 均在全局级别(如果适合你的用例,推荐) 2. 均在路由或服务级别 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下使用 `data-mask` 插件。 虽然所有示例都使用 `file-logger` 插件进行日志记录,但该插件仅用于演示数据屏蔽的结果。请选择最适合你环境的日志记录插件。 ### 屏蔽 URL 查询中的敏感信息[​](#屏蔽-url-查询中的敏感信息 "屏蔽 URL 查询中的敏感信息的直接链接") 以下示例演示了如何在 `file-logger` 插件将请求记录到本地文件之前,屏蔽请求 URL 查询中的敏感信息。 创建一个带有 `file-logger` 插件(用于记录请求)和 `data-mask` 插件(带有三个数据屏蔽规则)的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "data-mask-route", "uri": "/anything", "plugins": { "data-mask": { "request": [ { "action": "remove", "name": "password", "type": "query" }, { "action": "replace", "name": "token", "type": "query", "value": "*****" }, { "action": "regex", "name": "card", "regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)", "type": "query", "value": "$1-****-****-$2" } ] }, "file-logger": { "path": "/tmp/mask-query.log" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: data-mask-service routes: - name: data-mask-route uris: - /anything plugins: data-mask: request: - action: remove name: password type: query - action: replace name: token type: query value: "*****" - action: regex name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: query value: "$1-****-****-$2" file-logger: path: /tmp/mask-query.log upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD data-mask-query-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: data-mask-query-plugin-config spec: plugins: - name: data-mask config: request: - action: remove name: password type: query - action: replace name: token type: query value: "*****" - action: regex name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: query value: "$1-****-****-$2" - name: file-logger config: path: /tmp/mask-query.log --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: data-mask-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: data-mask-query-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f data-mask-query-ic.yaml ``` data-mask-query-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: data-mask-route spec: ingressClassName: apisix http: - name: data-mask-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: data-mask enable: true config: request: - action: remove name: password type: query - action: replace name: token type: query value: "*****" - action: regex name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: query value: "$1-****-****-$2" - name: file-logger enable: true config: path: /tmp/mask-query.log ``` 将配置应用到集群: ``` kubectl apply -f data-mask-query-ic.yaml ``` ❶ 从请求中删除 `password` URL 查询的数据屏蔽规则。 ❷ 将 `token` URL 查询的值替换为 `*****` 的数据屏蔽规则。 ❸ 使用正则表达式匹配 URL 查询中的卡号并屏蔽卡号中间部分的数据屏蔽规则。 ❹ 文件系统中保存日志的日志文件路径。 向路由发送带有 URL 查询中敏感信息的请求: ``` curl -i "http://127.0.0.1:9080/anything?password=abc&token=xyz&card=1234-1234-1234-1234" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 `/tmp/mask-query.log` 文件并检查日志内容,你应该看到类似以下的日志条目: ``` { "request": { "uri": "/anything?token=*****&card=1234-****-****-1234", "method": "GET", "url": "http://127.0.0.1:9080/anything?token=*****&card=1234-****-****-1234", "querystring": { "token": "*****", "card": "1234-****-****-1234" } } } ``` ### 屏蔽请求头中的敏感信息[​](#屏蔽请求头中的敏感信息 "屏蔽请求头中的敏感信息的直接链接") 以下示例演示了如何在 `file-logger` 插件将请求记录到本地文件之前,屏蔽请求头中的敏感信息。 创建一个带有 `file-logger` 插件(用于记录请求)和 `data-mask` 插件(带有三个数据屏蔽规则)的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "data-mask-route", "uri": "/anything", "plugins": { "data-mask": { "request": [ { "action": "remove", "name": "password", "type": "header" }, { "action": "replace", "name": "token", "type": "header", "value": "*****" }, { "action": "regex", "name": "card", "regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)", "type": "header", "value": "$1-****-****-$2" } ] }, "file-logger": { "path": "/tmp/mask-header.log" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: data-mask-service routes: - name: data-mask-route uris: - /anything plugins: data-mask: request: - action: remove name: password type: header - action: replace name: token type: header value: "*****" - action: regex name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: header value: "$1-****-****-$2" file-logger: path: /tmp/mask-header.log upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD data-mask-header-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: data-mask-header-plugin-config spec: plugins: - name: data-mask config: request: - action: remove name: password type: header - action: replace name: token type: header value: "*****" - action: regex name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: header value: "$1-****-****-$2" - name: file-logger config: path: /tmp/mask-header.log --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: data-mask-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: data-mask-header-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f data-mask-header-ic.yaml ``` data-mask-header-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: data-mask-route spec: ingressClassName: apisix http: - name: data-mask-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: data-mask enable: true config: request: - action: remove name: password type: header - action: replace name: token type: header value: "*****" - action: regex name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: header value: "$1-****-****-$2" - name: file-logger enable: true config: path: /tmp/mask-header.log ``` 将配置应用到集群: ``` kubectl apply -f data-mask-header-ic.yaml ``` ❶ 从请求中删除 `password` 头的数据屏蔽规则。 ❷ 将 `token` 请求头的值替换为 `*****` 的数据屏蔽规则。 ❸ 使用正则表达式匹配请求头中的卡号并屏蔽卡号中间部分的数据屏蔽规则。 ❹ 文件系统中保存日志的日志文件路径。 向路由发送带有头中敏感信息的 POST 请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST \ -H "password: abc" \ -H "token: xyz" \ -H "card: 1234-1234-1234-1234" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 `/tmp/mask-header.log` 文件并检查日志内容,你应该看到类似以下的日志条目: ``` { "request": { "uri": "/anything", "method": "GET", "url": "http://127.0.0.1:9080/anything", "headers": { "user-agent": "curl/8.6.0", "token": "*****", "card": "1234-****-****-1234" } } } ``` ### 屏蔽 URL 编码请求体中的敏感信息[​](#屏蔽-url-编码请求体中的敏感信息 "屏蔽 URL 编码请求体中的敏感信息的直接链接") 以下示例演示了如何在 `file-logger` 插件将请求记录到本地文件之前,屏蔽 URL 编码请求体中的敏感信息。 创建一个带有 `file-logger` 插件(用于记录请求)和 `data-mask` 插件(带有三个数据屏蔽规则)的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "data-mask-route", "uri": "/anything", "plugins": { "data-mask": { "request": [ { "action": "remove", "body_format": "urlencoded", "name": "password", "type": "body" }, { "action": "replace", "body_format": "urlencoded", "name": "token", "type": "body", "value": "*****" }, { "action": "regex", "body_format": "urlencoded", "name": "card", "regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)", "type": "body", "value": "$1-****-****-$2" } ] }, "file-logger": { "include_req_body": true, "path": "/tmp/mask-urlencoded-body.log" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: data-mask-service routes: - name: data-mask-route uris: - /anything plugins: data-mask: request: - action: remove body_format: urlencoded name: password type: body - action: replace body_format: urlencoded name: token type: body value: "*****" - action: regex body_format: urlencoded name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: body value: "$1-****-****-$2" file-logger: include_req_body: true path: /tmp/mask-urlencoded-body.log upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD data-mask-urlencoded-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: data-mask-urlencoded-plugin-config spec: plugins: - name: data-mask config: request: - action: remove body_format: urlencoded name: password type: body - action: replace body_format: urlencoded name: token type: body value: "*****" - action: regex body_format: urlencoded name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: body value: "$1-****-****-$2" - name: file-logger config: include_req_body: true path: /tmp/mask-urlencoded-body.log --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: data-mask-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: data-mask-urlencoded-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f data-mask-urlencoded-ic.yaml ``` data-mask-urlencoded-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: data-mask-route spec: ingressClassName: apisix http: - name: data-mask-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: data-mask enable: true config: request: - action: remove body_format: urlencoded name: password type: body - action: replace body_format: urlencoded name: token type: body value: "*****" - action: regex body_format: urlencoded name: card regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: body value: "$1-****-****-$2" - name: file-logger enable: true config: include_req_body: true path: /tmp/mask-urlencoded-body.log ``` 将配置应用到集群: ``` kubectl apply -f data-mask-urlencoded-ic.yaml ``` ❶ 从请求体中删除 `password` 信息的数据屏蔽规则。 ❷ 将请求体中的 `token` 信息替换为 `*****` 的数据屏蔽规则。 ❸ 使用正则表达式匹配请求体中的卡号并屏蔽卡号中间部分的数据屏蔽规则。 ❹ 文件系统中保存日志的日志文件路径。 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" \ --data-urlencode "password=abc" \ --data-urlencode "token=xyz" \ --data-urlencode "card=1234-1234-1234-1234" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 `/tmp/mask-urlencoded-body.log` 文件并检查日志内容,你应该看到类似以下的日志条目: ``` { "request": { "uri": "/anything", "body": "token=*****&card=1234-****-****-1234", "method": "POST", "url": "http://127.0.0.1:9080/anything" } } ``` ### 屏蔽 JSON 编码请求体中的敏感信息[​](#屏蔽-json-编码请求体中的敏感信息 "屏蔽 JSON 编码请求体中的敏感信息的直接链接") 以下示例展示了如何在 `file-logger` 插件将请求记录到本地文件之前,使用插件中的 [JSONPath](https://goessner.net/articles/JsonPath) 语法查找目标字段,并对 JSON 编码请求体中的敏感信息进行脱敏。 创建一个带有 `file-logger` 插件(用于记录请求)和 `data-mask` 插件(带有三个数据屏蔽规则)的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "data-mask-route", "uri": "/anything", "plugins": { "data-mask": { "request": [ { "action": "remove", "body_format": "json", "name": "$.password", "type": "body" }, { "action": "replace", "body_format": "json", "name": "users[*].token", "type": "body", "value": "*****" }, { "action": "regex", "body_format": "json", "name": "$.users[*].credit.card", "regex": "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)", "type": "body", "value": "$1-****-****-$2" } ] }, "file-logger": { "include_req_body": true, "path": "/tmp/mask-json-body.log" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: data-mask-service routes: - name: data-mask-route uris: - /anything plugins: data-mask: request: - action: remove body_format: json name: "$.password" type: body - action: replace body_format: json name: "users[*].token" type: body value: "*****" - action: regex body_format: json name: "$.users[*].credit.card" regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: body value: "$1-****-****-$2" file-logger: include_req_body: true path: /tmp/mask-json-body.log upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD data-mask-json-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: data-mask-json-plugin-config spec: plugins: - name: data-mask config: request: - action: remove body_format: json name: "$.password" type: body - action: replace body_format: json name: "users[*].token" type: body value: "*****" - action: regex body_format: json name: "$.users[*].credit.card" regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: body value: "$1-****-****-$2" - name: file-logger config: include_req_body: true path: /tmp/mask-json-body.log --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: data-mask-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: data-mask-json-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f data-mask-json-ic.yaml ``` data-mask-json-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: data-mask-route spec: ingressClassName: apisix http: - name: data-mask-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: data-mask enable: true config: request: - action: remove body_format: json name: "$.password" type: body - action: replace body_format: json name: "users[*].token" type: body value: "*****" - action: regex body_format: json name: "$.users[*].credit.card" regex: "(\\d+)\\-\\d+\\-\\d+\\-(\\d+)" type: body value: "$1-****-****-$2" - name: file-logger enable: true config: include_req_body: true path: /tmp/mask-json-body.log ``` 将配置应用到集群: ``` kubectl apply -f data-mask-json-ic.yaml ``` ❶ 从请求体中删除 `password` 信息的数据屏蔽规则。 ❷ 将请求体中的 `token` 信息替换为 `*****` 的数据屏蔽规则。 ❸ 使用正则表达式匹配请求体中的卡号并屏蔽卡号中间部分的数据屏蔽规则。 ❹ 文件系统中保存日志的日志文件路径。 向路由发送带有请求体中敏感信息的请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -d ' { "password": "abc", "users": [ { "token": "xyz", "credit": { "card": "1234-1234-1234-1234" } }, { "token": "xyz", "credit": { "card": "1234-1234-1234-1234" } } ] }' ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 `/tmp/mask-json-body.log` 文件并检查日志内容,你应该看到类似以下的日志条目: ``` { "request": { "uri": "/anything", "body": "{\"users\":[{\"token\":\"*****\",\"credit\":{\"card\":\"1234-****-****-1234\"}},{\"token\":\"*****\",\"credit\":{\"card\":\"1234-****-****-1234\"}}]}", "method": "POST", "url": "http://127.0.0.1:9080/anything" } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * request array\[object] *** 屏蔽请求中敏感信息的动作数组。 * type string 必填 有效值: `query`、`header` 或 `body` *** 应屏蔽敏感信息的位置。 * body\_format string 有效值: `json` 或 `urlencoded` *** 请求体的编码。当 `type` 为 `body` 时需要。 * name string 必填 *** 包含敏感数据的信息字段名称。对于 JSON 体,你可以使用 [JSONPath](https://goessner.net/articles/JsonPath) 语法。 * action string 必填 有效值: `regex`、`replace` 或 `remove` *** 屏蔽敏感数据的动作。 * regex string *** 用于匹配敏感数据的正则表达式。当 `action` 为 `regex` 时需要。 * value string *** 用于替换敏感数据的值。当 `action` 为 `regex` 或 `replace` 时需要。 * max\_body\_size integer 默认值:`1048576` *** 允许的最大请求体大小(字节)。如果请求的体大小超过配置的值,则数据屏蔽规则将被忽略。 * max\_req\_post\_args integer 默认值:`100` 有效值: 大于或等于 0 *** 当 `body_format` 设置为 `urlencoded` 且对请求体数据进行脱敏时,最多解析的 URL 编码表单字段数。 --- # datadog `datadog` 插件支持与云应用程序最常用的可观测性服务之一 [Datadog](https://www.datadoghq.com) 集成。启用后,该插件会通过 UDP 协议将指标推送到 [Datadog agent](https://docs.datadoghq.com/agent) 附带的 [DogStatsD](https://docs.datadoghq.com/developers/dogstatsd/?tab=hostagent) 服务器。 ## 指标[​](#指标 "指标的直接链接") 默认情况下,该插件导出以下指标。 所有指标都将以元数据中配置的 `namespace` 为前缀。例如,如果 `namespace` 配置为 `apisix`,你将在 Datadog 中看到 `request.counter` 指标导出为 `apisix.request.counter`。 | 名称 | 类型 | 描述 | | ---------------- | --------- | ---------------------------------------------------------- | | request.counter | counter | 接收到的请求数量。 | | request.latency | histogram | 处理请求所花费的时间(毫秒)。 | | upstream.latency | histogram | 将请求代理到上游服务器直到接收到响应所花费的时间(毫秒)。 | | apisix.latency | histogram | APISIX agent 处理请求所花费的时间(毫秒)。 | | ingress.size | timer | 请求体大小(字节)。 | | egress.size | timer | 响应体大小(字节)。 | ## 标签[​](#标签 "标签的直接链接") 该插件导出带有以下 [标签](https://docs.datadoghq.com/getting_started/tagging) 的指标。 如果没有适合特定标签的值,则该标签将被省略。 | 名称 | 描述 | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | route\_name | 路由的名称。如果不存在或 `prefer_name` 属性设置为 false,则回退到路由 ID。 | | service\_name | 服务的名称。如果不存在或 `prefer_name` 属性设置为 false,则回退到服务 ID。 | | consumer | 消费者的用户名(如果路由连接到消费者)。 | | balancer\_ip | 处理当前请求的上游负载均衡器的 IP 地址。 | | response\_status | HTTP 响应状态码,例如 `201`、`404` 或 `503`。 | | response\_status\_class | HTTP 响应状态码类别,例如 `2xx`、`4xx` 或 `5xx`。在 APISIX 3.14.0 及更高版本和 API7 企业版 3.9.0 及更高版本中可用。 | | scheme | 请求协议,例如 HTTP 和 gRPC。 | | path | HTTP 路径模式。仅当参数 `include_path` 设置为 `true` 时可用。在 APISIX 3.14.0 及更高版本和 API7 企业版 3.9.0 及更高版本中可用。 | | method | HTTP 方法。仅当属性 `include_method` 设置为 true 时可用。在 APISIX 3.14.0 及更高版本和 API7 企业版 3.9.0 及更高版本中可用。 | ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `datadog` 插件。 在继续之前,请确保你已安装 [Datadog agent](https://docs.datadoghq.com/agent),它会从受监控对象收集事件和指标并将其发送到 Datadog。 在 Docker 中启动 Datadog agent: * Docker * Kubernetes ``` docker run -d \ --name dogstatsd-agent \ -e DD_API_KEY=35ebe12345678dec56218930b79fdb4cf \ -e DD_SITE="us5.datadoghq.com" \ -e DD_HOSTNAME=apisix.quickstart \ -e DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true \ -p 8125:8125/udp \ datadog/dogstatsd:latest ``` ❶ `DD_API_KEY`: 替换为你的 API 密钥。 ❷ `DD_SITE`: 替换为你的 Datadog 站点。 ❸ `DD_HOSTNAME`: 替换为你的主机名。 ❹ `DD_DOGSTATSD_NON_LOCAL_TRAFFIC`: 设置为 true 以监听来自其他容器的 DogStatsD 数据包。 为 Datadog DogStatsD Agent 创建 Kubernetes 清单文件: dogstatsd-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: dogstatsd-agent spec: replicas: 1 selector: matchLabels: app: dogstatsd-agent template: metadata: labels: app: dogstatsd-agent spec: containers: - name: dogstatsd-agent image: datadog/dogstatsd:latest env: - name: DD_API_KEY value: "35ebe12345678dec56218930b79fdb4cf" - name: DD_SITE value: "us5.datadoghq.com" - name: DD_HOSTNAME value: "apisix.quickstart" - name: DD_DOGSTATSD_NON_LOCAL_TRAFFIC value: "true" ports: - containerPort: 8125 protocol: UDP ``` ❶ `DD_API_KEY`: 替换为你的 API 密钥。 ❷ `DD_SITE`: 替换为你的 Datadog 站点。 ❸ `DD_HOSTNAME`: 替换为你的主机名。 ❹ `DD_DOGSTATSD_NON_LOCAL_TRAFFIC`: 设置为 true 以监听来自其他容器的 DogStatsD 数据包。 为 DogStatsD Service 创建 Kubernetes 清单文件: dogstatsd-service.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: dogstatsd-agent spec: selector: app: dogstatsd-agent ports: - name: dogstatsd port: 8125 targetPort: 8125 protocol: UDP type: ClusterIP ``` 应用清单: ``` kubectl apply -f dogstatsd-deployment.yaml -f dogstatsd-service.yaml ``` 你可以通过环境变量配置 agent 主配置文件 `datadog.yaml` 中的大多数选项,前缀为 `DD_`。有关更多信息,请参阅 [agent 环境变量](https://docs.datadoghq.com/agent/guide/environment-variables)。 ### 更新 Datadog Agent 地址和其他元数据[​](#更新-datadog-agent-地址和其他元数据 "更新 Datadog Agent 地址和其他元数据的直接链接") 默认情况下,插件期望 DogStatsD 服务器在 `127.0.0.1:8125` 上可用。要自定义地址和其他元数据,请更新 [插件元数据](https://docs.apiseven.com/hub/datadog/configuration.md#metadata),如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/datadog" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "host": "192.168.0.90", "port": 8125, "namespace": "apisix", "constant_tags": [ "source:apisix", "service:custom" ] }' ``` ❶ 替换为你的私有 IP 地址。如果在 Kubernetes 中运行 Datadog Agent,请使用 Service DNS 名称(例如 `dogstatsd-agent.aic.svc`)。 ❷ 设置为 Datadog agent 监听端口。 ❸ 设置所有指标的前缀命名空间。 ❹ 配置常量标签。 要恢复为默认配置,请向 `datadog` 插件元数据发送一个空体的请求: ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/datadog" -X PUT -d '{}' ``` adc.yaml ``` plugin_metadata: - name: datadog host: "192.168.0.90" port: 8125 namespace: apisix constant_tags: - "source:apisix" - "service:custom" ``` ❶ 替换为你的私有 IP 地址。如果在 Kubernetes 中运行 Datadog Agent,请使用 Service DNS 名称(例如 `dogstatsd-agent.aic.svc`)。 ❷ 设置为 Datadog agent 监听端口。 ❸ 设置所有指标的前缀命名空间。 ❹ 配置常量标签。 将配置同步到网关: ``` adc sync -f adc.yaml ``` datadog-metadata.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: service: name: apisix-admin port: 9180 auth: type: AdminKey adminKey: value: edd1c9f034335f136f87ad84b625c8f1 pluginMetadata: datadog: host: "dogstatsd-agent.aic.svc" port: 8125 namespace: apisix constant_tags: - "source:apisix" - "service:custom" ``` ❶ 设置为 Kubernetes 中 Datadog DogStatsD Agent 的 Service DNS 名称。 ❷ 设置为 Datadog agent 监听端口。 ❸ 设置所有指标的前缀命名空间。 ❹ 配置常量标签。 应用配置: ``` kubectl apply -f datadog-metadata.yaml ``` ### 监控路由指标[​](#监控路由指标 "监控路由指标的直接链接") 以下示例展示了如何将特定路由的指标发送到 Datadog。 创建一个带有 `datadog` 插件和一些可选配置项的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "datadog-route", "uri": "/anything", "plugins": { "datadog": { "batch_max_size" : 1, "max_retry_count": 0 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: datadog-route plugins: datadog: batch_max_size: 1 max_retry_count: 0 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD datadog-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: datadog-plugin-config spec: plugins: - name: datadog config: batch_max_size: 1 max_retry_count: 0 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: datadog-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: datadog-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` datadog-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: datadog-route spec: ingressClassName: apisix http: - name: datadog-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: datadog config: batch_max_size: 1 max_retry_count: 0 ``` 应用配置: ``` kubectl apply -f datadog-ic.yaml ``` ❶ `batch_max_size`: 设置为 1 以立即发送指标。 ❷ `max_retry_count`: 设置为 0 以在指标发送失败时不重试。 向之前创建的路由发送一些请求: ``` curl "http://127.0.0.1:9080/anything" ``` 在 Datadog 中,从左侧菜单选择 **Metrics** 并进入 **Explorer**。选择 `apisix.ingress.size.count` 作为指标。你应该看到反映生成的请求数量的计数: ![Datadog Metrics Explorer 显示 apisix.ingress.size.count 查询及其生成的折线图](https://static.api7.ai/uploads/2024/01/17/Y0uHlIeS_dd-count.png) --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * prefer\_name boolean 默认值:`true` *** 如果为 true,在指标标签中导出路由/服务名称而不是其 ID。 * include\_path boolean 默认值:`false` *** 如果为 true,则在指标标签中包含路径模式。此选项在 APISIX 中可用,但在 API7 企业版中尚不支持。 * include\_method boolean 默认值:`false` *** 如果为 true,则在指标标签中包含 HTTP 方法。此选项在 APISIX 中可用,但在 API7 企业版中尚不支持。 * constant\_tags array\[string] *** 附加到所有指标的静态键值标签。这些标签可用于添加团队归属或环境等元数据,从而更容易在相关端点之间进行筛选、聚合和告警。自 APISIX 3.14.0 和 API7 企业版 3.9.0 起可用。 * name string 默认值:`datadog` *** 批处理器中的插件唯一标识符。如果使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称会导出到 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每个批次允许的最大日志条目数。一旦达到该数量,批次将被发送到 Datadog agent。将此参数设置为 1 表示立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(秒)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 在将批次发送到日志服务之前,允许的最早条目的最大存在时间(秒)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(秒)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 允许的最大重试次数,超过此次数将丢弃日志条目。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * host string 默认值:`127.0.0.1` *** DogStatsD 服务器主机地址。 * port integer 默认值:`8125` *** DogStatsD 服务器端口。 * namespace string 默认值:`apisix` *** 所有指标的前缀。例如,将命名空间配置为 `apisix` 后,导出到 Datadog 的 `request.counter` 指标将显示为 `apisix.request.counter`。 * constant\_tags array\[string] 默认值:`[source:apisix]` *** 指标[标签](https://docs.datadoghq.com/getting_started/tagging)。 * max\_pending\_entries integer 默认值:`` 在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192` `` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.9.x 系列中自 3.9.19 起可用,在 3.10.x 系列中自 3.10.6 起可用,并且在 APISIX 中自 3.18.0 起可用。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # degraphql `degraphql` 插件通过将 GraphQL 查询映射到 HTTP 端点,支持使用常规 HTTP 请求与上游 GraphQL 服务通信。 ## 示例[​](#示例 "示例的直接链接") 以下示例使用 [Pokemon GraphQL API](https://graphql-pokemon.js.org/) 作为上游 GraphQL 服务器,并演示如何配置 `degraphql` 来转换不同类型的 GraphQL 查询。 ### 转换基本查询[​](#转换基本查询 "转换基本查询的直接链接") 以下示例演示了如何转换下面的简单查询: ``` query { getAllPokemon { key color } } ``` * Admin API * ADC * Ingress Controller 创建一个启用 `degraphql` 插件的路由,如下所示: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "degraphql-route", "methods": ["POST"], "uri": "/v8", "upstream": { "type": "roundrobin", "nodes": { "graphqlpokemon.favware.tech": 1 }, "scheme": "https", "pass_host": "node" }, "plugins": { "degraphql": { "query": "{\n getAllPokemon {\n key\n color\n }\n}" } } }' ``` 创建一个启用 `degraphql` 插件的路由,如下所示: adc.yaml ``` services: - name: degraphql-service routes: - name: degraphql-route methods: - POST uris: - /v8 plugins: degraphql: query: | { getAllPokemon { key color } } upstream: type: roundrobin nodes: - host: graphqlpokemon.favware.tech port: 443 weight: 1 scheme: https ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD degraphql-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: graphql-pokemon spec: type: ExternalName externalName: graphqlpokemon.favware.tech --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: graphql-pokemon-https spec: targetRefs: - name: graphql-pokemon kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: degraphql-plugin-config spec: plugins: - name: degraphql config: query: | { getAllPokemon { key color } } --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: degraphql-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /v8 method: - POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: degraphql-plugin-config backendRefs: - name: graphql-pokemon port: 443 ``` degraphql-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: degraphql-route spec: ingressClassName: apisix http: - name: degraphql-route match: paths: - /v8 methods: - POST upstreams: - name: graphql-pokemon plugins: - name: degraphql enable: true config: query: | { getAllPokemon { key color } } --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: graphql-pokemon spec: ingressClassName: apisix externalNodes: - type: Domain name: graphqlpokemon.favware.tech port: 443 scheme: https passHost: node ``` 将配置应用到集群: ``` kubectl apply -f degraphql-ic.yaml ``` 向路由发送请求进行验证: ``` curl "http://127.0.0.1:9080/v8" -X POST ``` 你应该会看到类似以下的响应: ``` { "data": { "getAllPokemon": [ { "key": "pokestarsmeargle", "color": "White" }, { "key": "pokestarufo", "color": "White" }, { "key": "pokestarufo2", "color": "White" }, ... { "key": "terapagosstellar", "color": "Blue" }, { "key": "pecharunt", "color": "Purple" } ] } } ``` ### 转换带变量的查询[​](#转换带变量的查询 "转换带变量的查询的直接链接") 以下示例演示了如何转换下面带有变量的查询: ``` query ($pokemon: PokemonEnum!) { getPokemon( pokemon: $pokemon ) { color species } } variable: { "pokemon": "pikachu" } ``` * Admin API * ADC * Ingress Controller 创建一个启用 `degraphql` 插件的路由,如下所示: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "degraphql-route", "uri": "/v8", "upstream": { "type": "roundrobin", "nodes": { "graphqlpokemon.favware.tech": 1 }, "scheme": "https", "pass_host": "node" }, "plugins": { "degraphql": { "query": "query ($pokemon: PokemonEnum!) {\n getPokemon(\n pokemon: $pokemon\n ) {\n color\n species\n }\n}\n", "variables": ["pokemon"] } } }' ``` 创建一个启用 `degraphql` 插件的路由,如下所示: adc.yaml ``` services: - name: degraphql-service routes: - name: degraphql-route uris: - /v8 plugins: degraphql: query: | query ($pokemon: PokemonEnum!) { getPokemon( pokemon: $pokemon ) { color species } } variables: - pokemon upstream: type: roundrobin nodes: - host: graphqlpokemon.favware.tech port: 443 weight: 1 scheme: https ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD degraphql-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: graphql-pokemon spec: type: ExternalName externalName: graphqlpokemon.favware.tech --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: graphql-pokemon-https spec: targetRefs: - name: graphql-pokemon kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: degraphql-plugin-config spec: plugins: - name: degraphql config: query: | query ($pokemon: PokemonEnum!) { getPokemon( pokemon: $pokemon ) { color species } } variables: - pokemon --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: degraphql-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /v8 filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: degraphql-plugin-config backendRefs: - name: graphql-pokemon port: 443 ``` degraphql-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: degraphql-route spec: ingressClassName: apisix http: - name: degraphql-route match: paths: - /v8 upstreams: - name: graphql-pokemon plugins: - name: degraphql enable: true config: query: | query ($pokemon: PokemonEnum!) { getPokemon( pokemon: $pokemon ) { color species } } variables: - pokemon --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: graphql-pokemon spec: ingressClassName: apisix externalNodes: - type: Domain name: graphqlpokemon.favware.tech port: 443 scheme: https passHost: node ``` 将配置应用到集群: ``` kubectl apply -f degraphql-ic.yaml ``` 向路由发送请求进行验证: ``` curl "http://127.0.0.1:9080/v8" -X POST \ -d '{ "pokemon": "pikachu" }' ``` 你应该会看到类似以下的响应: ``` { "data": { "getPokemon": { "color": "Yellow", "species": "pikachu" } } } ``` 或者,你也可以在 GET 请求的 URL 查询字符串中传递变量: ``` curl "http://127.0.0.1:9080/v8?pokemon=pikachu" -H "x-apollo-operation-name: GET" ``` 你应该看到与之前相同的响应。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * query string 必填 *** 发送到上游的 GraphQL 查询。 * operation\_name string *** 操作名称。如果查询中包含多个操作,则该字段为必填项。 * variables array\[string] *** GraphQL 查询中使用的变量。 * max\_req\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** 提取配置的 GraphQL `variables` 时读取的 POST 请求体最大字节数。超过该大小的请求体会返回 `503 Service Unavailable`。未配置 `variables` 时不会使用请求体。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 --- # dingtalk-auth [企业版](https://api7.ai/enterprise) `dingtalk-auth` 插件基于钉钉开放平台的 OAuth 2.0 协议实现身份认证,通过验证请求中的钉钉授权码(code)获取用户信息,并将用户信息注入请求头或上下文,同时支持会话缓存避免重复认证,对接钉钉企业内部应用的访问控制。 ## 插件时序流程[​](#插件时序流程 "插件时序流程的直接链接") ## 使用示例[​](#使用示例 "使用示例的直接链接") ### 前提条件[​](#前提条件 "前提条件的直接链接") 1. 在[钉钉开放平台](https://open-dev.dingtalk.com/)创建企业内部应用,获取 `app_key` 和 `app_secret`; 2. 配置钉钉授权页面 URI;其中携带的实际回调地址需在钉钉开放平台登记为可信回调地址; 3. 确保网关能访问钉钉开放平台的 HTTPS 接口(`api.dingtalk.com`、`oapi.dingtalk.com`)。 ### 在路由上配置钉钉认证插件[​](#在路由上配置钉钉认证插件 "在路由上配置钉钉认证插件的直接链接") 以下示例演示如何在路由上实现钉钉认证。 创建路由并启用 `dingtalk-auth` 插件,具体插件配置如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes/dingtalk-auth-route" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d ' { "uri": "/get", "plugins": { "dingtalk-auth": { "app_key": "dingxxxxxx", "app_secret": "xxxxxx", "secret": "session-secret-12345678", "redirect_uri": "https://login.dingtalk.com/oauth2/auth?appid=dingxxxxxx&response_type=code&scope=openid&redirect_uri=https%3A%2F%2Fyour-domain.com%2Fcallback", "cookie_expires_in": 86400, "set_userinfo_header": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 替换为你的 app key。 ❷ 替换为你的 app secret。 ❸ 替换为你的 secret,该值应为随机字符串。 ❹ 替换为钉钉授权页面 URI,并将其中的实际回调地址参数替换为已在钉钉开放平台登记的可信回调地址。 1. **首次请求(无 `code`)**: 访问 `http://127.0.0.1:9080/get` 时,响应状态码为 `302 Found`,响应头 `Location` 指向配置的 `redirect_uri`(钉钉授权页)。 2. **携带 `code` 的请求**: > 为了便于测试,这里可以通过 [JSAPI Explorer ](https://open.dingtalk.com/tools/explorer/jsapi?id=11723)获取授权码,在实际的生产环境中,用户会在浏览器中完成钉钉授权流程后自动获得授权码。 从钉钉授权页获取 `code` 后,携带 `code` 发起请求:`http://127.0.0.1:9080/get?code=xxxx`。验证成功时,响应包含会话 Cookie `dingtalk_session`,状态码为 200,上游服务可读取 `X-Userinfo` 请求头获取用户信息。 3. **会话缓存验证**: 携带会话 Cookie 发起请求 `http://127.0.0.1:9080/get`,此时网关验证 Cookie 中的用户信息,并注入 `X-Userinfo` 头转发到上游服务。 ### 解码用户信息[​](#解码用户信息 "解码用户信息的直接链接") 用户身份认证成功后,插件会在请求中添加包含 Base64 编码用户信息的 `X-Userinfo` 请求头。 上游服务可解码 `X-Userinfo` 头获取用户信息: ``` import base64 import json # 示例:使用 Python 解码 X-Userinfo userinfo_header = "eyJ1c2VyaWQiOiJkaW50YWxsaW5lLXVzZXJpZCJ9" userinfo = json.loads(base64.b64decode(userinfo_header).decode('utf-8')) print(userinfo) # 输出:{"userid": "dingtalk-userid"} ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * app\_key string 必填 有效值: 非空字符串 *** 钉钉开放平台创建的应用唯一标识(AppKey),用于调用钉钉开放平台接口的身份认证。 * app\_secret string 必填 有效值: 非空字符串 *** 钉钉开放平台应用的密钥(AppSecret),插件会加密存储该字段,用于获取钉钉接口的 `access_token`。 * code\_header string 默认值:`X-DingTalk-Code` 有效值: 非空字符串 *** 提取钉钉授权码(code)的 HTTP 请求头名称,优先级高于 `code_query`。 * code\_query string 默认值:`code` 有效值: 非空字符串 *** 提取钉钉授权码(code)的 URL Query 参数名称,当 `code_header` 未获取到 code 时使用。 * userinfo\_url string 默认值:`https://oapi.dingtalk.com/topapi/v2/user/getuserinfo` 有效值: 合法的 HTTP/HTTPS URL *** 钉钉开放平台用于验证授权码并获取用户信息的接口地址。 * access\_token\_url string 默认值:`https://api.dingtalk.com/v1.0/oauth2/accessToken` 有效值: 合法的 HTTP/HTTPS URL *** 钉钉开放平台用于获取 access\_token 的接口地址。 * set\_userinfo\_header boolean 默认值:`true` *** 如果为 `true`,则将钉钉用户信息经过 Base64 编码后注入 `X-Userinfo` 请求头,传递给上游服务。 * redirect\_uri string 必填 有效值: 合法的 HTTP/HTTPS URL *** 当请求中未携带授权码(code)且无有效会话时,重定向到该钉钉授权页面 URI。该 URI 通常包含回调地址参数,其中的实际回调地址需在钉钉开放平台登记为可信回调地址。 * timeout integer 默认值:`6000` 有效值: 大于 0 *** 调用钉钉开放平台接口的超时时间(以毫秒为单位)。 * ssl\_verify boolean 默认值:`true` *** 如果为 `true`,则验证钉钉开放平台接口的 SSL 证书;测试环境可设置为 `false` 以关闭验证。 * secret string 必填 有效值: 8 到 32 个字符 *** 用于加密会话 Cookie 的密钥,确保存储的用户信息不被篡改,插件会加密存储该字段。 * secret\_fallbacks array\[string] 有效值: 数组中的每个字符串包含 8 到 32 个字符 *** 会话密钥轮换的备用密钥列表,当主密钥(secret)更新后,仍可解密使用旧密钥加密的会话 Cookie。 * cookie\_expires\_in integer 默认值:`86400` 有效值: 大于 0 *** 会话 Cookie(dingtalk\_session)的有效期(以秒为单位),默认 86400 秒(1 天),过期后需重新认证。 --- # elasticsearch-logger `elasticsearch-logger` 插件将请求和响应日志分批推送到 [Elasticsearch](https://www.elastic.co) 并支持自定义日志格式。启用后,该插件会将请求上下文信息序列化为 [Elasticsearch Bulk 格式](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk) 并将它们添加到队列中,然后再推送到 Elasticsearch。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `elasticsearch-logger` 插件。 要跟随示例操作,请启动 Elasticsearch 和 Kibana: * Docker * Kubernetes 要跟随示例操作,请在 Docker 中启动一个 Elasticsearch 实例: ``` docker run -d \ --name elasticsearch \ --network apisix-quickstart-net \ -v elasticsearch_vol:/usr/share/elasticsearch/data/ \ -p 9200:9200 \ -p 9300:9300 \ -e ES_JAVA_OPTS="-Xms512m -Xmx512m" \ -e discovery.type=single-node \ -e xpack.security.enabled=false \ docker.elastic.co/elasticsearch/elasticsearch:7.17.29 ``` 在 Docker 中启动一个 Kibana 实例以可视化 Elasticsearch 中的索引数据: ``` docker run -d \ --name kibana \ --network apisix-quickstart-net \ -p 5601:5601 \ -e ELASTICSEARCH_HOSTS="http://elasticsearch:9200" \ docker.elastic.co/kibana/kibana:7.17.29 ``` 为 Elasticsearch Deployment 创建 Kubernetes 清单文件: elasticsearch-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: elasticsearch spec: replicas: 1 selector: matchLabels: app: elasticsearch template: metadata: labels: app: elasticsearch spec: containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch:7.17.29 env: - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m" - name: discovery.type value: single-node - name: xpack.security.enabled value: "false" ports: - containerPort: 9200 - containerPort: 9300 ``` 为 Elasticsearch Service 创建 Kubernetes 清单文件: elasticsearch-service.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: elasticsearch spec: selector: app: elasticsearch ports: - name: http port: 9200 targetPort: 9200 - name: transport port: 9300 targetPort: 9300 type: ClusterIP ``` 为 Kibana Deployment 创建 Kubernetes 清单文件: kibana-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: kibana spec: replicas: 1 selector: matchLabels: app: kibana template: metadata: labels: app: kibana spec: containers: - name: kibana image: docker.elastic.co/kibana/kibana:7.17.29 env: - name: ELASTICSEARCH_HOSTS value: "http://elasticsearch.aic.svc:9200" ports: - containerPort: 5601 ``` 为 Kibana Service 创建 Kubernetes 清单文件: kibana-service.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: kibana spec: selector: app: kibana ports: - name: http port: 5601 targetPort: 5601 type: ClusterIP ``` 应用清单: ``` kubectl apply -f elasticsearch-deployment.yaml -f elasticsearch-service.yaml -f kibana-deployment.yaml -f kibana-service.yaml ``` 要访问 Kibana,请转发 Service 端口: ``` kubectl port-forward -n aic svc/kibana 5601:5601 ``` 如果成功,你应该能在 [localhost:5601](http://localhost:5601) 看到 Kibana 仪表板。 ### 使用默认日志格式记录日志[​](#使用默认日志格式记录日志 "使用默认日志格式记录日志的直接链接") 以下示例展示了如何在路由上启用 `elasticsearch-logger` 插件,该插件记录客户端请求和响应,并将日志推送到 Elasticsearch。 创建一个启用 `elasticsearch-logger` 的路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "elasticsearch-logger-route", "uri": "/anything", "plugins": { "elasticsearch-logger": { "endpoint_addrs": ["http://elasticsearch:9200"], "field": { "index": "gateway" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: elasticsearch-logger-route plugins: elasticsearch-logger: endpoint_addrs: - "http://elasticsearch:9200" field: index: gateway upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD elasticsearch-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: elasticsearch-logger-plugin-config spec: plugins: - name: elasticsearch-logger config: endpoint_addrs: - "http://elasticsearch.aic.svc:9200" field: index: gateway --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: elasticsearch-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: elasticsearch-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` elasticsearch-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: elasticsearch-logger-route spec: ingressClassName: apisix http: - name: elasticsearch-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: elasticsearch-logger config: endpoint_addrs: - "http://elasticsearch.aic.svc:9200" field: index: gateway ``` 应用配置: ``` kubectl apply -f elasticsearch-logger-ic.yaml ``` ❶ 配置 Elasticsearch 的端点地址。 ❷ 将 `index` 字段配置为 `gateway`。 发送一个请求到该路由以生成一条日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 [localhost:5601](http://localhost:5601) 的 Kibana 仪表板,在 **Discover** 标签页下,创建一个新的索引模式 `gateway` 以从 Elasticsearch 获取数据。配置完成后,导航回 **Discover** 标签页,你应该看到生成的日志,类似如下: ``` { "_index": "gateway", "_id": "CE-JL5QBOkdYRG7kEjTJ", "_version": 1, "_score": 1, "_source": { "request": { "headers": { "host": "127.0.0.1:9080", "accept": "*/*", "user-agent": "curl/8.6.0" }, "size": 85, "querystring": {}, "method": "GET", "url": "http://127.0.0.1:9080/anything", "uri": "/anything" }, "response": { "headers": { "content-type": "application/json", "access-control-allow-credentials": "true", "server": "APISIX/3.13.0", "content-length": "390", "access-control-allow-origin": "*", "connection": "close", "date": "Mon, 13 Jan 2025 10:18:14 GMT" }, "status": 200, "size": 618 }, "route_id": "elasticsearch-logger-route", "latency": 585.00003814697, "apisix_latency": 18.000038146973, "upstream_latency": 567, "upstream": "50.19.58.113:80", "server": { "hostname": "0b9a772e68f8", "version": "3.13.0" }, "service_id": "", "client_ip": "192.168.65.1" }, "fields": { ... } } ``` ### 使用插件元数据自定义日志格式[​](#使用插件元数据自定义日志格式 "使用插件元数据自定义日志格式的直接链接") 以下示例展示了如何使用 [插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md) 和 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 自定义日志格式,以记录请求头和响应头中的特定信息。 在 APISIX 中,[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md) 用于配置同一插件的所有插件实例的通用元数据字段。当一个插件在多个资源中启用并需要统一更新其元数据字段时,这非常有用。 首先,创建一个启用 `elasticsearch-logger` 的路由如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "elasticsearch-logger-route", "uri": "/anything", "plugins": { "elasticsearch-logger": { "endpoint_addrs": ["http://elasticsearch:9200"], "field": { "index": "gateway" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` 接下来,配置 `elasticsearch-logger` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/elasticsearch-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr", "env": "$http_env", "resp_content_type": "$sent_http_Content_Type" } }' ``` adc.yaml ``` plugin_metadata: - name: elasticsearch-logger log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` elasticsearch-logger-metadata.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: service: name: apisix-admin port: 9180 auth: type: AdminKey adminKey: value: edd1c9f034335f136f87ad84b625c8f1 pluginMetadata: elasticsearch-logger: log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 应用配置: ``` kubectl apply -f elasticsearch-logger-metadata.yaml ``` ❶ 记录自定义请求头 `env`。 ❷ 记录响应头 `Content-Type`。 发送带有 `env` 头的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -H "env: dev" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 [localhost:5601](http://localhost:5601) 的 Kibana 仪表板,在 **Discover** 标签页下,创建一个新的索引模式 `gateway` 以从 Elasticsearch 获取数据(如果你尚未创建)。配置完成后,导航回 **Discover** 标签页,你应该看到生成的日志,类似如下: ``` { "_index": "gateway", "_id": "Ck-WL5QBOkdYRG7kODS0", "_version": 1, "_score": 1, "_source": { "client_ip": "192.168.65.1", "route_id": "elasticsearch-logger-route", "@timestamp": "2025-01-06T10:32:36+00:00", "host": "127.0.0.1", "resp_content_type": "application/json" }, "fields": { ... } } ``` ### 有条件地记录请求体[​](#有条件地记录请求体 "有条件地记录请求体的直接链接") 以下示例展示了如何有条件地记录请求体。 创建一个启用 `elasticsearch-logger` 的路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "elasticsearch-logger": { "endpoint_addrs": ["http://elasticsearch:9200"], "field": { "index": "gateway" }, "include_req_body": true, "include_req_body_expr": [["arg_log_body", "==", "yes"]] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" }, "uri": "/anything", "id": "elasticsearch-logger-route" }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: elasticsearch-logger-route plugins: elasticsearch-logger: endpoint_addrs: - "http://elasticsearch:9200" field: index: gateway include_req_body: true include_req_body_expr: - - arg_log_body - "==" - "yes" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD elasticsearch-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: elasticsearch-logger-plugin-config spec: plugins: - name: elasticsearch-logger config: endpoint_addrs: - "http://elasticsearch.aic.svc:9200" field: index: gateway include_req_body: true include_req_body_expr: - - arg_log_body - "==" - "yes" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: elasticsearch-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: elasticsearch-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` elasticsearch-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: elasticsearch-logger-route spec: ingressClassName: apisix http: - name: elasticsearch-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: elasticsearch-logger config: endpoint_addrs: - "http://elasticsearch.aic.svc:9200" field: index: gateway include_req_body: true include_req_body_expr: - - arg_log_body - "==" - "yes" ``` 应用配置: ``` kubectl apply -f elasticsearch-logger-ic.yaml ``` ❶ `include_req_body`: 设置为 true 以包含请求体。 ❷ `include_req_body_expr`: 仅当 URL 查询字符串 `log_body` 为 `true` 时包含请求体。 发送一个满足条件的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}' ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 [localhost:5601](http://localhost:5601) 的 Kibana 仪表板,在 **Discover** 标签页下,创建一个新的索引模式 `gateway` 以从 Elasticsearch 获取数据(如果你尚未创建)。配置完成后,导航回 **Discover** 标签页,你应该看到生成的日志,类似如下: ``` { "_index": "gateway", "_id": "Dk-cL5QBOkdYRG7k7DSW", "_version": 1, "_score": 1, "_source": { "request": { "headers": { "user-agent": "curl/8.6.0", "accept": "*/*", "content-length": "14", "host": "127.0.0.1:9080", "content-type": "application/x-www-form-urlencoded" }, "size": 182, "querystring": { "log_body": "yes" }, "body": "{\"env\": \"dev\"}", "method": "POST", "url": "http://127.0.0.1:9080/anything?log_body=yes", "uri": "/anything?log_body=yes" }, "start_time": 1735965595203, "response": { "headers": { "content-type": "application/json", "server": "APISIX/3.13.0", "access-control-allow-credentials": "true", "content-length": "548", "access-control-allow-origin": "*", "connection": "close", "date": "Mon, 13 Jan 2025 11:02:32 GMT" }, "status": 200, "size": 776 }, "route_id": "elasticsearch-logger-route", "latency": 703.9999961853, "apisix_latency": 34.999996185303, "upstream_latency": 669, "upstream": "34.197.122.172:80", "server": { "hostname": "0b9a772e68f8", "version": "3.13.0" }, "service_id": "", "client_ip": "192.168.65.1" }, "fields": { ... } } ``` 发送一个不带 URL 查询字符串的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}' ``` 导航到 Kibana 仪表板的 **Discover** 标签页,你应该看到生成的日志,但不包含请求体: ``` { "_index": "gateway", "_id": "EU-eL5QBOkdYRG7kUDST", "_version": 1, "_score": 1, "_source": { "request": { "headers": { "content-type": "application/x-www-form-urlencoded", "accept": "*/*", "content-length": "14", "host": "127.0.0.1:9080", "user-agent": "curl/8.6.0" }, "size": 169, "querystring": {}, "method": "POST", "url": "http://127.0.0.1:9080/anything", "uri": "/anything" }, "start_time": 1735965686363, "response": { "headers": { "content-type": "application/json", "access-control-allow-credentials": "true", "server": "APISIX/3.13.0", "content-length": "510", "access-control-allow-origin": "*", "connection": "close", "date": "Mon, 13 Jan 2025 11:15:54 GMT" }, "status": 200, "size": 738 }, "route_id": "elasticsearch-logger-route", "latency": 680.99999427795, "apisix_latency": 4.9999942779541, "upstream_latency": 676, "upstream": "34.197.122.172:80", "server": { "hostname": "0b9a772e68f8", "version": "3.13.0" }, "service_id": "", "client_ip": "192.168.65.1" }, "fields": { ... } } ``` 信息 如果你在设置 `include_req_body` 或 `include_resp_body` 为 `true` 的同时自定义了 `log_format`,插件将不会在日志中包含这些内容。 作为变通方法,你可以在日志格式中使用 NGINX 变量 `$request_body`,例如: ``` { "elasticsearch-logger": { ..., "log_format": {"body": "$request_body"} } } ``` ### 在 Elasticsearch 索引中包含请求日期[​](#在-elasticsearch-索引中包含请求日期 "在 Elasticsearch 索引中包含请求日期的直接链接") 以下示例展示了如何配置 `elasticsearch-logger` 插件以在 Elasticsearch 索引中包含请求日期。 创建一个启用 `elasticsearch-logger` 的路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "elasticsearch-logger-route", "uri": "/anything", "plugins": { "elasticsearch-logger": { "endpoint_addrs": ["http://elasticsearch:9200"], "field": { "index": "api7-{%Y.%m.%d}" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: elasticsearch-logger-route plugins: elasticsearch-logger: endpoint_addrs: - "http://elasticsearch:9200" field: index: "api7-{%Y.%m.%d}" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD elasticsearch-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: elasticsearch-logger-plugin-config spec: plugins: - name: elasticsearch-logger config: endpoint_addrs: - "http://elasticsearch.aic.svc:9200" field: index: "api7-{%Y.%m.%d}" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: elasticsearch-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: elasticsearch-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` elasticsearch-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: elasticsearch-logger-route spec: ingressClassName: apisix http: - name: elasticsearch-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: elasticsearch-logger config: endpoint_addrs: - "http://elasticsearch.aic.svc:9200" field: index: "api7-{%Y.%m.%d}" ``` 应用配置: ``` kubectl apply -f elasticsearch-logger-ic.yaml ``` ❶ 配置 Elasticsearch 的端点地址。 ❷ 配置 `index` 字段以使用当前年、月和日。 发送一个请求到该路由以生成一条日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 [localhost:5601](http://localhost:5601) 的 Kibana 仪表板,在 **Discover** 标签页下,创建一个新的索引模式 `api7*` 以从 Elasticsearch 获取数据。配置完成后,导航回 **Discover** 标签页,你应该看到生成的日志,类似如下: ``` { "_index": "api7-2025.3.10", "_id": "CE-KL5QB0kdYRG7dEiTJ", "_version": 1, "_score": 1, "_source": { "request": { ... }, "response": { ... }, "status": 200, "size": 618 }, ... } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * endpoint\_addr string *** 已废弃,请改用 `endpoint_addrs`。Elasticsearch API 端点地址。`endpoint_addr` 和 `endpoint_addrs` 二选一配置。 * endpoint\_addrs array\[string] *** Elasticsearch API 端点地址。如果配置了多个端点,每次写入会随机选择一个。`endpoint_addrs` 和已废弃的 `endpoint_addr` 二选一配置。 * field object 必填 *** Elasticsearch 字段配置。 * index string 必填 *** Elasticsearch [`_index`](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-index-field.html#mapping-index-field) 字段。 自 API7 企业版 3.8.0 和 APISIX 3.17.0 起,`index` 支持在大括号中配置[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)和 [Lua 时间格式](https://www.lua.org/pil/22.1.html),以包含当前日期,例如 `service-$host-{%Y-%m-%d}`。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,支持最多 5 层深度的嵌套日志格式结构。在 API7 企业版中,仅支持扁平键值结构;暂不支持嵌套结构。 你还可以使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)全局配置日志格式,这将为所有 `elasticsearch-logger` 插件实例配置日志格式。如果单个插件实例上配置的日志格式与插件元数据上配置的日志格式不同,则以单个插件实例上配置的日志格式为准。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/elasticsearch-logger.md#使用插件元数据自定义日志格式)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * auth object *** Elasticsearch 用户认证配置。 * username string *** Elasticsearch 认证用户名。 * password string *** Elasticsearch 认证密码。该值会在存储前加密。 * headers object *** 发送到 Elasticsearch 的自定义 HTTP 请求头,以键值对形式配置。可作为 `auth` 的替代或补充,用于认证或其他用途。自 API7 企业版 3.9.16、3.10.2 和 APISIX 3.16.0 起引入。请求头值加密自 API7 企业版 3.9.16、3.10.2 和 APISIX 3.18.0 起引入。启用数据加密时,这些值会在[存储前加密](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md)。经授权的 Admin API `GET` 请求会返回完整的已解密请求头对象;静态加密不会在 API 响应中隐藏请求头名称或值。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则执行 SSL 验证。 * timeout integer 默认值:`10` *** Elasticsearch 发送数据超时时间(秒)。 * include\_req\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含请求体。注意,如果请求体太大无法保存在内存中,由于 NGINX 的限制,它可能无法被记录。 * include\_req\_body\_expr array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。仅当 `include_req_body` 为 true 时使用。只有当此处配置的表达式计算结果为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。仅当 `include_resp_body` 为 true 时使用。只有当此处配置的表达式计算结果为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * name string 默认值:`elasticsearch-logger` *** 批处理器中的插件唯一标识符。如果使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称会导出到 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 一个批次允许的日志条目数。达到该数量后,批次会发送到 Elasticsearch。将此参数设置为 1 可启用立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 发送批次前等待新日志的最长时间,单位为秒。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 从最早条目起计,发送批次前允许等待的最长时间,单位为秒。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 批次失败后重试前的等待时间,单位为秒。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 丢弃日志条目前允许的最大失败重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,支持最多 5 层深度的嵌套日志格式结构。在 API7 企业版中,仅支持扁平键值结构;暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # error-log-collect [企业版](https://api7.ai/enterprise) `error-log-collect` 插件捕获网关在处理匹配请求时产生的错误日志,并将其写入网关错误日志(`error.log`)。捕获的日志条目包括 `INFO`、`DEBUG` 等所配置的错误日志级别通常会丢弃的低级别日志。这使你能够针对部分目标流量收集详细的、按请求维度的诊断日志,而无需为所有请求降低全局错误日志级别。 每条捕获的日志均以 `error` 级别写入,并带有 `[error-log-collect]` 前缀和请求 ID,便于你在网关日志中过滤和关联这些条目。使用 `vars` 将收集范围限定为满足条件的请求,使用 `sample_ratio` 在高流量路由上仅捕获一部分请求。 该插件配置在路由或服务上,自 API7 企业版 3.10.0 版本起可用。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `error-log-collect` 插件。 ### 在路由上收集错误日志[​](#在路由上收集错误日志 "在路由上收集错误日志的直接链接") 以下示例演示了如何在路由上启用该插件并查看收集到的日志。 创建一个上游为 httpbin.org 并启用 `error-log-collect` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "error-log-collect-route", "uri": "/anything", "plugins": { "error-log-collect": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: error-log-collect-service routes: - name: error-log-collect-route uris: - /anything plugins: error-log-collect: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` error-log-collect.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: error-log-collect-route spec: ingressClassName: apisix http: - name: anything match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: error-log-collect config: {} ``` 将配置应用到集群: ``` kubectl apply -f error-log-collect.yaml ``` 向该路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。 在网关日志中查找以 `[error-log-collect]` 为前缀的条目,每个条目都带有请求 ID。插件会重新输出处理请求时生成的内部日志,其中包括 DNS 解析和上游选择等 `INFO` 级别条目;默认的 `warn` 日志级别通常会省略这些条目: ``` 2026/06/26 09:21:31 [error] 47#47: 1750901491123#0 [error-log-collect] 2026-06-26 09:21:31 b9f8c1d2e3a4f5061728394a5b6c7d8e parse_domain():118: dns resolve httpbin.org, context: ngx.timer ``` 备注 插件会在每个工作进程的内存中缓冲捕获的日志,最多可保存 `buffer_max_size` 个条目。当请求匹配 `vars` 时,插件会将其刷新到 `error.log`;如果未设置 `vars`,则会对每个请求执行刷新。缓冲区由同一工作进程处理的所有请求共享,因此刷新时也可能输出该工作进程近期其他请求的缓冲日志。这有助于捕获匹配事件发生前的上下文。 ### 仅收集匹配请求的日志[​](#仅收集匹配请求的日志 "仅收集匹配请求的日志的直接链接") 要仅收集满足条件的请求的日志,请将 `vars` 设置为一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)。例如,以下配置仅在请求带有 `X-Debug: true` 请求头时收集日志: ``` { "plugins": { "error-log-collect": { "vars": [ ["http_x_debug", "==", "true"] ] } } } ``` 不匹配条件的请求不会自行将日志刷写到错误日志。在高流量路由上,可以将 `sample_ratio` 设置为小于 `1` 的值,仅收集随机抽样的部分请求,以保持日志量可控。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * vars array\[array] *** 一个或多个匹配条件数组,格式为 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)。仅当所有表达式都为 true 时,才将缓存的日志刷写到错误日志。未设置时,对每个请求都收集日志。 * sample\_ratio number 默认值:`1` 有效值: 介于 0.00001 和 1 之间(含边界值) *** 收集某个请求日志的概率。默认值 1 表示收集所有请求的日志。设置为小于 1 的值可仅收集随机抽样的部分请求的日志。 * buffer\_max\_size integer 默认值:`1000` 有效值: 大于或等于 1 *** 每个 worker 缓冲区中保存的最大日志条目数。当缓存的日志数量超过该值时,最早的条目将被覆盖。 --- # error-log-logger `error-log-logger` 插件将 APISIX 的错误日志 (`error.log`) 分批推送到 TCP、Apache SkyWalking、Apache Kafka 或 ClickHouse 服务器。你可以指定插件发送相应日志的严重级别。 该插件默认禁用。一旦启用,它将自动开始将错误日志推送到远程服务器。你应该仅在 [插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md) 中配置远程服务器详细信息,而不是在路由等其他资源上配置。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了如何在不同场景下配置 `error-log-logger` 插件。 APISIX 和 API7 网关运行时配置默认不会加载 `error-log-logger`。配置插件元数据前,请先在网关静态配置中启用该插件。 * Host or Docker * Kubernetes (Helm) 保留 `config.yaml` 中现有插件列表,并加入 `error-log-logger`: config.yaml ``` plugins: # 保留当前网关使用的完整插件列表。 - error-log-logger ``` 重新加载网关以使更改生效。 对于 APISIX Helm Chart,`apisix.plugins` 会替换已加载插件列表。请从当前网关使用的完整插件列表开始,并加入 `error-log-logger`: values.yaml ``` apisix: plugins: # 保留当前网关使用的完整插件列表。 - error-log-logger ``` 对于 API7 网关 Helm 部署,请先确认网关插件列表中已加载 `error-log-logger`,然后继续配置插件元数据。当前 Chart 没有提供用于将 `error-log-logger` 添加到已加载插件列表的专用 `values.yaml` 字段。请查看 [API7 网关 Helm Chart 参考](https://docs.apiseven.com/api7-gateway/reference/helm-chart.md),了解最新支持的插件列表配置。 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ### 发送日志到 TCP 服务器[​](#发送日志到-tcp-服务器 "发送日志到 TCP 服务器的直接链接") 以下示例展示了如何配置 `error-log-logger` 插件将错误日志发送到 TCP 服务器。 在端口 `19000` 上启动一个 netcat 监听器作为示例 TCP 服务器: * Docker * Kubernetes ``` nc -l 19000 ``` 为使用 `socat` 的 TCP 服务器 Deployment 创建 Kubernetes 清单: tcp-server.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: tcp-server spec: replicas: 1 selector: matchLabels: app: tcp-server template: metadata: labels: app: tcp-server spec: containers: - name: tcp-server image: alpine/socat args: ["TCP-LISTEN:19000,fork,reuseaddr", "STDOUT"] ports: - containerPort: 19000 --- apiVersion: v1 kind: Service metadata: namespace: aic name: tcp-server spec: selector: app: tcp-server ports: - name: tcp port: 19000 targetPort: 19000 type: ClusterIP ``` 应用清单: ``` kubectl apply -f tcp-server.yaml ``` 配置 `error-log-logger` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "tcp": { "host": "192.168.2.103", "port": 19000 }, "level": "INFO" }' ``` adc.yaml ``` plugin_metadata: - name: error-log-logger tcp: host: "192.168.2.103" port: 19000 level: INFO ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` error-log-logger-metadata.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: service: name: apisix-admin port: 9180 auth: type: AdminKey adminKey: value: edd1c9f034335f136f87ad84b625c8f1 pluginMetadata: error-log-logger: tcp: host: "tcp-server.aic.svc" port: 19000 level: INFO ``` 应用配置: ``` kubectl apply -f error-log-logger-metadata.yaml ``` ❶ 替换为你的内部 IP 地址。 ❷ 配置为你的 TCP 服务器监听端口。 ❸ 将严重级别配置为 `INFO`,以便发送大多数日志,方便验证。 要进行验证,可以通过[重新加载 APISIX](https://docs.apiseven.com/apisix/reference/apisix-cli.md#apisix-reload) 手动生成一条 `warn` 级别的日志。 如果使用 Docker,你应该会在 netcat 监听的终端会话中看到一条日志。如果使用 Kubernetes,请检查 `tcp-server` Pod 的日志: ``` kubectl logs -n aic -l app=tcp-server ``` 你应该看到类似于以下的日志条目: ``` 2025/01/26 20:15:29 [warn] 211#211: *35552 [lua] plugin.lua:205: load(): new plugins: {"cas-auth":true,"real-ip":true,"ai":true,"client-control":true,"proxy-control":true,"request-id":true,"zipkin":true,"ext-plugin-pre-req":true,"fault-injection":true,"mocking":true,"serverless-pre-function":true,"cors":true,"ip-restriction":true,"ua-restriction":true,"referer-restriction":true,"csrf":true,"uri-blocker":true,"request-validation":true,"chaitin-waf":true,"multi-auth":true,"openid-connect":true,"authz-casbin":true,"authz-casdoor":true,"wolf-rbac":true,"ldap-auth":true,"hmac-auth":true,"basic-auth":true,"jwt-auth":true,"redirect":true,"key-auth":true,"consumer-restriction":true,"attach-consumer-label":true,"authz-keycloak":true,"proxy-cache":true,"body-transformer":true,"ai-prompt-template":true,"ai-prompt-decorator":true,"proxy-mirror":true,"proxy-rewrite":true,"workflow":true,"api-breaker":true,"ai-proxy":true,"limit-conn":true,"limit-count":true,"limit-req":true,"gzip":true,"server-info":true,"traffic-split":true,"response-rewrite":true,"degraphql":true,"kafka-proxy":true,"grpc-transcode":true,"grpc-web":true,"http-dubbo":true,"public-api":true,"prometheus":true,"datadog":true,"loki-logger":true,"elasticsearch-logger":true,"echo":true,"loggly":true,"http-logger":true,"splunk-hec-logging":true,"skywalking-logger":true,"google-cloud-logging":true,"sls-logger":true,"tcp-logger":true,"kafka-logger":true,"rocketmq-logger":true,"syslog":true,"udp-logger":true,"file-logger":true,"clickhouse-logger":true,"tencent-cloud-cls":true,"inspect":true,"example-plugin":true,"aws-lambda":true,"azure-functions":true,"openwhisk":true,"openfunction":true,"error-log-logger":true,"ext-plugin-post-req":true,"ext-plugin-post-resp":true,"serverless-post-function":true,"opa":true,"forward-auth":true,"jwe-decrypt":true}, context: init_worker_by_lua* ``` ### 发送日志到 SkyWalking[​](#发送日志到-skywalking "发送日志到 SkyWalking的直接链接") 以下示例展示了如何配置 `error-log-logger` 插件将错误日志发送到 SkyWalking。 设置 SkyWalking OAP 服务器: * Docker * Kubernetes 使用 Docker Compose 启动 SkyWalking 存储、OAP 和 Booster UI,参考 [Skywalking 文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-docker/)。设置完成后,OAP 服务器应在 `12800` 上监听,你应该能够访问 的 UI。 为 SkyWalking OAP 服务器创建 Kubernetes 清单: skywalking-oap.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: skywalking-oap spec: replicas: 1 selector: matchLabels: app: skywalking-oap template: metadata: labels: app: skywalking-oap spec: containers: - name: skywalking-oap image: apache/skywalking-oap-server:10.1.0 env: - name: SW_STORAGE value: H2 ports: - containerPort: 11800 - containerPort: 12800 --- apiVersion: v1 kind: Service metadata: namespace: aic name: skywalking-oap spec: selector: app: skywalking-oap ports: - name: grpc port: 11800 targetPort: 11800 - name: http port: 12800 targetPort: 12800 type: ClusterIP ``` 应用清单: ``` kubectl apply -f skywalking-oap.yaml ``` 等待 OAP 服务器就绪: ``` kubectl wait --for=condition=available --timeout=120s -n aic deployment/skywalking-oap ``` 配置 `error-log-logger` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "skywalking": { "endpoint_addr": "http://192.168.2.103:12800/v3/logs" }, "level": "INFO" }' ``` adc.yaml ``` plugin_metadata: - name: error-log-logger skywalking: endpoint_addr: "http://192.168.2.103:12800/v3/logs" level: INFO ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` error-log-logger-metadata.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: service: name: apisix-admin port: 9180 auth: type: AdminKey adminKey: value: edd1c9f034335f136f87ad84b625c8f1 pluginMetadata: error-log-logger: skywalking: endpoint_addr: "http://skywalking-oap.aic.svc:12800/v3/logs" level: INFO ``` 应用配置: ``` kubectl apply -f error-log-logger-metadata.yaml ``` ❶ 替换为你的 SkyWalking 服务器地址。 ❷ 将严重级别配置为 `INFO`,以便发送大多数日志,方便验证。 要进行验证,可以通过[重新加载 APISIX](https://docs.apiseven.com/apisix/reference/apisix-cli.md#apisix-reload) 手动生成一条 `warn` 级别的日志。 在 [Skywalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该看到一个名为 `APISIX` 的服务,其中包含以下日志条目: ``` 2025/01/27 07:40:06 [warn] 211#211: *35552 [lua] plugin.lua:205: load(): new plugins: {"cas-auth":true,"real-ip":true,"ai":true,"client-control":true,"proxy-control":true,"request-id":true,"zipkin":true,"ext-plugin-pre-req":true,"fault-injection":true,"mocking":true,"serverless-pre-function":true,"cors":true,"ip-restriction":true,"ua-restriction":true,"referer-restriction":true,"csrf":true,"uri-blocker":true,"request-validation":true,"chaitin-waf":true,"multi-auth":true,"openid-connect":true,"authz-casbin":true,"authz-casdoor":true,"wolf-rbac":true,"ldap-auth":true,"hmac-auth":true,"basic-auth":true,"jwt-auth":true,"redirect":true,"key-auth":true,"consumer-restriction":true,"attach-consumer-label":true,"authz-keycloak":true,"proxy-cache":true,"body-transformer":true,"ai-prompt-template":true,"ai-prompt-decorator":true,"proxy-mirror":true,"proxy-rewrite":true,"workflow":true,"api-breaker":true,"ai-proxy":true,"limit-conn":true,"limit-count":true,"limit-req":true,"gzip":true,"server-info":true,"traffic-split":true,"response-rewrite":true,"degraphql":true,"kafka-proxy":true,"grpc-transcode":true,"grpc-web":true,"http-dubbo":true,"public-api":true,"prometheus":true,"datadog":true,"loki-logger":true,"elasticsearch-logger":true,"echo":true,"loggly":true,"http-logger":true,"splunk-hec-logging":true,"skywalking-logger":true,"google-cloud-logging":true,"sls-logger":true,"tcp-logger":true,"kafka-logger":true,"rocketmq-logger":true,"syslog":true,"udp-logger":true,"file-logger":true,"clickhouse-logger":true,"tencent-cloud-cls":true,"inspect":true,"example-plugin":true,"aws-lambda":true,"azure-functions":true,"openwhisk":true,"openfunction":true,"error-log-logger":true,"ext-plugin-post-req":true,"ext-plugin-post-resp":true,"serverless-post-function":true,"opa":true,"forward-auth":true,"jwe-decrypt":true}, context: init_worker_by_lua* ``` 当生成其他严重级别(如 `error`、`emerg` 和 `info`)的日志时,你也应该观察到它们。 ### 通过 TLS 将日志发送到 Kafka[​](#通过-tls-将日志发送到-kafka "通过 TLS 将日志发送到 Kafka的直接链接") 以下示例会将网关的 error 级别日志发送到启用了 TLS 的 Kafka Broker。请先按照 [Kafka Logger 的“将日志发送到启用 TLS 的 Broker”章节](https://docs.apiseven.com/hub/kafka-logger.md#send-logs-to-a-tls-enabled-broker)完成受信任 CA 配置,再设置 Broker 地址和主题: ``` export KAFKA_TLS_HOST="kafka-tls" export KAFKA_TLS_PORT="9093" export KAFKA_ERROR_TOPIC="apisix-error-logs" ``` 创建专用的错误日志主题: ``` docker exec kafka-tls /opt/kafka/bin/kafka-topics.sh \ --bootstrap-server kafka-tls:9093 \ --command-config /etc/kafka/secrets/client.properties \ --create \ --if-not-exists \ --topic "${KAFKA_ERROR_TOPIC}" \ --partitions 1 \ --replication-factor 1 ``` 配置插件元数据: ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/error-log-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <\n \n 404\n \n \n
\n

404 not found

\n
\n
\n
Gateway
\n \n", "content_type": "text/html" } }' ``` 为了演示插件的功能,创建一个带有 [`serverless-post-function`](https://docs.apiseven.com/hub/serverless-functions.md) 插件的路由,该插件从网关返回 404 错误代码给所有对该路由的请求: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/*", "id": "error-page-route", "plugins": { "serverless-post-function": { "functions": [ "return function (conf, ctx) local core = require(\"apisix.core\") core.response.exit(404) end" ] }, "error-page": {} }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` ❶ 对所有请求返回 404 状态码。 ❷ 启用 `error-page` 以返回自定义错误页面。 配置插件元数据,并创建启用了 `serverless-post-function` 和 `error-page` 插件的路由: adc.yaml ``` plugin_metadata: error-page: enable: true error_404: body: "\n \n 404\n \n \n
\n

404 not found

\n
\n
\n
Gateway
\n \n" content_type: text/html services: - name: error-page-service routes: - name: error-page-route uris: - /* plugins: serverless-post-function: functions: - | return function (conf, ctx) local core = require("apisix.core") core.response.exit(404) end error-page: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 对所有请求返回 404 状态码。 ❷ 启用 `error-page` 以返回自定义错误页面。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建启用了 `serverless-post-function` 和 `error-page` 插件的路由: error-page-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: error-page-plugin-config spec: plugins: - name: serverless-post-function config: functions: - | return function (conf, ctx) local core = require("apisix.core") core.response.exit(404) end - name: error-page config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: error-page-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: error-page-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 对所有请求返回 404 状态码。 ❷ 启用 `error-page` 以返回自定义错误页面。 创建启用了 `serverless-post-function` 和 `error-page` 插件的路由: error-page-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: error-page-route spec: ingressClassName: apisix http: - name: error-page-route match: paths: - /* upstreams: - name: httpbin-external-domain plugins: - name: serverless-post-function enable: true config: functions: - | return function (conf, ctx) local core = require("apisix.core") core.response.exit(404) end - name: error-page enable: true config: {} ``` ❶ 对所有请求返回 404 状态码。 ❷ 启用 `error-page` 以返回自定义错误页面。 更新 `GatewayProxy` 清单以配置 `error-page` 插件元数据: gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: error-page: enable: true error_404: body: "\n \n 404\n \n \n
\n

404 not found

\n
\n
\n
Gateway
\n \n" content_type: text/html ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f error-page-ic.yaml ``` 发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该看到 `HTTP/1.1 404 Not Found` 响应,并包含以下响应体: ``` 404

404 not found


Gateway
``` --- ## 参数[​](#参数 "参数的直接链接") 在路由和服务上配置此插件时,没有可配置的参数。所有配置选项都应通过[插件元数据](#%E6%8F%92%E4%BB%B6%E5%85%83%E6%95%B0%E6%8D%AE)进行设置。 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * enable boolean 默认值:`false` *** 如果为 true,启用插件。 * error\_404 object *** 当 APISIX 返回 404 状态码时返回的错误页面。 * body string 默认值:`与产品发行版相关的 HTML 响应` *** 响应体。默认内容会根据网关发行版标识 Apache APISIX 或 API7 Enterprise Edition。 * content\_type string 默认值:`text/html` *** 响应内容类型。 * error\_500 object *** 当 APISIX 返回 500 状态码时返回的错误页面。 * body string 默认值:`与产品发行版相关的 HTML 响应` *** 响应体。默认内容会根据网关发行版标识 Apache APISIX 或 API7 Enterprise Edition。 * content\_type string 默认值:`text/html` *** 响应内容类型。 * error\_502 object *** 当 APISIX 返回 502 状态码时返回的错误页面。 * body string 默认值:`与产品发行版相关的 HTML 响应` *** 响应体。默认内容会根据网关发行版标识 Apache APISIX 或 API7 Enterprise Edition。 * content\_type string 默认值:`text/html` *** 响应内容类型。 * error\_503 object *** 当 APISIX 返回 503 状态码时返回的错误页面。 * body string 默认值:`与产品发行版相关的 HTML 响应` *** 响应体。默认内容会根据网关发行版标识 Apache APISIX 或 API7 Enterprise Edition。 * content\_type string 默认值:`text/html` *** 响应内容类型。 --- # exit-transformer `exit-transformer` 插件可自定义通过 APISIX response-exit 路径产生的响应,包括插件拒绝和路由不存在响应。它不会转换上游服务返回的普通响应。 转换逻辑在插件中使用 Lua 函数定义,遵循以下语法: ``` return (function(code, body, header) if {{ condition }} then return {{ modified_resp }} end return code, body, header end)(...) ``` ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `exit-transformer`。 ### 启用 `exit-transformer` 插件[​](#启用-exit-transformer-插件 "启用-exit-transformer-插件的直接链接") 对于 APISIX 部署,在配置使用 `exit-transformer` 的全局规则或路由前,请先在网关静态配置中加载该插件。当已安装的网关版本启用此插件时,API7 Gateway 用户可通过 Dashboard 或 Admin API 配置它。 * 宿主机或 Docker * Kubernetes (Helm) 对于 APISIX 宿主机或 Docker 部署,请保留 `config.yaml` 中现有插件列表,并加入 `exit-transformer`: config.yaml ``` plugins: # 保留现有插件列表。 - exit-transformer ``` 重新加载网关以使更改生效。 对于 APISIX Helm Chart,`apisix.plugins` 会替换已加载插件列表。请从当前网关使用的完整插件列表开始,加入 `exit-transformer`,并保留列表中的其他插件: values.yaml ``` apisix: plugins: # 保留网关使用的完整插件列表。 - exit-transformer ``` 使用 APISIX Helm Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ### 修改 404 路由未找到响应[​](#修改-404-路由未找到响应 "修改 404 路由未找到响应的直接链接") 以下示例演示了当路由不存在时,如何使用该插件更新 `404 Not Found` 响应代码和头。在这种情况下,插件需要配置为全局规则插件。 创建一个启用 `exit-transformer` 插件的全局规则,其中函数将响应状态码更新为 `405`,如果原始状态码为 `404`,则添加自定义 `X-Custom-Header` 头: * Admin API * ADC * Ingress Controller ``` curl -i "http://127.0.0.1:9180/apisix/admin/global_rules" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "transform-404-not-found", "plugins": { "exit-transformer": { "functions": ["return (function(code, body, header) header = header or {} if code == 404 then header[\"X-Custom-Header\"] = \"Modified\" return 405, body, header end return code, body, header end)(...)"] } } }' ``` adc.yaml ``` global_rules: - id: transform-404-not-found plugins: exit-transformer: functions: - "return (function(code, body, header) header = header or {} if code == 404 then header[\"X-Custom-Header\"] = \"Modified\" return 405, body, header end return code, body, header end)(...)" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # 在此添加控制面连接配置 # .... plugins: - name: exit-transformer enabled: true config: functions: - "return (function(code, body, header) header = header or {} if code == 404 then header[\"X-Custom-Header\"] = \"Modified\" return 405, body, header end return code, body, header end)(...)" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` exit-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixGlobalRule metadata: namespace: aic name: transform-404-not-found spec: ingressClassName: apisix plugins: - name: exit-transformer enable: true config: functions: - "return (function(code, body, header) header = header or {} if code == 404 then header[\"X-Custom-Header\"] = \"Modified\" return 405, body, header end return code, body, header end)(...)" ``` 应用配置: ``` kubectl apply -f exit-transformer-ic.yaml ``` 发送请求到一个不存在的路由: ``` curl -i "http://127.0.0.1:9080/non-existent" ``` 你应该收到 `HTTP/1.1 405 Not Allowed` 响应,并看到 `X-Custom-Header: Modified` 头。 ### 修改认证失败的 401 未授权响应[​](#修改认证失败的-401-未授权响应 "修改认证失败的 401 未授权响应的直接链接") 以下示例演示了当认证失败时,如何使用该插件更新 `401 Unauthorized` 响应。 * Admin API * ADC * Ingress Controller 创建一个启用 `exit-transformer` 插件的路由,其中函数如果原始状态码为 `401`,则将响应状态码更新为 `402`;并启用 `key-auth`: ``` curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "transform-auth-route", "uri": "/get", "plugins": { "exit-transformer": { "functions": ["return (function(code, body, header) if code == 401 then return 402, body, header end return code, body, header end)(...)"] }, "key-auth":{} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为消费者配置 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建一个配置了 `key-auth` 凭证的消费者,以及一个配置了 `exit-transformer` 和 `key-auth` 插件的路由: adc.yaml ``` consumers: - username: john credentials: - name: key-auth type: key-auth config: key: john-key services: - name: httpbin routes: - name: transform-auth-route uris: - /get plugins: exit-transformer: functions: - "return (function(code, body, header) if code == 401 then return 402, body, header end return code, body, header end)(...)" key-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `key-auth` 凭证的消费者,以及一个配置了 `exit-transformer` 和 `key-auth` 插件的路由: * Gateway API * APISIX CRD exit-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-cred config: key: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: exit-transformer-plugin-config spec: plugins: - name: exit-transformer config: functions: - "return (function(code, body, header) if code == 401 then return 402, body, header end return code, body, header end)(...)" - name: key-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: transform-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: exit-transformer-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` exit-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: transform-auth-route spec: ingressClassName: apisix http: - name: transform-auth-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: exit-transformer enable: true config: functions: - "return (function(code, body, header) if code == 401 then return 402, body, header end return code, body, header end)(...)" - name: key-auth enable: true ``` 应用配置: ``` kubectl apply -f exit-transformer-ic.yaml ``` 在没有凭证的情况下发送请求到路由: ``` curl -i "http://127.0.0.1:9080/get" ``` 对于未授权访问,你应该收到 `HTTP/1.1 402 Payment Required` 响应,其中响应状态码已被修改。 ### 根据请求头有条件地修改响应[​](#根据请求头有条件地修改响应 "根据请求头有条件地修改响应的直接链接") 以下示例演示了如何使用该插件根据请求头有条件地修改响应。 创建一个启用 `exit-transformer` 插件的路由,其中函数根据 `Content-Type` 头更新响应状态码。如果头值为 `application/json` 且原始状态码为 `404`,则将响应状态码更新为 `405`。为了演示目的,在条件评估内外打印警告消息。 * Admin API * ADC * Ingress Controller ``` curl -i "http://127.0.0.1:9180/apisix/admin/global_rules" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "transform-by-header-condition", "plugins": { "exit-transformer": { "functions": [ "return (function(code, body, header) local core = require(\"apisix.core\") local ct = ngx.req.get_headers()[\"Content-Type\"] core.log.warn(\"exit transformer logics running outside the condition\") if ct == \"application/json\" and code == 404 then core.log.warn(\"exit transformer logics running inside the condition\") return 405 end return code, body, header end) (...)" ] } } }' ``` adc.yaml ``` global_rules: - id: transform-by-header-condition plugins: exit-transformer: functions: - "return (function(code, body, header) local core = require(\"apisix.core\") local ct = ngx.req.get_headers()[\"Content-Type\"] core.log.warn(\"exit transformer logics running outside the condition\") if ct == \"application/json\" and code == 404 then core.log.warn(\"exit transformer logics running inside the condition\") return 405 end return code, body, header end)(...)" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # 在此添加控制面连接配置 # .... plugins: - name: exit-transformer config: functions: - "return (function(code, body, header) local core = require(\"apisix.core\") local ct = ngx.req.get_headers()[\"Content-Type\"] core.log.warn(\"exit transformer logics running outside the condition\") if ct == \"application/json\" and code == 404 then core.log.warn(\"exit transformer logics running inside the condition\") return 405 end return code, body, header end)(...)" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` exit-transformer-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixGlobalRule metadata: namespace: aic name: transform-by-header-condition spec: ingressClassName: apisix plugins: - name: exit-transformer enable: true config: functions: - "return (function(code, body, header) local core = require(\"apisix.core\") local ct = ngx.req.get_headers()[\"Content-Type\"] core.log.warn(\"exit transformer logics running outside the condition\") if ct == \"application/json\" and code == 404 then core.log.warn(\"exit transformer logics running inside the condition\") return 405 end return code, body, header end)(...)" ``` 应用配置: ``` kubectl apply -f exit-transformer-ic.yaml ``` 发送请求到一个不存在的路由,不带任何头: ``` curl -i "http://127.0.0.1:9080/non-existent" ``` 你应该收到 `HTTP/1.1 404 Not Found` 响应,并在日志中看到以下消息: ``` exit transformer logics running outside the condition ``` 发送带有 JSON `Content-Type` 头的请求到不存在的路由: ``` curl -i "http://127.0.0.1:9080/non-existent" -H "Content-Type: application/json" ``` 你应该收到 `HTTP/1.1 405 Not Allowed` 响应,其中响应状态码已被修改,并在日志中看到以下消息: ``` exit transformer logics running outside the condition exit transformer logics running inside the condition ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * functions array\[string] 必填 *** 退出转换 Lua 函数。 出于安全原因,函数不允许使用 `coroutine`、`math`、`os`、`string` 或 `table`。 --- # fault-injection `fault-injection` 插件旨在通过模拟受控故障或延迟来测试应用程序的弹性。它在其他配置的插件之前执行,确保故障被一致地应用。这使其非常适合混沌工程等场景,在这些场景中,需要分析系统在故障条件下的行为。 该插件支持两个关键动作:`abort`,它会立即以指定的 HTTP 状态码(例如 `503 Service Unavailable`)终止请求,并跳过所有后续插件;以及 `delay`,它在进一步处理请求之前引入指定的延迟。这些功能允许你模拟服务中断或延迟等场景,帮助你验证错误处理逻辑并提高系统可靠性。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `fault-injection` 插件。 ### 注入故障[​](#注入故障 "注入故障的直接链接") 以下示例演示了如何在路由上配置 `fault-injection` 插件,以拦截进一步的请求发送,并返回特定的 HTTP 代码。 创建一个使用 `fault-injection` 插件的路由,使用 `abort` 动作将任何请求响应为 `404` 并返回指定的响应体: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "fault-injection-route", "uri": "/anything", "plugins": { "fault-injection": { "abort": { "http_status": 404, "body": "APISIX Fault Injection" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: fault-injection-route uris: - /anything plugins: fault-injection: abort: http_status: 404 body: "APISIX Fault Injection" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD fault-injection-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: fault-injection-plugin-config spec: plugins: - name: fault-injection config: abort: http_status: 404 body: "APISIX Fault Injection" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: fault-injection-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: fault-injection-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f fault-injection-ic.yaml ``` fault-injection-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: fault-injection-route spec: ingressClassName: apisix http: - name: fault-injection-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: fault-injection enable: true config: abort: http_status: 404 body: "APISIX Fault Injection" ``` 将配置应用到集群: ``` kubectl apply -f fault-injection-ic.yaml ``` 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 404 Not Found` 响应并看到以下响应体,而请求不会被转发到上游服务: ``` APISIX Fault Injection ``` ### 注入延迟[​](#注入延迟 "注入延迟的直接链接") 以下示例演示了如何在路由上配置 `fault-injection` 插件以注入请求延迟。 创建一个使用 `fault-injection` 插件的路由,使用 `delay` 动作将响应发送延迟 3 秒: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "fault-injection-route", "uri": "/anything", "plugins": { "fault-injection": { "delay": { "duration": 3 } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: fault-injection-route uris: - /anything plugins: fault-injection: delay: duration: 3 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD fault-injection-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: fault-injection-plugin-config spec: plugins: - name: fault-injection config: delay: duration: 3 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: fault-injection-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: fault-injection-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f fault-injection-ic.yaml ``` fault-injection-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: fault-injection-route spec: ingressClassName: apisix http: - name: fault-injection-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: fault-injection enable: true config: delay: duration: 3 ``` 将配置应用到集群: ``` kubectl apply -f fault-injection-ic.yaml ``` 发送请求到路由,并使用 `time` 命令总结请求完成所需的时间: ``` time curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到来自上游服务的 `HTTP/1.1 200 OK` 响应,并看到以下计时摘要: ``` 0.01s user 0.01s system 0% cpu 3.685 total ``` ### 有条件地注入故障[​](#有条件地注入故障 "有条件地注入故障的直接链接") 以下示例演示了如何在路由上配置 `fault-injection` 插件,以拦截进一步的请求发送,并返回特定的 HTTP 代码。 创建一个使用 `fault-injection` 插件的路由,使用 `abort` 动作,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "fault-injection-route", "uri": "/anything", "plugins": { "fault-injection": { "abort": { "http_status": 404, "body": "APISIX Fault Injection", "headers": { "X-APISIX-Remote-Addr": "$remote_addr" }, "vars": [ [ [ "arg_name","==","john" ] ] ] } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: fault-injection-route uris: - /anything plugins: fault-injection: abort: http_status: 404 body: "APISIX Fault Injection" headers: X-APISIX-Remote-Addr: $remote_addr vars: - - - arg_name - "==" - john upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD fault-injection-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: fault-injection-plugin-config spec: plugins: - name: fault-injection config: abort: http_status: 404 body: "APISIX Fault Injection" headers: X-APISIX-Remote-Addr: $remote_addr vars: - - - arg_name - "==" - john --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: fault-injection-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: fault-injection-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f fault-injection-ic.yaml ``` fault-injection-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: fault-injection-route spec: ingressClassName: apisix http: - name: fault-injection-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: fault-injection enable: true config: abort: http_status: 404 body: "APISIX Fault Injection" headers: X-APISIX-Remote-Addr: $remote_addr vars: - - - arg_name - "==" - john ``` 将配置应用到集群: ``` kubectl apply -f fault-injection-ic.yaml ``` ❶ 使用 HTTP 状态码 `404` 响应请求。 ❷ 使用 `APISIX Fault Injection` 作为响应体。 ❸ 响应请求时添加头 `X-APISIX-Remote-Addr` 和请求来源的 IP。 ❹ 仅当 URL 参数 `name` 的值为 `john` 时,才按上述规范响应请求。 发送带有 URL 参数 `name` 为 `john` 的请求到路由: ``` curl -i "http://127.0.0.1:9080/anything?name=john" ``` 你应该收到 `HTTP/1.1 404 Not Found` 响应: ``` HTTP/1.1 404 Not Found ... X-APISIX-Remote-Addr: 192.168.65.1 APISIX Fault Injection ``` 发送带有 URL 参数 `name` 为不同值的请求到路由: ``` curl -i "http://127.0.0.1:9080/anything?name=jane" ``` 你应该收到来自上游服务的 `HTTP/1.1 200 OK` 响应,而没有注入故障。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * abort object *** Abort 动作配置。 * http\_status integer 必填 有效值: 大于或等于 200 *** 返回给客户端的 HTTP 响应状态码。 * body string *** 返回给客户端的响应体。支持在响应体中使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * headers object *** 返回给客户端的响应头。支持在响应头中使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * percentage integer 有效值: 介于 0 和 100 之间(含边界值) *** 要中止的请求百分比。 * vars array\[array] *** 一个或多个匹配条件的数组,采用 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)的形式,用于有条件地执行插件。 * delay object *** Delay 动作配置。 * duration number 必填 *** 延迟持续时间(秒)。 * percentage integer 有效值: 介于 0 和 100 之间(含边界值) *** 要延迟的请求百分比。 * vars array\[array] *** 一个或多个匹配条件的数组,采用 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)的形式,用于有条件地执行插件。 --- # feishu-auth [企业版](https://api7.ai/enterprise) `feishu-auth` 插件支持 [飞书](https://www.feishu.cn/) OAuth 2.0 身份认证,作为客户端在访问上游资源前进行身份认证的机制。 启用该插件后,将实现 OAuth 2.0 授权码流程:用户被重定向到飞书完成身份认证,认证完成后携带授权码重定向回来。插件使用该授权码换取访问令牌、获取用户信息,并为后续请求维护会话状态。 当消费者成功通过身份认证后,插件会在请求中添加包含 Base64 编码用户信息的 `X-Userinfo` 请求头,再将请求代理到上游服务。上游服务可据此区分用户并按需实现额外逻辑。 ## 使用示例[​](#使用示例 "使用示例的直接链接") 在开始之前,请确保你已创建飞书应用并获取所需的凭证。 1. 创建飞书应用。 * 进入 [飞书开放平台](https://open.feishu.cn/)。 * 在开发者后台中创建一个新应用。 * 将其配置为支持 OAuth 2.0 的网页应用。 2. 在创建的应用中: * 进入 **凭证与基础信息**,记录你的 app ID 和 app secret。 * 进入 **安全设置**,将重定向 URI 设置为与 `auth_redirect_uri` 配置匹配的地址,例如 `http://192.168.2.102:9080/anything`。 * 进入 **权限与范围**,添加获取用户信息所需的权限,例如 `contact:user.base:readonly`。 更多信息请参阅 [自建应用开发流程](https://open.feishu.cn/document/develop-process/self-built-application-development-process) 与 [浏览器网页接入指南](https://open.feishu.cn/document/sso/web-application-end-user-consent/guide)。 ### 在路由上配置飞书认证[​](#在路由上配置飞书认证 "在路由上配置飞书认证的直接链接") 以下示例演示如何在路由上启用飞书认证。 创建路由并配置 `feishu-auth` 插件: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "feishu-auth-route", "uri": "/anything", "plugins": { "feishu-auth": { "app_id": "cli_1234567890abcdef", "app_secret": "replace-with-your-app-secret-here", "secret": "strong-secret", "auth_redirect_uri": "http://192.168.2.102:9080/anything", "redirect_uri": "https://accounts.feishu.cn/open-apis/authen/v1/authorize?app_id=cli_xxxx&redirect_uri=http%3A%2F%2F192.168.2.102%3A9080%2Fanything&response_type=code&state=feishu" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 替换为你的 app ID。 ❷ 替换为你的 app secret。 ❸ 替换为你的 secret,应为一个随机字符串。 ❹ 替换为你在飞书注册的 OAuth 回调重定向 URI。 ❺ 根据你的应用信息更新 URI 查询参数。详见 [构造授权链接](https://open.feishu.cn/document/sso/web-application-end-user-consent/guide#9948213f)。 在浏览器中访问该路由(例如 `http://192.168.2.102:9080/anything`),你应被重定向到飞书授权页面: ![通过飞书登录](https://static.api7.ai/uploads/2026/02/13/8fL3TC4o_feishu-auth-1-masked.png)
成功通过飞书认证后,你应在浏览器中看到上游服务返回的响应: ![来自 HTTPBIN 的响应](https://static.api7.ai/uploads/2026/02/13/rWcXrYeP_feishu-auth-ok.png) --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * app\_id string 必填 *** 飞书应用 ID(client ID)。 * app\_secret string 必填 *** 飞书应用密钥(client secret)。 该密钥在存入数据库之前会通过 AES 加密。你也可以将其保存在环境变量中并通过 `env://` 前缀引用,或保存在 HashiCorp Vault 的 [KV secrets engine](https://developer.hashicorp.com/vault/docs/secrets/kv) 等密钥管理服务中,通过 `secret://` 前缀引用。更多信息请参阅 [密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * auth\_redirect\_uri string 必填 *** 在飞书注册的 OAuth 回调重定向 URI,需与你在飞书应用设置中配置的重定向 URI 一致。飞书完成认证后会携带授权码重定向到该地址。 * redirect\_uri string 必填 *** 用户被重定向进行身份认证的 URI。详见 [构造授权链接](https://open.feishu.cn/document/sso/web-application-end-user-consent/guide#9948213f)。 * secret string 必填 有效值: 8 到 32 个字符 *** 用于会话密钥派生和 Cookie 加密的密钥。该密钥应为强随机字符串以保障安全。 该值在存入数据库之前会通过 AES 加密。 * secret\_fallbacks array\[string] *** 用于密钥轮换期间会话校验的备用密钥列表,使主密钥更新后由旧密钥创建的现有会话仍然有效。 * code\_header string 默认值:`X-Feishu-Code` *** 用于提取授权码的请求头名称。若请求头与查询参数同时提供,请求头优先。 * code\_query string 默认值:`code` *** 用于提取授权码的查询参数名称。当飞书在查询字符串中通过授权码回跳时使用。 * access\_token\_url string 默认值:`https://open.feishu.cn/open-apis/authen/v2/oauth/token` *** 用于使用授权码换取访问令牌的飞书 OAuth 令牌端点 URL。 * userinfo\_url string 默认值:`https://open.feishu.cn/open-apis/authen/v1/user_info` *** 用于使用访问令牌获取用户信息的飞书用户信息端点 URL。 * set\_userinfo\_header boolean 默认值:`true` *** 如果为 `true`,则在转发到上游服务的请求中设置 `X-Userinfo` 请求头,其中包含 Base64 编码的飞书用户信息。 * timeout integer 默认值:`6000` *** 调用飞书 API 时 HTTP 请求的超时时间(毫秒),同时适用于令牌交换和用户信息获取请求。 * ssl\_verify boolean 默认值:`true` *** 如果为 `true`,则在调用飞书 API 时验证 SSL 证书。 * cookie\_expires\_in integer 默认值:`86400` *** 会话 Cookie 的过期时间(秒)。Cookie 在该时长内保持有效。 --- # forward-auth `forward-auth` 插件支持与外部授权服务集成以进行认证和授权。如果认证失败,将向客户端返回可自定义的错误消息。如果认证成功,请求将连同 APISIX 添加的以下请求头一起转发到上游服务: * `X-Forwarded-Proto`: 协议 * `X-Forwarded-Method`: HTTP 方法 * `X-Forwarded-Host`: 主机 * `X-Forwarded-Uri`: URI * `X-Forwarded-For`: 源 IP ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `forward-auth`。 要跟随前两个示例,请先设置好你的外部授权服务,或者使用 [serverless function 插件](https://docs.apiseven.com/hub/serverless-functions.md) 创建一个模拟认证服务,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "id": "auth-mock", "uri": "/auth", "plugins": { "serverless-pre-function": { "phase": "rewrite", "functions": [ "return function (conf, ctx) local core = require(\"apisix.core\"); local authorization = core.request.header(ctx, \"Authorization\"); if authorization == \"123\" then core.response.exit(200); elseif authorization == \"321\" then core.response.set_header(\"X-User-ID\", \"i-am-user\"); core.response.exit(200); else core.response.set_header(\"X-Forward-Auth\", \"Fail\"); core.response.exit(403); end end" ] } } }' ``` ❶ 如果 `Authorization` 头的值为 `123`,响应 `200 OK`; ❷ 如果 `Authorization` 头的值为 `321`,设置头 `X-User-ID: i-am-user` 并响应 `200 OK`; ❸ 否则,设置头 `X-Forward-Auth: Fail` 并响应 `403 Forbidden`。 adc-auth-mock.yaml ``` services: - name: auth-mock-service routes: - name: auth-mock-route uris: - /auth plugins: serverless-pre-function: phase: rewrite functions: - | return function(conf, ctx) local core = require("apisix.core") local authorization = core.request.header(ctx, "Authorization") if authorization == "123" then core.response.exit(200) elseif authorization == "321" then core.response.set_header("X-User-ID", "i-am-user") core.response.exit(200) else core.response.set_header("X-Forward-Auth", "Fail") core.response.exit(403) end end upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 如果 `Authorization` 头的值为 `123`,响应 `200 OK`; ❷ 如果 `Authorization` 头的值为 `321`,设置头 `X-User-ID: i-am-user` 并响应 `200 OK`; ❸ 否则,设置头 `X-Forward-Auth: Fail` 并响应 `403 Forbidden`。 将配置同步到网关: ``` adc sync -f adc-auth-mock.yaml ``` * Gateway API * APISIX CRD forward-auth-mock-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: auth-mock-plugin-config spec: plugins: - name: serverless-pre-function config: phase: rewrite functions: - | return function(conf, ctx) local core = require("apisix.core") local authorization = core.request.header(ctx, "Authorization") if authorization == "123" then core.response.exit(200) elseif authorization == "321" then core.response.set_header("X-User-ID", "i-am-user") core.response.exit(200) else core.response.set_header("X-Forward-Auth", "Fail") core.response.exit(403) end end --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: auth-mock-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /auth filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: auth-mock-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 如果 `Authorization` 头的值为 `123`,响应 `200 OK`; ❷ 如果 `Authorization` 头的值为 `321`,设置头 `X-User-ID: i-am-user` 并响应 `200 OK`; ❸ 否则,设置头 `X-Forward-Auth: Fail` 并响应 `403 Forbidden`。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-mock-ic.yaml ``` forward-auth-mock-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: auth-mock-route spec: ingressClassName: apisix http: - name: auth-mock-route match: paths: - /auth upstreams: - name: httpbin-external-domain plugins: - name: serverless-pre-function enable: true config: phase: rewrite functions: - | return function(conf, ctx) local core = require("apisix.core") local authorization = core.request.header(ctx, "Authorization") if authorization == "123" then core.response.exit(200) elseif authorization == "321" then core.response.set_header("X-User-ID", "i-am-user") core.response.exit(200) else core.response.set_header("X-Forward-Auth", "Fail") core.response.exit(403) end end ``` ❶ 如果 `Authorization` 头的值为 `123`,响应 `200 OK`; ❷ 如果 `Authorization` 头的值为 `321`,设置头 `X-User-ID: i-am-user` 并响应 `200 OK`; ❸ 否则,设置头 `X-Forward-Auth: Fail` 并响应 `403 Forbidden`。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-mock-ic.yaml ``` ### 转发指定头到上游资源[​](#转发指定头到上游资源 "转发指定头到上游资源的直接链接") 以下示例演示了如何在路由上设置 `forward-auth`,根据请求头中的值控制客户端对上游资源的访问。它还允许将授权服务中的特定头传递到上游资源。 创建一个启用了 `forward-auth` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "forward-auth-route", "uri": "/headers", "plugins": { "forward-auth": { "uri": "http://127.0.0.1:9080/auth", "request_headers": ["Authorization"], "upstream_headers": ["X-User-ID"] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` ❶ 授权服务的 URI。 ❷ 应转发到授权服务的请求头。 ❷ 需要转发到授权服务的请求头。 adc.yaml ``` services: - name: forward-auth-service routes: - name: forward-auth-route uris: - /headers plugins: forward-auth: uri: http://127.0.0.1:9080/auth request_headers: - Authorization upstream_headers: - X-User-ID upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 授权服务的 URI。 ❷ 应转发到授权服务的请求头。 ❷ 需要转发到授权服务的请求头。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD forward-auth-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: forward-auth-plugin-config spec: plugins: - name: forward-auth config: uri: http://apisix-gateway.aic.svc.cluster.local/auth request_headers: - Authorization upstream_headers: - X-User-ID --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: forward-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: forward-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 授权服务的 URI。使用 Ingress Controller 时,请通过 Kubernetes 服务地址引用模拟授权服务。 ❷ 应转发到授权服务的请求头。 ❷ 需要转发到授权服务的请求头。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-ic.yaml ``` forward-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: forward-auth-route spec: ingressClassName: apisix http: - name: forward-auth-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: forward-auth enable: true config: uri: http://apisix-gateway.aic.svc.cluster.local/auth request_headers: - Authorization upstream_headers: - X-User-ID ``` ❶ 授权服务的 URI。使用 Ingress Controller 时,请通过 Kubernetes 服务地址引用模拟授权服务。 ❷ 应转发到授权服务的请求头。 ❷ 需要转发到授权服务的请求头。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-ic.yaml ``` 向路由发送带有授权详情的请求: ``` curl "http://127.0.0.1:9080/headers" -H 'Authorization: 123' ``` 你应该会看到如下的 `HTTP/1.1 200 OK` 响应: ``` { "headers": { "Accept": "*/*", "Authorization": "123", ... } } ``` 要验证授权服务设置的 `X-User-ID` 头是否转发到了上游服务,请发送带有相应授权详情的请求: ``` curl "http://127.0.0.1:9080/headers" -H 'Authorization: 321' ``` 你应该会看到如下的 `HTTP/1.1 200 OK` 响应,显示该头已转发到上游: ``` { "headers": { "Accept": "*/*", "Authorization": "123", "X-User-ID": "i-am-user", ... } } ``` ### 认证失败时返回指定头给客户端[​](#认证失败时返回指定头给客户端 "认证失败时返回指定头给客户端的直接链接") 以下示例演示了如何在路由上配置 `forward-auth` 以控制客户端对上游资源的访问。当认证失败时,它还会将授权服务返回的特定头传递给客户端。 创建一个启用了 `forward-auth` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "forward-auth-route", "uri": "/headers", "plugins": { "forward-auth": { "uri": "http://127.0.0.1:9080/auth", "request_headers": ["Authorization"], "client_headers": ["X-Forward-Auth"] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` ❶ 当认证失败时,将来自授权服务的 `X-Forward-Auth` 头传回给客户端。 adc.yaml ``` services: - name: forward-auth-service routes: - name: forward-auth-route uris: - /headers plugins: forward-auth: uri: http://127.0.0.1:9080/auth request_headers: - Authorization client_headers: - X-Forward-Auth upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 当认证失败时,将来自授权服务的 `X-Forward-Auth` 头传回给客户端。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD forward-auth-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: forward-auth-plugin-config spec: plugins: - name: forward-auth config: uri: http://apisix-gateway.aic.svc.cluster.local/auth request_headers: - Authorization client_headers: - X-Forward-Auth --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: forward-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: forward-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 当认证失败时,将来自授权服务的 `X-Forward-Auth` 头传回给客户端。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-ic.yaml ``` forward-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: forward-auth-route spec: ingressClassName: apisix http: - name: forward-auth-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: forward-auth enable: true config: uri: http://apisix-gateway.aic.svc.cluster.local/auth request_headers: - Authorization client_headers: - X-Forward-Auth ``` ❶ 当认证失败时,将来自授权服务的 `X-Forward-Auth` 头传回给客户端。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-ic.yaml ``` 发送一个不带任何认证信息的请求: ``` curl -i "http://127.0.0.1:9080/headers" ``` 你应该收到一个 `HTTP/1.1 403 Forbidden` 响应: ``` ... X-Forward-Auth: Fail Server: APISIX/3.x.x 403 Forbidden

403 Forbidden


openresty

Powered by APISIX.

``` ### 基于 POST Body 进行授权[​](#基于-post-body-进行授权 "基于 POST Body 进行授权的直接链接") 此示例演示了如何配置 `forward-auth` 插件以根据 POST Body 数据控制访问,将值作为头传递给授权服务,并在根据 Body 数据授权失败时拒绝请求。 此示例使用内置变量 `$post_arg.*` 读取请求体参数。APISIX 会从 `application/x-www-form-urlencoded`、`application/json` 和 `multipart/form-data` 请求体中解析 `$post_arg.*`,因此客户端必须根据实际发送的请求体设置正确的 `Content-Type` 请求头。详情请参阅[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 请先设置好你的外部授权服务,或者使用 [serverless function 插件](https://docs.apiseven.com/hub/serverless-functions.md) 创建一个模拟认证服务。该函数检查 `tenant_id` 头是否为 `123`,如果是则返回 `200 OK`,否则返回 403 错误。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "id": "auth-mock", "uri": "/auth", "plugins": { "serverless-pre-function": { "phase": "rewrite", "functions": [ "return function(conf, ctx) local core = require(\"apisix.core\") local tenant_id = core.request.header(ctx, \"tenant_id\") if tenant_id == \"123\" then core.response.exit(200); else core.response.exit(403, \"tenant_id is \"..tenant_id .. \" but expecting 123\"); end end" ] } } }' ``` adc-auth-mock.yaml ``` services: - name: auth-mock-service routes: - name: auth-mock-route uris: - /auth plugins: serverless-pre-function: phase: rewrite functions: - | return function(conf, ctx) local core = require("apisix.core") local tenant_id = core.request.header(ctx, "tenant_id") if tenant_id == "123" then core.response.exit(200) else core.response.exit(403, "tenant_id is " .. tenant_id .. " but expecting 123") end end upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc-auth-mock.yaml ``` * Gateway API * APISIX CRD forward-auth-post-mock-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: auth-mock-plugin-config spec: plugins: - name: serverless-pre-function config: phase: rewrite functions: - | return function(conf, ctx) local core = require("apisix.core") local tenant_id = core.request.header(ctx, "tenant_id") if tenant_id == "123" then core.response.exit(200) else core.response.exit(403, "tenant_id is " .. tenant_id .. " but expecting 123") end end --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: auth-mock-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /auth filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: auth-mock-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-post-mock-ic.yaml ``` forward-auth-post-mock-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: auth-mock-route spec: ingressClassName: apisix http: - name: auth-mock-route match: paths: - /auth upstreams: - name: httpbin-external-domain plugins: - name: serverless-pre-function enable: true config: phase: rewrite functions: - | return function(conf, ctx) local core = require("apisix.core") local tenant_id = core.request.header(ctx, "tenant_id") if tenant_id == "123" then core.response.exit(200) else core.response.exit(403, "tenant_id is " .. tenant_id .. " but expecting 123") end end ``` 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-post-mock-ic.yaml ``` 创建一个启用了 `forward-auth` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "forward-auth-route", "uri": "/post", "methods": ["POST"], "plugins": { "forward-auth": { "uri": "http://127.0.0.1:9080/auth", "request_method": "GET", "extra_headers": {"tenant_id": "$post_arg.tenant_id"} } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` ❶ 使用 POST 参数 `tenant_id` 的值设置额外的头 `tenant_id`。 adc.yaml ``` services: - name: forward-auth-service routes: - name: forward-auth-route uris: - /post methods: - POST plugins: forward-auth: uri: http://127.0.0.1:9080/auth request_method: GET extra_headers: tenant_id: "$post_arg.tenant_id" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 使用 POST 参数 `tenant_id` 的值设置额外的头 `tenant_id`。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD forward-auth-post-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: forward-auth-post-plugin-config spec: plugins: - name: forward-auth config: uri: http://apisix-gateway.aic.svc.cluster.local/auth request_method: GET extra_headers: tenant_id: "$post_arg.tenant_id" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: forward-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /post method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: forward-auth-post-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 使用 POST 参数 `tenant_id` 的值设置额外的头 `tenant_id`。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-post-ic.yaml ``` forward-auth-post-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: forward-auth-route spec: ingressClassName: apisix http: - name: forward-auth-route match: paths: - /post methods: - POST upstreams: - name: httpbin-external-domain plugins: - name: forward-auth enable: true config: uri: http://apisix-gateway.aic.svc.cluster.local/auth request_method: GET extra_headers: tenant_id: "$post_arg.tenant_id" ``` ❶ 使用 POST 参数 `tenant_id` 的值设置额外的头 `tenant_id`。 上述函数实现了以下逻辑: ``` kubectl apply -f forward-auth-post-ic.yaml ``` 发送一个在 JSON 请求体中包含 `tenant_id` 的 POST 请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H 'Content-Type: application/json' \ -d '{"tenant_id": "123"}' ``` 你应该收到一个 `HTTP/1.1 200 OK` 响应。 发送一个 Body 中包含错误 `tenant_id` 的 POST 请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H 'Content-Type: application/json' \ -d '{"tenant_id": "000"}' ``` 你应该收到如下的 `HTTP/1.1 403 Forbidden` 响应: ``` tenant_id is 000 but expecting 123 ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * uri string 必填 *** 外部授权服务的 URI。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,验证授权服务的 SSL 证书。 * request\_method string 默认值:`GET` 有效值: `GET` 或 `POST` *** APISIX 用来向外部授权服务发送请求的 HTTP 方法。默认情况下,APISIX 向外部授权服务发送 GET 请求。 当设置为 `POST` 时,APISIX 会向外部授权服务发送 POST 请求以及请求 Body。但这并不推荐。如果授权决策取决于 POST Body 中的请求参数,建议使用 `$post_arg.*` 提取所需字段,并通过 `extra_headers` 字段传递它们。这种方法避免了发送完整的请求 Body,减少了开销,并使授权服务专注于通过头信息进行决策。 * max\_req\_body\_size integer 默认值:`67108864` *** 当 `request_method` 为 `POST` 时,缓冲并转发到外部授权服务的最大请求体大小,单位为字节(默认 67108864 字节,即 64 MB)。请求体大于此限制的请求将以 HTTP 413 被拒绝。自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * request\_headers array\[string] 默认值:`[]` *** 应转发到外部授权服务的客户端请求头。如果未配置,则仅转发 APISIX 添加的头,例如 `X-Forwarded-*`。 * upstream\_headers array\[string] 默认值:`[]` *** 插件在将请求转发到上游前控制的外部授权响应头。授权服务返回已配置的响应头时,网关会转发该响应头;授权响应未返回时,网关会清除客户端提供的同名值。如果未配置,则不转发任何授权响应头。 * client\_headers array\[string] 默认值:`[]` *** 当认证失败时,应转发给客户端的外部授权服务响应头。如果未配置,则没有头会被转发给客户端。 * extra\_headers object *** 发送到授权服务的额外头。支持值中的 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * timeout integer 默认值:`3000` 有效值: 介于 1 和 60000 之间(含边界值) *** 外部授权服务 HTTP 调用的超时时间(以毫秒为单位)。 * keepalive boolean 默认值:`true` *** 如果为 true,则保持连接打开以用于多个请求。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 建立的 HTTP 连接在关闭前的空闲时间。 * keepalive\_pool integer 默认值:`5` 有效值: 大于或等于 1 *** 连接池中的最大连接数。 * allow\_degradation boolean 默认值:`false` *** 如果为 true,允许 APISIX 在插件或其依赖项不可用时继续处理请求(不使用插件)。 * status\_on\_error integer 默认值:`403` 有效值: 介于 200 和 599 之间(含边界值) *** 当外部授权服务出现网络错误时,返回给客户端的 HTTP 状态码。 --- # google-cloud-logging `google-cloud-logging` 插件将请求和响应日志以批处理的方式推送到 [Google Cloud Logging Service](https://cloud.google.com/logging?hl=en),并支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `google-cloud-logging` 插件。 要按照示例操作,你应该拥有一个已激活计费的 GCP 账户。你还应该首先通过完成以下步骤在 GCP 中获取身份认证凭据: * 访问 **IAM & Admin** 创建服务账户。 * 为服务账户分配 **Logs Writer** 角色,该角色为账户分配 `logging.logEntries.create` 和 `logging.logEntries.route` 权限。 * 为服务账户创建私钥并下载 JSON 格式的凭据。 凭据 JSON 文件内容应类似于以下内容: ``` { "type": "service_account", "project_id": "api7ai-docs", "private_key_id": "6330a8c37b15a26d3fb4e9e3986f04c004826d1a", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDYTl1QKxgClpgq\n1FyZNKZTq4os9AoXU+h/1gdngtc681xqMIWlwycrJ7Bo69L//7REyUKnuIOPgHU6\nPCp4rGFokxdXzBJC0+WsxwZ/FZoaqLAD5Fbs4BpZ9q2F8fKz07l9Da+Ul2lLlQq6\nEgij2NOh9ytBvFiYEAnMY5DDWFyoXWBB0OXfGEE6486+DcfG8gMWQ7rXKVbKNyA1\nJdbS63cDJNERLb6z8QsaZOqYZwaqIn6apEv9aadnNEU+4HrXrjxsoDtk7zLmsbtp\nUOpYVVSiYz2uYbUz3XRJjW+NAeyeVBK8tePbe1n5WHM4Sg1Mp1wYtaJknS5gmOXe\nxglMt4vTAgMBAAECggEAHzGZ6mRJ56GmcH1vRywyalw8JoR2ahZ7L+hX6VkTR0ND\nn2VqTf/pR6Nxy4fAG5QEKsFS1VOE1tk3I/6mP1XYtwHeEBbJcWK+kLP5CghoULzl\nTq0LeMikHu+uY6w8OUlVTS/UQtC+SxwVMbstlEGyhWERxjdu0VwL\nY/jb6DA123cqjHteEwOFuipG+GELKJGIjgNhzyRimowOsY6F+3WrDHZrf2sM7AlD\nLbjrA3MdvIe6rNC8zy7zf/didygjryrJpjiHkKsLIPIPbu0l5xENHd3TNWuVAg48\nhf4nRwyZ7q1RXgRYnp/SfPH1YB0p4+7D0xLQUd2OEQKBgQDxvOED6IQ3zxipW+uX\nX4c+6QxwnOCTY/oQOtCwmgPSvzIMSyoNCH0YY3sdoUmygSP0hmBFIaP\nBH6A5d3A06iMTUiAwEOp5JDQImqVTN+Sz/JBBOxCpjuW/dmG72MFlZBL161lY0g6\n79ku2xatxvncdJvcpEWqB4UBEQKBgQDlEV/Tapm950M+PYTtYHry1AYxGum+Eb2+\nNg9u5kWbgl6aWSgR/XsKQPTcsYX0gFSkrYhFrVwdruDeG9JYSCckH6FtCoa8yv5s\nMB+QR7VWJoa3ej7Hc0O6VUjwUfUkXuQRoFCEl8lFCZzugsjSw93xTeo6w3s9oaCB\neY9RXGn+owKBgQCMU/Tba/K04weR6MZOTSoZnveVt7u2U+cp3LqgigeGI29OK6Px\nhOf5bGZfwO0jLlJAVJin5tdtgK1FfUDPbPByqv2bnkLNj19zPikJSqG18QSmPsXa\nV9RtYgo0doNJF3tbFUQKTdRB8qW5oXSgofMVfCEiJ8uL6jVAVCwMk+jlwQKBgQCD\ntE6lbwhAcORvt81i8nMehRueRjwYpXi0Eb8j41AoTnf4RMTOOzDwP1LKRWOgpdyE\n5qWQclGhW3g9HD//tFSU537YBBJeIFTSfYTYXvJ7OyGAAtBvuu05CGosiuLo64o0\nPDmvUtpNUG6jkBzJWgaVBFhlOxnz4Kc5alwlyn3DAwKBgQCwNJsqb4pOjwjaJl/m\nePXpeX7YdVyFnBDbSQ1BFxDYGU12yTKRYqQVIB+VIIGN28acta1EPI8tF2ODG5az\nCBmgH5amLRHHCDYRKwrP+BTA39lK0pQEUP47RSzOdY82KQB13BW1uEZTcifjS9HN\niZPoV+OYHG5iJiiWEQi9/Q1AfQ==\n-----END PRIVATE KEY-----\n", "client_email": "api7-docs-log@api7ai-docs.iam.gserviceaccount.com", "client_id": "100920913890704420895", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/api7-docs-log%40api7ai-docs.iam.gserviceaccount.com", "universe_domain": "googleapis.com" } ``` ### 使用 `auth_config` 配置身份认证[​](#使用-auth_config-配置身份认证 "使用-auth_config-配置身份认证的直接链接") 以下示例展示了如何在路由上配置 `google-cloud-logging` 插件,记录客户端请求和响应,并将日志推送到 Google Cloud Logging。你将使用 `auth_config` 选项配置 GCP 身份认证详情。 创建一个启用 `google-cloud-logging` 的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "google-cloud-logging-route", "uri": "/anything", "plugins": { "google-cloud-logging": { "auth_config": { "client_email": "api7-docs-logging@api7ai-docs.iam.gserviceaccount.com", "project_id": "api7ai-docs", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDYTl1QKxgClpgq\n1FyZNKZTq4os9AoXU+h/1gdngtc681xqMIWlwycrJ7Bo69L//7REyUKnuIOPgHU6\nPCp4rGFokxdXzBJC0+WsxwZ/FZoaqLAD5Fbs4BpZ9q2F8fKz07l9Da+Ul2lLlQq6\nEgij2NOh9ytBvFiYEAnMY5DDWFyoXWBB0OXfGEE6486+DcfG8gMWQ7rXKVbKNyA1\nJdbS63cDJNERLb6z8QsaZOqYZwaqIn6apEv9aadnNEU+4HrXrjxsoDtk7zLmsbtp\nUOpYVVSiYz2uYbUz3XRJjW+NAeyeVBK8tePbe1n5WHM4SnS5gmOXe\nxglMt4vTAgMBAAECggEAHzGZ6mRJ56GmcH1vRywyalw8JoR2ahZ7L+hX6VkTR0ND\nn2VqTf/pR6Nxy4fAG5QEKsFS1VOE1tk3I/6mP1XYtwHeEBbJcWK+kLP5CghoULzl\nTq0LeMikHuI19FxH3HVwSV+uY6w8OUlVTS/UQtC+SxwVMbstlEGyhWERxjdu0VwL\nY/jb6DA123cqjHteEwOFuipG+GELKJGIjgNhzyRimowOsY6F+3WrDHZrf2sM7AlD\nLbjrA3MdvIe6rNC8zy7zf/didygjryrJpjiHkKsLIPIPbu0l5xENHd3TNWuVAg48\nhf4nRwyZ7q1RXgRYnp/SfPH1YB0p4+7D0xLQUd2xvOED6IQ3zxipW+uX\nX4c+6QxwnOCTY/oQOtCwmgPSvzIMSyoNCH0YY3sdoUmygS40v30OV8vP0hmBFIaP\nBH6A5d3A06iMTUiAwEOp5JDQImqVTN+Sz/JBBOxCpjuW/dmG72MFlZBL161lY0g6\n79ku2xatxvncdJvcpEWqB4UBEQKBgQDlEV/Tapm950M+PYTtYHry1AYxGum+Eb2+\nNg9u5kWbgl6aWSgR/XsKQPTcsYX0gFSkrYhFrVwdruDeG9JYSCckH6FtCoa8yv5s\nMB+QR7VWJoa3ej7Hc0O6VUjwUfUkXuQRoFCEl8lFCZzugsjSw93xTeo6w3s9oaCB\neY9RXGn+owKBgQCMU/Tba/K04weR6MZOTSoZnveVt7u2U+cp3LqgigeGI29OK6Px\nhOf5bGZfwO0jLlJAVJin5tdtgK1FfUDPbPByqv2bnkLNj19zPikJSqG18QSmPsXa\nV9RtYgo0doNJF3tbFUQKTdRB8qW5oXSgofMVfCEiJ8uL6jVAVCwMk+jlwQKBgQCD\ntE6lbwhAcORvt81i8nMehRueRjwYpXi0Eb8j41AoTnf4RMTOOzDwP1LKRWOgpdyE\n5qWQclGhW3g9HD//tFSU537YBBJeIFTSfYTYXvJ7OyGAAtBvuu05CGosiuLo64o0\nPDmvUtpNUG6jkBzJWgaVBFhlOxnz4Kc5alwlyn3DAwKBgQCwNJsqb4pOjwjaJl/m\nePXpeX7YdVyFnBDbSQ1BFxDYGU12yTKRYqQVIB+VIIGN28acta1EPI8tF2ODG5az\nCBmgH5amLRHHCDYRKwrP+BTA39lK0pQEUP47RSzOdY82KQB13BW1uEZTcifjS9HN\niZPoV+OYHG5iJiiWEQi9/Q1AfQ==\n-----END PRIVATE KEY-----\n", "token_uri": "https://oauth2.googleapis.com/token" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: google-cloud-logging-route plugins: google-cloud-logging: auth_config: client_email: "api7-docs-logging@api7ai-docs.iam.gserviceaccount.com" project_id: "api7ai-docs" private_key: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- token_uri: "https://oauth2.googleapis.com/token" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD google-cloud-logging-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: google-cloud-logging-plugin-config spec: plugins: - name: google-cloud-logging config: auth_config: client_email: "api7-docs-logging@api7ai-docs.iam.gserviceaccount.com" project_id: "api7ai-docs" private_key: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- token_uri: "https://oauth2.googleapis.com/token" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: google-cloud-logging-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: google-cloud-logging-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` google-cloud-logging-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: google-cloud-logging-route spec: ingressClassName: apisix http: - name: google-cloud-logging-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: google-cloud-logging config: auth_config: client_email: "api7-docs-logging@api7ai-docs.iam.gserviceaccount.com" project_id: "api7ai-docs" private_key: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- token_uri: "https://oauth2.googleapis.com/token" ``` 应用配置: ``` kubectl apply -f google-cloud-logging-ic.yaml ``` ❶ 替换为你的服务账户。 ❷ 替换为你的项目 ID。 ❸ 替换为你的私钥。 ❹ 替换为你的令牌 URI。 向路由发送请求以生成日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。 导航到 Google Cloud Logs Explorer,你应该会看到与你的请求对应的日志条目,类似如下: ``` { "insertId": "5400340ea330b35f2d557da2cbb9e88d", "jsonPayload": { "service_id": "", "route_id": "google-cloud-logging-route" }, "httpRequest": { "requestMethod": "GET", "requestUrl": "http://127.0.0.1:9080/anything", "requestSize": "85", "status": 200, "responseSize": "615", "userAgent": "curl/8.6.0", "remoteIp": "192.168.107.1", "serverIp": "54.86.137.185:80", "latency": "1.083s" }, "resource": { "type": "global", "labels": { "project_id": "api7ai-docs" } }, "timestamp": "2025-02-07T07:39:51.859Z", "labels": { "source": "apache-apisix-google-cloud-logging" }, "logName": "projects/api7ai-docs/logs/apisix.apache.org%2Flogs", "receiveTimestamp": "2025-02-07T07:39:58.012811475Z" } ``` ### 使用 `auth_file` 配置身份认证[​](#使用-auth_file-配置身份认证 "使用-auth_file-配置身份认证的直接链接") 以下示例展示了如何在路由上配置 `google-cloud-logging` 插件,记录客户端请求和响应,并将日志推送到 Google Cloud Logging。你将使用 `auth_file` 选项配置 GCP 身份认证详情。 将之前下载的 GCP 服务账户凭据 JSON 文件复制到 APISIX 可访问的位置。如果你在 Docker 中运行 APISIX,你应该将文件复制到容器中,例如 `/usr/local/apisix/conf/gcp-logging-auth.json`。 创建一个启用 `google-cloud-logging` 的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "google-cloud-logging-route", "uri": "/anything", "plugins": { "google-cloud-logging": { "auth_file": "/usr/local/apisix/conf/gcp-logging-auth.json" } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: google-cloud-logging-route plugins: google-cloud-logging: auth_file: "/usr/local/apisix/conf/gcp-logging-auth.json" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD google-cloud-logging-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: google-cloud-logging-plugin-config spec: plugins: - name: google-cloud-logging config: auth_file: "/usr/local/apisix/conf/gcp-logging-auth.json" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: google-cloud-logging-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: google-cloud-logging-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` google-cloud-logging-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: google-cloud-logging-route spec: ingressClassName: apisix http: - name: google-cloud-logging-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: google-cloud-logging config: auth_file: "/usr/local/apisix/conf/gcp-logging-auth.json" ``` 应用配置: ``` kubectl apply -f google-cloud-logging-ic.yaml ``` ❶ 替换为你的 GCP 服务账户凭据 JSON 文件路径。 向路由发送请求以生成日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。 导航到 Google Cloud Logs Explorer,你应该会看到与你的请求对应的日志条目,类似如下: ``` { "insertId": "5400340ea330b35f2d557da2cbb9e88d", "jsonPayload": { "service_id": "", "route_id": "google-cloud-logging-route" }, "httpRequest": { "requestMethod": "GET", "requestUrl": "http://127.0.0.1:9080/anything", "requestSize": "85", "status": 200, "responseSize": "615", "userAgent": "curl/8.6.0", "remoteIp": "192.168.107.1", "serverIp": "54.86.137.185:80", "latency": "1.083s" }, "resource": { "type": "global", "labels": { "project_id": "api7ai-docs" } }, "timestamp": "2025-02-07T08:25:11.325Z", "labels": { "source": "apache-apisix-google-cloud-logging" }, "logName": "projects/api7ai-docs/logs/apisix.apache.org%2Flogs", "receiveTimestamp": "2025-02-07T08:25:11.423190575Z" } ``` ### 通过插件元数据自定义日志格式[​](#通过插件元数据自定义日志格式 "通过插件元数据自定义日志格式的直接链接") 以下示例展示了如何使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)和[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)自定义日志格式,以记录请求和响应中的特定请求头和响应头。 在 APISIX 中,[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)用于配置同一插件的所有插件实例的通用元数据字段。当插件在多个资源中启用并且需要对其元数据字段进行统一更新时,这非常有用。 首先,创建一个启用 `google-cloud-logging` 的路由,如下所示,并替换为你的凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "google-cloud-logging-route", "uri": "/anything", "plugins": { "google-cloud-logging": { "auth_config": { "client_email": "api7-docs-logging@api7ai-docs.iam.gserviceaccount.com", "project_id": "api7ai-docs", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDYTl1QKxgClpgq\n1FyZNKZTq4os9AoXU+h/1gdngtc681xqMIWlwycrJ7Bo69L//7REyUKnuIOPgHU6\nPCp4rGFokxdXzBJC0+WsxwZ/FZoaqLAD5Fbs4BpZ9q2F8fKz07l9Da+Ul2lLlQq6\nEgij2NOh9ytBvFiYEAnMY5DDWFyoXWBB0OXfGEE6486+DcfG8gMWQ7rXKVbKNyA1\nJdbS63cDJNERLb6z8QsaZOqYZwaqIn6apEv9aadnNEU+4HrXrjxsoDtk7zLmsbtp\nUOpYVVSiYz2uYbUz3XRJjW+NAeyeVBK8tePbe1n5WHM4SnS5gmOXe\nxglMt4vTAgMBAAECggEAHzGZ6mRJ56GmcH1vRywyalw8JoR2ahZ7L+hX6VkTR0ND\nn2VqTf/pR6Nxy4fAG5QEKsFS1VOE1tk3I/6mP1XYtwHeEBbJcWK+kLP5CghoULzl\nTq0LeMikHuI19FxH3HVwSV+uY6w8OUlVTS/UQtC+SxwVMbstlEGyhWERxjdu0VwL\nY/jb6DA123cqjHteEwOFuipG+GELKJGIjgNhzyRimowOsY6F+3WrDHZrf2sM7AlD\nLbjrA3MdvIe6rNC8zy7zf/didygjryrJpjiHkKsLIPIPbu0l5xENHd3TNWuVAg48\nhf4nRwyZ7q1RXgRYnp/SfPH1YB0p4+7D0xLQUd2xvOED6IQ3zxipW+uX\nX4c+6QxwnOCTY/oQOtCwmgPSvzIMSyoNCH0YY3sdoUmygS40v30OV8vP0hmBFIaP\nBH6A5d3A06iMTUiAwEOp5JDQImqVTN+Sz/JBBOxCpjuW/dmG72MFlZBL161lY0g6\n79ku2xatxvncdJvcpEWqB4UBEQKBgQDlEV/Tapm950M+PYTtYHry1AYxGum+Eb2+\nNg9u5kWbgl6aWSgR/XsKQPTcsYX0gFSkrYhFrVwdruDeG9JYSCckH6FtCoa8yv5s\nMB+QR7VWJoa3ej7Hc0O6VUjwUfUkXuQRoFCEl8lFCZzugsjSw93xTeo6w3s9oaCB\neY9RXGn+owKBgQCMU/Tba/K04weR6MZOTSoZnveVt7u2U+cp3LqgigeGI29OK6Px\nhOf5bGZfwO0jLlJAVJin5tdtgK1FfUDPbPByqv2bnkLNj19zPikJSqG18QSmPsXa\nV9RtYgo0doNJF3tbFUQKTdRB8qW5oXSgofMVfCEiJ8uL6jVAVCwMk+jlwQKBgQCD\ntE6lbwhAcORvt81i8nMehRueRjwYpXi0Eb8j41AoTnf4RMTOOzDwP1LKRWOgpdyE\n5qWQclGhW3g9HD//tFSU537YBBJeIFTSfYTYXvJ7OyGAAtBvuu05CGosiuLo64o0\nPDmvUtpNUG6jkBzJWgaVBFhlOxnz4Kc5alwlyn3DAwKBgQCwNJsqb4pOjwjaJl/m\nePXpeX7YdVyFnBDbSQ1BFxDYGU12yTKRYqQVIB+VIIGN28acta1EPI8tF2ODG5az\nCBmgH5amLRHHCDYRKwrP+BTA39lK0pQEUP47RSzOdY82KQB13BW1uEZTcifjS9HN\niZPoV+OYHG5iJiiWEQi9/Q1AfQ==\n-----END PRIVATE KEY-----\n", "token_uri": "https://oauth2.googleapis.com/token" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` 接下来,配置 `google-cloud-logging` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/google-cloud-logging" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr", } }' ``` adc.yaml ``` plugin_metadata: - name: google-cloud-logging log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` google-cloud-logging-metadata.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: service: name: apisix-admin port: 9180 auth: type: AdminKey adminKey: value: edd1c9f034335f136f87ad84b625c8f1 pluginMetadata: google-cloud-logging: log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" ``` 应用配置: ``` kubectl apply -f google-cloud-logging-metadata.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。 导航到 Google Cloud Logs Explorer,你应该会看到与你的请求对应的日志条目,类似如下: ``` { "@timestamp":"2025-02-07T09:10:42+00:00", "client_ip":"192.168.107.1", "host":"127.0.0.1", "route_id":"google-cloud-logging-route" } ``` 如果在单个实例上未具体指定日志格式,则在插件元数据中配置的日志格式对 `google-cloud-logging` 的所有实例生效。 如果你在路由上的 `google-cloud-logging` 插件中具体配置了日志格式: ``` curl "http://127.0.0.1:9180/apisix/admin/routes/google-cloud-logging-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "google-cloud-logging": { "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr", "env": "$http_env", "resp_content_type": "$sent_http_Content_Type" } } } }' ``` ❶ 记录自定义请求头 `env`。 ❷ 记录响应头 `Content-Type`。 向路由发送带有 `env` 头的请求: ``` curl -i "http://127.0.0.1:9080/anything" -H "env: dev" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。 导航到 Google Cloud Logs Explorer,你应该会看到与你的请求对应的日志条目,类似如下: ``` { "@timestamp":"2025-02-07T09:38:55+00:00", "client_ip":"192.168.107.1", "host":"127.0.0.1", "env":"dev", "resp_content_type":"application/json", "route_id":"google-cloud-logging-route" } ``` 路由上的日志格式配置优先级高于 `google-cloud-logging` 插件元数据上配置的日志格式。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * auth\_config object *** 身份认证配置。必须提供 `auth_config` 和 `auth_file` 中的至少一个。 * client\_email string 必填 *** Google Cloud 服务账户的电子邮件地址。 * private\_key string 必填 *** Google Cloud 服务账户的私钥。该值在存储到 etcd 前会使用 AES 加密。 * project\_id string 必填 *** Google Cloud 服务账户中的项目 ID。 * token\_uri string 必填 默认值:`https://oauth2.googleapis.com/token` *** Google Cloud 服务账户的令牌 URI。 * entries\_uri string 默认值:`https://logging.googleapis.com/v2/entries:write` *** Google Cloud Logging 服务 API。 * scope array\[string] 默认值:`["https://www.googleapis.com/auth/logging.read", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/logging.admin", "https://www.googleapis.com/auth/cloud-platform"]` *** Google Cloud 服务账户的访问范围。请参阅 [Google API 的 OAuth 2.0 范围](https://developers.google.com/identity/protocols/oauth2/scopes#logging)。也可以使用 `scopes` 指定此字段。 * auth\_file string *** Google Cloud 服务账户身份认证 JSON 文件的路径。必须提供 `auth_config` 和 `auth_file` 中的至少一个。 * ssl\_verify boolean 默认值:`true` *** 如果设置为 true,验证服务器的 SSL 证书。 * resource object 默认值:`{"type": "global"}` *** Google 受监控资源由 `type` 和可选的 `labels` 组成,例如: ```json { "type": "gce_instance", "labels": { "project_id": "my-project", "instance_id": "12345678901234", "zone": "us-central1-a" } } ``` 有关更多详细信息,请参阅 [MonitoredResource](https://cloud.google.com/logging/docs/reference/v2/rest/v2/MonitoredResource)。 * log\_id string 默认值:`apisix.apache.org%2Flogs` *** Google Cloud 日志 ID。有关详细信息,请参阅 [LogEntry](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry)。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 你也可以通过配置[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)来全局配置日志格式,这将对所有 `google-cloud-logging` 插件实例生效。如果单个插件实例配置的日志格式与插件元数据中配置的日志格式不同,则单个插件实例的配置优先级更高。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/google-cloud-logging.md#通过插件元数据自定义日志格式)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * name string 默认值:`google-cloud-logging` *** 批处理器的唯一标识符。如果你使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称将导出在 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每一批次允许的最大日志条目数。一旦达到该数值,批次将被发送到日志服务。将此参数设置为 1 意味着立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(以秒为单位)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 批次中最旧条目在发送到日志服务之前允许保留的最长时间(以秒为单位)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(以秒为单位)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 在丢弃日志条目之前允许的最大失败重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # graphql-limit-count `graphql-limit-count` 插件使用固定窗口限制 GraphQL [查询(Queries)](https://graphql.org/learn/queries/)和[变更(Mutations)](https://graphql.org/learn/queries#mutations)的累计成本。查询深度是默认成本,保持了插件的原有行为。API7 企业版还提供 `complexity` 和 `node_quantifier` 策略,用于度量文档要求执行的工作量。 在 GraphQL 中,深度是指查询或变更中的嵌套层级数。以下是一个深度为 3 的查询示例: ``` { a { b { c } } } ``` 使用默认深度策略时,插件会在每个时间间隔内消耗深度配额。例如,如果 30 秒间隔内的配额为 4,则深度为 3 的请求会被允许,并剩余 1。同一间隔内深度为 2 的请求会被拒绝。 该插件接受包含 `query` 字段的 JSON 请求体,或正文直接包含 GraphQL 文档且媒体类型为 `application/graphql` 的 `POST` 请求。片段(fragment)会计入查询深度。不支持的方法返回 `405 Method Not Allowed`;无法读取、格式错误或无效的 GraphQL 请求返回 `400 Bad Request`。 APISIX 默认最多读取 1 MiB 的 GraphQL 请求数据。若要调整该限制,请在 `config.yaml` 中配置 `graphql.max_size` 并重新加载 APISIX: config.yaml ``` graphql: max_size: 1048576 ``` ## 本地限速与基于 Redis 的限速[​](#本地限速与基于-redis-的限速 "本地限速与基于 Redis 的限速的直接链接") `graphql-limit-count` 插件支持两种限速模式: * **本地限速**:每个网关实例独立实施限速。每个实例维护自己的计数器,因此当流量分散到多个实例时,实际限额约为“限额 × 实例数”。未设置 `policy` 或将其设置为 `local` 时,这是默认模式。 * **基于 Redis 的限速**:通过 Redis 在所有网关实例之间共享限额。所有实例共享同一配额,因此配置的限额适用于全部网关实例。 ## 查询成本[​](#查询成本 "查询成本的直接链接") `complexity`、`node_quantifier` 策略及其支持字段在 API7 企业版 3.10.6 中引入。 默认情况下,一个请求按其查询深度计费。`cost_strategy` 可以选择不同的成本模型,使请求按其向上游要求的工作量消耗配额: * `depth` 按选择集的嵌套深度计费。这是该插件一直以来的行为,也仍是默认值,因此升级后已有配置的行为不变。 * `complexity` 根据查询解析的节点计算原始分数。每个节点贡献的分数为 `(其所有子节点之和) × mul + add`,其中 `add` 与 `mul` 默认为 `1`。 * `node_quantifier` 只根据匹配成本装饰能在 `mul_arguments` 中找到可用量词的节点计算原始分数。例如,带有 `mul_arguments: ["first"]` 的装饰会把 `first: 10` 作为更深层量化节点的乘数。如果没有节点同时具备匹配装饰和可用量词,文档的原始分数为 `0`。默认 `score_factor` 会产生计费成本 `1`;执行 `0.01` 调整后,大于 `100` 的系数会提高该成本。 插件会把策略原始分数转换为计入配额的整数。对于 `complexity` 和 `node_quantifier`,它会先给原始分数加 `0.01`,再应用 `score_factor` 并向上取整。因此,使用默认系数 `1` 时,原始整数分数 `3` 会按 `4` 计费。`depth` 策略不执行 `0.01` 调整,但仍会应用系数并向上取整。 `max_cost` 会在查询到达上游前,以 `403 Forbidden` 拒绝计费成本超过配置值的查询。插件会先计入配额,再执行该检查,因此因成本过高而被拒绝的查询仍会消耗计算出的配额。启用 `show_limit_quota_header` 时,`X-Graphql-Query-Cost` 会报告该数值。 `resolve_variables` 默认开启,此时插件会先解析已提供的 GraphQL 变量、操作声明的变量默认值,以及上游 schema 中的参数默认值,再计算成本。关闭它会把 `first: $n` 当作未提供参数,从而可能低估通过变量提交量词的查询成本。 把成本装饰与查询匹配需要上游 schema。每个网关 Worker 会在第一次处理适用请求时内省配置了装饰的服务,并缓存 schema,直到插件重新加载。没有装饰的路由从不触发内省。在这种情况下,`complexity` 使用默认权重计算每个节点,而 `node_quantifier` 的原始分数为 `0`;其计费成本遵循上述调整和缩放规则。当内省端点不是上游本身时,请设置 `introspection_endpoint`;当该端点需要凭据时,请设置 `introspection_headers`。凭据取自配置而不是请求,因为每个缓存的 schema 会被该 Worker 处理的所有调用方复用。 ### 成本装饰[​](#成本装饰 "成本装饰的直接链接") 一条装饰用于调整上游 schema 中某个位置对成本的贡献。装饰在服务上以 `graphql_cost_decorations` 管理,因此由该服务下的所有路由共享,并且无需编辑承载该插件的路由即可修改。 一条装饰指定一个 `field_path`,它可以标识 GraphQL 类型(如 `Product`)、类型加字段(如 `Product.name`),也可以标识一条字段链(如 `Query.products.nodes`)。装饰会调整它匹配到的节点: | 字段 | 作用 | | --------------- | ------------------------------------------------------------------------------------------------- | | `add_value` | 加到该节点自身的成本上。 | | `mul_value` | 对该节点子节点的成本做乘法。 | | `add_arguments` | 指定若干参数,其取值会加到该节点自身的成本上。 | | `mul_arguments` | 指定若干参数,其取值会乘以后代成本。在 `node_quantifier` 策略下,该乘数会传递到更深层的量化节点。 | 同一个服务上,一个 `field_path` 只能被装饰一次。 ## 示例[​](#示例 "示例的直接链接") 以下示例使用 [GitHub GraphQL API](https://docs.github.com/en/graphql) 端点作为上游,并演示了如何在不同场景下配置 `graphql-limit-count`。 要进行后续操作,请创建一个 GitHub [个人访问令牌(Personal Access Token)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens),并为你想要交互的资源配置适当的权限范围。 ### 基于远程地址进行速率限制[​](#基于远程地址进行速率限制 "基于远程地址进行速率限制的直接链接") 以下示例演示了如何通过单个变量 `remote_addr` 对 GraphQL 请求进行速率限制。 创建一个启用了 `graphql-limit-count` 插件的路由,配置为每个远程地址在 30 秒窗口内允许的深度配额为 2: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-route", "uri": "/graphql", "plugins": { "graphql-limit-count": { "count": 2, "time_window": 30, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "local" } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "api.github.com:443": 1 } } }' ``` adc.yaml ``` services: - name: graphql-service routes: - uris: - /graphql name: graphql-limit-count-route plugins: graphql-limit-count: count: 2 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local upstream: type: roundrobin scheme: https nodes: - host: api.github.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: github-graphql-https spec: targetRefs: - name: github-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-limit-count-plugin-config spec: plugins: - name: graphql-limit-count config: count: 2 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-limit-count-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 ``` graphql-limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: github-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: api.github.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-limit-count-route spec: ingressClassName: apisix http: - name: graphql-limit-count-route match: paths: - /graphql upstreams: - name: github-graphql-external-domain plugins: - name: graphql-limit-count enable: true config: count: 2 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local ``` 将配置应用到集群: ``` kubectl apply -f graphql-limit-count-ic.yaml ``` #### 使用 GraphQL 查询进行验证[​](#使用-graphql-查询进行验证 "使用 GraphQL 查询进行验证的直接链接") 发送一个深度为 2 的 GraphQL 查询请求进行验证: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login}}"}' ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 该请求已消耗了时间窗口内允许的所有配额。如果你在同一个 30 秒时间间隔内再次发送请求,应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,表明请求超过了配额阈值。 #### 使用 GraphQL 变更进行验证[​](#使用-graphql-变更进行验证 "使用 GraphQL 变更进行验证的直接链接") 你也可以发送一个深度为 3 的 GraphQL 变更请求进行验证: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "mutation AddReactionToIssue {addReaction(input:{subjectId:\"MDU6SXNzdWUyMzEzOTE1NTE=\",content:HOORAY}) {reaction {content} subject {id}}}"}' ``` 你会随时看到 `HTTP/1.1 429 Too Many Requests` 响应,因为深度 3 总是超过深度 2 的配额。 ### 基于远程地址和消费者名称进行速率限制[​](#基于远程地址和消费者名称进行速率限制 "基于远程地址和消费者名称进行速率限制的直接链接") 以下示例演示了如何通过变量组合 `remote_addr` 和 `consumer_name` 对 GraphQL 请求进行速率限制。它允许每个远程地址和每个[消费者](https://docs.apiseven.com/apisix/key-concepts/consumers.md)在 30 秒窗口内的深度配额为 2。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建第二个消费者 `jane`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jane" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 创建一个启用了 `key-auth` 和 `graphql-limit-count` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-route", "uri": "/graphql", "plugins": { "key-auth": {}, "graphql-limit-count": { "count": 2, "time_window": 30, "rejected_code": 429, "policy": "local", "key_type": "var_combination", "key": "$remote_addr $consumer_name" } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "api.github.com:443": 1 } } }' ``` 创建两个消费者和一个按消费者启用限速的路由: adc.yaml ``` consumers: - username: john credentials: - name: key-auth type: key-auth config: key: john-key - username: jane credentials: - name: key-auth type: key-auth config: key: jane-key services: - name: graphql-limit-service routes: - name: graphql-limit-count-route uris: - /graphql plugins: key-auth: {} graphql-limit-count: count: 2 time_window: 30 rejected_code: 429 policy: local key_type: var_combination key: "$remote_addr $consumer_name" upstream: type: roundrobin scheme: https nodes: - host: api.github.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建两个消费者和一个按消费者启用限速的路由: * Gateway API * APISIX CRD graphql-limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jane spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: github-graphql-https spec: targetRefs: - name: github-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-limit-count-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: graphql-limit-count config: count: 2 time_window: 30 rejected_code: 429 policy: local key_type: var_combination key: "$remote_addr $consumer_name" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-limit-count-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 ``` graphql-limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: github-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: api.github.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-limit-count-route spec: ingressClassName: apisix http: - name: graphql-limit-count-route match: paths: - /graphql upstreams: - name: github-graphql-external-domain plugins: - name: key-auth enable: true - name: graphql-limit-count enable: true config: count: 2 time_window: 30 rejected_code: 429 policy: local key_type: var_combination key: "$remote_addr $consumer_name" ``` 将配置应用到集群: ``` kubectl apply -f graphql-limit-count-ic.yaml ``` ❶ `key-auth`:在路由上启用密钥认证。 ❷ `key_type`:设置为 `var_combination`,将 `key` 解释为变量组合。 ❸ `key`: 设置为 `$remote_addr $consumer_name` 以根据远程地址和消费者应用限速配额。 作为消费者 `jane` 发送一个深度为 2 的 GraphQL 查询请求: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -H 'apikey: jane-key' \ -d '{"query": "query {viewer{login}}"}' ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 此请求已消耗了该时间窗口的所有配额。如果你在同一个 30 秒时间间隔内再次以消费者 `jane` 的身份发送相同的请求,应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,表明请求超过了配额阈值。 在同一个 30 秒时间间隔内以消费者 `john` 的身份发送相同的请求: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -H 'apikey: john-key' \ -d '{"query": "query {viewer{login}}"}' ``` 你应该会看到带有相应响应体的 `HTTP/1.1 200 OK` 响应,表明该请求未被限速。 在同一个 30 秒时间间隔内再次以消费者 `john` 的身份发送相同的请求,你应该会收到 `HTTP/1.1 429 Too Many Requests` 响应。 这验证了插件是根据变量组合 `remote_addr` 和 `consumer_name` 进行速率限制的。 ### 在路由间共享配额[​](#在路由间共享配额 "在路��由间共享配额的直接链接") 以下示例演示了如何通过配置 `graphql-limit-count` 插件的 `group` 字段,在多个路由之间共享 GraphQL 速率限制配额。 请注意,同一 `group` 的 `graphql-limit-count` 插件配置应完全相同。为了避免更新异常和重复配置,你可以创建一个启用了 `graphql-limit-count` 插件的[服务(Service)](https://docs.apiseven.com/apisix/key-concepts/services.md)供路由连接。 * Admin API * ADC * Ingress Controller 创建一个服务: ``` curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-service", "plugins": { "graphql-limit-count": { "count": 2, "time_window": 30, "rejected_code": 429, "policy": "local", "group": "srv1" } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "api.github.com:443": 1 } } }' ``` 创建两个路由并将它们的 `service_id` 配置为 `graphql-limit-count-service`,以便它们共享相同的插件和上游配置: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-route-1", "service_id": "graphql-limit-count-service", "uri": "/graphql1", "plugins": { "proxy-rewrite": { "uri": "/graphql" } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-route-2", "service_id": "graphql-limit-count-service", "uri": "/graphql2", "plugins": { "proxy-rewrite": { "uri": "/graphql" } } }' ``` 创建一个包含两条路由的服务,使两条路由共享同一限速配额: adc.yaml ``` services: - name: graphql-limit-count-service plugins: graphql-limit-count: count: 2 time_window: 30 rejected_code: 429 policy: local group: srv1 routes: - name: graphql-limit-count-route-1 uris: - /graphql1 plugins: proxy-rewrite: uri: /graphql - name: graphql-limit-count-route-2 uris: - /graphql2 plugins: proxy-rewrite: uri: /graphql upstream: type: roundrobin scheme: https nodes: - host: api.github.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建两个引用同一 `PluginConfig` 的 `HTTPRoute` 以共享配额: graphql-limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: github-graphql-https spec: targetRefs: - name: github-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-limit-count-plugin-config spec: plugins: - name: graphql-limit-count config: count: 2 time_window: 30 rejected_code: 429 policy: local group: srv1 - name: proxy-rewrite config: uri: /graphql --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-limit-count-route-1 spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql1 filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-limit-count-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-limit-count-route-2 spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql2 filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-limit-count-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 ``` 创建一个包含多个路径的 `ApisixRoute`,使这些路径共享同一插件配置: graphql-limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: github-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: api.github.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-limit-count-shared-route spec: ingressClassName: apisix http: - name: graphql-limit-count-shared match: paths: - /graphql1 - /graphql2 upstreams: - name: github-graphql-external-domain plugins: - name: proxy-rewrite enable: true config: uri: /graphql - name: graphql-limit-count enable: true config: count: 2 time_window: 30 rejected_code: 429 policy: local group: srv1 ``` 将配置应用到集群: ``` kubectl apply -f graphql-limit-count-ic.yaml ``` 备注 [`proxy-rewrite`](https://docs.apiseven.com/hub/proxy-rewrite.md) 插件用于将 URI 重写为 `/graphql`,使请求转发到正确的端点。 发送一个深度为 2 的 GraphQL 查询请求到路由 `/graphql1`: ``` curl -i "http://127.0.0.1:9080/graphql1" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login}}"}' ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在同一个 30 秒时间间隔内发送相同的深度为 2 的查询到路由 `/graphql2`: ``` curl -i "http://127.0.0.1:9080/graphql2" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login}}"}' ``` 你应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,这验证了两个路由共享相同的限速配额。 ### 使用 Redis 服务器在网关节点间共享配额[​](#使用-redis-服务器在网关节点间共享配额 "使用 Redis 服务器在网关节点间共享配额的直接链接") 以下示例演示了如何通过 Redis 服务器在多个网关节点之间对 GraphQL 请求进行速率限制,从而使不同的网关节点共享相同的速率限制配额。 * Admin API * ADC * Ingress Controller 在网关组中创建一个具有以下配置的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-route", "uri": "/graphql", "plugins": { "graphql-limit-count": { "count": 2, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis", "redis_host": "192.168.xxx.xxx", "redis_port": 6379, "redis_password": "p@ssw0rd", "redis_database": 1 } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "api.github.com:443": 1 } } }' ``` 创建一条使用 Redis 限速的路由: adc.yaml ``` services: - name: graphql-redis-limit-service routes: - name: graphql-redis-limit-route uris: - /graphql plugins: graphql-limit-count: count: 2 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "192.168.xxx.xxx" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 upstream: type: roundrobin scheme: https nodes: - host: api.github.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: github-graphql-https spec: targetRefs: - name: github-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-limit-count-redis-plugin-config spec: plugins: - name: graphql-limit-count config: count: 2 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-redis-limit-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-limit-count-redis-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 ``` graphql-limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: github-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: api.github.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-redis-limit-route spec: ingressClassName: apisix http: - name: graphql-redis-limit-route match: paths: - /graphql upstreams: - name: github-graphql-external-domain plugins: - name: graphql-limit-count enable: true config: count: 2 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 ``` 将配置应用到集群: ``` kubectl apply -f graphql-limit-count-ic.yaml ``` ❶ `policy`: 设置为 `redis` 以使用 Redis 实例进行限速。 ❷ `redis_host`: 设置为 Redis 实例的 IP 地址。 ❸ `redis_port`: 设置为 Redis 实例的监听端口。 ❹ `redis_password`: 设置为 Redis 实例的密码(如果有)。 ❺ `redis_database`: 设置为 Redis 实例中的数据库编号。 发送一个深度为 2 的 GraphQL 查询请求到一个网关实例: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login}}"}' ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在同一个 30 秒时间间隔内发送相同的请求到另一个网关实例,你应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应,验证了配置在不同网关节点上的路由共享相同的配额。 ### 使用 Redis 集群在网关节点之间共享配额[​](#使用-redis-集群在网关节点之间共享配额 "使用 Redis 集群在网关节点之间共享配额的直接链接") 你也可以使用 Redis 集群在多个网关节点之间应用相同的配额,从而使不同的网关节点共享相同的速率限制配额。 确保你的 Redis 实例运行在[集群模式(Cluster Mode)](https://redis.io/docs/management/scaling/#create-and-use-a-redis-cluster)。`graphql-limit-count` 插件配置至少需要两个节点。 * Admin API * ADC * Ingress Controller 在网关组中创建一个具有以下配置的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-limit-count-route", "uri": "/graphql", "plugins": { "graphql-limit-count": { "count": 2, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis-cluster", "redis_cluster_nodes": [ "192.168.xxx.xxx:6379", "192.168.xxx.xxx:16379" ], "redis_password": "p@ssw0rd", "redis_cluster_name": "redis-cluster-1", "redis_cluster_ssl": true } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "api.github.com:443": 1 } } }' ``` 创建一条使用 Redis 集群限速的路由: adc.yaml ``` services: - name: graphql-redis-cluster-limit-service routes: - name: graphql-redis-cluster-limit-route uris: - /graphql plugins: graphql-limit-count: count: 2 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "192.168.xxx.xxx:6379" - "192.168.xxx.xxx:16379" redis_password: "p@ssw0rd" redis_cluster_name: redis-cluster-1 redis_cluster_ssl: true upstream: type: roundrobin scheme: https nodes: - host: api.github.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: github-graphql-https spec: targetRefs: - name: github-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-limit-count-redis-cluster-plugin-config spec: plugins: - name: graphql-limit-count config: count: 2 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: redis-cluster-1 redis_cluster_ssl: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-redis-cluster-limit-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-limit-count-redis-cluster-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 ``` graphql-limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: github-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: api.github.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-redis-cluster-limit-route spec: ingressClassName: apisix http: - name: graphql-redis-cluster-limit-route match: paths: - /graphql upstreams: - name: github-graphql-external-domain plugins: - name: graphql-limit-count enable: true config: count: 2 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: redis-cluster-1 redis_cluster_ssl: true ``` 将配置应用到集群: ``` kubectl apply -f graphql-limit-count-ic.yaml ``` ❶ `policy`: 设置为 `redis-cluster` 以使用 Redis 集群进行限速。 ❷ `redis_cluster_nodes`: 设置为 Redis 集群中的 Redis 节点地址。 ❸ `redis_password`: 设置为 Redis 集群的密码(如果有)。 ❹ `redis_cluster_name`: 设置为 Redis 集群名称。 ❺ `redis_cluster_ssl`: 启用与 Redis 集群的 SSL/TLS 通信。 发送一个深度为 2 的 GraphQL 查询请求到一个网关实例: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login}}"}' ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在同一个 30 秒时间间隔内发送相同的请求到另一个网关实例,你应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应,验证了配置在不同网关节点上的路由共享相同的配额。 ### 按查询复杂度限速[​](#按查询复杂度限速 "按查询复杂度限速的直接链接") 以下示例展示了如何根据查询解析的节点(而不是查询深度)计算原始分数,并直接拒绝计费成本超出固定预算的查询。本示例适用于 API7 企业版 3.10.6 及更高版本。 创建一条配置了 `graphql-limit-count` 插件的路由,按 `complexity` 计费。它为每个远程地址在 30 秒窗口内提供 100 的配额,并拒绝单次成本超过 20 的查询: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-cost-route", "uri": "/graphql", "plugins": { "graphql-limit-count": { "count": 100, "time_window": 30, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "local", "show_limit_quota_header": true, "cost_strategy": "complexity", "max_cost": 20 } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "api.github.com:443": 1 } } }' ``` adc.yaml ``` services: - name: graphql-service routes: - uris: - /graphql name: graphql-cost-route plugins: graphql-limit-count: count: 100 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local show_limit_quota_header: true cost_strategy: complexity max_cost: 20 upstream: type: roundrobin scheme: https nodes: - host: api.github.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-cost-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: github-graphql-https spec: targetRefs: - name: github-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-cost-plugin-config spec: plugins: - name: graphql-limit-count config: count: 100 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local show_limit_quota_header: true cost_strategy: complexity max_cost: 20 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-cost-route spec: parentRefs: - name: api7ee3-apisix-gateway rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-cost-plugin-config backendRefs: - name: github-graphql-external-domain port: 443 ``` 将配置应用到集群: ``` kubectl apply -f graphql-cost-ic.yaml ``` graphql-cost-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: github-graphql-external-domain spec: type: ExternalName externalName: api.github.com --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: github-graphql-external-domain spec: ingressClassName: apisix passHost: node scheme: https --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-cost-route spec: ingressClassName: apisix http: - name: graphql-cost-route match: paths: - /graphql backends: - serviceName: github-graphql-external-domain servicePort: 443 plugins: - name: graphql-limit-count enable: true config: count: 100 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local show_limit_quota_header: true cost_strategy: complexity max_cost: 20 ``` 将配置应用到集群: ``` kubectl apply -f graphql-cost-ic.yaml ``` 向网关实例发送一个较小的查询: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login}}"}' ``` 你应该会收到 `HTTP/1.1 200 OK` 响应,其中带有本次计费的成本: ``` X-Graphql-Query-Cost: 4 ``` 再发送一个计费成本超出预算的查询: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${GH_ACCESS_TOKEN}" \ -d '{"query": "query {viewer{login name email location company bio websiteUrl twitterUsername createdAt updatedAt databaseId url avatarUrl isHireable isViewer isEmployee isSiteAdmin pronouns}}"}' ``` 你应该会收到 `HTTP/1.1 403 Forbidden` 响应,且该查询从未到达上游: ``` {"message":"Invalid graphql request: query cost 21 exceeds max_cost 20"} ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * count integer | string 有效值: 大于 0 *** 给定时间间隔内允许累计的最大 GraphQL 查询成本。默认策略下,查询成本即为深度。未配置 `rules` 时必填。当配置为字符串时,该值可以使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * time\_window integer | string 有效值: 大于 0 *** 与限流 `count` 对应的时间间隔,单位为秒。未配置 `rules` 时必填。当配置为字符串时,该值可以使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * rules array\[object] *** 按顺序应用的限流规则数组。`rules` 与顶层 `count` 和 `time_window` 二选一配置,不能同时使用。 * count integer | string 必填 有效值: 大于 0 *** 规则的 `time_window` 内允许累计的最大 GraphQL 查询成本。默认策略下,查询成本即为深度。当配置为字符串时,该值可以使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * time\_window integer | string 必填 有效值: 大于 0 *** 与规则 `count` 对应的时间间隔,单位为秒。当配置为字符串时,该值可以使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * key string 必填 *** 用于计数请求的 Key。支持[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)组合,每个变量必须以美元符号(`$`)为前缀。如果 Key 无法解析,则不会应用该规则。 * header\_prefix string *** 插入到该规则限流响应头中的前缀。例如,`foo` 会生成 `X-foo-RateLimit-Limit`、`X-foo-RateLimit-Remaining` 和 `X-foo-RateLimit-Reset`。 * cost\_strategy string 默认值:`depth` 有效值: `depth`、`complexity` 或 `node_quantifier` *** 计算 GraphQL 文档原始成本的方式。`depth` 按选择集的嵌套深度计算,也就是该插件一直以来的行为。`complexity` 对查询解析的节点计分。`node_quantifier` 只对匹配的成本装饰能解析出 `mul_arguments` 所列参数的节点计分。如果没有节点同时具备匹配装饰和可用量词,文档的原始分数为 `0`。对于 `complexity` 和 `node_quantifier`,插件先加 `0.01`、应用 `score_factor`,再向上取整后计入配额。默认系数会把原始分数 `0` 变为计费成本 `1`;大于 `100` 的系数会进一步提高该成本。该能力在 API7 企业版 3.10.6 中引入。 * max\_cost number 默认值:`0` 有效值: 大于或等于 0 *** 计费成本超过该值的文档在到达上游之前即以 `403 Forbidden` 拒绝。请求会先消耗配额,再执行该检查。设为 `0` 表示关闭该检查,仅由配额决定。该能力在 API7 企业版 3.10.6 中引入。 * score\_factor number 默认值:`1` 有效值: 大于 0 *** 在成本向上取整、计入配额并与 `max_cost` 比较之前应用的缩放系数。该能力在 API7 企业版 3.10.6 中引入。 * resolve\_variables boolean 默认值:`true` *** 如果为 true,则在计算成本时解析已提供的 GraphQL 变量、操作声明的变量默认值,以及上游 schema 中的参数默认值。默认开启可确保以变量提供的量词计入其解析值。该能力在 API7 企业版 3.10.6 中引入。 * introspection\_endpoint string 有效值: 以 `http://` 或 `https://` 开头 *** 用于内省上游 GraphQL schema 的端点,`complexity` 与 `node_quantifier` 策略需要它来匹配成本装饰。未设置时从上游推导。结果按 Worker 和服务缓存。该能力在 API7 企业版 3.10.6 中引入。 * introspection\_headers object *** 发起 schema 内省请求时携带的请求头,适用于内省端点需要凭据的上游。这些请求头取自配置而不是请求,因为内省得到的 schema 按 Worker 和服务缓存。启用数据面数据加密时,该字段会加密落盘。该能力在 API7 企业版 3.10.6 中引入。 * key\_type string 默认值:`var` 有效值: `var`、`var_combination` 或 `constant` *** 键的类型。 如果 `key_type` 为 `var`,则 `key` 被解释为变量。 如果 `key_type` 为 `var_combination`,则 `key` 被解释为变量组合。 如果 `key_type` 为 `constant`,则 `key` 被解释为常量。 * key string 默认值:`remote_addr` *** 用于计数请求的键。 如果 `key_type` 为 `var`,则 `key` 被解释为变量。变量不需要以美元符号(`$`)作为前缀。查看[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)以获取可用变量。 如果 `key_type` 为 `var_combination`,则 `key` 被解释为变量组合。所有变量都应以美元符号(`$`)作为前缀。例如,要将 `key` 配置为使用两个请求头 `custom-a` 和 `custom-b` 的组合,`key` 应配置为 `$http_custom_a $http_custom_b`。 如果 `key_type` 为 `constant`,则 `key` 被解释为常量值。 * rejected\_code integer 默认值:`503` 有效值: 介于 200 和 599 之间(含边界值) *** 当请求因超过阈值而被拒绝时返回的 HTTP 状态码。 * rejected\_msg string 有效值: 任意非空字符串 *** 当请求因超过阈值而被拒绝时返回的响应体。 * policy string 默认值:`local` 有效值: `local`、`redis` 或 `redis-cluster` *** 速率限制计数器的策略。如果为 `local`,则计数器存储在本地内存中。如果为 `redis`,则计数器存储在 Redis 实例中。如果为 `redis-cluster`,则计数器存储在 Redis 集群中。 * allow\_degradation boolean 默认值:`false` *** 如果为 true,则在插件或其依赖项不可用时,允许网关继续处理请求而不使用该插件。 * show\_limit\_quota\_header boolean 默认值:`true` *** 如果为 true,则包含以下速率限制响应头: * `X-RateLimit-Limit` 显示总配额。 * `X-RateLimit-Remaining` 显示剩余配额。 * `X-RateLimit-Reset` 显示计数器重置前的剩余秒数。 * group string 有效值: 非空 *** 插件的 `group` ID,同一 `group` 的路由可以共享相同的速率限制计数器。 * redis\_host string *** Redis 节点的地址。当 `policy` 为 `redis` 时必填。 * redis\_port integer 默认值:`6379` 有效值: 大于或等于 1 *** Redis 节点的端口。当 `policy` 为 `redis` 时使用。 * redis\_username string *** 如果使用 Redis ACL,则为 Redis 的用户名。如果你使用传统的认证方法 `requirepass`,则只需配置 `redis_password`。当 `policy` 为 `redis` 时使用。 * redis\_password string *** Redis 节点的密码。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。 * redis\_database integer 默认值:`0` 有效值: 大于或等于 0 *** Redis 中的数据库编号。当 `policy` 为 `redis` 时使用。 * redis\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接到 Redis。 * redis\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。 * redis\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** Redis 超时时间(毫秒)。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。 * redis\_keepalive\_timeout integer 默认值:`10000` 有效值: 大于或等于 1000 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 的保活超时时间,单位为毫秒。 此参数在 API7 企业版 3.9.x 系列中自 3.9.16 起可用,在 3.10.x 系列中自 3.10.3 起可用,并且在 APISIX 中自 3.17.0 起可用。 * redis\_keepalive\_pool integer 默认值:`100` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 的保活连接池大小。 此参数在 API7 企业版 3.9.x 系列中自 3.9.16 起可用,在 3.10.x 系列中自 3.10.3 起可用,并且在 APISIX 中自 3.17.0 起可用。 * redis\_cluster\_nodes array\[string] *** Redis 集群节点列表,至少包含两个地址。当 `policy` 为 `redis-cluster` 时必填。 * redis\_cluster\_name string *** Redis 集群的名称。当 `policy` 为 `redis-cluster` 时必填。 * redis\_cluster\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时使用 SSL 连接到 Redis 集群。 * redis\_cluster\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时验证服务器 SSL 证书。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * limit\_header string 默认值:`X-RateLimit-Limit` *** 表示速率限制总配额的默认响应头名称。在 API7 企业版中自 3.10.6 起可用。 * remaining\_header string 默认值:`X-RateLimit-Remaining` *** 表示速率限制剩余配额的默认响应头名称。在 API7 企业版中自 3.10.6 起可用。 * reset\_header string 默认值:`X-RateLimit-Reset` *** 表示速率限制计数器重置前剩余秒数的默认响应头名称。在 API7 企业版中自 3.10.6 起可用。 --- # graphql-proxy-cache `graphql-proxy-cache` 插件使用磁盘或内存缓存 GraphQL 查询响应。它支持 GraphQL [GET](https://graphql.org/learn/serving-over-http/#get-request) 和 [POST](https://graphql.org/learn/serving-over-http/#post-request) 请求。 该插件根据插件配置版本、请求主机、路由 ID、服务 ID、已认证的消费者身份以及完整的 GraphQL 请求体生成 MD5 缓存键。当 APISIX 将请求解析为消费者或远程用户时,默认会将消费者身份包含在缓存键中。 如果请求包含 [变更(Mutation)](https://graphql.org/learn/queries#mutations) 操作,插件将不会缓存数据。相反,它会在响应中添加 `Apisix-Cache-Status: BYPASS` 头,以表明该请求绕过了缓存机制。 对于 `GET` 请求,请在 `query` 查询参数中提供 GraphQL 文档。`POST` 请求可以使用包含 `query` 字段的 JSON 请求体,或媒体类型为 `application/graphql` 的正文。不支持的方法返回 `405 Method Not Allowed`;无法读取、格式错误或无效的 GraphQL 请求返回 `400 Bad Request`。 APISIX 默认最多读取 1 MiB 的 GraphQL 请求数据。若要调整该限制,请在 `config.yaml` 中配置 `graphql.max_size` 并重新加载 APISIX: config.yaml ``` graphql: max_size: 1048576 ``` ## 示例[​](#示例 "示例的直接链接") 以下示例使用公开的 [Countries GraphQL API](https://countries.trevorblades.com/) 作为上游,并演示了如何在不同场景下配置 `graphql-proxy-cache`。 ### 在磁盘上缓存数据[​](#在磁盘上缓存数据 "在磁盘上缓存数据的直接链接") 与内存缓存相比,磁盘缓存策略具有系统重启时数据持久化和存储容量更大的优点。它适用于优先考虑持久性并且可以容忍稍大的缓存访问延迟的应用程序。 以下示例演示了如何在路由上使用 `graphql-proxy-cache` 插件将数据缓存到磁盘上。 创建一个启用了 `graphql-proxy-cache` 插件的路由,使用默认配置将数据缓存到磁盘: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-proxy-cache-route", "uri": "/graphql", "plugins": { "graphql-proxy-cache": {} }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "countries.trevorblades.com:443": 1 } } }' ``` adc.yaml ``` services: - name: graphql-service routes: - uris: - /graphql name: graphql-proxy-cache-route plugins: graphql-proxy-cache: {} upstream: type: roundrobin scheme: https nodes: - host: countries.trevorblades.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: countries-graphql-external-domain spec: type: ExternalName externalName: countries.trevorblades.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: countries-graphql-https spec: targetRefs: - name: countries-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-proxy-cache-plugin-config spec: plugins: - name: graphql-proxy-cache config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-proxy-cache-plugin-config backendRefs: - name: countries-graphql-external-domain port: 443 ``` graphql-proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: countries-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: countries.trevorblades.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-proxy-cache-route spec: ingressClassName: apisix http: - name: graphql-proxy-cache-route match: paths: - /graphql upstreams: - name: countries-graphql-external-domain plugins: - name: graphql-proxy-cache enable: true ``` 将配置应用到集群: ``` kubectl apply -f graphql-proxy-cache-ic.yaml ``` 发送一个带有 GraphQL 查询的请求进行验证: ``` curl -i "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -d '{"query": "query { country(code: \"US\") { name capital } }"}' ``` 你应该会看到一个 `HTTP/1.1 200 OK` 响应,其中包含以下响应头,表明插件已成功启用: ``` APISIX-Cache-Key: 5908e74856ea02835af198678b879a71 Apisix-Cache-Status: MISS ``` 由于第一个响应之前没有可用缓存,因此显示 `Apisix-Cache-Status: MISS`。确切的缓存键取决于你的配置。 在缓存 TTL 窗口内再次发送相同的请求。你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明缓存命中: ``` APISIX-Cache-Key: 5908e74856ea02835af198678b879a71 Apisix-Cache-Status: HIT ``` 等待缓存超过 TTL 后过期,然后再次发送相同的请求。你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明缓存已过期: ``` APISIX-Cache-Key: 5908e74856ea02835af198678b879a71 Apisix-Cache-Status: EXPIRED ``` ### 在内存中缓存数据[​](#在内存中缓存数据 "在内存中缓存数据的直接链接") 内存缓存策略具有访问缓存数据延迟低的优点,因为从 RAM 检索数据比从磁盘存储检索数据更快。它也适用于存储不需要长期持久化的临时数据,从而可以高效地缓存经常更改的数据。 以下示例演示了如何在路由上使用 `graphql-proxy-cache` 插件将数据缓存到内存中。 创建一个启用了 `graphql-proxy-cache` 的路由,并将其配置为使用基于内存的缓存: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-proxy-cache-route", "uri": "/graphql", "plugins": { "graphql-proxy-cache": { "cache_strategy": "memory", "cache_zone": "memory_cache", "cache_ttl": 10 } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "countries.trevorblades.com:443": 1 } } }' ``` adc.yaml ``` services: - name: graphql-service routes: - uris: - /graphql name: graphql-proxy-cache-route plugins: graphql-proxy-cache: cache_strategy: memory cache_zone: memory_cache cache_ttl: 10 upstream: type: roundrobin scheme: https nodes: - host: countries.trevorblades.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: countries-graphql-external-domain spec: type: ExternalName externalName: countries.trevorblades.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: countries-graphql-https spec: targetRefs: - name: countries-graphql-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-proxy-cache-plugin-config spec: plugins: - name: graphql-proxy-cache config: cache_strategy: memory cache_zone: memory_cache cache_ttl: 10 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /graphql filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-proxy-cache-plugin-config backendRefs: - name: countries-graphql-external-domain port: 443 ``` graphql-proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: countries-graphql-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: countries.trevorblades.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-proxy-cache-route spec: ingressClassName: apisix http: - name: graphql-proxy-cache-route match: paths: - /graphql upstreams: - name: countries-graphql-external-domain plugins: - name: graphql-proxy-cache enable: true config: cache_strategy: memory cache_zone: memory_cache cache_ttl: 10 ``` 将配置应用到集群: ``` kubectl apply -f graphql-proxy-cache-ic.yaml ``` ❶ `cache_strategy`: 设置为 `memory` 以进行内存设置。 ❷ `cache_zone`: 设置为内存缓存区域的名称。 ❸ `cache_ttl`:设置内存缓存的生存时间。 发送一个带有 GraphQL 查询的请求进行验证: ``` curl "http://127.0.0.1:9080/graphql" -i -X POST \ -H "Content-Type: application/json" \ -d '{"query": "query { country(code: \"US\") { name capital } }"}' ``` 你应该会看到一个 `HTTP/1.1 200 OK` 响应,其中包含以下响应头,表明插件已成功启用: ``` APISIX-Cache-Key: a661316c4b1b70ae2db5347743dec6b6 Apisix-Cache-Status: MISS ``` 由于第一个响应之前没有可用缓存,因此显示 `Apisix-Cache-Status: MISS`。确切的缓存键取决于你的配置。 在缓存 TTL 窗口内再次发送相同的请求。你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明缓存命中: ``` APISIX-Cache-Key: a661316c4b1b70ae2db5347743dec6b6 Apisix-Cache-Status: HIT ``` ### 手动清除缓存[​](#手动清除缓存 "手动清除缓存的直接链接") 虽然大多数时候不需要这样做,但在某些情况下,你可能希望手动清除缓存数据。 以下示例演示了如何使用 `public-api` 插件公开由 `graphql-proxy-cache` 插件创建的 `/apisix/plugin/graphql-proxy-cache/{cache_strategy}/{route_id}/{key}` 端点。该示例还启用了 `key-auth`,确保只有通过身份认证的运维人员才能清除缓存响应。 创建一个带有 `key-auth` 凭证的消费者,以及一个匹配 URI `/apisix/plugin/graphql-proxy-cache/*` 的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "cache-operator" }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/cache-operator/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cache-operator-key-auth", "plugins": { "key-auth": { "key": "purge-key" } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "graphql-cache-purge", "uri": "/apisix/plugin/graphql-proxy-cache/*", "plugins": { "key-auth": {}, "public-api": {} } }' ``` adc.yaml ``` consumers: - username: cache-operator credentials: - name: cache-operator-key-auth type: key-auth config: key: purge-key services: - name: graphql-cache-purge-service routes: - name: graphql-cache-purge-route uris: - /apisix/plugin/graphql-proxy-cache/* plugins: key-auth: {} public-api: {} ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD graphql-proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: cache-operator spec: gatewayRef: name: apisix credentials: - type: key-auth name: cache-operator-key-auth config: key: purge-key --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: graphql-cache-purge-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: public-api config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: graphql-cache-purge-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /apisix/plugin/graphql-proxy-cache/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: graphql-cache-purge-plugin-config ``` graphql-proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: cache-operator spec: ingressClassName: apisix authParameter: keyAuth: value: key: purge-key --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: graphql-cache-purge-route spec: ingressClassName: apisix http: - name: graphql-cache-purge-route match: paths: - /apisix/plugin/graphql-proxy-cache/* plugins: - name: key-auth enable: true - name: public-api enable: true ``` 将配置应用到集群: ``` kubectl apply -f graphql-proxy-cache-ic.yaml ``` 发送磁盘缓存请求,并保存生成的 `APISIX-Cache-Key` 响应头: ``` CACHE_KEY=$(curl -sS -D - -o /dev/null "http://127.0.0.1:9080/graphql" -X POST \ -H "Content-Type: application/json" \ -d '{"query": "query { country(code: \"US\") { name capital } }"}' | \ awk 'tolower($1) == "apisix-cache-key:" {gsub("\\r", "", $2); print $2}') ``` 使用该值和包含 `graphql-proxy-cache` 的路由 ID 发送 PURGE 请求: ``` curl -i "http://127.0.0.1:9080/apisix/plugin/graphql-proxy-cache/disk/graphql-proxy-cache-route/${CACHE_KEY}" -X PURGE \ -H "apikey: purge-key" ``` Admin API 和 ADC 示例使用 `graphql-proxy-cache-route` 作为路由 ID。对于 Ingress Controller 部署,请将其替换为生成的 APISIX 路由 ID。 `HTTP/1.1 200 OK` 响应验证了与该键对应的缓存已成功清除。 如果你再次发送相同的 PURGE 请求,应该会看到 `HTTP/1.1 404 Not Found` 响应,表明清除缓存后,磁盘上不再存在使用该缓存键的缓存。 包含 `Vary` 响应头的响应可能会产生多个缓存变体。PURGE 请求成功仅表示目标缓存条目已清除,并不能保证所有变体都已清除。 --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 网关默认配置包含磁盘缓存和缓存区域的代理缓存设置。需要更新的文件取决于网关的部署方式: * 主机或 Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` apisix: proxy_cache: cache_ttl: 10s # 用于磁盘缓存 zones: - name: disk_cache_one memory_size: 50m disk_size: 1G disk_path: /tmp/disk_cache_one cache_levels: 1:2 # - name: disk_cache_two # memory_size: 50m # disk_size: 1G # disk_path: "/tmp/disk_cache_two" # cache_levels: "1:2" - name: memory_cache memory_size: 50m ``` 然后重新加载网关,使更改生效。 在 APISIX Helm Chart 2.16.0 或更高版本和 API7 Gateway Helm Chart 3.10.3 或更高版本中,请设置 `apisix.proxyCache`。 两个 Chart 都会在网关配置中将此值渲染为 `apisix.proxy_cache`: values.yaml ``` apisix: proxyCache: cacheTtl: 10s zones: - name: disk_cache_one memory_size: 50m disk_size: 1G disk_path: /tmp/disk_cache_one cache_levels: 1:2 - name: memory_cache memory_size: 50m ``` 然后使用该网关发布版本对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * cache\_strategy string 默认值:`disk` 有效值: `disk` 或 `memory` *** 缓存策略。缓存到磁盘或内存中。 * cache\_zone string 默认值:`disk_cache_one` *** 与缓存策略一起使用的缓存区域。该值应与[配置文件](https://docs.apiseven.com/hub/graphql-proxy-cache/configuration.md#静态配置)中定义的缓存区域之一匹配,并应对应于缓存策略。例如,当使用内存缓存策略时,应使用内存缓存区域。 * cache\_ttl integer 默认值:`300` 有效值: 大于或等于 1 *** 使用内存缓存时的缓存生存时间(TTL),单位为秒。 要调整磁盘缓存的 TTL,请更新[配置文件](https://docs.apiseven.com/hub/proxy-cache/configuration.md#静态配置)中的 `cache_ttl`。请注意,仅当响应头中同时缺少 [`Cache-Control`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control) 和 [`Expires`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expires) 时,才会使用该 TTL 值。 * consumer\_isolation boolean 默认值:`true` *** 如果为 true,当请求解析为 APISIX Consumer 或远程用户时,将已认证的 Consumer 身份添加到实际缓存键前。任意上游凭据(例如转发的 Bearer Token)不会被用作身份。如果路由在未使用 APISIX 身份认证插件的情况下转发用户专属凭据,不同用户可能会收到相同的缓存响应。请为该路由启用 APISIX 身份认证插件或禁用缓存。自 API7 企业版 3.9.13 和 APISIX 3.17.0 起可用。 * cache\_set\_cookie boolean 默认值:`false` *** 如果为 true,则允许内存缓存策略缓存包含 `Set-Cookie` 响应头的响应。默认情况下,此类响应不会被缓存。自 API7 企业版 3.9.13 和 APISIX 3.17.0 起可用。 --- # grpc-transcode `grpc-transcode` 插件用于在 HTTP 请求和 gRPC 请求及其对应响应之间进行转换。 启用该插件后,APISIX 接收客户端的 HTTP 请求,将其转换后转发到上游 gRPC 服务。APISIX 收到 gRPC 响应后,会将响应转换回 HTTP 响应并发送给客户端。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `grpc-transcode` 插件。 要跟随示例操作,请在 Docker 中启动一个[示例 gRPC 服务器](https://github.com/api7/grpc_server_example): ``` docker run -d \ --name grpc-example-server \ -p 50051:50051 \ api7/grpc-server-example:1.0.2 ``` ### 在 HTTP 和 gRPC 请求之间转换[​](#在-http-和-grpc-请求之间转换 "在 HTTP 和 gRPC 请求之间转换的直接链接") 以下示例演示了如何在 APISIX 中配置 protobuf,并使用 `grpc-transcode` 插件在 HTTP 和 gRPC 请求之间进行转换。 * Admin API * ADC * Ingress Controller 创建一个 proto 资源来存储 protobuf: ``` curl "http://127.0.0.1:9180/apisix/admin/protos" -X PUT -d ' { "id": "echo-proto", "content": "syntax = \"proto3\"; package echo; service EchoService { rpc Echo (EchoMsg) returns (EchoMsg); } message EchoMsg { string msg = 1; }" }' ``` 创建一个启用 `grpc-transcode` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d ' { "id": "grpc-transcode-route", "methods": ["GET"], "uri": "/echo", "plugins": { "grpc-transcode": { "proto_id": "echo-proto", "service": "echo.EchoService", "method": "Echo" } }, "upstream": { "scheme": "grpc", "type": "roundrobin", "nodes": { "grpc-example-server:50051": 1 } } }' ``` ❶ `proto_id`:定义 gRPC 服务的 proto 对象的 ID ❷ `service`:要交互的 gRPC 服务 ❸ `method`:要使用的 gRPC 方法 为了验证,向路由发送一个带有 `EchoMsg` 中定义的参数的 HTTP 请求: ``` curl "http://127.0.0.1:9080/echo?msg=Hello" ``` 你应该收到以下响应: ``` {"msg":"Hello"} ``` 警告 ADC 目前不支持配置 proto 资源,因此无法仅使用 ADC 完成此示例。 警告 Ingress Controller 目前不支持配置 proto 资源,因此无法使用 Ingress Controller 资源完成此示例。 ### 使用 `.pb` 文件配置 Protobuf[​](#使用-pb-文件配置-protobuf "使用-pb-文件配置-protobuf的直接链接") 以下示例演示了如何在 APISIX 中使用 `.pb` 文件配置 protobuf,并使用 `grpc-transcode` 插件在 HTTP 和 gRPC 请求之间进行转换。 如果你的 proto 文件包含导入,或者你想要组合多个 proto 文件,可以使用 [protoc](https://google.github.io/proto-lens/installing-protoc.html) 工具生成 `.pb` 文件,并在 APISIX 中使用它,步骤如下。 * Admin API * ADC * Ingress Controller 将 protocol buffer 定义保存到名为 `echo.proto` 的文件中: echo.proto ``` syntax = "proto3"; package echo; service EchoService { rpc Echo (EchoMsg) returns (EchoMsg); } message EchoMsg { string msg = 1; } ``` 使用 [protoc](https://google.github.io/proto-lens/installing-protoc.html) 工具生成 `.pb` 文件,并将其输出到名为 `echo_proto.pb` 的新文件中: ``` protoc --include_imports --descriptor_set_out=echo_proto.pb echo.proto ``` 将 `.pb` 文件从二进制转换为 base64 并在 APISIX 中进行配置: ``` curl "http://127.0.0.1:9180/apisix/admin/protos" -X PUT --data-binary @- <
## 请求处理[​](#请求处理 "请求处理的直接链接") `grpc-web` 插件使用特定的 HTTP 方法、内容类型和 CORS 规则处理客户端请求。 ### 支持的 HTTP 方法[​](#支持的-http-方法 "支持的 HTTP 方法的直接链接") 插件支持: * `POST` 用于 gRPC-Web 请求 * `OPTIONS` 用于 CORS 预检检查 有关详细信息,请参阅 [CORS 支持](https://github.com/grpc/grpc-web/blob/master/doc/browser-features.md#cors-support)。 ### 支持的内容类型[​](#支持的内容类型 "支持的内容类型的直接链接") 插件识别以下内容类型: * `application/grpc-web` * `application/grpc-web-text` * `application/grpc-web+proto` * `application/grpc-web-text+proto` 它自动解码二进制或 Base64 文本格式的消息,并将其转换为上游服务器的标准 gRPC。有关详细信息,请参阅[协议与 gRPC over HTTP2 的差异](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2)。 ### CORS 处理[​](#cors-处理 "CORS 处理的直接链接") 插件自动处理跨域请求。默认情况下: * 允许所有来源 (`*`) * 允许 `POST` 请求 * 接受的请求头:`content-type`, `x-grpc-web`, `x-user-agent` * 暴露的响应头:`grpc-status`, `grpc-message` ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何配置和使用 `grpc-web` 插件与 gRPC-Web 客户端。 ### 先决条件[​](#先决条件 "先决条件的直接链接") 在继续示例之前,请完成以下初步步骤以设置上游服务器和 gRPC-Web 客户端。 #### 启动上游服务器[​](#启动上游服务器 "启动上游服务器的直接链接") 在 Docker 中启动 [grpcbin 服务器](https://github.com/moul/grpcbin)作为示例上游: * Docker * Kubernetes ``` docker run -d \ --name grpcbin \ -p 9000:9000 \ moul/grpcbin ``` 创建用于部署 grpcbin 服务器的 Kubernetes 清单文件: grpcbin.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: grpcbin spec: replicas: 1 selector: matchLabels: app: grpcbin template: metadata: labels: app: grpcbin spec: containers: - name: grpcbin image: moul/grpcbin ports: - containerPort: 9000 --- apiVersion: v1 kind: Service metadata: namespace: aic name: grpcbin spec: selector: app: grpcbin ports: - protocol: TCP port: 9000 targetPort: 9000 type: ClusterIP ``` 将配置应用到集群: ``` kubectl apply -f grpcbin.yaml ``` #### 生成 gRPC-Web 客户端代码[​](#生成-grpc-web-客户端代码 "生成 gRPC-Web 客户端代码的直接链接") 下载 protocol buffer 定义 `hello.proto`: ``` curl -O https://raw.githubusercontent.com/moul/pb/refs/heads/master/hello/hello.proto ``` 安装 [`protobuf`](https://github.com/protocolbuffers/protobuf/releases) 和 [`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases)。 从 `hello.proto` 生成 gRPC-Web 客户端代码: ``` protoc \ --js_out=import_style=commonjs:. \ --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. \ hello.proto ``` 你应该在当前目录中看到生成的两个文件:用于 protocol buffers 消息类的 `hello_pb.js` 和用于 gRPC-Web 客户端存根的 `hello_grpc_web_pb.js`。 #### 创建客户端[​](#创建客户端 "创建客户端的直接链接") 创建一个 Node.js 项目并安装所需的依赖项: ``` npm init -y npm install xhr2 grpc-web google-protobuf ``` 创建客户端文件: client.js ``` const XMLHttpRequest = require('xhr2'); const { HelloServiceClient } = require('./hello_grpc_web_pb'); const { HelloRequest } = require('./hello_pb'); global.XMLHttpRequest = XMLHttpRequest; function sayHello(){ const client = new HelloServiceClient('http://127.0.0.1:9080/grpc/web', null, { format: 'text', }); const req = new HelloRequest(); req.setGreeting('jack'); const call = client.sayHello(req, {}, (err, resp) => { if (err) { console.error('grpc error:', err.code, err.message); } else { console.log('reply:', resp.getReply()); } }); call.on('metadata', (metadata) => { console.log('Response headers:', metadata); }); } function lotsOfReplies() { const client = new HelloServiceClient('http://127.0.0.1:9080/grpc/web', null, { format: 'text', }); const req = new HelloRequest(); req.setGreeting('rep'); const stream = client.lotsOfReplies(req, {}); stream.on('metadata', (metadata) => { console.log('Response headers:', metadata); }); } lotsOfReplies() sayHello() ``` 稍后你可以运行客户端 `node client.js`,通过网关向 gRPC 服务器发送一元和服务器流式请求。 ### 代理 gRPC-Web(前缀匹配路由)[​](#代理-grpc-web前缀匹配路由 "代理 gRPC-Web(前缀匹配路由)的直接链接") 以下示例演示了如何配置和使用 `grpc-web` 插件与之前设置的 gRPC-Web 客户端。 创建一个启用 `grpc-web` 插件的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d ' { "id": "grpc-web-route", "uri": "/grpc/web/*", "plugins": { "grpc-web": {} }, "upstream": { "scheme": "grpc", "type": "roundrobin", "nodes": { "192.168.10.103:9000": 1 } } }' ``` ❶ 配置 `uri` 以匹配 `client.js` 中请求的路由的前缀。 ❷ 启用 `grpc-web` 插件。 ❸ 将上游协议设置为 `grpc`。 ❹ 替换为你的上游服务器地址。 adc.yaml ``` services: - name: grpcbin routes: - name: grpc-web-route uris: - /grpc/web/* plugins: grpc-web: {} upstream: scheme: grpc type: roundrobin nodes: - host: grpcbin port: 9000 weight: 1 ``` ❶ 配置 `uri` 以匹配 `client.js` 中请求的路由的前缀。 ❷ 启用 `grpc-web` 插件。 ❸ 将上游协议设置为 `grpc`。 ❹ 替换为你的上游服务器地址。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD Gateway API 与 gRPC-Web Gateway API `GRPCRoute` 按 gRPC 服务名称和方法名称匹配请求,而不是按 HTTP 路径前缀匹配。要使用 `grpc-web` 插件代理 gRPC-Web 流量,请配置不包含方法匹配条件的 `GRPCRoute`,使其接受所有传入的 gRPC 请求。使用此配置时,请将 `client.js` 中的 `HelloServiceClient` 基础 URL 更新为 `http://127.0.0.1:9080`(不包含 `/grpc/web` 前缀)。 grpc-web-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: grpc-web-plugin-config spec: plugins: - name: grpc-web config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: namespace: aic name: grpc-web-route spec: parentRefs: - name: apisix rules: - filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: grpc-web-plugin-config backendRefs: - name: grpcbin port: 9000 ``` grpc-web-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: grpcbin spec: ingressClassName: apisix scheme: grpc --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: grpc-web-route spec: ingressClassName: apisix http: - name: grpc-web-route match: paths: - /grpc/web/* backends: - serviceName: grpcbin servicePort: 9000 plugins: - name: grpc-web enable: true config: {} ``` ❶ 将上游协议设置为 `grpc`。 ❷ 将路由路径配置为前缀匹配 `client.js` 中请求的路由。 ❸ 替换为你的上游服务名称和端口。 ❹ 启用 `grpc-web` 插件。 将配置应用到集群: ``` kubectl apply -f grpc-web-ic.yaml ``` 理解 URI 在 APISIX 3.15.0 之前和 API7 企业版 3.8.21 之前的版本中,路由 URI 必须使用前缀匹配,因为 gRPC-Web 客户端在请求 URI 中包含包名、服务名和方法名。在这些版本中使用绝对 URI 匹配将导致请求无法匹配路由。后续版本支持[绝对 URI 路由](#proxy-grpc-web-absolute-uri)。 在此示例中,路由 URI 必须配置为 `/grpc/web/*` 才能正确匹配客户端请求(例如 `/grpc/web/hello.HelloService/SayHello`)。使用更广泛的前缀(如 `/grpc/*`)将导致网关无法正确提取完整的服务路径,从而导致错误(例如 `unknown service web/hello.HelloService`)。 运行客户端以向网关路由发送请求: ``` node client.js ``` 你应该看到来自上游 gRPC 服务器的回复: ``` Response headers: { ... 'access-control-allow-origin': '*', 'access-control-expose-headers': 'grpc-message,grpc-status' } Response headers: { ... 'access-control-allow-origin': '*', 'access-control-expose-headers': 'grpc-message,grpc-status' } reply: hello jack ``` ### 代理 gRPC-Web(绝对 URI)[​](#proxy-grpc-web-absolute-uri "代理 gRPC-Web(绝对 URI)的直接链接") 此示例适用于 APISIX 3.15.0 及更高版本,以及 API7 企业版 3.8.21 及更高版本。 当使用绝对 URI 时,网关不会自动剥离 URI 路径前缀。为了将请求正确转发到上游 gRPC 服务器,请使用 `proxy-rewrite` 插件调整请求路径。 创建一个启用 `grpc-web` 插件的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d ' { "id": "grpc-web-route", "uri": "/grpc/web/hello.HelloService/SayHello", "plugins": { "grpc-web": {}, "proxy-rewrite": { "uri": "/hello.HelloService/SayHello", "set_ngx_uri": "true" } }, "upstream": { "scheme": "grpc", "type": "roundrobin", "nodes": { "192.168.10.103:9000": 1 } } }' ``` ❶ 配置 `uri` 使用绝对路径,包括基本前缀和 gRPC 完整服务路径。 ❷ 配置 `proxy-rewrite` 以重写路径并剥离路由前缀。 ❸ 将 `set_ngx_uri` 设置为 `true` 以将请求的路径更新为 `proxy-rewrite` 插件中定义的 URI。如果不设置此项,网关将无法将请求正确转发到上游,从而导致错误(例如 `unknown service grpc/web/hello.HelloService`)。 ❹ 将上游协议设置为 `grpc`。 ❺ 替换为你的上游服务器地址。 adc.yaml ``` services: - name: grpcbin routes: - name: grpc-web-route uris: - /grpc/web/hello.HelloService/SayHello plugins: grpc-web: {} proxy-rewrite: uri: /hello.HelloService/SayHello set_ngx_uri: "true" upstream: scheme: grpc type: roundrobin nodes: - host: grpcbin port: 9000 weight: 1 ``` ❶ 配置 `uri` 使用绝对路径,包括基本前缀和 gRPC 完整服务路径。 ❷ 配置 `proxy-rewrite` 以重写路径并剥离路由前缀。 ❸ 将 `set_ngx_uri` 设置为 `true` 以将请求的路径更新为 `proxy-rewrite` 插件中定义的 URI。如果不设置此项,网关将无法将请求正确转发到上游,从而导致错误(例如 `unknown service grpc/web/hello.HelloService`)。 ❹ 将上游协议设置为 `grpc`。 ❺ 替换为你的上游服务器地址。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD Gateway API 与 gRPC-Web Gateway API `GRPCRoute` 按 gRPC 服务名称和方法名称匹配请求,而不是按 HTTP 路径前缀匹配。包含 `service: hello.HelloService` 和 `method: SayHello` 的 `GRPCRoute` 会在 `/hello.HelloService/SayHello` 创建精确路由。由于路由路径已与 gRPC 方法路径匹配,因此无需使用 `proxy-rewrite`。使用此配置时,请将 `client.js` 中的 `HelloServiceClient` 基础 URL 更新为 `http://127.0.0.1:9080`(不包含 `/grpc/web` 前缀)。 grpc-web-absolute-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: grpc-web-absolute-plugin-config spec: plugins: - name: grpc-web config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: namespace: aic name: grpc-web-absolute-route spec: parentRefs: - name: apisix rules: - matches: - method: service: hello.HelloService method: SayHello filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: grpc-web-absolute-plugin-config backendRefs: - name: grpcbin port: 9000 ``` grpc-web-absolute-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: grpcbin spec: ingressClassName: apisix scheme: grpc --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: grpc-web-absolute-route spec: ingressClassName: apisix http: - name: grpc-web-absolute-route match: paths: - /grpc/web/hello.HelloService/SayHello backends: - serviceName: grpcbin servicePort: 9000 plugins: - name: grpc-web enable: true config: {} - name: proxy-rewrite enable: true config: uri: /hello.HelloService/SayHello set_ngx_uri: "true" ``` ❶ 将上游协议设置为 `grpc`。 ❷ 将路由路径配置为绝对 URI,包括基础前缀和完整的 gRPC 服务路径。 ❸ 替换为你的上游服务名称和端口。 ❹ 配置 `proxy-rewrite` 以重写路径并移除路由前缀。 ❺ 将 `set_ngx_uri` 设置为 `true`,把请求路径更新为 `proxy-rewrite` 插件中定义的 URI。如果不设置此项,网关将无法把请求正确转发到上游,并可能产生 `unknown service grpc/web/hello.HelloService` 等错误。 将配置应用到集群: ``` kubectl apply -f grpc-web-absolute-ic.yaml ``` 运行客户端以向网关路由发送请求: ``` node client.js ``` 你应该看到来自上游 gRPC 服务器的回复: ``` Response headers: { ... 'access-control-allow-origin': '*', 'access-control-expose-headers': 'grpc-message,grpc-status' } Response headers: { ... 'access-control-allow-origin': '*', 'access-control-expose-headers': 'grpc-message,grpc-status' } reply: hello jack ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * cors\_allow\_headers string 默认值:`content-type,x-grpc-web,x-user-agent` *** 允许跨域请求的请求头列表,以逗号分隔。 * max\_req\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** gRPC-Web 处理时读取的请求体最大字节数。超过该大小的请求体会以 `400 Bad Request` 被拒绝。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 --- # hmac-auth `hmac-auth` 插件支持 HMAC (Hash-based Message Authentication Code) 认证,作为确保请求完整性的机制,防止其在传输过程中被修改。要使用该插件,你需要在 [消费者](https://docs.apiseven.com/apisix/key-concepts/consumers.md) 上配置 HMAC 密钥,并在路由或服务上启用该插件。 消费者成功通过身份认证后,APISIX 会在将请求代理到上游服务前,为请求添加 `X-Consumer-Username`、`X-Credential-Identifier` 等请求头,以及已配置的其他消费者自定义请求头。上游服务可以据此区分不同消费者,并按需实现其他逻辑。如果某个值不可用,则不会添加对应的请求头。 关于 X-Consumer-Username 使用 Ingress Controller 配置消费者时,消费者名称会生成为 `namespace_consumername` 格式。因此,`X-Consumer-Username` 请求头也会采用此格式,而不只是 `consumername`。 ## 实现[​](#实现 "实现的直接链接") 启用后,插件会验证请求 `Authorization` 请求头中的 HMAC 签名,并检查传入请求是否来自可信来源。具体而言,当 APISIX 收到 HMAC 签名请求时,会从 `Authorization` 请求头中提取 Key ID,然后检索包含 Secret Key 的对应消费者配置。如果 Key ID 有效且存在,APISIX 会使用请求的 `Date` 请求头和 Secret Key 生成 HMAC 签名。如果生成的签名与 `Authorization` 请求头中提供的签名一致,请求将通过身份认证并转发到上游服务。 该插件的实现基于 [draft-cavage-http-signatures](https://www.ietf.org/archive/id/draft-cavage-http-signatures-12.txt)。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `hmac-auth` 插件。 ### 在路由上实现 HMAC 认证[​](#在路由上实现-hmac-认证 "在路由上实现 HMAC 认证的直接链接") 以下示例演示如何在路由上实现 HMAC 身份认证。你还将通过 `X-Consumer-Custom-Id` 请求头为通过身份认证的请求附加消费者自定义 ID,以便按需实现其他逻辑。 * Admin API * ADC * Ingress Controller 创建一个带有自定义 ID 标签的消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john", "labels": { "custom_id": "495aec6a" } }' ``` 为消费者创建 `hmac-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-hmac-auth", "plugins": { "hmac-auth": { "key_id": "john-key", "secret_key": "john-secret-key" } } }' ``` 使用默认配置创建一个启用 `hmac-auth` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "hmac-auth-route", "uri": "/get", "methods": ["GET"], "plugins": { "hmac-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `hmac-auth` 凭证的消费者,以及一个配置了 `hmac-auth` 插件的路由: adc.yaml ``` consumers: - username: john labels: custom_id: "495aec6a" credentials: - name: hmac-auth type: hmac-auth config: key_id: john-key secret_key: john-secret-key services: - name: hmac-auth-service routes: - name: hmac-auth-route uris: - /get methods: - GET plugins: hmac-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `hmac-auth` 凭证的消费者,以及一个配置了 `hmac-auth` 插件的路由: * Gateway API * APISIX CRD hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john labels: custom_id: "495aec6a" spec: gatewayRef: name: apisix credentials: - type: hmac-auth name: primary-cred config: key_id: john-key secret_key: john-secret-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: hmac-auth-plugin-config spec: plugins: - name: hmac-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: hmac-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get method: GET filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: hmac-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john labels: custom_id: "495aec6a" spec: ingressClassName: apisix authParameter: hmacAuth: value: key_id: john-key secret_key: john-secret-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: hmac-auth-route spec: ingressClassName: apisix http: - name: hmac-auth-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: hmac-auth enable: true ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` 生成签名。你可以使用下面的 Python 代码片段或你选择的其他技术栈: hmac-sig-header-gen.py ``` import hmac import hashlib import base64 from datetime import datetime, timezone key_id = "john-key" # key id secret_key = b"john-secret-key" # secret key request_method = "GET" # HTTP method request_path = "/get" # route URI algorithm= "hmac-sha256" # 可以使用 allowed_algorithms 中的其他算法 # 获取当前 GMT 时间 # 注意:签名将在时钟偏差时间(默认 300 秒)后失效 # 签名失效后可重新生成,或在建议的安全边界内增大时钟偏差, # 以延长签名有效期 gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT') # 按顺序构造签名字符串 # date 和后续自定义请求头应转换为小写,并以单个空格分隔, # 即 `:` # https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6 signing_string = ( f"{key_id}\n" f"{request_method} {request_path}\n" f"date: {gmt_time}\n" ) # 创建签名 signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest() signature_base64 = base64.b64encode(signature).decode('utf-8') # 构造请求头 headers = { "Date": gmt_time, "Authorization": ( f'Signature keyId="{key_id}",algorithm="{algorithm}",' f'headers="@request-target date",' f'signature="{signature_base64}"' ) } # 输出请求头 print(headers) ``` 运行脚本: ``` python3 hmac-sig-header-gen.py ``` 你应该看到打印出的请求头: ``` {'Date': 'Fri, 06 Sep 2024 06:41:29 GMT', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM="'} ``` 使用生成的请求头,向路由发送请求: ``` curl -X GET "http://127.0.0.1:9080/get" \ -H "Date: Fri, 06 Sep 2024 06:41:29 GMT" \ -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM="' ``` 你应该看到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Authorization": "Signature keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target date\",signature=\"wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM=\"", "Date": "Fri, 06 Sep 2024 06:41:29 GMT", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66d96513-2e52d4f35c9b6a2772d667ea", "X-Consumer-Username": "john", "X-Credential-Identifier": "cred-john-hmac-auth", "X-Consumer-Custom-Id": "495aec6a", "X-Forwarded-Host": "127.0.0.1" }, "origin": "192.168.65.1, 34.0.34.160", "url": "http://127.0.0.1/get" } ``` 如果你想将更多消费者自定义请求头添加到已认证请求中,请参阅 [`attach-consumer-label`](https://docs.apiseven.com/hub/attach-consumer-label.md) 插件。 ### 从上游隐藏授权信息[​](#从上游隐藏授权信息 "从上游隐藏授权信息的直接链接") 如上例所示,传递给上游的 `Authorization` 请求头包含签名和所有其他详细信息,这可能会带来安全风险。 此示例接续[上一个示例](#%E5%9C%A8%E8%B7%AF%E7%94%B1%E4%B8%8A%E5%AE%9E%E7%8E%B0-hmac-%E8%AE%A4%E8%AF%81),演示如何防止将这些信息发送到上游服务。 * Admin API * ADC * Ingress Controller 更新插件配置,将 `hide_credentials` 设置为 `true`: ``` curl "http://127.0.0.1:9180/apisix/admin/routes/hmac-auth-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "hmac-auth": { "hide_credentials": true } } }' ``` 按如下方式更新插件配置: adc.yaml ``` consumers: - username: john labels: custom_id: "495aec6a" credentials: - name: hmac-auth type: hmac-auth config: key_id: john-key secret_key: john-secret-key services: - name: hmac-auth-service routes: - name: hmac-auth-route uris: - /get methods: - GET plugins: hmac-auth: hide_credentials: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `PluginConfig`,将 `hide_credentials` 设置为 `true`: hmac-auth-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: hmac-auth-plugin-config spec: plugins: - name: hmac-auth config: _meta: disable: false hide_credentials: true ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` 更新 `ApisixRoute`,将 `hide_credentials` 设置为 `true`: hmac-auth-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: hmac-auth-route spec: ingressClassName: apisix http: - name: hmac-auth-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: hmac-auth enable: true config: hide_credentials: true ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` 向路由发送请求: ``` curl -X GET "http://127.0.0.1:9080/get" \ -H "Date: Fri, 06 Sep 2024 06:41:29 GMT" \ -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="wWfKQvPDr0wHQ4IHdluB4IzeNZcj0bGJs2wvoCOT5rM="' ``` 你应该看到 `HTTP/1.1 200 OK` 响应,并注意到 `Authorization` 请求头已被完全移除: ``` { "args": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66d96513-2e52d4f35c9b6a2772d667ea", "X-Consumer-Username": "john", "X-Credential-Identifier": "cred-john-hmac-auth", "X-Forwarded-Host": "127.0.0.1" }, "origin": "192.168.65.1, 34.0.34.160", "url": "http://127.0.0.1/get" } ``` ### 启用 Body 校验[​](#启用-body-校验 "启用 Body 校验的直接链接") 以下示例演示了如何校验请求体,并将其摘要绑定到 HMAC 签名。 当 `validate_request_body` 为 `true` 时,APISIX 会比较 `Digest` 请求头与请求体的 SHA-256 摘要。缺少 `Digest` 请求头或摘要不匹配时,请求会被拒绝。但仅做此比较并不会将摘要绑定到 HMAC 签名,客户端仍可同时替换请求体和 `Digest` 请求头。因此还应对 `digest` 签名,并在 `signed_headers` 中列出该请求头,使摘要一旦更改就会导致签名失效。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为消费者创建 `hmac-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-hmac-auth", "plugins": { "hmac-auth": { "key_id": "john-key", "secret_key": "john-secret-key" } } }' ``` 创建一个启用 `hmac-auth` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "hmac-auth-route", "uri": "/post", "methods": ["POST"], "plugins": { "hmac-auth": { "signed_headers": ["date", "digest"], "validate_request_body": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `hmac-auth` 凭证的消费者,以及一个配置了 `hmac-auth` 插件的路由: adc.yaml ``` consumers: - username: john credentials: - name: hmac-auth type: hmac-auth config: key_id: john-key secret_key: john-secret-key services: - name: hmac-auth-service routes: - name: hmac-auth-route uris: - /post methods: - POST plugins: hmac-auth: signed_headers: - date - digest validate_request_body: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `hmac-auth` 凭证的消费者,以及一个配置了 `hmac-auth` 插件的路由: * Gateway API * APISIX CRD hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: hmac-auth name: primary-cred config: key_id: john-key secret_key: john-secret-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: hmac-auth-plugin-config spec: plugins: - name: hmac-auth config: _meta: disable: false signed_headers: - date - digest validate_request_body: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: hmac-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /post method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: hmac-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: hmacAuth: value: key_id: john-key secret_key: john-secret-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: hmac-auth-route spec: ingressClassName: apisix http: - name: hmac-auth-route match: paths: - /post methods: - POST upstreams: - name: httpbin-external-domain plugins: - name: hmac-auth enable: true config: signed_headers: - date - digest validate_request_body: true ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` 生成签名。你可以使用下面的 Python 代码片段或你选择的其他技术栈: hmac-sig-digest-header-gen.py ``` import hmac import hashlib import base64 from datetime import datetime, timezone key_id = "john-key" # key id secret_key = b"john-secret-key" # secret key request_method = "POST" # HTTP method request_path = "/post" # route URI algorithm= "hmac-sha256" # 可以使用 allowed_algorithms 中的其他算法 body = '{"name": "world"}' # example request body # 获取当前 GMT 时间 # 注意:签名将在时钟偏差时间(默认 300 秒)后失效 # 签名失效后可重新生成,或在建议的安全边界内增大时钟偏差, # 以延长签名有效期 gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT') # 创建请求体的 SHA-256 摘要,并将其放入签名字符串 body_digest = hashlib.sha256(body.encode('utf-8')).digest() digest_header = "SHA-256=" + base64.b64encode(body_digest).decode('utf-8') # 按顺序构造签名字符串 # date 和后续自定义请求头应转换为小写,并以单个空格分隔, # 即 `:` # https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6 signing_string = ( f"{key_id}\n" f"{request_method} {request_path}\n" f"date: {gmt_time}\n" f"digest: {digest_header}\n" ) # 创建签名 signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest() signature_base64 = base64.b64encode(signature).decode('utf-8') # 构造请求头 headers = { "Date": gmt_time, "Digest": digest_header, "Authorization": ( f'Signature keyId="{key_id}",algorithm="hmac-sha256",' f'headers="@request-target date digest",' f'signature="{signature_base64}"' ) } # 输出请求头 print(headers) ``` 运行脚本: ``` python3 hmac-sig-digest-header-gen.py ``` 你应该看到打印出的请求头: ``` {'Date': 'Thu, 20 Aug 2026 09:40:53 GMT', 'Digest': 'SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date digest",signature="GD+WVdC2hIzLCgMfLlEx5gYqGC4wUQl59kl2XMqKbKM="'} ``` 使用生成的请求头,向路由发送请求: ``` curl "http://127.0.0.1:9080/post" -X POST \ -H "Date: Thu, 20 Aug 2026 09:40:53 GMT" \ -H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \ -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date digest",signature="GD+WVdC2hIzLCgMfLlEx5gYqGC4wUQl59kl2XMqKbKM="' \ -d '{"name": "world"}' ``` 你应该看到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "", "files": {}, "form": { "{\"name\": \"world\"}": "" }, "headers": { "Accept": "*/*", "Authorization": "Signature keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target date digest\",signature=\"GD+WVdC2hIzLCgMfLlEx5gYqGC4wUQl59kl2XMqKbKM=\"", "Content-Length": "17", "Content-Type": "application/x-www-form-urlencoded", "Date": "Thu, 20 Aug 2026 09:40:53 GMT", "Digest": "SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=", "Host": "127.0.0.1:9080", "User-Agent": "curl/8.7.1", "X-Consumer-Username": "john", "X-Credential-Identifier": "cred-john-hmac-auth", "X-Forwarded-For": "192.168.117.1", "X-Forwarded-Host": "127.0.0.1:9080", "X-Forwarded-Port": "9080", "X-Forwarded-Proto": "http", "X-Real-IP": "192.168.117.1" }, "json": null, "origin": "192.168.117.3", "url": "http://127.0.0.1/post" } ``` 如果使用相同的已签名请求头发送不同的请求体,`Digest` 请求头将不再匹配: ``` curl "http://127.0.0.1:9080/post" -X POST \ -H "Date: Thu, 20 Aug 2026 09:40:53 GMT" \ -H "Digest: SHA-256=78qzJuLwSpZ8HacsTdFCQJWxzPMOf8bYctRk2ySLpS8=" \ -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date digest",signature="GD+WVdC2hIzLCgMfLlEx5gYqGC4wUQl59kl2XMqKbKM="' \ -d '{"name": "tampered"}' ``` 你应该看到带有以下消息的 `HTTP/1.1 401 Unauthorized` 响应: ``` {"message":"client request can't be validated"} ``` ### 强制签名请求头[​](#强制签名请求头 "强制签名请求头的直接链接") 以下示例演示了如何强制某些请求头必须包含在请求的 HMAC 签名中。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为消费者创建 `hmac-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-hmac-auth", "plugins": { "hmac-auth": { "key_id": "john-key", "secret_key": "john-secret-key" } } }' ``` 创建一个启用 `hmac-auth` 插件的路由,该路由要求 HMAC 签名中必须包含三个请求头: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "hmac-auth-route", "uri": "/get", "methods": ["GET"], "plugins": { "hmac-auth": { "signed_headers": ["date","x-custom-header-a", "x-custom-header-b"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `hmac-auth` 凭证的消费者,以及一个配置了 `hmac-auth` 插件的路由: adc.yaml ``` consumers: - username: john credentials: - name: hmac-auth type: hmac-auth config: key_id: john-key secret_key: john-secret-key services: - name: hmac-auth-service routes: - name: hmac-auth-route uris: - /get methods: - GET plugins: hmac-auth: signed_headers: - date - x-custom-header-a - x-custom-header-b upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `hmac-auth` 凭证的消费者,以及一个配置了 `hmac-auth` 插件的路由: * Gateway API * APISIX CRD hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: hmac-auth name: primary-cred config: key_id: john-key secret_key: john-secret-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: hmac-auth-plugin-config spec: plugins: - name: hmac-auth config: _meta: disable: false signed_headers: - date - x-custom-header-a - x-custom-header-b --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: hmac-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get method: GET filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: hmac-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: hmacAuth: value: key_id: john-key secret_key: john-secret-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: hmac-auth-route spec: ingressClassName: apisix http: - name: hmac-auth-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: hmac-auth enable: true config: signed_headers: - date - x-custom-header-a - x-custom-header-b ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` 生成签名。你可以使用下面的 Python 代码片段或你选择的其他技术栈: hmac-sig-req-header-gen.py ``` import hmac import hashlib import base64 from datetime import datetime, timezone key_id = "john-key" # key id secret_key = b"john-secret-key" # secret key request_method = "GET" # HTTP method request_path = "/get" # route URI algorithm= "hmac-sha256" # 可以使用 allowed_algorithms 中的其他算法 custom_header_a = "hello123" # required custom header custom_header_b = "world456" # required custom header # 获取当前 GMT 时间 # 注意:签名将在时钟偏差时间(默认 300 秒)后失效 # 签名失效后可重新生成,或在建议的安全边界内增大时钟偏差, # 以延长签名有效期 gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT') # 按顺序构造签名字符串 # date 和后续自定义请求头应转换为小写,并以单个空格分隔, # 即 `:` # https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6 signing_string = ( f"{key_id}\n" f"{request_method} {request_path}\n" f"date: {gmt_time}\n" f"x-custom-header-a: {custom_header_a}\n" f"x-custom-header-b: {custom_header_b}\n" ) # 创建签名 signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest() signature_base64 = base64.b64encode(signature).decode('utf-8') # 构造请求头 headers = { "Date": gmt_time, "Authorization": ( f'Signature keyId="{key_id}",algorithm="hmac-sha256",' f'headers="@request-target date x-custom-header-a x-custom-header-b",' f'signature="{signature_base64}"' ), "x-custom-header-a": custom_header_a, "x-custom-header-b": custom_header_b } # 输出请求头 print(headers) ``` 运行脚本: ``` python3 hmac-sig-req-header-gen.py ``` 你应该看到打印出的请求头: ``` {'Date': 'Fri, 06 Sep 2024 09:58:49 GMT', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="MwJR8JOhhRLIyaHlJ3Snbrf5hv0XwdeeRiijvX3A3yE="', 'x-custom-header-a': 'hello123', 'x-custom-header-b': 'world456'} ``` 使用生成的请求头,向路由发送请求: ``` curl -X GET "http://127.0.0.1:9080/get" \ -H "Date: Fri, 06 Sep 2024 09:58:49 GMT" \ -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="MwJR8JOhhRLIyaHlJ3Snbrf5hv0XwdeeRiijvX3A3yE="' \ -H "x-custom-header-a: hello123" \ -H "x-custom-header-b: world456" ``` 你应该看到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Authorization": "Signature keyId=\"john-key\",algorithm=\"hmac-sha256\",headers=\"@request-target date x-custom-header-a x-custom-header-b\",signature=\"MwJR8JOhhRLIyaHlJ3Snbrf5hv0XwdeeRiijvX3A3yE=\"", "Date": "Fri, 06 Sep 2024 09:58:49 GMT", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66d98196-64a58db25ece71c077999ecd", "X-Consumer-Username": "john", "X-Credential-Identifier": "cred-john-hmac-auth", "X-Custom-Header-A": "hello123", "X-Custom-Header-B": "world456", "X-Forwarded-Host": "127.0.0.1" }, "origin": "192.168.65.1, 103.97.2.206", "url": "http://127.0.0.1/get" } ``` ### 匿名消费者的速率限制[​](#匿名消费者的速率限制 "匿名消费者的速率限制的直接链接") 以下示例演示如何为普通消费者和匿名消费者配置不同的限流策略。匿名消费者无需进行身份认证,但配额更少。 * Admin API * ADC * Ingress Controller 创建常规消费者 `john` 并配置 `limit-count` 插件,允许在 30 秒窗口内有 3 次配额: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john", "plugins": { "limit-count": { "count": 3, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 为消费者 `john` 创建 `hmac-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-hmac-auth", "plugins": { "hmac-auth": { "key_id": "john-key", "secret_key": "john-secret-key" } } }' ``` 创建匿名用户 `anonymous` 并配置 `limit-count` 插件,允许在 30 秒窗口内有 1 次配额: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "anonymous", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 创建路由并配置 `hmac-auth` 插件以接受匿名消费者 `anonymous` 绕过认证: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "hmac-auth-route", "uri": "/get", "methods": ["GET"], "plugins": { "hmac-auth": { "anonymous_consumer": "anonymous" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: adc.yaml ``` consumers: - username: john plugins: limit-count: count: 3 time_window: 30 rejected_code: 429 policy: local credentials: - name: hmac-auth type: hmac-auth config: key_id: john-key secret_key: john-secret-key - username: anonymous plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 policy: local services: - name: anonymous-rate-limit-service routes: - name: hmac-auth-route uris: - /get methods: - GET plugins: hmac-auth: anonymous_consumer: anonymous upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: hmac-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: hmac-auth name: primary-cred config: key_id: john-key secret_key: john-secret-key plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: anonymous spec: gatewayRef: name: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: hmac-auth-plugin-config spec: plugins: - name: hmac-auth config: anonymous_consumer: aic_anonymous # namespace_consumername --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: hmac-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get method: GET filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: hmac-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-ic.yaml ``` hmac-auth-apisix-crd.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: hmacAuth: value: key_id: john-key secret_key: john-secret-key plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: anonymous spec: ingressClassName: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: hmac-auth-route spec: ingressClassName: apisix http: - name: hmac-auth-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: hmac-auth config: anonymous_consumer: aic_anonymous ``` 将配置应用到集群: ``` kubectl apply -f hmac-auth-apisix-crd.yaml ``` 生成签名。你可以使用下面的 Python 代码片段或你选择的其他技术栈: hmac-sig-header-gen.py ``` import hmac import hashlib import base64 from datetime import datetime, timezone key_id = "john-key" # key id secret_key = b"john-secret-key" # secret key request_method = "GET" # HTTP method request_path = "/get" # route URI algorithm= "hmac-sha256" # 可以使用 allowed_algorithms 中的其他算法 # 获取当前 GMT 时间 # 注意:签名将在时钟偏差时间(默认 300 秒)后失效 # 签名失效后可重新生成,或在建议的安全边界内增大时钟偏差, # 以延长签名有效期 gmt_time = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT') # 按顺序构造签名字符串 # date 和后续自定义请求头应转换为小写,并以单个空格分隔, # 即 `:` # https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.1.6 signing_string = ( f"{key_id}\n" f"{request_method} {request_path}\n" f"date: {gmt_time}\n" ) # 创建签名 signature = hmac.new(secret_key, signing_string.encode('utf-8'), hashlib.sha256).digest() signature_base64 = base64.b64encode(signature).decode('utf-8') # 构造请求头 headers = { "Date": gmt_time, "Authorization": ( f'Signature keyId="{key_id}",algorithm="{algorithm}",' f'headers="@request-target date",' f'signature="{signature_base64}"' ) } # 输出请求头 print(headers) ``` 运行脚本: ``` python3 hmac-sig-header-gen.py ``` 你应该看到打印出的请求头: ``` {'Date': 'Mon, 21 Oct 2024 17:31:18 GMT', 'Authorization': 'Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="ztFfl9w7LmCrIuPjRC/DWSF4gN6Bt8dBBz4y+u1pzt8="'} ``` 要进行验证,请使用生成的请求头发送五个连续请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/get" -H "Date: Mon, 21 Oct 2024 17:31:18 GMT" -H 'Authorization: Signature keyId="john-key",algorithm="hmac-sha256",headers="@request-target date",signature="ztFfl9w7LmCrIuPjRC/DWSF4gN6Bt8dBBz4y+u1pzt8="' -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示在 5 个请求中,3 个请求成功(状态码 200),而其他请求被拒绝(状态码 429)。 ``` 200: 3, 429: 2 ``` 发送五个匿名请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/get" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示只有一个请求成功: ``` 200: 1, 429: 4 ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 ### 凭据[​](#凭据 "凭据的直接链接") 以下是可在 [凭据](https://docs.apiseven.com/apisix/key-concepts/credentials.md) 上配置的插件属性。 * key\_id string 必填 *** 消费者的唯一标识符,用于识别关联的配置,例如密钥。 * secret\_key string 必填 *** 用于生成 HMAC 的密钥。 该密钥在存储到 etcd 之前会使用 AES 加密。你也可以将其存储在环境变量中并使用 `env://` 前缀引用,或者存储在如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv) 等密钥管理器中,并使用 `secret://` 前缀引用。更多信息请参考[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 ### 路由或服务[​](#路由或服务 "路由或服务的直接链接") 以下是可在 [路由](https://docs.apiseven.com/apisix/key-concepts/routes.md) 或 [服务](https://docs.apiseven.com/apisix/key-concepts/services.md) 上配置的插件属性。 * allowed\_algorithms array\[string] 默认值:`["hmac-sha1", "hmac-sha256", "hmac-sha512"]` *** 允许的 HMAC 算法列表。 * clock\_skew integer 默认值:`300` 有效值: 大于或等于 1 *** 允许的客户端请求时间戳与 APISIX 服务器当前时间之间的最大时间差(秒)。这有助于解决客户端与服务器时钟之间的时间同步差异,并防止重放攻击。计算时使用 `Date` 请求头中的时间戳(必须为 GMT 格式)。 * signed\_headers array\[string] 默认值:`["date"]` *** 客户端请求的 HMAC 签名中必须包含的请求头列表。自 API7 企业版 3.10.0 和 APISIX 3.17.0 起,该字段默认值为 `["date"]`,因此除非覆盖该字段,否则必须对 `Date` 请求头签名。如果启用了 `validate_request_body`,还应包含 `digest`,以便签名覆盖请求体摘要。 * validate\_request\_body boolean *** 如果为 `true`,则比较请求体与 `Digest` 请求头。插件会计算请求体的 SHA-256 摘要并使用 Base64 编码,且要求 `Digest` 的格式为 `SHA-256=`。缺少 `Digest` 请求头或摘要不匹配时,验证将失败。此检查不会将摘要绑定到 HMAC 签名;如需由签名覆盖请求体摘要,请在签名请求头列表中包含 `digest`。 * max\_req\_body\_size integer 默认值:`524288 in API7 Enterprise 3.9.14, 3.10.0, and 3.10.1; 67108864 in API7 Enterprise from 3.9.15 and APISIX from 3.17.0` *** 当 `validate_request_body` 为 `true` 时,插件读取的请求体大小上限(字节)。在 API7 企业版 3.9.15 及更高版本和 APISIX 3.17.0 及更高版本中,超过该大小的请求将以 HTTP 413 拒绝。API7 企业版 3.9.14、3.10.0 和 3.10.1 中的默认值为 524288 字节(512 KiB);API7 企业版 3.9.15 及更高版本和 APISIX 3.17.0 及更高版本中的默认值为 67108864 字节(64 MiB)。 * hide\_credentials boolean 默认值:`false` *** 如果为 true,则不将 authorization 请求头传递给上游服务。 * anonymous\_consumer string *** 匿名消费者名称。如果配置了此项,允许匿名用户绕过认证。详情请参考 [匿名消费者的速率限制](https://docs.apiseven.com/hub/hmac-auth.md#匿名消费者的��速率限制)。 * realm string 默认值:`hmac` *** 身份认证失败时返回的 `401 Unauthorized` 响应中 [`WWW-Authenticate`](https://datatracker.ietf.org/doc/html/rfc7235#section-4.1) 响应头的 Realm。例如: * 如果 `realm` 设置为 `hmac-auth`,401 响应将包含以下响应头: ``` WWW-Authenticate: hmac realm="hmac-auth" ``` * 如果未配置 `realm`,401 响应将包含以下响应头: ``` WWW-Authenticate: hmac realm="hmac" ``` 该参数在 API7 企业版版本 3.9.2 及更高版本,以及 Apache APISIX 版本 3.15.0 及更高版本中可用。 --- # http-logger `http-logger` 插件将请求和响应日志作为 JSON 对象分批推送到 HTTP(S) 服务器,并支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `http-logger` 插件。 要跟随示例操作,请使用 [mockbin](https://mockbin.io) 启动一个模拟 HTTP 日志端点,并记下 mockbin URL。 ### 以默认日志格式记录请求[​](#以默认日志格式记录请求 "以默认日志格式记录请求的直接链接") 以下示例演示了如何在路由上配置 `http-logger` 插件,以记录访问该路由的请求信息。 创建一个带有 `http-logger` 插件的路由,并配置你的服务器 URI: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "http-logger-route", "uri": "/anything", "plugins": { "http-logger": { "uri": "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: http-logger-route plugins: http-logger: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD http-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: http-logger-plugin-config spec: plugins: - name: http-logger config: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: http-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: http-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` http-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: http-logger-route spec: ingressClassName: apisix http: - name: http-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: http-logger config: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" ``` 应用配置: ``` kubectl apply -f http-logger-ic.yaml ``` 向路由发送请求: ``` curl "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。在你的 mockbin 中,你应该看到类似于以下的日志条目: ``` [ { "upstream": "3.213.1.197:80", "server": { "hostname": "7d8d831179d4", "version": "3.9.0" }, "start_time": 1718291190508, "client_ip": "192.168.65.1", "response": { "status": 200, "headers": { "server": "APISIX/3.9.0", "content-length": "390", "access-control-allow-credentials": "true", "connection": "close", "date": "Thu, 13 Jun 2024 15:06:31 GMT", "access-control-allow-origin": "*", "content-type": "application/json" }, "size": 617 }, "latency": 1200.0000476837, "upstream_latency": 1133, "apisix_latency": 67.000047683716, "request": { "url": "http://127.0.0.1:9080/anything", "querystring": {}, "method": "GET", "uri": "/anything", "headers": { "accept": "*/*", "user-agent": "curl/8.6.0", "host": "127.0.0.1:9080" }, "size": 85 }, "service_id": "", "route_id": "http-logger-route" } ] ``` ### 使用插件元数据记录请求和响应头[​](#使用插件元数据记录请求和响应头 "使用插件元数据记录请求和响应头的直接链接") 以下示例演示了如何使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)和[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)自定义日志格式,以记录请求和响应中的特定头。 在 APISIX 中,[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)用于配置同一插件的所有插件实例的通用元数据字段。当一个插件在多个资源中启用并且需要对其元数据字段进行通用更新时,这非常有用。 首先,创建一个带有 `http-logger` 插件的路由,并配置你的服务器 URI: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "http-logger-route", "uri": "/anything", "plugins": { "http-logger": { "uri": "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: http-logger-route plugins: http-logger: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD http-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: http-logger-plugin-config spec: plugins: - name: http-logger config: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: http-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: http-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` http-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: http-logger-route spec: ingressClassName: apisix http: - name: http-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: http-logger config: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" ``` 应用配置: ``` kubectl apply -f http-logger-ic.yaml ``` 接下来,为 `http-logger` 配置插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/http-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr", "env": "$http_env", "resp_content_type": "$sent_http_Content_Type" } }' ``` adc.yaml ``` plugin_metadata: - name: http-logger log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: http-logger: log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` ❶ 记录自定义请求头 `env`。 ❷ 记录响应头 `Content-Type`。 向路由发送带有 `env` 头的请求: ``` curl "http://127.0.0.1:9080/anything" -H "env: dev" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。在你的 mockbin 中,你应该看到类似于以下的日志条目: ``` [ { "route_id": "http-logger-route", "client_ip": "192.168.65.1", "@timestamp": "2024-06-13T15:19:34+00:00", "host": "127.0.0.1", "env": "dev", "resp_content_type": "application/json" } ] ``` ### 有条件地记录请求体[​](#有条件地记录请求体 "有条件地记录请求体的直接�链接") 以下示例演示了如何有条件地记录请求体。 创建如下配置 `http-logger` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "http-logger-route", "uri": "/anything", "plugins": { "http-logger": { "uri": "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/", "include_req_body": true, "include_req_body_expr": [["arg_log_body", "==", "yes"]] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: http-logger-route plugins: http-logger: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD http-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: http-logger-plugin-config spec: plugins: - name: http-logger config: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: http-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: http-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` http-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: http-logger-route spec: ingressClassName: apisix http: - name: http-logger-route match: paths: - /anything methods: - GET - POST upstreams: - name: httpbin-external-domain plugins: - name: http-logger config: uri: "https://669f05eb10ca49f18763e023312c3d77.api.mockbin.io/" include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" ``` 应用配置: ``` kubectl apply -f http-logger-ic.yaml ``` ❶ `include_req_body`: 设置为 true 以包含请求体。 ❷ `include_req_body_expr`: 仅当 URL 查询字符串 `log_body` 为 `yes` 时才包含请求体。 向路由发送满足条件的带有 URL 查询字符串的请求: ``` curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}' ``` 你应该看到记录的请求体: ``` [ { "request": { "url": "http://127.0.0.1:9080/anything?log_body=yes", "querystring": { "log_body": "yes" }, "uri": "/anything?log_body=yes", ..., "body": "{\"env\": \"dev\"}", }, ... } ] ``` 向路由发送不带任何 URL 查询字符串的请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}' ``` 你不应在日志中观察到请求体。 信息 如果你除了将 `include_req_body` 或 `include_resp_body` 设置为 `true` 之外还自定义了 `log_format`,则插件将不会在日志中包含这些主体。 作为解决方法,你可以在日志格式中使用 NGINX 变量 `$request_body`,例如: ``` { "http-logger": { ..., "log_format": {"body": "$request_body"} } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * uri string 必填 *** HTTP(S) 服务器的 URI。 * auth\_header string *** HTTP(S) 服务器所需的授权头(如果需要)。该值在存储到 etcd 前会使用 AES 加密。 * timeout integer 默认值:`3` 有效值: 大于 0 *** 发送请求后保持连接活动的时间。 * log\_format object *** 使用 JSON 格式的键值对的自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 在 APISIX 3.15.0 及更高版本中,日志格式嵌套结构支持最多五层深度。在 API7 企业版中,仅支持扁平键值结构;尚不支持嵌套结构。 你还可以使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)在全局范围内配置日志格式,这将为所有 `http-logger` 插件实例配置日志格式。如果单个插件实例上配置的日志格式与插件元数据上配置的日志格式不同,则以单个插件实例上配置的日志格式为准。请参阅[示例](https://docs.apiseven.com/hub/http-logger.md#使用插件元数据记录请求和响应头)了解更多详情。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * include\_req\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含请求体。请注意,如果请求体太大而无法保存在内存中,由于 NGINX 的限制,它无法被记录。 * include\_req\_body\_expr array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的条件数组。当 `include_req_body` 为 true 时使用。仅当此处配置的表达式评估为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的条件数组。当 `include_resp_body` 为 true 时使用。仅当此处配置的表达式评估为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * concat\_method string 默认值:`json` 有效值: `json` 或 `new_line` *** 连接日志的方法。设置为 `json` 时,对所有挂起的日志使用 `json.encode`。设置为 `new_line` 时,也使用 `json.encode`,但使用换行符 ``连接行。 * ssl\_verify boolean 默认值:`false` *** 如果为 true,则验证服务器的 SSL 证书。 * name string 默认值:`http logger` *** 批处理器中的插件唯一标识符。如果使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称会导出到 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 一个批次允许的日志条目数。达到该数量后,批次会发送到日志服务。将此参数设置为 1 可启用立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 发送批次前等待新日志的最长时间,单位为秒。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 从最早条目起计,发送批次前允许等待的最长时间,单位为秒。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 批次失败后重试前的等待时间,单位为秒。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 丢弃日志条目前允许的最大失败重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对的自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 在 APISIX 3.15.0 及更高版本中,日志格式嵌套结构支持最多五层深度。在 API7 企业版中,仅支持扁平键值结构;尚不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # ip-restriction `ip-restriction` 插件支持通过配置 IP 地址白名单或黑名单来限制对上游资源的访问。限制对资源的 IP 访问有助于防止未经授权的访问并加强 API 安全性。 ## 示例[​](#示例 "��示例的直接链接") 下面的示例展示了如何在不同场景下配置 `ip-restriction` 插件。 ### 通过白名单限制访问[​](#通过白名单限制访问 "通过白名单限制访问的直接链接") 以下示例展示了如何将允许访问上游资源的 IP 地址列入白名单,并自定义拒绝访问时的错误消息。 * Admin API * ADC * Ingress Controller 创建一个启用了 `ip-restriction` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ip-restriction-route", "uri": "/anything", "plugins": { "ip-restriction": { "whitelist": [ "192.168.0.1/24" ], "message": "Access denied" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: ip-restriction-service routes: - name: ip-restriction-route uris: - /anything plugins: ip-restriction: whitelist: - "192.168.0.1/24" message: "Access denied" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 使用 kubectl port-forward 时的客户端 IP 使用 `kubectl port-forward` 进行本地测试时,无论本机的实际 IP 地址是什么,APISIX 都会将 `127.0.0.1` 视为客户端 IP。采用这种方式测试时,请确保白名单或黑名单中包含 `127.0.0.1`。在使用 `NodePort` 或 `LoadBalancer` 服务的生产环境中,APISIX 会收到真实的客户端 IP。 * Gateway API * APISIX CRD ip-restriction-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ip-restriction-plugin-config spec: plugins: - name: ip-restriction config: whitelist: - "192.168.0.1/24" message: "Access denied" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ip-restriction-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ip-restriction-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f ip-restriction-ic.yaml ``` ip-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ip-restriction-route spec: ingressClassName: apisix http: - name: ip-restriction-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: ip-restriction enable: true config: whitelist: - "192.168.0.1/24" message: "Access denied" ``` 将配置应用到集群: ``` kubectl apply -f ip-restriction-ic.yaml ``` ❶ 替换为你想要列入白名单的 IP 地址。 ❷ 自定义拒绝访问时的错误消息。 发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 如果你的 IP 被允许,你应该收到 `HTTP/1.1 200 OK` 响应。如果不是,你应该收到 `HTTP/1.1 403 Forbidden` 响应以及以下错误消息: ``` {"message":"Access denied"} ``` ### 使用修改后的 IP 限制访问[​](#使用修改后的-ip-限制访问 "使用修改后的 IP 限制访问的直接链接") 以下示例展示了如何使用 `real-ip` 插件修改用于 IP 限制的 IP。这在 APISIX 位于反向代理之后且 APISIX 无法获取真实客户端 IP 时特别有用。 * Admin API * ADC * Ingress Controller 创建一个路由如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ip-restriction-route", "uri": "/anything", "plugins": { "ip-restriction": { "whitelist": [ "192.168.1.241" ] }, "real-ip": { "source": "arg_realip" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 从 URL 参数 `realip` 获取客户端 IP 地址。 adc.yaml ``` services: - name: ip-restriction-service routes: - name: ip-restriction-route uris: - /anything plugins: ip-restriction: whitelist: - "192.168.1.241" real-ip: source: arg_realip upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 从 URL 参数 `realip` 获取客户端 IP 地址。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD ip-restriction-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ip-restriction-realip-plugin-config spec: plugins: - name: ip-restriction config: whitelist: - "192.168.1.241" - name: real-ip config: source: arg_realip --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ip-restriction-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ip-restriction-realip-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ip-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ip-restriction-route spec: ingressClassName: apisix http: - name: ip-restriction-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: ip-restriction enable: true config: whitelist: - "192.168.1.241" - name: real-ip enable: true config: source: arg_realip ``` ❶ 使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 从 URL 参数 `realip` 获取客户端 IP 地址。 将配置应用到集群: ``` kubectl apply -f ip-restriction-ic.yaml ``` 发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything?realip=192.168.1.241" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 发送另一个使用不同 IP 地址的请求: ``` curl -i "http://127.0.0.1:9080/anything?realip=192.168.10.24" ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * whitelist array\[string] *** 白名单 IP 列表。支持 IPv4、IPv6 和 CIDR 格式。 `whitelist` 和 `blacklist` 必须至少配置其中之一,但不能同时配置。 * blacklist array\[string] *** 黑名单 IP 列表。支持 IPv4、IPv6 和 CIDR 格式。 `whitelist` 和 `blacklist` 必须至少配置其中之一,但不能同时配置。 * message string 默认值:`Your IP address is not allowed` *** 当 IP 地址被拒绝访问时返回的消息。 * response\_code integer 默认值:`403` 有效值: 介于 403 和 404 之间(含边界值) *** 因 IP 地址限制拒绝请求时返回的 HTTP 响应码。自 API7 企业版 3.10.3 起可用。 --- # jwe-decrypt API7 企业版 3.10.7 起可用。 `jwe-decrypt` 插件从请求头读取五段式紧凑 Token,根据 Token 的 `kid` 选择 [Consumer](https://docs.apiseven.com/apisix/key-concepts/consumers.md),并使用 AES-256-GCM 解密加密 Payload。在代理请求之前,插件会将明文写入配置的请求头。你可以在 APISIX [路由](https://docs.apiseven.com/apisix/key-concepts/routes.md)或[服务](https://docs.apiseven.com/apisix/key-concepts/services.md)上启用该插件,并在 Consumer 上配置 32 字节的解密 Secret。 该 Token 采用 [JWE 紧凑序列化](https://datatracker.ietf.org/doc/html/rfc7516#section-3.1)。插件根据解码后受保护请求头中的 `kid` 选择 Consumer,并以 direct 加密方式和 A256GCM 解密 Payload。 有两项行为取决于版本。在 API7 企业版 3.10.7 及以后的版本中,编码后的受保护请求头会按 RFC 7516 的规定被用作 AES-GCM 附加认证数据(AAD),因此标准 JWE 库生成的 Token 可以直接使用;不带 AAD 的 Token 同样仍被接受,所以升级前签发的 Token 继续有效。携带的 `alg` 不是 `dir`、或者 `enc` 不是 `A256GCM` 的 Token 会被直接拒绝,而不是在后续解密时才失败;省略其中任一字段的 Token 仍然会被接受。在不具备这两项行为的版本中,受保护请求头既不会被用作 AAD,也不会被校验:`alg` 和 `enc` 会被忽略,标准 RFC 7516 库不能直接互操作,Token 必须严格按照下文所述格式、由固定且可信的生成器生成,并且请求头字段不能被视为已经过认证。 警告 解密后的明文会通过请求头转发。对于敏感明文,不要仅依赖 HTTPS 上游:除非上游启用了校验并提供了自己的 CA 证书,否则上游服务器证书不会被验证;自 API7 企业版 3.10.7 起,该校验对 HTTPS 和 gRPC 上游均生效。请通过能够验证上游服务器身份的代理或服务网格等经过认证和保护的网络路径发送请求,同时限制对上游的访问,并避免记录配置的转发请求头。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `jwe-decrypt` 插件。 ### 解密插件 Token 中的数据[​](#解密插件-token-中的数据 "解密插件 Token 中的数据的直接链接") 以下示例演示如何解密插件 Token。在 APISIX 外部生成 Token,在 Consumer 上配置匹配的解密密钥,并创建启用 `jwe-decrypt` 插件的路由来解密 Authorization 请求头。 * Admin API * ADC * Ingress Controller 创建一个启用 `jwe-decrypt` 的 Consumer 并配置解密密钥: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack", "plugins": { "jwe-decrypt": { "key": "jack-key", "secret": "key-length-should-be-32-chars123" } } }' ``` 创建一个启用 `jwe-decrypt` 的路由以解密 Authorization 头: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwe-decrypt-route", "uri": "/anything/jwe", "plugins": { "jwe-decrypt": { "header": "Authorization", "forward_header": "Authorization" } }, "upstream": { "type": "roundrobin", "scheme": "https", "nodes": { "httpbin.org:443": 1 } } }' ``` adc.yaml ``` consumers: - username: jack plugins: jwe-decrypt: key: jack-key secret: key-length-should-be-32-chars123 services: - name: jwe-decrypt-service routes: - name: jwe-decrypt-route uris: - /anything/jwe plugins: jwe-decrypt: header: Authorization forward_header: Authorization upstream: type: roundrobin scheme: https nodes: - host: httpbin.org port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 以下 Ingress Controller 配置仅将公共 HTTPBin 用于本页所示的非敏感演示 Payload。转发真实的解密数据之前,请将其替换为受控上游,并使用经过认证和保护的网络路径。除非上游启用了校验并提供了自己的 CA 证书,否则上游服务器证书不会被验证;否则请使用能够验证上游服务器身份的代理或服务网格。 * Gateway API * APISIX CRD jwe-decrypt-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack spec: gatewayRef: name: apisix plugins: - name: jwe-decrypt config: key: jack-key secret: key-length-should-be-32-chars123 --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: jwe-decrypt-plugin-config spec: plugins: - name: jwe-decrypt config: header: Authorization forward_header: Authorization --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: jwe-decrypt-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything/jwe filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: jwe-decrypt-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f jwe-decrypt-ic.yaml ``` jwe-decrypt-apisix-crd.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack spec: ingressClassName: apisix plugins: - name: jwe-decrypt config: key: jack-key secret: key-length-should-be-32-chars123 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: jwe-decrypt-route spec: ingressClassName: apisix http: - name: jwe-decrypt-route match: paths: - /anything/jwe upstreams: - name: httpbin-external-domain plugins: - name: jwe-decrypt config: header: Authorization forward_header: Authorization ``` 将配置应用到集群: ``` kubectl apply -f jwe-decrypt-apisix-crd.yaml ``` 在 APISIX 外部生成 Token:使用 AES-256-GCM 加密 Payload,并使用 Consumer Secret 作为密钥。在 API7 企业版 3.10.7 及以后的版本中,编码后的受保护请求头会被用作 AAD,因此标准 RFC 7516 库生成的 Token 即可被接受;在不具备该行为的版本中,受保护请求头不会被用作 AAD,Token 必须在不带 AAD 的情况下生成。从 3.10.7 起两种形式都能被接受。Token 结构如下: ``` base64url(header)..base64url(iv).base64url(ciphertext).base64url(tag) ``` 其中,请求头为 `{"alg":"dir","enc":"A256GCM","kid":""}`,`kid` 用于标识 Consumer。在 API7 企业版 3.10.7 及以后的版本中,`alg` 和 `enc` 会被校验——取值不是 `dir` 或 `A256GCM` 的会被拒绝——并且编码后的请求头会被用作 AAD 进行认证;在不具备该行为的版本中,这两个字段既不会被校验也不会被认证。请为每个 Token 使用唯一且随机生成的 IV;切勿对同一个密钥重复使用 IV。 Payload 和认证标签使用 AES-256-GCM 解密。在 API7 企业版 3.10.7 及以后的版本中,会先带着编码后的受保护请求头作为 AAD 尝试解密,再不带 AAD 尝试一次,因此标准 JWE 库生成的 Token 和不带 AAD 的 Token 都能正常工作。在不具备该行为的版本中,受保护请求头从不作为 AAD 传入,使用标准受保护请求头 AAD 生成的 Token 会失败并报告 `failed to decrypt JWE token`。 在 `Authorization` 请求头中携带加密的插件 Token 向路由发送请求。例如,以下 Token 使用上面配置的 Secret 和 Consumer Key `jack-key`,对 Payload `{"uid":10000,"uname":"test"}` 进行加密: ``` curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A' ``` 你应该看到类似于以下的响应,其中 `Authorization` 头显示了 Payload 的明文: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Authorization": "{\"uid\":10000,\"uname\":\"test\"}", "Host": "127.0.0.1", "User-Agent": "curl/8.1.2", "X-Amzn-Trace-Id": "Root=1-6510f2c3-1586ec011a22b5094dbe1896", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "GET", "origin": "127.0.0.1, 119.143.79.94", "url": "http://127.0.0.1/anything/jwe" } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 ### 消费者[​](#消费者 "消费者的直接链接") 以下是可在[消费者](https://docs.apiseven.com/apisix/key-concepts/consumers.md)上配置的插件属性。 * key string 必填 *** 标识 Consumer 凭据的唯一 Key。 * secret string 必填 有效值: 32 字节 *** 32 字节的共享对称密钥,需以字面值给出——可以是明文,也可以在设置 `is_base64_encoded` 后使用 base64url 编码。控制面会按写入时的字面值校验长度,因此 `$env://` 或 `$secret://` 引用会被拒绝,除非该引用字符串本身恰好是 32 个字符。 * is\_base64\_encoded boolean 默认值:`false` *** 如果 Secret 使用 base64url 编码,则设置为 true。解码后的 Secret 仍必须为 32 字节。 ### 路由或服务[​](#路由或服务 "路由或服务的直接链接") 以下是可在[路由](https://docs.apiseven.com/apisix/key-concepts/routes.md)或[服务](https://docs.apiseven.com/apisix/key-concepts/services.md)上配置的插件属性。 * header string 必填 默认值:`Authorization` *** 从中获取令牌的请求头。 * forward\_header string 必填 默认值:`Authorization` *** 将明文传递给上游的请求头名称。 * strict boolean 默认值:`true` *** 如果为 true,则在缺少加密插件 Token 时返回 403 错误。如果为 false,则在未找到 Token 时继续处理请求。 --- # jwt-auth `jwt-auth` 插件支持使用 [JSON Web Token (JWT)](https://jwt.io/) 作为机制,在客户端访问上游资源之前验证其身份。 启用后,JWT 凭据会配置在 [消费者](https://docs.apiseven.com/apisix/key-concepts/consumers.md) 上,客户端携带签名后的令牌向 APISIX 标识自己。令牌可以包含在请求 URL 查询字符串、请求头或 Cookie 中。APISIX 随后将验证令牌,以决定允许或拒绝请求访问上游资源。 消费者成功通过身份认证后,APISIX 会在将请求代理到上游服务之前添加额外的请求头,例如 `X-Consumer-Username`、`X-Credential-Identifier` 以及配置的其他消费者自定义请求头。上游服务可以据此区分消费者并按需实现额外逻辑。如果这些值不可用,则不会添加相应的请求头。 关于 X-Consumer-Username 使用 Ingress Controller 配置消费者时,消费者名称会生成为 `namespace_consumername` 格式。因此,`X-Consumer-Username` 请求头也会采用此格式,而不只是 `consumername`。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `jwt-auth` 插件。 ### 使用 JWT 进行消费者认证[​](#使用-jwt-进行消费者认证 "使用 JWT 进行消费者认证的直接链接") 以下示例演示了如何实现基于 JWT 的消费者密钥认证。 * Admin API * ADC * Ingress Controller 创建消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack" }' ``` 为消费者创建 `jwt-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jack-key", "secret": "jack-hs256-secret-that-is-very-long" } } }' ``` 创建一个启用 `jwt-auth` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-route", "uri": "/headers", "plugins": { "jwt-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个配置了 `jwt-auth` 插件的路由: adc.yaml ``` consumers: - username: jack credentials: - name: jwt-auth type: jwt-auth config: key: jack-key secret: jack-hs256-secret-that-is-very-long services: - name: jwt-auth-service routes: - name: jwt-route uris: - /headers plugins: jwt-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个配置了 `jwt-auth` 插件的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: primary-cred config: key: jack-key secret: jack-hs256-secret-that-is-very-long --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: jwt-auth-plugin-config spec: plugins: - name: jwt-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: jwt-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: jwt-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 创建一个使用 HS256 的 `jwt-auth` 凭证消费者,并按如下方式创建一个启用了 `jwt-auth` 插件的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack spec: ingressClassName: apisix authParameter: jwtAuth: value: key: jack-key secret: jack-hs256-secret-that-is-very-long --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: jwt-route spec: ingressClassName: apisix http: - name: jwt-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: _meta: disable: false ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 要为 `jack` 签发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io) 或其他工具。如果你使用的是 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 在算法栏填写 `HS256`。 * 在 **Valid secret** 部分将密钥更新为 `jack-hs256-secret-that-is-very-long`。 * 使用消费者密钥 `jack-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "key": "jack-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU ``` 向路由发送在 `Authorization` 请求头中携带 JWT 的请求: ``` curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "headers": { "Accept": "*/*", "Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjUvYzWLt4lFr546PNsr9TXuf0Az5opoM", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66ea951a-4d740d724bd2a44f174d4daf", "X-Consumer-Username": "jack", "X-Credential-Identifier": "cred-jack-jwt-auth", "X-Forwarded-Host": "127.0.0.1" } } ``` 发送带有无效令牌的请求: ``` curl -i "http://127.0.0.1:9080/headers" -H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjY2NDk2NDAsImtleSI6ImphY2sta2V5In0.kdhumNWrZFxjU_random_random" ``` 你应该收到类似于以下的 `HTTP/1.1 401 Unauthorized` 响应: ``` {"message":"failed to verify jwt"} ``` ### 在请求头、查询字符串或 Cookie 中携带 JWT[​](#在请求头查询字符串或-cookie-中携带-jwt "在请求头、查询字符串或 Cookie 中携带 JWT的直接链接") 以下示例演示了如何接受指定请求头、查询字符串和 Cookie 中的 JWT。 * Admin API * ADC * Ingress Controller 创建消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack" }' ``` 为消费者创建 `jwt-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jack-key", "secret": "jack-hs256-secret-that-is-very-long" } } }' ``` 创建一个启用 `jwt-auth` 插件的路由,并指定携带令牌的请求参数: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-route", "uri": "/get", "plugins": { "jwt-auth": { "header": "jwt-auth-header", "query": "jwt-query", "cookie": "jwt-cookie" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个配置了 `jwt-auth` 插件的路由: adc.yaml ``` consumers: - username: jack credentials: - name: jwt-auth type: jwt-auth config: key: jack-key secret: jack-hs256-secret-that-is-very-long services: - name: jwt-auth-service routes: - name: jwt-route uris: - /get plugins: jwt-auth: header: jwt-auth-header query: jwt-query cookie: jwt-cookie upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个配置了 `jwt-auth` 插件的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: primary-cred config: key: jack-key secret: jack-hs256-secret-that-is-very-long --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: jwt-auth-plugin-config spec: plugins: - name: jwt-auth config: _meta: disable: false header: jwt-auth-header query: jwt-query cookie: jwt-cookie --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: jwt-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: jwt-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个配置了 `jwt-auth` 插件的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack spec: ingressClassName: apisix authParameter: jwtAuth: value: key: jack-key secret: jack-hs256-secret-that-is-very-long --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: jwt-route spec: ingressClassName: apisix http: - name: jwt-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: header: jwt-auth-header query: jwt-query cookie: jwt-cookie ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 要为 `jack` 签发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io) 或其他工具。如果你使用的是 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 在算法栏填写 `HS256`。 * 在 **Valid secret** 部分将密钥更新为 `jack-hs256-secret-that-is-very-long`。 * 使用消费者密钥 `jack-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "key": "jack-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU ``` #### 在请求头中验证 JWT[​](#在请求头中验证-jwt "在请求头中验证 JWT的直接链接") 发送带有请求头 JWT 的请求: ``` curl -i "http://127.0.0.1:9080/get" -H "jwt-auth-header: ${jwt_token}" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "Jwt-Auth-Header": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU", ... }, ... } ``` #### 在查询字符串中验证 JWT[​](#在查询字符串中验证-jwt "在查询字符串中验证 JWT的直接链接") 发送带有查询字符串 JWT 的请求: ``` curl -i "http://127.0.0.1:9080/get?jwt-query=${jwt_token}" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": { "jwt-query": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU" }, "headers": { "Accept": "*/*", ... }, "origin": "127.0.0.1, 183.17.233.107", "url": "http://127.0.0.1/get?jwt-query=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTEyOTA0NH0.EiktFX7di_tBbspbjmqDKoWAD9JG39Wo_CAQ1LZ9voQ" } ``` #### 在 Cookie 中验证 JWT[​](#在-cookie-中验证-jwt "在 Cookie 中验证 JWT的直接链接") 发送带有 Cookie JWT 的请求: ``` curl -i "http://127.0.0.1:9080/get" --cookie jwt-cookie=${jwt_token} ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Cookie": "jwt-cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU", ... }, ... } ``` ### 在环境变量中管理密钥[​](#在环境变量中管理密钥 "在环境变量中管理密钥的直接链接") 以下示例演示了如何将 `jwt-auth` 消费者密钥保存到环境变量并在配置中引用它。 APISIX 支持引用通过 [NGINX `env` 指令](https://nginx.org/en/docs/ngx_core_module.html#env) 配置的系统和用户环境变量。 将密钥保存到环境变量: ``` export JACK_JWT_SECRET=jack-hs256-secret-that-is-very-long ``` 提示 如果你在 Docker 中运行 APISIX,你应该在启动容器时使用 `-e` 标志设置环境变量。 * Admin API * ADC 创建消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack" }' ``` 为消费者创建 `jwt-auth` 凭据并引用环境变量: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jack-key", "secret": "$env://JACK_JWT_SECRET" } } }' ``` 创建一个启用 `jwt-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-route", "uri": "/get", "plugins": { "jwt-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个通过环境变量引用 `jwt-auth` 凭证的消费者,并按如下方式创建一个启用了 `jwt-auth` 插件的路由: adc.yaml ``` consumers: - username: jack credentials: - name: jwt-auth type: jwt-auth config: key: jack-key secret: $env://JACK_JWT_SECRET services: - name: jwt-auth-service routes: - name: jwt-route uris: - /get plugins: jwt-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 要为 `jack` 签发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io) 或其他工具。如果你使用的是 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 在算法栏填写 `HS256`。 * 在 **Valid secret** 部分将密钥更新为 `jack-hs256-secret-that-is-very-long`。 * 使用消费者密钥 `jack-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "key": "jack-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU ``` 发送带有请求头 JWT 的请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 ### 在密钥管理器中管理密钥[​](#在密钥管理器中管理密钥 "在密钥管理器中管理密钥的直接链接") 以下示例演示了如何在 [HashiCorp Vault](https://www.vaultproject.io) 中管理 `jwt-auth` 消费者密钥,并在插件配置中引用它。 在 Docker 中启动 Vault 开发服务器: ``` docker run -d \ --name vault \ -p 8200:8200 \ --cap-add IPC_LOCK \ -e VAULT_DEV_ROOT_TOKEN_ID=root \ -e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \ vault:1.9.0 \ vault server -dev ``` APISIX 目前支持 [Vault KV 引擎版本 1](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1)。在 Vault 中启用它: ``` docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv" ``` 你应该看到类似于以下的响应: ``` Success! Enabled the kv secrets engine at: kv/ ``` * Admin API * ADC 创建 [Secret](https://docs.apiseven.com/apisix/key-concepts/secrets.md) 并配置 Vault 地址和其他连接信息: ``` curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "http://127.0.0.1:8200", "prefix": "kv/apisix", "token": "root" }' ``` ❶ 相应地调整 Vault 地址。 创建消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack" }' ``` 为消费者创建 `jwt-auth` 凭据并引用该 Secret: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jwt-vault-key", "secret": "$secret://vault/jwt/jack/jwt-secret" } } }' ``` 创建一个启用 `jwt-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-route", "uri": "/get", "plugins": { "jwt-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建 Secret 并配置 Vault 地址: adc.yaml ``` secrets: - name: vault-jwt vault: url: http://127.0.0.1:8200 prefix: kv/apisix token: root consumers: - username: jack credentials: - name: jwt-auth type: jwt-auth config: key: jwt-vault-key secret: $secret://vault-jwt/jack/jwt-secret services: - name: jwt-auth-service routes: - name: jwt-route uris: - /get plugins: jwt-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 相应地调整 Vault 地址。 ❷ 引用 Secret Manager 中的 Secret。 将配置同步到网关: ``` adc sync -f adc.yaml ``` 在 Vault 中将 `jwt-auth` 密钥值设置为 `vault-hs256-secret-that-is-very-long`: ``` docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack jwt-secret=vault-hs256-secret-that-is-very-long" ``` 你应该看到类似于以下的响应: ``` Success! Data written to: kv/apisix/jack ``` 要签发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io) 或其他工具。如果你使用的是 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 在算法栏填写 `HS256`。 * 在 **Valid secret** 部分将密钥更新为 `vault-hs256-secret-that-is-very-long`。 * 使用消费者密钥 `jwt-vault-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "key": "jwt-vault-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.i2pLj7QcQvnlSjB7iV5V522tIV43boQRtee7L0rwlkQ ``` 发送带有请求头令牌的请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 ### 使用 RS256 算法签署 JWT[​](#使用-rs256-算法签署-jwt "使用 RS256 算法签署 JWT的直接链接") 以下示例演示了在实施 JWT 进行消费者身份认证时,如何使用非对称算法(如 RS256)来签署和验证 JWT。你将使用 [openssl](https://openssl-library.org/source/) 生成 RSA 密钥对,并使用 [JWT.io](https://jwt.io) 生成 JWT,以更好地理解 JWT 的组成。 生成 2048 位 RSA 私钥并提取 PEM 格式的对应公钥: ``` openssl genrsa -out jwt-rsa256-private.pem 2048 openssl rsa -in jwt-rsa256-private.pem -pubout -out jwt-rsa256-public.pem ``` 你应该在当前工作目录中看到生成的 `jwt-rsa256-private.pem` 和 `jwt-rsa256-public.pem`。 访问 [JWT.io 的 JWT 编码器](https://jwt.io) 并执行以下操作: * 在算法栏填写 `RS256`。 * 将私钥内容复制并粘贴到 **SIGN JWT: PRIVATE KEY** 部分。 * 使用消费者密钥 `jack-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 你的 payload 应该类似于以下内容: ``` { "key": "jack-key", "nbf": 1729132271 } ``` 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.K-I13em84kAcyH1jfIJl7ls_4jlwg1GzEzo5_xrDu-3wt3Xa3irS6naUsWpxX-a-hmcZZxRa9zqunqQjUP4kvn5e3xg2f_KyCR-_ZbwqYEPk3bXeFV1l4iypv6z5L7W1Niharun-dpMU03b1Tz64vhFx6UwxNL5UIZ7bunDAo_BXZ7Xe8rFhNHvIHyBFsDEXIBgx8lNYMq8QJk3iKxZhZZ5Om7lgYjOOKRgew4WkhBAY0v1AkO77nTlvSK0OEeeiwhkROyntggyx-S-U222ykMQ6mBLxkP4Cq5qHwXD8AUcLk5mhEij-3QhboYnt7yhKeZ3wDSpcjDvvL2aasC25ng ``` * Admin API * ADC * Ingress Controller 创建消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack" }' ``` 为消费者创建 `jwt-auth` 凭据并配置 RSA 密钥: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jack-key", "algorithm": "RS256", "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoTxe7ZPycrEP0SK4OBA2\n0OUQsDN9gSFSHVvx/t++nZNrFxzZnV6q6/TRsihNXUIgwaOu5icFlIcxPL9Mf9UJ\na5/XCQExp1TxpuSmjkhIFAJ/x5zXrC8SGTztP3SjkhYnQO9PKVXI6ljwgakVCfpl\numuTYqI+ev7e45NdK8gJoJxPp8bPMdf8/nHfLXZuqhO/btrDg1x+j7frDNrEw+6B\nCK2SsuypmYN+LwHfaH4Of7MQFk3LNIxyBz0mdbsKJBzp360rbWnQeauWtDymZxLT\nATRNBVyl3nCNsURRTkc7eyknLaDt2N5xTIoUGHTUFYSdE68QWmukYMVGcEHEEPkp\naQIDAQAB\n-----END PUBLIC KEY-----" } } }' ``` ❶ 将消费者密钥配置为 `jack-key`。 ❷ 将 JWT 签名算法配置为 `RS256`。 ❸ 配置 RSA 公钥。 提示 你应该在起始行之后和结束行之前添加换行符,例如 `-----BEGIN PUBLIC KEY-----\n......\n-----END PUBLIC KEY-----`。 密钥内容可以直接拼接。 创建一个启用 `jwt-auth` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-route", "uri": "/headers", "plugins": { "jwt-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个使用 RS256 算法的 `jwt-auth` 凭证消费者,并按如下方式创建一个启用了 `jwt-auth` 插件的路由: adc.yaml ``` consumers: - username: jack credentials: - name: jwt-auth type: jwt-auth config: key: jack-key algorithm: RS256 public_key: | -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoTxe7ZPycrEP0SK4OBA2 0OUQsDN9gSFSHVvx/t++nZNrFxzZnV6q6/TRsihNXUIgwaOu5icFlIcxPL9Mf9UJ a5/XCQExp1TxpuSmjkhIFAJ/x5zXrC8SGTztP3SjkhYnQO9PKVXI6ljwgakVCfpl umuTYqI+ev7e45NdK8gJoJxPp8bPMdf8/nHfLXZuqhO/btrDg1x+j7frDNrEw+6B CK2SsuypmYN+LwHfaH4Of7MQFk3LNIxyBz0mdbsKJBzp360rbWnQeauWtDymZxLT ATRNBVyl3nCNsURRTkc7eyknLaDt2N5xTIoUGHTUFYSdE68QWmukYMVGcEHEEPkp aQIDAQAB -----END PUBLIC KEY----- services: - name: jwt-auth-service routes: - name: jwt-route uris: - /headers plugins: jwt-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个使用 RS256 算法的 `jwt-auth` 凭证消费者,并按如下方式创建一个启用了 `jwt-auth` 插件的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: primary-cred config: key: jack-key algorithm: RS256 public_key: | -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoTxe7ZPycrEP0SK4OBA2 0OUQsDN9gSFSHVvx/t++nZNrFxzZnV6q6/TRsihNXUIgwaOu5icFlIcxPL9Mf9UJ a5/XCQExp1TxpuSmjkhIFAJ/x5zXrC8SGTztP3SjkhYnQO9PKVXI6ljwgakVCfpl umuTYqI+ev7e45NdK8gJoJxPp8bPMdf8/nHfLXZuqhO/btrDg1x+j7frDNrEw+6B CK2SsuypmYN+LwHfaH4Of7MQFk3LNIxyBz0mdbsKJBzp360rbWnQeauWtDymZxLT ATRNBVyl3nCNsURRTkc7eyknLaDt2N5xTIoUGHTUFYSdE68QWmukYMVGcEHEEPkp aQIDAQAB -----END PUBLIC KEY----- --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: jwt-auth-plugin-config spec: plugins: - name: jwt-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: jwt-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: jwt-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 创建一个使用 RS256 算法的 `jwt-auth` 凭证消费者,并按如下方式创建一个启用了 `jwt-auth` 插件的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack spec: ingressClassName: apisix authParameter: jwtAuth: value: key: jack-key algorithm: RS256 public_key: | -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyBhBBT5u2BtQs3+s2nnq IXq9DRD8rWrmuk9lTI+rvzELaPZYzT7YxhBGuRJmbW+RnrIIB6dG6v9Kpn18qsvi 3u6UfsXKtoXckdk2tTCXSweNg1rzR9Szf/TxLSoi3KqA/0b/l9DqO9LYiWacEGgS mqs0bCKtvxq+0TGQfuPHJiapvzgPTT1CYAp84CYDvyIo6d4NJOiPPSTEb1jxagSq eLGZ3LVLZjSOC1kP4rbZP5U2VBMbkAtPtdFB1rOTCLykOQrH5eJxYxMkgiaDe9Da ZilQ3vhGBTeqPL07NwOoiK0/iuBojMCdCKOdZfqgsBpEPP7qxqM3GNgPjAY0ah8x awIDAQAB -----END PUBLIC KEY----- --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: jwt-route spec: ingressClassName: apisix http: - name: jwt-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: _meta: disable: false ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 要进行验证,请向路由发送在 `Authorization` 请求头中携带 JWT 的请求: ``` curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 ### 将消费者自定义 ID 添加到请求头[​](#将消费者自定义-id-添加到请求头 "将消费者自定义 ID 添加到请求头的直接链接") 以下示例演示了如何将消费者自定义 ID 添加到已认证请求的 `Consumer-Custom-Id` 请求头中,以便按需实现额外逻辑。 * Admin API * ADC * Ingress Controller 创建一个带有自定义 ID 标签的消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack", "labels": { "custom_id": "495aec6a" } }' ``` 为消费者创建 `jwt-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jack-key", "secret": "jack-hs256-secret-that-is-very-long" } } }' ``` 创建一个启用 `jwt-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-auth-route", "uri": "/anything", "plugins": { "jwt-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个按如下方式启用了 `jwt-auth` 插件的路由: adc.yaml ``` consumers: - username: jack labels: custom_id: "495aec6a" credentials: - name: jwt-auth type: jwt-auth config: key: jack-key secret: jack-hs256-secret-that-is-very-long services: - name: jwt-auth-service routes: - name: jwt-auth-route uris: - /anything plugins: jwt-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `jwt-auth` 凭证的消费者,以及一个启用了 `jwt-auth` 插件的路由: * Gateway API * APISIX CRD jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack labels: custom_id: "495aec6a" spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: primary-cred config: key: jack-key secret: jack-hs256-secret-that-is-very-long --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: jwt-auth-plugin-config spec: plugins: - name: jwt-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: jwt-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: jwt-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack labels: custom_id: "495aec6a" spec: ingressClassName: apisix authParameter: jwtAuth: value: key: jack-key secret: jack-hs256-secret-that-is-very-long --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: jwt-auth-route spec: ingressClassName: apisix http: - name: jwt-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: _meta: disable: false ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 要为 `jack` 签发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io) 或其他工具。如果你使用的是 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 在算法栏填写 `HS256`。 * 在 **Valid secret** 部分将密钥更新为 `jack-hs256-secret-that-is-very-long`。 * 使用消费者密钥 `jack-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "key": "jack-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU ``` 要进行验证,请向路由发送在 `Authorization` 请求头中携带 JWT 的请求: ``` curl -i "http://127.0.0.1:9080/anything" -H "Authorization: ${jwt_token}" ``` 你应该看到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "headers": { "Accept": "*/*", "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-6873b19d-329331db76e5e7194c942b47", "X-Consumer-Custom-Id": "495aec6a", "X-Consumer-Username": "aic_jack", "X-Forwarded-Host": "127.0.0.1" }, "url": "http://127.0.0.1/anything" } ``` 如果你想将更多消费者自定义请求头添加到已认证请求中,请参阅 [`attach-consumer-label`](https://docs.apiseven.com/hub/attach-consumer-label.md) 插件。 ### 匿名消费者的速率限制[​](#匿名消费者的速率限制 "匿名消费者的速率限制的直接链接") 以下示例演示了如何针对常规消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者无需认证且配额较少。 * Admin API * ADC * Ingress Controller 创建常规消费者 `jack` 并配置 `limit-count` 插件,允许在 30 秒窗口内有 3 次配额: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack", "plugins": { "limit-count": { "count": 3, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 为消费者 `jack` 创建 `jwt-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-jwt-auth", "plugins": { "jwt-auth": { "key": "jack-key", "secret": "jack-hs256-secret-that-is-very-long" } } }' ``` 创建匿名用户 `anonymous` 并配置 `limit-count` 插件,允许在 30 秒窗口内有 1 次配额: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "anonymous", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 创建路由并配置 `jwt-auth` 插件以接受匿名消费者 `anonymous` 绕过认证: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "jwt-auth-route", "uri": "/anything", "plugins": { "jwt-auth": { "anonymous_consumer": "anonymous" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: adc.yaml ``` consumers: - username: jack plugins: limit-count: count: 3 time_window: 30 rejected_code: 429 policy: local credentials: - name: jwt-auth type: jwt-auth config: key: jack-key secret: jack-hs256-secret-that-is-very-long - username: anonymous plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 policy: local services: - name: anonymous-rate-limit-service routes: - name: jwt-auth-route uris: - /anything plugins: jwt-auth: anonymous_consumer: anonymous upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: primary-key config: key: jack-key secret: jack-hs256-secret-that-is-very-long plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: anonymous spec: gatewayRef: name: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: jwt-auth-plugin-config spec: plugins: - name: jwt-auth config: anonymous_consumer: aic_anonymous # namespace_consumername --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: jwt-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: jwt-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 为消费者配置不同的限流策略,并创建一个接受匿名用户的路由: jwt-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack spec: ingressClassName: apisix authParameter: jwtAuth: value: key: jack-key secret: jack-hs256-secret-that-is-very-long plugins: - name: limit-count enable: true config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: anonymous spec: ingressClassName: apisix plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: jwt-auth-route spec: ingressClassName: apisix http: - name: jwt-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: anonymous_consumer: aic_anonymous ``` 将配置应用到集群: ``` kubectl apply -f jwt-auth-ic.yaml ``` 要为 `jack` 签发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io) 或其他工具。如果你使用的是 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 在算法栏填写 `HS256`。 * 在 **Valid secret** 部分将密钥更新为 `jack-hs256-secret-that-is-very-long`。 * 使用消费者密钥 `jack-key` 更新 payload;并添加 UNIX 时间戳格式的 `exp` 或 `nbf`。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "key": "jack-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量中: ``` export jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqYWNrLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.UEPXy5jpid624T1XpfjM0PLY73LZPjV3Qt8yZ92kVuU ``` 要验证速率限制,请使用 `jack` 的 JWT 发送五个连续请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H "Authorization: ${jwt_token}" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示在 5 个请求中,3 个请求成功(状态码 200),而其他请求被拒绝(状态码 429)。 ``` 200: 3, 429: 2 ``` 发送五个匿名请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示只有一个请求成功: ``` 200: 1, 429: 4 ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 ### 凭据[​](#凭据 "凭据的直接链接") 以下是可在 [凭据](https://docs.apiseven.com/apisix/key-concepts/credentials.md) 上配置的插件属性。 * key string 必填 有效值: 非空 *** 唯一标识消费者凭据的密钥。 * secret string 有效值: 非空 *** 算法为对称时用于签名和验证 JWT 的共享密钥。当使用 `HS256`、`HS384` 或 `HS512` 作为算法时必填。 该密钥在存储到 etcd 之前会使用 AES 加密。你也可以将其存储在环境变量中并使用 `env://` 前缀引用,或者存储在如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv) 等密钥管理器中,并使用 `secret://` 前缀引用。更多信息请参考[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * public\_key string *** RSA 或 ECDSA 公钥。如果 `algorithm` 为 `RS256`、`ES256`、`RS384`、`RS512`、`ES256`、`ES384`、`ES512`、`PS256`、`PS384`、`PS512` 或 `EdDSA`,则此项必填。 * algorithm string 默认值:`HS256` 有效值: `HS256`、`HS384`、`HS512`、`RS256`、`RS384`、`RS512`、`ES256`、`ES384`、`ES512`、`PS256`、`PS384`、`PS512`、`EdDSA` *** 用于签名和验证 Token 的算法。JWT Header 中的 `alg` 值必须与此配置值完全一致;不一致时会返回 `401 Unauthorized`。 * exp integer 默认值:`86400` 有效值: 大于或等于 1 *** 令牌的过期时间(秒)。 如果你不使用 APISIX 签署 JWT,则忽略此参数,你应该在签署 JWT 时在 payload 中指定过期时间。 * base64\_secret boolean 默认值:`false` *** 如果密钥是 base64 编码的,则设置为 true。 * lifetime\_grace\_period integer 默认值:`0` 有效值: 大于或等于 0 *** 宽限期(秒)。用于解决生成 JWT 的服务器与验证 JWT 的服务器之间的时钟偏差。 ### 路由或服务[​](#路由或服务 "路由或服务的直接链接") 以下是可在 [路由](https://docs.apiseven.com/apisix/key-concepts/routes.md) 或 [服务](https://docs.apiseven.com/apisix/key-concepts/services.md) 上配置的插件属性。 * header string 默认值:`authorization` *** 获取令牌的请求头。 * query string 默认值:`jwt` *** 获取令牌的查询字符串。优先级低于请求头。 * cookie string 默认值:`jwt` *** 获取令牌的 Cookie。优先级低于查询字符串。 * hide\_credentials boolean 默认值:`false` *** 如果为 true,则不将带有 JWT 的请求头、查询字符串或 Cookie 传递给上游服务。 * anonymous\_consumer string *** 匿名消费者名称。如果配置了此项,允许匿名用户绕过认证。详情请参考 [匿名消费者的速率限制](https://docs.apiseven.com/hub/jwt-auth.md#匿名消费者的速率限制)。 * claims\_to\_verify array\[string] 有效值: `exp` 和 `nbf` 的组合 *** 用于验证 Token 是否位于允许时间窗口内的 Claim。 非空列表会要求必须提供并校验列表中的每个 Claim。缺少任一已配置 Claim 的 Token 都会被拒绝。 当此选项未设置或为空时,APISIX 会校验已存在的 `exp` 和 `nbf`,但不要求必须提供这两个 Claim。 这些校验规则自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.17.0 起引入。 * key\_claim\_name string 默认值:`key` *** JWT Payload 中标识关联密钥的 Claim,例如 `iss`。 * store\_in\_ctx boolean 默认值:`false` *** 如果为 true,将 JWT Payload 存储在请求上下文变量 `ctx.jwt_auth_payload` 中。这允许在同一请求中 `jwt-auth` 之后执行的插件检索和使用 payload 信息。例如,要在 payload 中检索密钥,可以使用 `ctx.jwt_auth_payload.key`。 支持版本:APISIX 以及企业版 3.8.9 起。 * realm string 默认值:`jwt` *** 身份认证失败时返回的 `401 Unauthorized` 响应中 [`WWW-Authenticate`](https://datatracker.ietf.org/doc/html/rfc7235#section-4.1) 响应头的 Realm。例如: * 如果 `realm` 设置为 `jwt-auth`,401 响应将包含以下响应头: ``` WWW-Authenticate: Bearer realm="jwt-auth" ``` * 如果未配置 `realm`,401 响应将包含以下响应头: ``` WWW-Authenticate: Bearer realm="jwt" ``` 该参数在 API7 企业版版本 3.9.2 及更高版本,以及 Apache APISIX 版本 3.15.0 及更高版本中可用。 --- # kafka-logger `kafka-logger` 插件将请求和响应日志作为 JSON 对象分批推送到 Apache Kafka 集群,并支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `kafka-logger` 插件。 如需跟随示例操作,请先启动一个示例 Kafka 集群。Docker 示例会把 Broker 连接到 [APISIX Docker 快速入门](https://docs.apiseven.com/apisix/getting-started/.md)创建的 `apisix-quickstart-net` 网络,使网关能够解析 `notkafka:29092`。 * Docker * Kubernetes docker-compose.yml ``` services: zookeeper: image: confluentinc/cp-zookeeper:7.8.0 container_name: zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 networks: - apisix-quickstart-net notkafka: image: confluentinc/cp-kafka:7.8.0 container_name: notkafka depends_on: - zookeeper environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://notkafka:29092,PLAINTEXT_HOST://127.0.0.1:9092 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" ports: - "9092:9092" networks: - apisix-quickstart-net networks: apisix-quickstart-net: external: true ``` 启动容器: ``` docker compose up -d ``` 为 Zookeeper 和 Kafka Deployment 创建 Kubernetes 清单文件: kafka-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: zookeeper spec: replicas: 1 selector: matchLabels: app: zookeeper template: metadata: labels: app: zookeeper spec: containers: - name: zookeeper image: confluentinc/cp-zookeeper:7.8.0 env: - name: ZOOKEEPER_CLIENT_PORT value: "2181" - name: ZOOKEEPER_TICK_TIME value: "2000" ports: - containerPort: 2181 --- apiVersion: v1 kind: Service metadata: namespace: aic name: zookeeper spec: selector: app: zookeeper ports: - port: 2181 targetPort: 2181 type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: kafka-server spec: replicas: 1 selector: matchLabels: app: kafka-server template: metadata: labels: app: kafka-server spec: containers: - name: kafka-server image: confluentinc/cp-kafka:7.8.0 env: - name: KAFKA_BROKER_ID value: "1" - name: KAFKA_ZOOKEEPER_CONNECT value: "zookeeper:2181" - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP value: "PLAINTEXT:PLAINTEXT" - name: KAFKA_ADVERTISED_LISTENERS value: "PLAINTEXT://kafka-server.aic.svc:9092" - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR value: "1" - name: KAFKA_AUTO_CREATE_TOPICS_ENABLE value: "true" ports: - containerPort: 9092 --- apiVersion: v1 kind: Service metadata: namespace: aic name: kafka-server spec: selector: app: kafka-server ports: - port: 9092 targetPort: 9092 type: ClusterIP ``` 在配置的 Kafka 主题中等待消息: ``` kubectl apply -f kafka-deployment.yaml ``` 在配置的 Kafka 主题中等待消息: * Docker * Kubernetes ``` docker exec -it notkafka kafka-console-consumer --bootstrap-server localhost:9092 --topic test2 --from-beginning ``` ``` kubectl exec -n aic deploy/kafka-server -- kafka-console-consumer --bootstrap-server kafka-server.aic.svc:9092 --topic test2 --from-beginning ``` 打开一个新的终端会话以执行以下与 APISIX 相关的步骤。 ### 以不同的元日志格式记录日志[​](#以不同的元日志格式记录日志 "以不同的元日志格式记录日志的直接链接") 以下示例演示了如何在路由上启用 `kafka-logger` 插件,该插件记录对路由的客户端请求并将日志推送到 Kafka。你还将了解 `default` 和 `origin` 元日志格式之间的区别。 创建如下配置 `kafka-logger` 的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "kafka-logger-route", "uri": "/get", "plugins": { "kafka-logger": { "meta_format": "default", "brokers": [ { "host": "notkafka", "port": 29092 } ], "kafka_topic": "test2", "key": "key1", "batch_max_size": 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: kafka-logger-route plugins: kafka-logger: meta_format: "default" brokers: - host: "notkafka" port: 29092 kafka_topic: "test2" key: "key1" batch_max_size: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD kafka-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: kafka-logger-plugin-config spec: plugins: - name: kafka-logger config: meta_format: "default" brokers: - host: "kafka-server.aic.svc" port: 9092 kafka_topic: "test2" key: "key1" batch_max_size: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: kafka-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: kafka-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` kafka-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: kafka-logger-route spec: ingressClassName: apisix http: - name: kafka-logger-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: kafka-logger config: meta_format: "default" brokers: - host: "kafka-server.aic.svc" port: 9092 kafka_topic: "test2" key: "key1" batch_max_size: 1 ``` 应用配置: ``` kubectl apply -f kafka-logger-ic.yaml ``` ❶ `meta_format`: 设置为 `default` 日志格式。 ❷ `batch_max_size`: 设置为 1 以立即发送日志条目。 向路由发送请求以生成日志条目: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该看到 `HTTP/1.1 200 OK` 响应。 你应该在 Kafka 主题中看到类似于以下的日志条目: ``` { "latency": 411.00001335144, "request": { "querystring": {}, "headers": { "host": "127.0.0.1:9080", "user-agent": "curl/8.7.1", "accept": "*/*", "x-forwarded-proto": "http", "x-forwarded-host": "127.0.0.1", "x-forwarded-port": "9080" }, "method": "GET", "size": 83, "uri": "/get", "url": "http://127.0.0.1:9080/get" }, "response": { "headers": { "content-length": "233", "access-control-allow-credentials": "true", "content-type": "application/json", "connection": "close", "access-control-allow-origin": "*", "date": "Fri, 10 Nov 2023 06:02:44 GMT", "server": "APISIX/3.16.0" }, "status": 200, "size": 475 }, "route_id": "kafka-logger-route", "client_ip": "127.0.0.1", "server": { "hostname": "apisix", "version": "3.16.0" }, "apisix_latency": 18.00001335144, "service_id": "", "upstream_latency": 393, "start_time": 1699596164550, "upstream": "54.90.18.68:80" } ``` 将元日志格式更新为 `origin`: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/kafka-logger-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "kafka-logger": { "meta_format": "origin" } } }' ``` 更新 `adc.yaml`,将 `meta_format` 设置为 `origin`: adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: kafka-logger-route plugins: kafka-logger: meta_format: "origin" brokers: - host: "notkafka" port: 29092 kafka_topic: "test2" key: "key1" batch_max_size: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `kafka-logger-ic.yaml`,将 `meta_format` 设置为 `origin`: kafka-logger-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: kafka-logger-plugin-config spec: plugins: - name: kafka-logger config: meta_format: "origin" brokers: - host: "kafka-server.aic.svc" port: 9092 kafka_topic: "test2" key: "key1" batch_max_size: 1 ``` 更新 `kafka-logger-ic.yaml`,将 `meta_format` 设置为 `origin`: kafka-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: kafka-logger-route spec: ingressClassName: apisix http: - name: kafka-logger-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: kafka-logger config: meta_format: "origin" brokers: - host: "kafka-server.aic.svc" port: 9092 kafka_topic: "test2" key: "key1" batch_max_size: 1 ``` 应用更新后的配置: ``` kubectl apply -f kafka-logger-ic.yaml ``` 再次向路由发送请求以生成新的日志条目: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该看到 `HTTP/1.1 200 OK` 响应。 你应该在 Kafka 主题中看到类似于以下的日志条目: ``` GET /get HTTP/1.1 x-forwarded-proto: http x-forwarded-host: 127.0.0.1 user-agent: curl/8.7.1 x-forwarded-port: 9080 host: 127.0.0.1:9080 accept: */* ``` ### 将日志发送到启用 TLS 的 Broker[​](#send-logs-to-a-tls-enabled-broker "将日志发送到启用 TLS 的 Broker的直接链接") 以下 Docker 示例会在 `apisix-quickstart-net` 网络中启动一个使用 CA 签名 TLS 证书的本地 Kafka Broker。随后,网关会在验证证书的情况下连接该 Broker,并使用 Produce API 版本 `2`,使 Kafka 为消息记录时间戳。继续操作前,请安装 OpenSSL 和 Java `keytool` 命令。 生成示例 CA、用于 `kafka-tls` 容器主机名的 Broker 证书,以及 Kafka 所需的 Java KeyStore 和 TrustStore 文件: ``` mkdir -p kafka-tls-certs openssl req -x509 -newkey rsa:2048 -nodes -days 365 \ -subj "/CN=kafka-example-ca" \ -keyout kafka-tls-certs/ca.key \ -out kafka-tls-certs/ca.crt openssl req -newkey rsa:2048 -nodes \ -subj "/CN=kafka-tls" \ -keyout kafka-tls-certs/server.key \ -out kafka-tls-certs/server.csr printf "subjectAltName=DNS:kafka-tls\n" > kafka-tls-certs/server-ext.cnf openssl x509 -req -days 365 \ -in kafka-tls-certs/server.csr \ -CA kafka-tls-certs/ca.crt \ -CAkey kafka-tls-certs/ca.key \ -CAcreateserial \ -extfile kafka-tls-certs/server-ext.cnf \ -out kafka-tls-certs/server.crt openssl pkcs12 -export \ -name kafka-tls \ -in kafka-tls-certs/server.crt \ -inkey kafka-tls-certs/server.key \ -certfile kafka-tls-certs/ca.crt \ -out kafka-tls-certs/kafka.keystore.p12 \ -passout pass:changeit keytool -importkeystore -noprompt \ -srckeystore kafka-tls-certs/kafka.keystore.p12 \ -srcstoretype PKCS12 \ -srcstorepass changeit \ -destkeystore kafka-tls-certs/kafka.keystore.jks \ -deststoretype JKS \ -deststorepass changeit \ -destkeypass changeit keytool -importcert -noprompt \ -alias kafka-example-ca \ -file kafka-tls-certs/ca.crt \ -keystore kafka-tls-certs/kafka.truststore.jks \ -storepass changeit printf "changeit\n" > kafka-tls-certs/kafka_keystore_creds printf "changeit\n" > kafka-tls-certs/kafka_ssl_key_creds ``` 创建稍后用于验证记录的客户端配置: kafka-tls-certs/client.properties ``` security.protocol=SSL ssl.truststore.location=/etc/kafka/secrets/kafka.truststore.jks ssl.truststore.password=changeit ssl.endpoint.identification.algorithm=https ``` 在 APISIX Quickstart 网络中启动启用 TLS 的 Broker: ``` docker run -d \ --name kafka-tls \ --hostname kafka-tls \ --network apisix-quickstart-net \ -v "${PWD}/kafka-tls-certs:/etc/kafka/secrets:ro" \ -e KAFKA_NODE_ID=1 \ -e KAFKA_PROCESS_ROLES=broker,controller \ -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP="SSL:SSL,CONTROLLER:PLAINTEXT" \ -e KAFKA_ADVERTISED_LISTENERS="SSL://kafka-tls:9093" \ -e KAFKA_LISTENERS="SSL://:9093,CONTROLLER://:29093" \ -e KAFKA_CONTROLLER_QUORUM_VOTERS="1@kafka-tls:29093" \ -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \ -e KAFKA_INTER_BROKER_LISTENER_NAME=SSL \ -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \ -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \ -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \ -e KAFKA_SSL_KEYSTORE_FILENAME=kafka.keystore.jks \ -e KAFKA_SSL_KEYSTORE_CREDENTIALS=kafka_keystore_creds \ -e KAFKA_SSL_KEY_CREDENTIALS=kafka_ssl_key_creds \ -e KAFKA_SSL_TRUSTSTORE_LOCATION=/etc/kafka/secrets/kafka.truststore.jks \ -e KAFKA_SSL_TRUSTSTORE_PASSWORD=changeit \ -e KAFKA_SSL_CLIENT_AUTH=none \ -e CLUSTER_ID="4L6g3nShT-eMCtK--X86sw" \ apache/kafka:4.1.0 ``` 当 Broker 日志中出现 `Transition from STARTING to STARTED` 后,创建 Topic: ``` docker exec kafka-tls /opt/kafka/bin/kafka-topics.sh \ --bootstrap-server kafka-tls:9093 \ --command-config /etc/kafka/secrets/client.properties \ --create \ --if-not-exists \ --topic apisix-logs \ --partitions 1 \ --replication-factor 1 ``` 为路由配置设置 Broker 地址和 Topic: ``` export KAFKA_TLS_HOST="kafka-tls" export KAFKA_TLS_PORT="9093" export KAFKA_TOPIC="apisix-logs" ``` 将生成的 CA 证书复制到 Quickstart 网关。把它追加到现有系统 Trust Bundle 中,使网关继续信任容器中已安装的公共 CA 证书: ``` docker cp kafka-tls-certs/ca.crt \ apisix-quickstart:/usr/local/apisix/conf/kafka-example-ca.crt docker exec apisix-quickstart sh -c ' cat /etc/ssl/certs/ca-certificates.crt \ /usr/local/apisix/conf/kafka-example-ca.crt \ > /usr/local/apisix/conf/combined-ca-bundle.pem ' ``` 在 Quickstart 配置中更新 Trust Bundle 路径并重新加载网关: ``` docker exec apisix-quickstart sh -c ' config=/usr/local/apisix/conf/config.yaml certificate=/usr/local/apisix/conf/combined-ca-bundle.pem if grep -q "^ ssl_trusted_certificate:" "$config"; then sed "s#ssl_trusted_certificate:.*#ssl_trusted_certificate: $certificate#" "$config" elif grep -q "^ ssl:$" "$config"; then sed "/^ ssl:$/a\\ ssl_trusted_certificate: $certificate" "$config" else sed "/^apisix:$/a\\ ssl:\\ ssl_trusted_certificate: $certificate" "$config" fi > /tmp/config.yaml cat /tmp/config.yaml > /usr/local/apisix/conf/config.yaml apisix reload ' ``` 对于多实例部署,请将组合后的 Trust Bundle 和配置更改分发到每个网关实例。`kafka-tls` 主机名与示例 Broker 证书中的 DNS 名称匹配。 创建一条路由,将每条日志立即发送到 TLS Listener: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- <`;取值 `basic` 时使用标准的 `Authorization: Basic `,因此已有的 HTTP Basic 客户端无需改动即可认证。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `ldap-auth-advanced` 插件。 ### 前置条件[​](#前置条件 "前置条件的直接链接") 以下示例假设有一个可通过 `192.168.1.10:389` 访问的 LDAP 目录,用户条目位于 `ou=users,dc=example,dc=org` 下,其中一个用户的 `uid` 为 `johndoe`、密码为 `john-secret`,检索时以 `cn=admin,dc=example,dc=org` 身份绑定。请根据你自己的目录调整这些取值。 ### 对接 LDAP 目录完成认证[​](#对接-ldap-目录完成认证 "对接 LDAP 目录完成认证的直接链接") 以下示例演示了如何把 `consumer_required` 设为 `false`,只对接 LDAP 目录完成客户端认证,而不映射到消费者。 * Admin API * ADC * Ingress Controller 创建一个配置了 `ldap-auth-advanced` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ldap-auth-route", "uri": "/anything", "plugins": { "ldap-auth-advanced": { "ldap_uri": "192.168.1.10:389", "base_dn": "ou=users,dc=example,dc=org", "attribute": "uid", "bind_dn": "cn=admin,dc=example,dc=org", "ldap_password": "admin-secret", "consumer_required": false } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `ldap-auth-advanced` 插件的路由: adc.yaml ``` services: - name: ldap-auth-service routes: - name: ldap-auth-route uris: - /anything plugins: ldap-auth-advanced: ldap_uri: 192.168.1.10:389 base_dn: ou=users,dc=example,dc=org attribute: uid bind_dn: cn=admin,dc=example,dc=org ldap_password: admin-secret consumer_required: false upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 把配置同步到网关: ``` adc sync -f adc.yaml ``` 创建一个配置了 `ldap-auth-advanced` 插件的路由: * Gateway API * APISIX CRD ldap-auth-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ldap-auth-plugin-config spec: plugins: - name: ldap-auth-advanced config: ldap_uri: 192.168.1.10:389 base_dn: ou=users,dc=example,dc=org attribute: uid bind_dn: cn=admin,dc=example,dc=org ldap_password: admin-secret consumer_required: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ldap-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ldap-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 把配置应用到集群: ``` kubectl apply -f ldap-auth-ic.yaml ``` ldap-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ldap-auth-route spec: ingressClassName: apisix http: - name: ldap-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: ldap-auth-advanced enable: true config: ldap_uri: 192.168.1.10:389 base_dn: ou=users,dc=example,dc=org attribute: uid bind_dn: cn=admin,dc=example,dc=org ldap_password: admin-secret consumer_required: false ``` 把配置应用到集群: ``` kubectl apply -f ldap-auth-ic.yaml ``` #### 使用正确的凭据验证[​](#使用正确的凭据验证 "使用正确的凭据验证的直接链接") 用目录用户的凭据向该路由发送请求,凭据经 base64 编码后以 `ldap` 方案携带: ``` curl -i "http://127.0.0.1:9080/anything" \ -H "Authorization: ldap $(printf '%s' 'johndoe:john-secret' | base64)" ``` 应当收到 `HTTP/1.1 200 OK` 响应。 #### 使用错误的凭据验证[​](#使用错误的凭据验证 "使用错误的凭据验证的直接链接") 用错误的密码向该路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" \ -H "Authorization: ldap $(printf '%s' 'johndoe:wrong-password' | base64)" ``` 应当收到 `HTTP/1.1 401 Unauthorized` 响应: ``` WWW-Authenticate: ldap realm="ldap" ``` ``` {"message":"Authorization required"} ``` #### 不携带凭据验证[​](#不携带凭据验证 "不携带凭据验证的直接链接") 不携带任何凭据向该路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 应当收到 `HTTP/1.1 401 Unauthorized` 响应。 ### 把 LDAP 用户映射为消费者[​](#把-ldap-用户映射为消费者 "把 LDAP 用户映射为消费者的直接链接") 以下示例演示了如何把目录用户映射为消费者,从而让消费者级的配置对其流量生效。消费者的凭据中记录用户的完整 DN,也就是插件通过目录检索解析出来的那个值。 信息 `ldap-auth-advanced` 类型的消费者凭据通过 Admin API 或 Dashboard 创建。ADC 与 Ingress Controller 目前只支持 `key-auth`、`basic-auth`、`jwt-auth` 和 `hmac-auth` 类型的凭据。 创建消费者 `johndoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "johndoe" }' ``` 为该消费者创建 `ldap-auth-advanced` 凭据,记录目录条目的 DN: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-ldap-auth", "plugins": { "ldap-auth-advanced": { "user_dn": "uid=johndoe,ou=users,dc=example,dc=org" } } }' ``` 创建一个配置了 `ldap-auth-advanced` 的路由,`consumer_required` 保持默认值 `true`: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ldap-auth-consumer-route", "uri": "/anything", "plugins": { "ldap-auth-advanced": { "ldap_uri": "192.168.1.10:389", "base_dn": "ou=users,dc=example,dc=org", "attribute": "uid", "bind_dn": "cn=admin,dc=example,dc=org", "ldap_password": "admin-secret" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 用目录用户的凭据向该路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" \ -H "Authorization: ldap $(printf '%s' 'johndoe:john-secret' | base64)" ``` 应当收到 `HTTP/1.1 200 OK` 响应,上游会看到消费者相关的请求头: ``` { "headers": { "X-Consumer-Username": "johndoe", "X-Credential-Identifier": "cred-john-ldap-auth", ... }, ... } ``` 如果目录用户认证成功,但其 DN 没有记录在任何消费者凭据中,则会收到 `HTTP/1.1 401 Unauthorized` 响应。 ### 接受 HTTP Basic 认证方案[​](#接受-http-basic-认证方案 "接受 HTTP Basic 认证方案的直接链接") 以下示例演示了如何接受标准 HTTP Basic 方案而非 `ldap` 方案的凭据,从而让已有的 Basic 客户端无需改动即可使用。 在路由上把 `header_type` 设为 `basic`: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ldap-auth-basic-route", "uri": "/anything", "plugins": { "ldap-auth-advanced": { "ldap_uri": "192.168.1.10:389", "base_dn": "ou=users,dc=example,dc=org", "attribute": "uid", "bind_dn": "cn=admin,dc=example,dc=org", "ldap_password": "admin-secret", "header_type": "basic", "consumer_required": false } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 用普通的 Basic 凭据发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-secret ``` 应当收到 `HTTP/1.1 200 OK` 响应。此时未认证请求收到的挑战头也变为 Basic 方案: ``` WWW-Authenticate: Basic realm="ldap" ``` ### 通过 TLS 连接目录[​](#通过-tls-连接目录 "通过 TLS 连接目录的直接链接") 以下示例演示了如何通过 LDAPS 访问目录。设置 `use_ldaps` 并把 `ldap_uri` 指向 LDAPS 端口;省略端口时,启用 LDAPS 使用 `636`,否则使用 `389`。若要在 `389` 端口上把明文连接升级为 TLS,改用 `use_starttls`。这两个选项互斥。 ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ldaps-auth-route", "uri": "/anything", "plugins": { "ldap-auth-advanced": { "ldap_uri": "192.168.1.10:636", "use_ldaps": true, "base_dn": "ou=users,dc=example,dc=org", "attribute": "uid", "bind_dn": "cn=admin,dc=example,dc=org", "ldap_password": "admin-secret", "consumer_required": false } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 证书校验由 `ssl_verify` 控制,默认开启。建议保持开启,并确保网关信任签发目录证书的 CA。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 该插件支持使用 `env://` 前缀引用环境变量中的敏感参数值,或使用 `secret://` 前缀引用 Secret 管理器(如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv))中的值。更多信息,请参阅环境变量中的[插件](https://docs.apiseven.com/apisix/reference/environment-variables.md#plugins)和[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 ### 凭据[​](#凭据 "凭据的直接链接") 以下是可在[凭据](https://docs.apiseven.com/apisix/key-concepts/credentials.md)上配置的插件属性。 * user\_dn string 必填 有效值: 1 到 4096 个字符 *** 该消费者所代表的目录条目的可分辨名称(DN),例如 `uid=johndoe,ou=users,dc=example,dc=org`。它必须与插件通过目录检索解析出来的 DN 一致。 ### 路由或服务[​](#路由或服务 "路由或服务的直接链接") 以下是可用于 [路由 (Routes)](https://docs.apiseven.com/apisix/key-concepts/routes.md) 或 [服务 (Services)](https://docs.apiseven.com/apisix/key-concepts/services.md) 配置的插件属性。 * ldap\_uri string 必填 有效值: 1 到 256 个字符 *** LDAP 目录的地址,格式为 `host` 或 `host:port`。省略端口时,启用 `use_ldaps` 使用 `636`,否则使用 `389`。 * base\_dn string 必填 有效值: 1 到 4096 个字符 *** 插件检索用户时所在子树的可分辨名称,例如 `ou=users,dc=example,dc=org`。 * attribute string 默认值:`cn` 有效值: 符合 `RFC 4512` 的属性描述,最多 256 个字符 *** 用于与客户端提供的用户名匹配的属性。检索过滤器为 `(attribute=username)`,因此大多数 OpenLDAP 目录适合使用 `uid`,Active Directory 适合使用 `sAMAccountName`。 * bind\_dn string 有效值: 1 到 4096 个字符 *** 插件执行检索时所绑定的可分辨名称。未设置时以匿名方式检索。设置该字段时必须同时设置 `ldap_password`。 * ldap\_password string 有效值: 1 到 4096 个字符 *** `bind_dn` 对应的密码。设置 `bind_dn` 时必填。启用数据面数据加密时,该字段会落盘加密。 * use\_ldaps boolean 默认值:`false` *** 如果为 true,则通过 LDAPS 连接目录。与 `use_starttls` 互斥。 * use\_starttls boolean 默认值:`false` *** 如果为 true,则通过 StartTLS 把明文连接升级为 TLS。与 `use_ldaps` 互斥。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则在通过 LDAPS 或 StartTLS 连接时校验目录的 TLS 证书。 * timeout integer 默认值:`10000` 有效值: 1 到 60000 之间(含) *** 与目录建立连接的超时时间,单位为毫秒。 * size\_limit integer 默认值:`2` 有效值: 大于或等于 2 *** 目录为本次检索返回的最大条目数。默认值 `2` 足以发现用户名存在歧义的情况;此时插件会拒绝请求,而不是绑定到其中任意一条匹配。 * time\_limit integer 默认值:`5` 有效值: 大于或等于 0 *** 目录对本次检索施加的时间上限,单位为秒。设为 `0` 表示使用目录自身的默认值。 * consumer\_required boolean 默认值:`true` *** 如果为 true,则认证成功的用户还必须能映射到某个凭据中记录了其可分辨名称的消费者,否则请求被拒绝。设为 `false` 表示只对接目录完成认证,不涉及消费者。 * header\_type string 默认值:`ldap` 有效值: `ldap` 或 `basic` *** 插件在 `Authorization` 或 `Proxy-Authorization` 请求头中接受的认证方案,同时也是 `WWW-Authenticate` 挑战头中声明的方案。两种取值下凭据本身都是 `base64(username:password)`,因此 `basic` 对应标准的 HTTP Basic 交互。 * hide\_credentials boolean 默认值:`false` *** 如果为 true,则在客户端通过认证后移除携带目录凭据的请求头,使用户名和密码不会被转发到上游。在 API7 企业版中自 3.10.6 起可用。 * realm string 默认值:`ldap` *** 返回给未认证客户端的 `WWW-Authenticate` 请求头中声明的 realm。 * keepalive boolean 默认值:`true` *** 如果为 true,则保持与目录的连接存活,使其在请求之间复用。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 连接池中与目录的连接在空闲多久后被关闭,单位为毫秒。 * keepalive\_pool\_size integer 默认值:`5` 有效值: 大于或等于 1 *** 每个 worker 与目录之间连接池的最大连接数。 * keepalive\_pool\_name string 有效值: 1 到 256 个字符 *** 连接池的名称。设置该字段可以把不同插件配置的连接隔离到各自的连接池中。 --- # limit-conn `limit-conn` 插件通过限制并发连接数来限制请求速率。根据配置,超过阈值的请求将被延迟或拒绝,从而确保受控的资源使用并防止过载。 ## 本地限速与基于 Redis 的限速[​](#本地限速与基于-redis-的限速 "本地限速与基于 Redis 的限速的直接链接") `limit-conn` 插件支持两种限速模式: * **本地限速**:每个网关实例独立实施限速。每个实例维护自己的计数器,因此当流量分散到多个实例时,实际限额约为“限额 × 实例数”。未设置 `policy` 或将其设置为 `local` 时,这是默认模式。 * **基于 Redis 的限速**:所有网关实例通过 Redis 共享限额,因此配置的限额会应用到所有网关实例。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `limit-conn`。 ### 基于远程地址进行速率限制[​](#基于远程地址进行速率限制 "基于远程地址进行速率限制的直接链接") 以下示例演示了如何使用 `limit-conn` 通过 `remote_addr` 对请求进行速率限制,并配置连接数和突发阈值。 创建一个启用了 `limit-conn` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-conn-route", "uri": "/get", "plugins": { "limit-conn": { "conn": 2, "burst": 1, "default_conn_delay": 0.1, "key_type": "var", "key": "remote_addr", "policy": "local", "rejected_code": 429 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-conn-route plugins: limit-conn: conn: 2 burst: 1 default_conn_delay: 0.1 key_type: var key: remote_addr policy: local rejected_code: 429 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-conn-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-conn-plugin-config spec: plugins: - name: limit-conn config: conn: 2 burst: 1 default_conn_delay: 0.1 key_type: var key: remote_addr policy: local rejected_code: 429 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-conn-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-conn-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-conn-route spec: ingressClassName: apisix http: - name: limit-conn-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-conn config: conn: 2 burst: 1 default_conn_delay: 0.1 key_type: var key: remote_addr policy: local rejected_code: 429 ``` 应用配置: ``` kubectl apply -f limit-conn-ic.yaml ``` ❶ `conn`:允许 2 个并发请求。 ❷ `burst`:允许 1 个额外的并发请求。 ❸ `default_conn_delay`:对于并发数介于 `conn` 和 `conn + burst` 之间的请求,允许 0.1 秒的处理延迟。 ❹ `key_type`:设置为 `var`,将 `key` 解释为变量。 ❺ `key`:根据请求的 `remote_addr` 计算限速计数。 ❻ `policy`:使用内存中的本地计数器。 ❼ `rejected_code`:将拒绝状态码设置为 `429`。 向该路由发送五个并发请求: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"' ``` 你应该会看到类似于以下的响应,其中多余的请求被拒绝: ``` Response: 200 Response: 200 Response: 200 Response: 429 Response: 429 ``` ### 基于远程地址和消费者名称进行速率限制[​](#基于远程地址和消费者名称进行速率限制 "基于远程地址和消费者名称进行速率限制的直接链接") 以下示例演示了如何使用 `limit-conn` 通过变量组合 `remote_addr` 和 `consumer_name` 对请求进行速率限制。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建第二个消费者 `jane`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jane" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 创建一个启用了 `key-auth` 和 `limit-conn` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-conn-route", "uri": "/get", "plugins": { "key-auth": {}, "limit-conn": { "conn": 2, "burst": 1, "default_conn_delay": 0.1, "rejected_code": 429, "policy": "local", "key_type": "var_combination", "key": "$remote_addr $consumer_name" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建两个消费者和一个按消费者启用限速的路由: adc.yaml ``` consumers: - username: john credentials: - name: key-auth type: key-auth config: key: john-key - username: jane credentials: - name: key-auth type: key-auth config: key: jane-key services: - name: limit-conn-service routes: - name: limit-conn-route uris: - /get plugins: key-auth: {} limit-conn: conn: 2 burst: 1 default_conn_delay: 0.1 rejected_code: 429 policy: local key_type: var_combination key: "$remote_addr $consumer_name" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建两个消费者和一个按消费者启用限速的路由: * Gateway API * APISIX CRD limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jane spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-conn-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: limit-conn config: conn: 2 burst: 1 default_conn_delay: 0.1 rejected_code: 429 policy: local key_type: var_combination key: "$remote_addr $consumer_name" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-conn-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-conn-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-conn-route spec: ingressClassName: apisix http: - name: limit-conn-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: key-auth config: _meta: disable: false - name: limit-conn config: conn: 2 burst: 1 default_conn_delay: 0.1 rejected_code: 429 policy: local key_type: var_combination key: "$remote_addr $consumer_name" ``` 应用配置: ``` kubectl apply -f limit-conn-ic.yaml ``` ❶ `key-auth`:在路由上启用密钥认证。 ❷ `key_type`:设置为 `var_combination`,将 `key` 解释为变量组合。 ❸ `key`: 设置为 `$remote_addr $consumer_name` 以根据远程地址和消费者应用限速配额。 作为消费者 `john` 发送五个并发请求: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "apikey: john-key"' ``` 你应该会看到类似于以下的响应,其中多余的请求被拒绝: ``` Response: 200 Response: 200 Response: 200 Response: 429 Response: 429 ``` 立即作为消费者 `jane` 发送五个并发请求: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "apikey: jane-key"' ``` 你应该也会看到类似于以下的响应,其中多余的请求被拒绝: ``` Response: 200 Response: 200 Response: 200 Response: 429 Response: 429 ``` 在这种情况下,插件通过变量组合 `remote_addr` 和 `consumer_name` 进行速率限制,这意味着每个消费者的配额是独立的。 ### 限制 WebSocket 连接速率[​](#限制-websocket-连接速率 "限制 WebSocket 连接速率的直接链接") 以下示例演示了如何使用 `limit-conn` 插件来限制并发 WebSocket 连接数。 启动一个[示例上游 WebSocket 服务器](https://hub.docker.com/r/jmalloc/echo-server): * Docker * Kubernetes ``` docker run -d \ -p 8080:8080 \ --name websocket-server \ --network=apisix-quickstart-net \ jmalloc/echo-server ``` 为 WebSocket 服务器部署创建 Kubernetes 清单文件: ws-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: websocket-server spec: replicas: 1 selector: matchLabels: app: websocket-server template: metadata: labels: app: websocket-server spec: containers: - name: echo-server image: jmalloc/echo-server ports: - containerPort: 8080 ``` 为 WebSocket 服务再创建一个 Kubernetes 清单文件: ws-service.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: websocket-server spec: selector: app: websocket-server ports: - protocol: TCP port: 8080 targetPort: 8080 appProtocol: kubernetes.io/ws type: ClusterIP ``` Gateway API 与 WebSocket 对于 Gateway API,通过 `Service` 的 `appProtocol` 字段(`kubernetes.io/ws` 或 `kubernetes.io/wss`)启用 WebSocket。与 `ApisixRoute` 不同,`HTTPRoute` 不提供直接的 `websocket` 字段或注解支持。使用 Gateway API 资源时,请确保已在 `Service` 中配置 `appProtocol`。 有关更多信息,请参阅[使用 appProtocol 检测上游协议](https://docs.apiseven.com/ingress-controller/detect-upstream-protocol-appprotocol.md)。 该服务器在 `/.ws` 提供 WebSocket 端点,会原样返回收到的所有消息。 创建一条到 WebSocket 服务器端点的路由,并为该路由启用 WebSocket: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d ' { "id": "ws-route", "uri": "/.ws", "plugins": { "limit-conn": { "conn": 2, "burst": 1, "default_conn_delay": 0.1, "key_type": "var", "key": "remote_addr", "rejected_code": 429, "policy": "local" } }, "enable_websocket": true, "upstream": { "type": "roundrobin", "nodes": { "websocket-server:8080": 1 } } }' ``` ❶ 为路由启用 WebSocket。 ❷ 替换为你的 WebSocket 服务器地址。 adc.yaml ``` services: - name: websocket-service routes: - name: ws-route uris: - /.ws enable_websocket: true plugins: limit-conn: conn: 2 burst: 1 default_conn_delay: 0.1 key_type: var key: remote_addr rejected_code: 429 policy: local upstream: type: roundrobin nodes: - host: websocket-server port: 8080 weight: 1 ``` ❶ 为路由启用 WebSocket。 ❷ 替换为你的 WebSocket 服务器地址。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-conn-plugin-config spec: plugins: - name: limit-conn config: conn: 2 burst: 1 default_conn_delay: 0.1 key_type: var key: remote_addr rejected_code: 429 policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ws-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /.ws filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-conn-plugin-config backendRefs: - name: websocket-server port: 8080 ``` limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ws-route spec: ingressClassName: apisix http: - name: ws-route match: paths: - /.ws methods: - GET websocket: true backends: - serviceName: websocket-server servicePort: 8080 plugins: - name: limit-conn config: conn: 2 burst: 1 default_conn_delay: 0.1 key_type: var key: remote_addr rejected_code: 429 policy: local ``` 应用配置: ``` kubectl apply -f limit-conn-ic.yaml ``` 安装一个 WebSocket 客户端,例如 [websocat](https://github.com/vi/websocat)(如果你还没有安装)。通过路由与 WebSocket 服务器建立连接: ``` websocat "ws://127.0.0.1:9080/.ws" ``` 在终端中发送一条 "hello" 消息,你应该会看到 WebSocket 服务器回显相同的消息: ``` Request served by 1cd244052136 hello hello ``` 再打开三个终端会话并运行: ``` websocat "ws://127.0.0.1:9080/.ws" ``` 当你尝试与服务器建立 WebSocket 连接时,你应该会看到最后一个终端会话打印 `429 Too Many Requests`,这是由于速率限制的影响。 ### 使用 Redis 服务器在 APISIX 节点间共享配额[​](#使用-redis-服务器在-apisix-节点间共享配额 "使用 Redis 服务器在 APISIX 节点间共享配额的直接链接") 以下示例演示了如何使用 Redis 服务器在多个 APISIX 节点之间进行限速,以便不同的 APISIX 节点共享相同的限速配额。 在每个 APISIX 实例上,使用以下配置创建路由,并根据实际环境调整配置详情。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-conn-route", "uri": "/get", "plugins": { "limit-conn": { "conn": 1, "burst": 1, "default_conn_delay": 0.1, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "redis", "redis_host": "192.168.xxx.xxx", "redis_port": 6379, "redis_password": "p@ssw0rd", "redis_database": 1 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-conn-route plugins: limit-conn: conn: 1 burst: 1 default_conn_delay: 0.1 rejected_code: 429 key_type: var key: remote_addr policy: redis redis_host: "192.168.xxx.xxx" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-conn-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-conn-plugin-config spec: plugins: - name: limit-conn config: conn: 1 burst: 1 default_conn_delay: 0.1 rejected_code: 429 key_type: var key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-conn-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-conn-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-conn-route spec: ingressClassName: apisix http: - name: limit-conn-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-conn config: conn: 1 burst: 1 default_conn_delay: 0.1 rejected_code: 429 key_type: var key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 ``` 应用配置: ``` kubectl apply -f limit-conn-ic.yaml ``` ❶ `policy`: 设置为 `redis` 以使用 Redis 实例进行限速。 ❷ `redis_host`: 设置为 Redis 实例的 IP 地址。 ❸ `redis_port`: 设置为 Redis 实例的监听端口。 ❹ `redis_password`: 设置为 Redis 实例的密码(如果有)。 ❺ `redis_database`: 设置为 Redis 实例中的数据库编号。 向该路由发送五个并发请求: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"' ``` 你应该会看到类似于以下的响应,其中多余的请求被拒绝: ``` Response: 200 Response: 200 Response: 429 Response: 429 Response: 429 ``` 这表明配置在不同 APISIX 实例中的两个路由共享相同的配额。 ### 使用 Redis 集群在 APISIX 节点间共享配额[​](#使用-redis-集群在-apisix-节点间共享配额 "使用 Redis 集群在 APISIX 节点间共享配额的直接链接") 你还可以使用 Redis 集群在多个 APISIX 节点之间应用相同的配额,以便不同的 APISIX 节点共享相同的限速配额。 确保 Redis 实例以[集群模式](https://redis.io/docs/management/scaling/#create-and-use-a-redis-cluster)运行。在 `limit-conn` 插件中配置 `redis_cluster_name`,并在 `redis_cluster_nodes` 中配置一个或多个节点地址。 在每个 APISIX 实例上,使用以下配置创建路由,并根据实际环境调整配置详情。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-conn-route", "uri": "/get", "plugins": { "limit-conn": { "conn": 1, "burst": 1, "default_conn_delay": 0.1, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "redis-cluster", "redis_cluster_nodes": [ "192.168.xxx.xxx:6379", "192.168.xxx.xxx:16379" ], "redis_password": "p@ssw0rd", "redis_cluster_name": "redis-cluster", "redis_cluster_ssl": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-conn-route plugins: limit-conn: conn: 1 burst: 1 default_conn_delay: 0.1 rejected_code: 429 key_type: var key: remote_addr policy: redis-cluster redis_cluster_nodes: - "192.168.xxx.xxx:6379" - "192.168.xxx.xxx:16379" redis_password: "p@ssw0rd" redis_cluster_name: "redis-cluster" redis_cluster_ssl: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-conn-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-conn-plugin-config spec: plugins: - name: limit-conn config: conn: 1 burst: 1 default_conn_delay: 0.1 rejected_code: 429 key_type: var key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: "redis-cluster" redis_cluster_ssl: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-conn-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-conn-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-conn-route spec: ingressClassName: apisix http: - name: limit-conn-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-conn config: conn: 1 burst: 1 default_conn_delay: 0.1 rejected_code: 429 key_type: var key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: "redis-cluster" redis_cluster_ssl: true ``` 应用配置: ``` kubectl apply -f limit-conn-ic.yaml ``` ❶ `policy`: 设置为 `redis-cluster` 以使用 Redis 集群进行限速。 ❷ `redis_cluster_nodes`: 设置为 Redis 集群中的 Redis 节点地址。 ❸ `redis_password`: 设置为 Redis 集群的密码(如果有)。 ❹ `redis_cluster_name`: 设置为 Redis 集群名称。 ❺ `redis_cluster_ssl`: 启用与 Redis 集群的 SSL/TLS 通信。 向该路由发送五个并发请求: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"' ``` 你应该会看到类似于以下的响应,其中多余的请求被拒绝: ``` Response: 200 Response: 200 Response: 429 Response: 429 Response: 429 ``` 这表明配置在不同 APISIX 实例中的两个路由共享相同的配额。 ### 基于规则的速率限制[​](#基于规则的速率限制 "基于规则的速率限制的直接链接") 以下示例演示了如何配置 `limit-conn` 以根据请求属性应用不同的速率限制规则(从 API7 Enterprise 3.8.17 开始可用)。在此示例中,速率限制基于代表调用者访问层级的 HTTP 头值应用。 请注意,所有规则按顺序应用。如果配置的键不存在,则将跳过相应的规则。 提示 除 HTTP 请求头外,还可以根据其他[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)配置规则,以实现更灵活、更细粒度的限速策略。 创建一个启用了 `limit-conn` 插件的路由,该插件根据请求头应用不同的速率限制,允许每个订阅(`X-Subscription-ID`)进行速率限制,并对试用用户(`X-Trial-ID`)强制执行更严格的限制: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-conn-rules-route", "uri": "/get", "plugins": { "limit-conn": { "rejected_code": 429, "default_conn_delay": 0.1, "policy": "local", "rules": [ { "key": "${http_x_subscription_id}", "conn": "${http_x_custom_conn ?? 5}", "burst": 1 }, { "key": "${http_x_trial_id}", "conn": 1, "burst": 1 } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-conn-rules-route plugins: limit-conn: rejected_code: 429 default_conn_delay: 0.1 policy: local rules: - key: "${http_x_subscription_id}" conn: "${http_x_custom_conn ?? 5}" burst: 1 - key: "${http_x_trial_id}" conn: 1 burst: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-conn-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-conn-plugin-config spec: plugins: - name: limit-conn config: rejected_code: 429 default_conn_delay: 0.1 policy: local rules: - key: "${http_x_subscription_id}" conn: "${http_x_custom_conn ?? 5}" burst: 1 - key: "${http_x_trial_id}" conn: 1 burst: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-conn-rules-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-conn-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-conn-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-conn-rules-route spec: ingressClassName: apisix http: - name: limit-conn-rules-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-conn config: rejected_code: 429 default_conn_delay: 0.1 policy: local rules: - key: "${http_x_subscription_id}" conn: "${http_x_custom_conn ?? 5}" burst: 1 - key: "${http_x_trial_id}" conn: 1 burst: 1 ``` 应用配置: ``` kubectl apply -f limit-conn-ic.yaml ``` ❶ 使用 `X-Subscription-ID` 请求头的值作为速率限制键。 ❷ 根据 `X-Custom-Conn` 头动态设置请求连接。如果未提供该头,则应用默认并发连接数 5。 ❸ 使用 `X-Trial-ID` 请求头的值作为速率限制键。 要验证速率限制,使用相同的订阅 ID 发送 7 个并发请求到该路由: ``` seq 1 7 | xargs -n1 -P7 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "X-Subscription-ID: sub-123456789"' ``` 你应该会看到以下响应,显示当未提供 `X-Custom-Conn` 头时,应用了 5 个并发连接限制和 1 个突发请求: ``` Response: 429 Response: 200 Response: 200 Response: 200 Response: 200 Response: 200 Response: 200 ``` 使用相同的订阅 ID 发送 5 个并发请求到该路由,并将 `X-Custom-Conn` 头设置为 1: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "X-Subscription-ID: sub-123456789" -H "X-Custom-Conn: 1"' ``` 你应该会看到以下响应,显示应用了 1 个并发连接限制和 1 个突发请求: ``` Response: 429 Response: 429 Response: 429 Response: 200 Response: 200 ``` 最后,使用试用 ID 头生成 5 个请求到该路由: ``` seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "X-Trial-ID: trial-123456789"' ``` 你应该会看到以下响应,显示应用了 1 个并发连接限制和 1 个突发请求: ``` Response: 429 Response: 429 Response: 429 Response: 200 Response: 200 ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 备注 在 API7 企业版 3.8.17 及更高版本和 Apache APISIX 3.16.0 及更高版本中,请配置以下两组参数之一,不要同时配置: * `conn`, `burst`, `default_conn_delay`, `key` * `rules`, `default_conn_delay` - conn integer | string 必填 有效值: 大于 0 *** 允许的最大并发请求数。超过此配置限制但低于 `conn + burst` 的请求将被延迟处理。 字符串值可以通过在变量名前添加美元符号(`$`)来引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。字符串解析结果必须为不大于 `9007199254740991` 的正整数。解析失败或结果无效时,除非启用降级,否则网关返回 `500 Internal Server Error`。 字符串值支持自 API7 企业版 3.8.17 和 APISIX 3.16.0 起提供。上述校验要求自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.17.0 起提供。更早的 APISIX 版本仅接受整数值。 - burst integer | string 必填 有效值: 大于或等于 0 *** 允许延迟处理的额外并发请求数。超过 `conn + burst` 的请求将被立即拒绝。 字符串值可以通过在变量名前添加美元符号(`$`)来引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。字符串解析结果必须为不大于 `9007199254740991` 的非负整数。解析失败或结果无效时,除非启用降级,否则网关返回 `500 Internal Server Error`。 字符串值支持自 API7 企业版 3.8.17 和 APISIX 3.16.0 起提供。上述校验要求自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.17.0 起提供。更早的 APISIX 版本仅接受整数值。 - default\_conn\_delay number 必填 有效值: 大于 0 *** 对于超过 `conn` 但不超过 `conn + burst` 的并发请求,允许的处理延迟(秒)。此值可根据 `only_use_default_delay` 设置动态调整。 - only\_use\_default\_delay boolean 默认值:`false` *** 如果为 false,则根据请求超出 `conn` 限制的程度按比例延迟请求。拥塞越严重,延迟越大。例如,`conn` 为 `5`,`burst` 为 `3`,`default_conn_delay` 为 `1` 时,6 个并发请求会导致 1 秒延迟,7 个请求导致 2 秒延迟,8 个请求导致 3 秒延迟,依此类推,直至达到 `conn + burst` 的总限制,超出此限制的请求将被拒绝。 如果为 true,则使用 `default_conn_delay` 来延迟所有在 `burst` 范围内的额外请求。超出 `conn + burst` 的请求将被立即拒绝。例如,`conn` 为 `5`,`burst` 为 `3`,`default_conn_delay` 为 `1` 时,6、7 或 8 个并发请求都将被精确地延迟 1 秒。 - key\_type string 默认值:`var` 有效值: `var` 或 `var_combination` *** 键的类型。 如果 `key_type` 是 `var`,则 `key` 被解释为一个变量。 如果 `key_type` 是 `var_combination`,则 `key` 被解释为多个变量的组合。 - key string 必填 *** 用于统计请求的键。 如果 `key_type` 是 `var`,则 `key` 被解释为一个变量。变量不需要以美元符号 (`$`) 为前缀。可用的变量请参见[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 如果 `key_type` 是 `var_combination`,则 `key` 被解释为多个变量的组合。所有变量都应加上美元符号 (`$`) 前缀。例如,要配置 `key` 使用两个请求头 `custom-a` 和 `custom-b` 的组合,`key` 应配置为 `$http_custom_a $http_custom_b`。 - rejected\_code integer 默认值:`503` 有效值: 介于 200 和 599 之间(含边界值) *** 当请求因超过阈值而被拒绝时返回的 HTTP 状态码。 - rejected\_msg string 有效值: 任意非空字符串 *** 当请求因超过阈值而被拒绝时返回的响应体。 - allow\_degradation boolean 默认值:`false` *** 如果为 true,当插件或其依赖项不可用时,允许网关在没有该插件的情况下继续处理请求。 - rules array\[object] *** 按顺序应用的限流规则数组。 规则支持自 API7 企业版 3.8.17 和 APISIX 3.16.0 起提供。 * conn integer | string 必填 有效值: 大于 0 *** 允许的最大并发请求数。超过此配置限制但低于 `conn + burst` 的请求将被延迟处理。 字符串值可以通过在变量名前添加美元符号(`$`)来引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。字符串解析结果必须为不大于 `9007199254740991` 的正整数。 字符串值校验自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.17.0 起提供。 * burst integer | string 必填 有效值: 大于或等于 0 *** 允许延迟处理的额外并发请求数。超过 `conn + burst` 的请求将被立即拒绝。 字符串值可以通过在变量名前添加美元符号(`$`)来引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。字符串解析结果必须为不大于 `9007199254740991` 的非负整数。 字符串值校验自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.17.0 起提供。 * key string 必填 *** 用于统计请求的键。如果配置的键不存在,则不会执行该规则。 如果 `key_type` 是 `var`,则 `key` 被解释为一个变量。变量不需要以美元符号 (`$`) 为前缀。可用的变量请参见[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 如果 `key_type` 是 `var_combination`,则 `key` 被解释为多个变量的组合。所有变量都应加上美元符号 (`$`) 前缀。例如,要配置 `key` 使用两个请求头 `custom-a` 和 `custom-b` 的组合,`key` 应配置为 `$http_custom_a $http_custom_b`。 - policy string 默认值:`local` 有效值: `local`、`redis` 或 `redis-cluster` *** 限流计数器的策略。如果是 `local`,计数器存储在本地内存中。如果是 `redis`,计数器存储在 Redis 实例上。如果是 `redis-cluster`,计数器存储在 Redis 集群中。 如果你使用的是 API7 企业版,此选项从 3.9.0 版本开始可用。 - redis\_host string *** Redis 节点的地址。当 `policy` 为 `redis` 时必须配置。 - redis\_port integer 默认值:`6379` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 时 Redis 节点的端口。 - redis\_username string *** 如果使用 Redis ACL,则为此 Redis 的用户名。如果使用传统的认证方法 `requirepass`,则只配置 `redis_password`。在 `policy` 为 `redis` 时使用。 - redis\_password string *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 节点的密码。API7 企业版会对静态存储的该值进行加密;在 APISIX 中,请[启用数据加密](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md),以便在存入 etcd 前加密该值。加密能力自 API7 企业版 3.9.16 和 3.10.2,以及 APISIX 3.18.0 起可用。 - redis\_database integer 默认值:`0` 有效值: 大于或等于 0 *** 当 `policy` 为 `redis` 时 Redis 中的数据库编号。 - redis\_ssl boolean 默认值:`false` *** 如果为 true,当 `policy` 为 `redis` 时使用 SSL 连接 Redis。 - redis\_ssl\_verify boolean 默认值:`false` *** 如果为 true,当 `policy` 为 `redis` 时验证服务器 SSL 证书。 - redis\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 的超时值(毫秒)。 - redis\_keepalive\_timeout integer 默认值:`10000` 有效值: 大于或等于 1000 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 的保活超时时间(毫秒)。 此参数在 API7 企业版 3.9.x 系列中自 3.9.17 起可用,在 3.10.x 系列中自 3.10.4 起可用,并且在 APISIX 中自 3.15.0 起可用。 - redis\_keepalive\_pool integer 默认值:`100` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 的保活连接池大小。 此参数在 API7 企业版 3.9.x 系列中自 3.9.17 起可用,在 3.10.x 系列中自 3.10.4 起可用,并且在 APISIX 中自 3.15.0 起可用。 - key\_ttl integer 默认值:`3600` *** 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis Key 的 TTL,单位为秒。自 API7 企业版 3.9.4 和 APISIX 3.15.0 起可用。 - redis\_cluster\_nodes array\[string] *** Redis 集群节点的列表,至少包含两个地址。当 `policy` 为 `redis-cluster` 时必须配置。 - redis\_cluster\_name string *** Redis 集群的名称。当 `policy` 为 `redis-cluster` 时必须配置。 - redis\_cluster\_ssl boolean 默认值:`false` *** 如果为 true,当 `policy` 为 `redis-cluster` 时使用 SSL 连接 Redis 集群。 - redis\_cluster\_ssl\_verify boolean 默认值:`false` *** 如果为 true,当 `policy` 为 `redis-cluster` 时验证服务器 SSL 证书。 --- # limit-count `limit-count` 插件使用固定窗口算法,根据给定时间间隔内的请求数量来限制请求速率。超过配置配额的请求将被拒绝。 你可能会在响应中看到以下限速响应头: * `X-RateLimit-Limit`:总配额 * `X-RateLimit-Remaining`:剩余配额 * `X-RateLimit-Reset`:计数器重置前的剩余秒数 如果你使用的是 API7 企业版,可以通过[插件元数据](#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%80%9F%E7%8E%87%E9%99%90%E5%88%B6%E5%A4%B4)自定义这些响应头的名称。 ## 本地限速与基于 Redis 的限速[​](#本地限速与基于-redis-的限速 "本地限速与基于 Redis 的限速的直接链接") `limit-count` 插件支持以下两种限速模式: * **本地限速**:每个网关实例独立实施限速。每个实例维护自己的计数器,因此当流量分散到多个实例时,实际限额约为“限额 × 实例数”。未设置 `policy` 或将其设置为 `local` 时,这是默认模式。 * **基于 Redis 的限速**:所有网关实例通过 Redis 共享限额,因此配置的限额会应用到所有网关实例。将 `policy` 设置为 `redis` 可使用单个 Redis 实例,设置为 `redis-cluster` 可使用 Redis 集群,设置为 `redis-sentinel` 可使用 Redis Sentinel 管理的 Redis 节点。 备注 从 API7 企业版 3.9.14 起,高级限速能力已直接内置到 `limit-count` 中,包括用于高可用的 `redis-sentinel` 策略、在窗口边界平滑实施限速的 `sliding` `window_type`、通过 `sync_interval` 延迟同步、通过 `rules` 数组配置多条限速规则,以及从请求变量派生 `count`。独立的 `limit-count-advanced` 插件仍保留,以实现向后兼容。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `limit-count`。 ### 基于远程地址进行速率限制[​](#基于远程地址进行速率限制 "基于远程地址进行速率限制的直接链接") 以下示例演示了如何通过单个变量 `remote_addr` 对请求进行限速。 创建一个使用 `limit-count` 插件的路由,允许每个远程地址在 30 秒窗口内请求 1 次: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "local" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-count-route plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-plugin-config spec: plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` 发送请求进行验证: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该会看到一个 `HTTP/1.1 200 OK` 响应。 该请求已消耗了时间窗口内允许的所有配额。如果你在同一个 30 秒时间间隔内再次发送请求,应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,表明请求超过了配额阈值。 ### 使用滑动窗口实施限速[​](#使用滑动窗口实施限速 "使用滑动窗口实施限速的直接链接") 以下示例演示了如何通过将 `window_type` 设置为 `sliding`,使用 API7 企业版 3.9.14 起提供的滑动窗口算法。与默认的固定窗口相比,滑动窗口在计算当前请求数时会对上一窗口加权,从而平滑窗口边界处的流量突发。 创建一条配置了 `limit-count` 插件的路由,允许每个远程地址在 30 秒滑动窗口内请求 10 次: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count": { "count": 10, "time_window": 30, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "local", "window_type": "sliding" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: limit-count-route uris: - /get plugins: limit-count: count: 10 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local window_type: sliding upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-plugin-config spec: plugins: - name: limit-count config: count: 10 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local window_type: sliding --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: limit-count enable: true config: count: 10 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local window_type: sliding ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` 发送请求进行验证: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该会看到 `HTTP/1.1 200 OK` 响应。持续发送请求时,与固定窗口相比,滑动窗口会在相邻窗口的边界处更均匀地实施配额。 ### 基于远程地址和消费者名称进行速率限制[​](#基于远程地址和消费者名称进行速率限制 "基于远程地址和消费者名称进行速率限制的直接链接") 以下示例演示了如何通过变量组合 `remote_addr` 和 `consumer_name` 对请求进行限速。它允许每个远程地址和每个 [Consumer](https://docs.apiseven.com/apisix/key-concepts/consumers.md) 在 30 秒窗口内请求 1 次。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为消费者 `john` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建消费者 `jane`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jane" }' ``` 为消费者 `jane` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 创建一个启用 `key-auth` 和 `limit-count` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "key-auth": {}, "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "key_type": "var_combination", "key": "$remote_addr $consumer_name", "policy": "local" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建两个消费者和一个按消费者启用限速的路由: adc.yaml ``` consumers: - username: john credentials: - name: key-auth type: key-auth config: key: john-key - username: jane credentials: - name: key-auth type: key-auth config: key: jane-key services: - name: limit-count-service routes: - name: limit-count-route uris: - /get plugins: key-auth: {} limit-count: count: 1 time_window: 30 rejected_code: 429 key_type: var_combination key: "$remote_addr $consumer_name" policy: local upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建两个消费者和一个按消费者启用限速的路由: * Gateway API * APISIX CRD limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jane spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 key_type: var_combination key: "$remote_addr $consumer_name" policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: key-auth enable: true - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 key_type: var_combination key: "$remote_addr $consumer_name" policy: local ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` ❶ `key-auth`:在路由上启用密钥认证。 ❷ `key_type`:设置为 `var_combination`,将 `key` 解释为变量组合。 ❸ `key`:设置为 `$remote_addr $consumer_name`,按远程地址和消费者应用限速配额。 以消费者 `jane` 的身份发送请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key' ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 此请求已消耗了该时间窗口的所有配额。如果你在同一个 30 秒时间间隔内再次以消费者 `jane` 的身份发送相同的请求,应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,表明请求超过了配额阈值。 在同一个 30 秒时间间隔内以消费者 `john` 的身份发送相同的请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key' ``` 你应该会看到带有相应响应体的 `HTTP/1.1 200 OK` 响应,表明该请求未被限速。 在同一个 30 秒时间间隔内再次以消费者 `john` 的身份发送相同的请求,你应该会收到 `HTTP/1.1 429 Too Many Requests` 响应。 这验证了插件是根据变量组合 `remote_addr` 和 `consumer_name` 进行速率限制的。 ### 在路由间共享配额[​](#在路由间共享配额 "在路由间共享配额的直接链接") 以下示例演示了如何通过配置 `limit-count` 插件的 `group` 来在多个路由之间共享限速配额。 请注意,同一 `group` 的 `limit-count` 插件配置应完全相同。为了避免更新异常和重复配置,你可以创建一个包含 `limit-count` 插件和上游的 [Service](https://docs.apiseven.com/apisix/key-concepts/services.md),供路由连接。 * Admin API * ADC * Ingress Controller 创建一个配置限速组的服务: ``` curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-service", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "policy": "local", "group": "srv1" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建两条使用同一服务的路由以共享配额: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route-1", "service_id": "limit-count-service", "uri": "/get1", "plugins": { "proxy-rewrite": { "uri": "/get" } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route-2", "service_id": "limit-count-service", "uri": "/get2", "plugins": { "proxy-rewrite": { "uri": "/get" } } }' ``` 创建一个包含两条路由的服务,使两条路由共享同一限速配额: adc.yaml ``` services: - name: limit-count-service plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 policy: local group: srv1 routes: - name: limit-count-route-1 uris: - /get1 plugins: proxy-rewrite: uri: /get - name: limit-count-route-2 uris: - /get2 plugins: proxy-rewrite: uri: /get upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建两个引用同一 `PluginConfig` 的 `HTTPRoute` 以共享配额: limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-plugin-config spec: plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local group: srv1 - name: proxy-rewrite config: uri: /get --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route-1 spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get1 filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route-2 spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get2 filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 创建一个包含多个路径的 `ApisixRoute`,使这些路径共享同一插件配置: limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-shared-route spec: ingressClassName: apisix http: - name: limit-count-shared match: paths: - /get1 - /get2 upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: uri: /get - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 policy: local group: srv1 ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` 备注 [`proxy-rewrite`](https://docs.apiseven.com/hub/proxy-rewrite.md) 插件用于将 URI 重写为 `/get`,使请求转发到正确的端点。 向路由 `/get1` 发送请求: ``` curl -i "http://127.0.0.1:9080/get1" ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在同一个 30 秒时间间隔内向路由 `/get2` 发送相同的请求: ``` curl -i "http://127.0.0.1:9080/get2" ``` 你应该会收到 `HTTP/1.1 429 Too Many Requests` 响应,这验证了两个路由共享相同的限速配额。 ### 使用 Redis 服务器在 APISIX 节点间共享配额[​](#使用-redis-服务器在-apisix-节点间共享配额 "使用 Redis 服务器在 APISIX 节点间共享配额的直接链接") 以下示例演示了如何使用 Redis 服务器在多个 APISIX 节点之间实施限速,使不同 APISIX 节点共享同一限速配额。 为路由配置 Redis 连接详情,并根据实际环境调整 Redis 主机、凭证和数据库。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis", "redis_host": "192.168.xxx.xxx", "redis_port": 6379, "redis_password": "p@ssw0rd", "redis_database": 1 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一条使用 Redis 限速的路由: adc.yaml ``` services: - name: redis-limit-service routes: - name: redis-limit-route uris: - /get plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "192.168.xxx.xxx" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-redis-plugin-config spec: plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: redis-limit-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-redis-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: redis-limit-route spec: ingressClassName: apisix http: - name: redis-limit-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` ❶ `policy`: 设置为 `redis` 以使用 Redis 实例进行限速。 ❷ `redis_host`: 设置为 Redis 实例的 IP 地址。 ❸ `redis_port`: 设置为 Redis 实例的监听端口。 ❹ `redis_password`: 设置为 Redis 实例的密码(如果有)。 ❺ `redis_database`: 设置为 Redis 实例中的数据库编号。 向 APISIX 实例发送请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在相同的 30 秒时间窗口内,向另一个 APISIX 实例发送相同请求,应收到 `HTTP/1.1 429 Too Many Requests` 响应,这表明不同 APISIX 节点上配置的路由共享同一配额。 ### 使用延迟同步减少 Redis 往返[​](#使用延迟同步减少-redis-往返 "使用延迟同步减少 Redis 往返的直接链接") 默认情况下,基于 Redis 的策略会在每次请求时同步计数器。你也可以先在本地累积增量,再按配置的时间间隔将其同步到 Redis。此功能自 API7 企业版 3.9.14 和 3.10.1,以及 APISIX 3.18.0 起可用。 要在上面的完整 Redis 示例中启用延迟同步,请在 `limit-count` 配置中添加 `sync_interval: 1`。该值以秒为单位,必须不小于 `0.1`,并且必须小于数值类型的 `time_window`。此选项同样适用于 `redis-cluster` 和 `redis-sentinel` 策略。将其设置为默认值 `-1`,可恢复为每次请求都同步。 延迟同步可减少 Redis 往返,但在本地增量完成同步前,不同 Worker 或网关节点上的计数器可能暂时不一致。因此,在同步间隔内共享配额并不精确,并发请求可能超过配置的计数。当精确的跨节点限额执行比减少 Redis 流量更重要时,请使用直接同步。 ### 使用 Redis 集群在 APISIX 节点间共享配额[​](#使用-redis-集群在-apisix-节点间共享配额 "使用 Redis 集群在 APISIX 节点间共享配额的直接链接") 你还可以使用 Redis 集群在多个 APISIX 节点之间应用相同的配额,以便不同的 APISIX 节点共享相同的限速配额。 确保你的 Redis 实例以[集群模式](https://redis.io/docs/management/scaling/#create-and-use-a-redis-cluster)运行。`limit-count` 插件配置至少需要两个节点。 为路由配置 Redis 集群详情,并根据实际环境调整集群节点、凭证和集群名称。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis-cluster", "redis_cluster_nodes": [ "192.168.xxx.xxx:6379", "192.168.xxx.xxx:16379" ], "redis_password": "p@ssw0rd", "redis_cluster_name": "redis-cluster", "redis_cluster_ssl": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一条使用 Redis 集群限速的路由: adc.yaml ``` services: - name: redis-cluster-limit-service routes: - name: redis-cluster-limit-route uris: - /get plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "192.168.xxx.xxx:6379" - "192.168.xxx.xxx:16379" redis_password: "p@ssw0rd" redis_cluster_name: redis-cluster redis_cluster_ssl: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-redis-cluster-plugin-config spec: plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: redis-cluster redis_cluster_ssl: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: redis-cluster-limit-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-redis-cluster-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: redis-cluster-limit-route spec: ingressClassName: apisix http: - name: redis-cluster-limit-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: redis-cluster redis_cluster_ssl: true ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` ❶ `policy`: 设置为 `redis-cluster` 以使用 Redis 集群进行限速。 ❷ `redis_cluster_nodes`: 设置为 Redis 集群中的 Redis 节点地址。 ❸ `redis_password`: 设置为 Redis 集群的密码(如果有)。 ❹ `redis_cluster_name`: 设置为 Redis 集群名称。 ❺ `redis_cluster_ssl`: 启用与 Redis 集群的 SSL/TLS 通信。 向 APISIX 实例发送请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在相同的 30 秒时间窗口内,向另一个 APISIX 实例发送相同请求,应收到 `HTTP/1.1 429 Too Many Requests` 响应,这表明不同 APISIX 节点上配置的路由共享同一配额。 ### 使用 Redis Sentinel 在 APISIX 节点之间共享配额[​](#使用-redis-sentinel-在-apisix-节点之间共享配额 "使用 Redis Sentinel 在 APISIX 节点之间共享配额的直接链接") 从 API7 企业版 3.9.14 起,还可以使用由 [Redis Sentinel](https://redis.io/docs/management/sentinel/) 管理的 Redis 节点,在多个 APISIX 节点之间应用同一配额,并通过主节点自动故障转移实现高可用。 为路由配置 Redis Sentinel 详情,并根据实际环境调整 Sentinel 节点、凭证和受监控的主节点名称。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis-sentinel", "redis_sentinels": [ { "host": "192.168.xxx.xxx", "port": 26379 }, { "host": "192.168.xxx.xxx", "port": 26380 } ], "redis_master_name": "mymaster", "sentinel_username": "sentinel-user", "sentinel_password": "p@ssw0rd", "redis_database": 1 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: limit-count-route uris: - /get plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-sentinel redis_sentinels: - host: 192.168.xxx.xxx port: 26379 - host: 192.168.xxx.xxx port: 26380 redis_master_name: mymaster sentinel_username: sentinel-user sentinel_password: p@ssw0rd redis_database: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-plugin-config spec: plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-sentinel redis_sentinels: - host: 192.168.xxx.xxx port: 26379 - host: 192.168.xxx.xxx port: 26380 redis_master_name: mymaster sentinel_username: sentinel-user sentinel_password: p@ssw0rd redis_database: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-sentinel redis_sentinels: - host: 192.168.xxx.xxx port: 26379 - host: 192.168.xxx.xxx port: 26380 redis_master_name: mymaster sentinel_username: sentinel-user sentinel_password: p@ssw0rd redis_database: 1 ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` 其中: * 将 `policy` 设置为 `redis-sentinel`,以使用 Redis Sentinel 管理的 Redis 节点。 * `redis_sentinels` 列出 Sentinel 节点,每个节点包含 `host` 和 `port`。 * `redis_master_name` 是 Sentinel 监控的主节点名称。 * 如果需要,使用 `sentinel_username` 和 `sentinel_password` 向 Sentinel 节点进行身份认证。 向 APISIX 实例发送请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应看到 `HTTP/1.1 200 OK` 响应及对应的响应体。 在相同的 30 秒时间窗口内,向另一个 APISIX 实例发送相同请求,应收到 `HTTP/1.1 429 Too Many Requests` 响应,这表明不同 APISIX 节点上配置的路由共享同一配额。 ### 对匿名消费者进行限速[​](#对匿名消费者进行限速 "对匿名消费者进行限速的直接链接") 以下示例演示了如何为普通消费者和匿名消费者配置不同的限速策略。匿名消费者无需进行身份认证,且拥有较少的配额。尽管本示例使用 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 进行身份认证,也可以为匿名消费者配置 [`basic-auth`](https://docs.apiseven.com/hub/basic-auth.md)、[`jwt-auth`](https://docs.apiseven.com/hub/jwt-auth.md) 或 [`hmac-auth`](https://docs.apiseven.com/hub/hmac-auth.md)。 * Admin API * ADC * Ingress Controller 创建配额为 3 的消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john", "plugins": { "limit-count": { "count": 3, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 为消费者 `john` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建配额为 1 的匿名用户 `anonymous`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "anonymous", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "policy": "local" } } }' ``` 创建一条配置 `key-auth` 插件且接受匿名消费者的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "key-auth-route", "uri": "/anything", "plugins": { "key-auth": { "anonymous_consumer": "anonymous" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 为消费者配置不同的限额,并创建一条接受匿名用户的路由: adc.yaml ``` consumers: - username: john plugins: limit-count: count: 3 time_window: 30 rejected_code: 429 policy: local credentials: - name: key-auth type: key-auth config: key: john-key - username: anonymous plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 policy: local services: - name: anonymous-rate-limit-service routes: - name: key-auth-route uris: - /anything plugins: key-auth: anonymous_consumer: anonymous upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 为消费者配置不同的限额,并创建一条接受匿名用户的路由: limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: anonymous spec: gatewayRef: name: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: key-auth-plugin-config spec: plugins: - name: key-auth config: anonymous_consumer: aic_anonymous # namespace_consumername --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: key-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: key-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f limit-count-ic.yaml ``` limit-count-apisix-crd.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: anonymous spec: ingressClassName: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: key-auth-route spec: ingressClassName: apisix http: - name: anything match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: key-auth config: anonymous_consumer: aic_anonymous ``` 将配置应用到集群: ``` kubectl apply -f limit-count-apisix-crd.yaml ``` 要进行验证,请使用 `john` 的密钥发送五个连续请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: john-key' -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示在 5 个请求中,3 个请求成功(状态码 200),而其他请求被拒绝(状态码 `429`)。 ``` 200: 3, 429: 2 ``` 发送五个匿名请求: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示只有一个请求成功: ``` 200: 1, 429: 4 ``` ### 自定义速率限制头[​](#自定义速率限制头 "自定义速率限制头的直接链接") 以下示例演示了如何使用插件元数据自定义速率限制响应头名称,默认情况下为 `X-RateLimit-Limit`、`X-RateLimit-Remaining` 和 `X-RateLimit-Reset`。 * Admin API * ADC * Ingress Controller 配置插件元数据以自定义限速响应头: ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/limit-count" -X PUT -d ' { "limit_header": "X-Custom-RateLimit-Limit", "remaining_header": "X-Custom-RateLimit-Remaining", "reset_header": "X-Custom-RateLimit-Reset" }' ``` 创建一条配置了 `limit-count` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "policy": "local" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 配置插件元数据并创建一条启用限速的路由: adc.yaml ``` plugin_metadata: limit-count: limit_header: X-Custom-RateLimit-Limit remaining_header: X-Custom-RateLimit-Remaining reset_header: X-Custom-RateLimit-Reset services: - name: limit-count-service routes: - name: limit-count-route uris: - /get plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 更新 `GatewayProxy` 清单中的插件元数据: gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 你的控制面连接配置 pluginMetadata: limit-count: limit_header: X-Custom-RateLimit-Limit remaining_header: X-Custom-RateLimit-Remaining reset_header: X-Custom-RateLimit-Reset ``` * Gateway API * APISIX CRD 创建一条启用该插件的路由: limit-count-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-plugin-config spec: plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 创建一条启用该插件的路由: limit-count-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: limit-count enable: true config: count: 1 time_window: 30 rejected_code: 429 key_type: var key: remote_addr policy: local ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f limit-count-ic.yaml ``` 发送请求进行验证: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该收到一个 `HTTP/1.1 200 OK` 响应并看到以下头部: ``` X-Custom-RateLimit-Limit: 1 X-Custom-RateLimit-Remaining: 0 X-Custom-RateLimit-Reset: 28 ``` --- # limit-count-advanced [企业版](https://api7.ai/enterprise) `limit-count-advanced` 插件使用固定窗口或滑动窗口算法,通过限制给定时间间隔内的请求数量来限制请求速率。超过配置配额的请求将被拒绝。 具体来说: * 固定窗口算法在不重叠的时间间隔内跟踪请求。如果请求计数在任何间隔内超过配额,多余的请求将立即被拒绝,直到下一个时间窗口开始。 * 滑动窗口算法在重叠的间隔内跟踪请求,通过计算过去配置的时间段内的最近请求来平滑速率限制,而不管间隔何时开始。此方法减少了流量峰值,并且更有效地在一段时间内均匀分布请求。 此外,你可能还会看到以下速率限制响应头,其名称可以使用[插件元数据](#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%80%9F%E7%8E%87%E9%99%90%E5%88%B6%E5%A4%B4)进行自定义: * `X-RateLimit-Limit`:总配额 * `X-RateLimit-Remaining`:剩余配额 * `X-RateLimit-Reset`:计数器重置前的剩余秒数 偶尔,你可能会观察到 `X-RateLimit-Remaining` 出现较小的负值。这是可以接受的,因为滑动窗口算法是一种近似值。 ## 本地限速与基于 Redis 的限速[​](#本地限速与基于-redis-的限速 "本地限速与基于 Redis 的限速的直接链接") `limit-count-advanced` 插件支持两种限速模式: * **本地限速**:每个网关实例独立实施限速。每个实例维护自己的计数器,因此当流量分散到多个实例时,实际限额约为“限额 × 实例数”。未设置 `policy` 或将其设置为 `local` 时,这是默认模式。 * **基于 Redis 的限速**:通过 Redis 在所有网关实例之间共享限额。所有实例共享同一配额,因此配置的限额适用于全部网关实例。 ## 示例[​](#示例 "示例的直接链接") 除了 [`limit-count`](https://docs.apiseven.com/hub/limit-count.md) 插件功能外,该插件还支持滑动窗口算法。请参考 [`limit-count`](https://docs.apiseven.com/hub/limit-count.md#%E7%A4%BA%E4%BE%8B) 插件以获取固定窗口示例,这些示例也可以在 `limit-count-advanced` 中配置。 以下示例演示了如何使用 `limit-count-advanced` 进行滑动窗口算法的速率限制。 ### 使用本地计数器进行速率限制[​](#使用本地计数器进行速率限制 "使用本地计数器进行速率限制的直接链接") 以下示例演示了如何配置 `limit-count-advanced` 在路由上使用滑动窗口算法进行速率限制,并使用网关中的计数器。请注意,每个网关实例都有自己的计数器和独立配额。如果你有多个网关实例需要共享相同的配额,请参阅[使用 Redis 服务器在网关之间共享配额](#%E4%BD%BF%E7%94%A8-redis-%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9C%A8%E7%BD%91%E5%85%B3%E4%B9%8B%E9%97%B4%E5%85%B1%E4%BA%AB%E9%85%8D%E9%A2%9D)。 创建一个启用了 `limit-count-advanced` 插件的路由,配置为每个远程地址在 10 秒滑动窗口内允许的配额为 5: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-sliding-route", "uri": "/get", "plugins": { "limit-count-advanced": { "policy": "local", "count": 5, "time_window": 10, "rejected_code": 429, "key_type": "var", "key": "remote_addr", "window_type": "sliding" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-count-sliding-route plugins: limit-count-advanced: policy: local count: 5 time_window: 10 rejected_code: 429 key_type: var key: remote_addr window_type: sliding upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-advanced-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-advanced-plugin-config spec: plugins: - name: limit-count-advanced config: policy: local count: 5 time_window: 10 rejected_code: 429 key_type: var key: remote_addr window_type: sliding --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-sliding-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-advanced-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-advanced-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-sliding-route spec: ingressClassName: apisix http: - name: limit-count-sliding-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-count-advanced config: policy: local count: 5 time_window: 10 rejected_code: 429 key_type: var key: remote_addr window_type: sliding ``` 应用配置: ``` kubectl apply -f limit-count-advanced-ic.yaml ``` 每隔一秒生成 7 个请求到该路由: ``` for i in $(seq 7); do (curl -I "http://127.0.0.1:9080/get" &) sleep 1 done ``` 你应该收到大多数请求的 `HTTP/1.1 200 OK` 响应,其余为 `HTTP 429 Too Many Requests` 响应。具体被拒绝的数量取决于第一个请求发送的时间。 ### 使用 Redis 服务器在网关之间共享配额[​](#使用-redis-服务器在网关之间共享配额 "使用 Redis 服务器在网关之间共享配额的直接链接") 以下示例演示了如何使用 Redis 服务器在多个网关节点之间使用滑动窗口算法进行速率限制,从而使不同的网关节点共享相同的速率限制配额。 在网关组中创建一个具有以下配置的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-sliding-route", "uri": "/get", "plugins": { "limit-count-advanced": { "count": 1, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis", "redis_host": "192.168.xxx.xxx", "redis_port": 6379, "redis_password": "p@ssw0rd", "redis_database": 1, "window_type": "sliding", "sync_interval": 0.2 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-count-sliding-route plugins: limit-count-advanced: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "192.168.xxx.xxx" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 window_type: sliding sync_interval: 0.2 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-advanced-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-advanced-plugin-config spec: plugins: - name: limit-count-advanced config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 window_type: sliding sync_interval: 0.2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-sliding-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-advanced-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-advanced-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-sliding-route spec: ingressClassName: apisix http: - name: limit-count-sliding-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-count-advanced config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis redis_host: "redis-service.aic.svc" redis_port: 6379 redis_password: "p@ssw0rd" redis_database: 1 window_type: sliding sync_interval: 0.2 ``` 应用配置: ``` kubectl apply -f limit-count-advanced-ic.yaml ``` ❶ `policy`:设置为 `redis` 以使用 Redis 实例进行速率限制。 ❷ `redis_host`:设置为 Redis 实例的 IP 地址。 ❸ `redis_port`:设置为 Redis 实例的监听端口。 ❹ `redis_password`:如果有,设置为 Redis 实例的密码。 ❺ `redis_database`:设置为 Redis 实例中的数据库编号。 ❻ `window_type`:将窗口类型设置为滑动窗口。 ❼ `sync_interval`:设置同步间隔(可选)。 每隔一秒生成 7 个请求到该路由: ``` for i in $(seq 7); do (curl -I "http://127.0.0.1:9080/get" &) sleep 1 done ``` 你应该收到大多数请求的 `HTTP/1.1 200 OK` 响应,其余为 `HTTP 429 Too Many Requests` 响应。具体被拒绝的数量取决于第一个请求发送的时间。这验证了配置在不同网关节点上的路由共享相同的配额。 ### 使用 Redis 集群在网关节点之间共享配额[​](#使用-redis-集群在网关节点之间共享配额 "使用 Redis 集群在网关节点之间共享配额的直接链接") 以下示例演示了如何配置 `limit-count-advanced` 使用滑动窗口算法,并在多个网关节点之间应用相同的配额,从而使不同的网关节点共享相同的速率限制配额。 确保你的 Redis 实例运行在[集群模式(Cluster Mode)](https://redis.io/docs/management/scaling/#create-and-use-a-redis-cluster)。`limit-count-advanced` 插件配置至少需要两个节点。 在网关组中创建一个具有以下配置的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count-advanced": { "count": 1, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis-cluster", "redis_cluster_nodes": [ "192.168.xxx.xxx:6379", "192.168.xxx.xxx:16379" ], "redis_password": "p@ssw0rd", "redis_cluster_name": "redis-cluster", "redis_cluster_ssl": true, "window_type": "sliding", "sync_interval": 0.2 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-count-route plugins: limit-count-advanced: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "192.168.xxx.xxx:6379" - "192.168.xxx.xxx:16379" redis_password: "p@ssw0rd" redis_cluster_name: "redis-cluster" redis_cluster_ssl: true window_type: sliding sync_interval: 0.2 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-advanced-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-advanced-plugin-config spec: plugins: - name: limit-count-advanced config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: "redis-cluster" redis_cluster_ssl: true window_type: sliding sync_interval: 0.2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-advanced-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-advanced-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-count-advanced config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-cluster redis_cluster_nodes: - "redis-cluster-0.redis-cluster.aic.svc:6379" - "redis-cluster-1.redis-cluster.aic.svc:6379" redis_password: "p@ssw0rd" redis_cluster_name: "redis-cluster" redis_cluster_ssl: true window_type: sliding sync_interval: 0.2 ``` 应用配置: ``` kubectl apply -f limit-count-advanced-ic.yaml ``` ❶ `policy`:设置为 `redis-cluster` 以使用 Redis 集群进行速率限制。 ❷ `redis_cluster_nodes`:设置为 Redis 集群中的 Redis 节点地址。 ❸ `redis_password`:如果有,设置为 Redis 集群的密码。 ❹ `redis_cluster_name`:设置为 Redis 集群名称。 ❺ `redis_cluster_ssl`:启用与 Redis 集群的 SSL/TLS 通信。 ❻ `window_type`:将窗口类型设置为滑动窗口。 ❼ `sync_interval`:设置同步间隔(可选)。 每隔一秒生成 7 个请求到该路由: ``` for i in $(seq 7); do (curl -I "http://127.0.0.1:9080/get" &) sleep 1 done ``` 你应该收到大多数请求的 `HTTP/1.1 200 OK` 响应,其余为 `HTTP 429 Too Many Requests` 响应。具体被拒绝的数量取决于第一个请求发送的时间。这验证了配置在不同网关节点上的路由共享相同的配额。 ### 自定义速率限制头[​](#自定义速率限制头 "自定义速率限制头的直接链接") 以下示例演示了如何使用插件元数据自定义速率限制响应头名称,默认情况下为 `X-RateLimit-Limit`、`X-RateLimit-Remaining` 和 `X-RateLimit-Reset`。 本示例假设已存在一条配置了 `limit-count-advanced` 插件的 `/get` 路由。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/limit-count-advanced" -X PUT -d ' { "log_format": { "limit_header": "X-Custom-RateLimit-Limit", "remaining_header": "X-Custom-RateLimit-Remaining", "reset_header": "X-Custom-RateLimit-Reset" } }' ``` adc.yaml ``` ... # 其他 ADC 配置 plugin_metadata: limit-count-advanced: limit_header: X-Custom-RateLimit-Limit remaining_header: X-Custom-RateLimit-Remaining reset_header: X-Custom-RateLimit-Reset ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `GatewayProxy` 清单中的插件元数据: gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # 在此添加你的控制面连接配置 # .... pluginMetadata: limit-count-advanced: log_format: limit_header: X-Custom-RateLimit-Limit remaining_header: X-Custom-RateLimit-Remaining reset_header: X-Custom-RateLimit-Reset ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` 发送请求进行验证: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该收到一个 `HTTP/1.1 200 OK` 响应并看到以下头部: ``` X-Custom-RateLimit-Limit: 1 X-Custom-RateLimit-Remaining: 0 X-Custom-RateLimit-Reset: 28 ``` ### 使用 Redis Sentinel 在网关节点之间共享配额[​](#使用-redis-sentinel-在网关节点之间共享配额 "使用 Redis Sentinel 在网关节点之间共享配额的直接链接") 以下示例演示了如何使用带有 Redis Sentinel 策略的 `limit-count-advanced` 插件进行速率限制。 确保你的 Redis 实例运行在 [Sentinel 模式](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/)。 在网关组中创建一个具有以下配置的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-route", "uri": "/get", "plugins": { "limit-count-advanced": { "count": 1, "time_window": 30, "rejected_code": 429, "key": "remote_addr", "policy": "redis-sentinel", "redis_sentinels": [ {"host": "127.0.0.1", "port": 26379}, {"host": "127.0.10.1", "port": 26379}, {"host": "127.0.101.1", "port": 26379} ], "redis_master_name": "mymaster", "redis_role": "master", "sentinel_username": "admin", "sentinel_password": "admin-password" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-count-route plugins: limit-count-advanced: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-sentinel redis_sentinels: - host: "127.0.0.1" port: 26379 - host: "127.0.10.1" port: 26379 - host: "127.0.101.1" port: 26379 redis_master_name: "mymaster" redis_role: "master" sentinel_username: "admin" sentinel_password: "admin-password" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-advanced-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-advanced-plugin-config spec: plugins: - name: limit-count-advanced config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-sentinel redis_sentinels: - host: "redis-sentinel-0.redis-sentinel.aic.svc" port: 26379 - host: "redis-sentinel-1.redis-sentinel.aic.svc" port: 26379 - host: "redis-sentinel-2.redis-sentinel.aic.svc" port: 26379 redis_master_name: "mymaster" redis_role: "master" sentinel_username: "admin" sentinel_password: "admin-password" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-advanced-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-advanced-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-route spec: ingressClassName: apisix http: - name: limit-count-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-count-advanced config: count: 1 time_window: 30 rejected_code: 429 key: remote_addr policy: redis-sentinel redis_sentinels: - host: "redis-sentinel-0.redis-sentinel.aic.svc" port: 26379 - host: "redis-sentinel-1.redis-sentinel.aic.svc" port: 26379 - host: "redis-sentinel-2.redis-sentinel.aic.svc" port: 26379 redis_master_name: "mymaster" redis_role: "master" sentinel_username: "admin" sentinel_password: "admin-password" ``` 应用配置: ``` kubectl apply -f limit-count-advanced-ic.yaml ``` ❶ `policy`:设置为 `redis-sentinel` 以使用 Sentinel 模式下的 Redis 进行速率限制。 ❷ `redis_sentinels`:配置 Sentinel 节点地址列表(主机和端口)。 ❸ `redis_master_name`:配置 Sentinel 监控的 Redis 主组名称。 ❹ `redis_role`:设置为 `master` 以连接到当前的 Redis 主节点。 ❺ `sentinel_username`:配置用于通过 Redis Sentinel 进行身份验证的用户名。 ❻ `sentinel_password`:配置用于通过 Redis Sentinel 进行身份验证的密码。 每隔一秒生成 5 个请求到该路由: ``` for i in $(seq 5); do (curl -I "http://127.0.0.1:9080/get" &) sleep 1 done ``` 你应该在 30 秒窗口内收到一个请求的 `HTTP/1.1 200 OK` 响应,其余为 `HTTP 429 Too Many Requests` 响应。 ### 基于规则的速率限制[​](#基于规则的速率限制 "基于规则的速率限制的直接链接") 以下示例演示了如何配置 `limit-count-advanced` 以根据请求属性应用不同的速率限制规则(从 API7 Enterprise 3.8.17 开始可用)。在此示例中,速率限制基于代表调用者访问层级的 HTTP 头值应用。 请注意,所有规则按顺序应用。如果配置的键不存在,则将跳过相应的规则。 提示 除 HTTP 请求头外,还可以根据其他[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)配置规则,以实现更灵活、更细粒度的限速策略。 创建一个启用了 `limit-count-advanced` 插件的路由,该插件根据请求头应用不同的速率限制,允许每个订阅(`X-Subscription-ID`)进行速率限制,并对试用用户(`X-Trial-ID`)强制执行更严格的限制: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-count-rules-route", "uri": "/get", "plugins": { "limit-count-advanced": { "policy": "local", "rejected_code": 429, "rules": [ { "key": "${http_x_subscription_id}", "count": "${http_x_custom_count ?? 5}", "time_window": 60 }, { "key": "${http_x_trial_id}", "count": 1, "time_window": 60 } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-count-rules-route plugins: limit-count-advanced: policy: local rejected_code: 429 rules: - key: "${http_x_subscription_id}" count: "${http_x_custom_count ?? 5}" time_window: 60 - key: "${http_x_trial_id}" count: 1 time_window: 60 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-count-advanced-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-count-advanced-plugin-config spec: plugins: - name: limit-count-advanced config: policy: local rejected_code: 429 rules: - key: "${http_x_subscription_id}" count: "${http_x_custom_count ?? 5}" time_window: 60 - key: "${http_x_trial_id}" count: 1 time_window: 60 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-count-rules-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-count-advanced-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-count-advanced-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-count-rules-route spec: ingressClassName: apisix http: - name: limit-count-rules-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-count-advanced config: policy: local rejected_code: 429 rules: - key: "${http_x_subscription_id}" count: "${http_x_custom_count ?? 5}" time_window: 60 - key: "${http_x_trial_id}" count: 1 time_window: 60 ``` 应用配置: ``` kubectl apply -f limit-count-advanced-ic.yaml ``` ❶ 使用 `X-Subscription-ID` 请求头的值作为速率限制键。 ❷ 根据 `X-Custom-Count` 头动态设置请求限制。如果未提供该头,则应用默认计数 5 个请求。 ❸ 使用 `X-Trial-ID` 请求头的值作为速率限制键。 要验证速率限制,使用相同的订阅 ID 生成 7 个请求到该路由: ``` resp=$(seq 7 | xargs -I{} curl "http://127.0.0.1:9080/get" -H "X-Subscription-ID: sub-123456789" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示当未提供 `X-Custom-Count` 头时,应用了 5 个请求的默认计数: ``` 200: 5, 429: 2 ``` 等待时间窗口重置。使用相同的订阅 ID 生成 5 个请求到该路由,并将 `X-Custom-Count` 头设置为 3: ``` resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/get" -H "X-Subscription-ID: sub-123456789" -H "X-Custom-Count: 3" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示应用了来自 `X-Custom-Count` 头的 3 个请求的计数: ``` 200: 3, 429: 2 ``` 最后,使用相同的试用 ID 生成 3 个请求到该路由: ``` resp=$(seq 3 | xargs -I{} curl "http://127.0.0.1:9080/get" -H "X-Trial-ID: trial-123456789" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该会看到以下响应,显示应用了来自第二条规则的 1 个请求的计数: ``` 200: 1, 429: 2 ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 该插件支持使用 `env://` 前缀从环境变量引用敏感参数值,也支持使用 `secret://` 前缀从密钥管理器(例如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv))引用敏感参数值。有关更多信息,请参阅[插件中的环境变量](https://docs.apiseven.com/apisix/reference/environment-variables.md#plugins)和[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 备注 在 API7 企业版 3.8.17 及更高版本中,请配置以下两组参数之一,不要同时配置: * `count`, `time_window` * `rules` - count integer | string 必填 有效值: 大于 0 *** 给定时间间隔内允许的最大请求数。 在 API7 企业版(从 3.8.17 开始)中,此参数还支持字符串数据类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)。 - time\_window integer | string 必填 有效值: 大于 0 *** 与速率限制 `count` 对应的时间间隔,以秒为单位。 在 API7 企业版(从 3.8.17 开始)中,此参数还支持字符串数据类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)。 - window\_type string 默认值:`fixed` 有效值: `fixed` 或 `sliding` *** 速率限制算法,固定窗口或滑动窗口。 - key\_type string 默认值:`var` 有效值: `var`、`var_combination` 或 `constant` *** 键的类型。 如果 `key_type` 为 `var`,则 `key` 被解释为变量。 如果 `key_type` 为 `var_combination`,则 `key` 被解释为变量组合。 如果 `key_type` 为 `constant`,则 `key` 被解释为常量。 - key string 默认值:`remote_addr` *** 用于计数请求的键。 如果 `key_type` 为 `var`,则 `key` 被解释为变量。变量不需要以美元符号(`$`)作为前缀。查看[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)以获取可用变量。 如果 `key_type` 为 `var_combination`,则 `key` 被解释为变量组合。所有变量都应以美元符号(`$`)作为前缀。例如,要将 `key` 配置为使用两个请求头 `custom-a` 和 `custom-b` 的组合,`key` 应配置为 `$http_custom_a $http_custom_b`。 如果 `key_type` 为 `constant`,则 `key` 被解释为常量值。 - rejected\_code integer 默认值:`503` 有效值: 介于 200 和 599 之间(含边界值) *** 当请求因超过阈值而被拒绝时返回的 HTTP 状态码。 - rejected\_msg string 有效值: 任意非空字符串 *** 当请求因超过阈值而被拒绝时返回的响应体。 - policy string 默认值:`local` 有效值: `local`、`redis`、`redis-cluster` 或 `redis-sentinel` *** 速率限制计数器的策略。 设置为 `local` 以将计数器存储在本地内存中。 设置为 `redis` 以将计数器存储在 Redis 实例中。 设置为 `redis-cluster` 以将计数器存储在 Redis 集群中。 设置为 `redis-sentinel` 以将计数器存储在由 Redis Sentinel 管理的 Redis 主节点上,这通过在故障时自动将副本提升为主节点来确保高可用性。当不使用 Redis Cluster 时,Redis Sentinel 为 Redis 提供高可用性。 - redis\_sentinels array\[object] *** Redis Sentinel 节点数组(主机和端口)。当 `policy` 为 `redis-sentinel` 时必填。 - redis\_master\_name string *** Sentinel 监控的 Redis 主组名称。当 `policy` 为 `redis-sentinel` 时必填。 - redis\_role string 默认值:`master` 有效值: `master` 或 `slave` *** 要连接的 Redis 节点角色。当 `policy` 为 `redis-sentinel` 时可配置。设置为 `master` 以连接到当前的 Redis 主节点,设置为 `slave` 以连接到 Redis 副本。 - redis\_connect\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 建立到 Redis 节点的连接的超时时间(毫秒)。当 `policy` 为 `redis-sentinel` 时可配置。 - redis\_read\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 从 Redis 节点读取数据的超时时间(毫秒)。当 `policy` 为 `redis-sentinel` 时可配置。 - sentinel\_username string *** 用于通过 Redis Sentinel 实例进行身份验证的用户名。当 `policy` 为 `redis-sentinel` 时可配置。 - sentinel\_password string *** 用于通过 Redis Sentinel 实例进行身份验证的密码。当 `policy` 为 `redis-sentinel` 时可配置。 - allow\_degradation boolean 默认值:`false` *** 如果为 true,则在插件或其依赖项不可用时,允许网关继续处理请求而不使用该插件。 - rules array\[object] *** 速率限制规则数组,按顺序应用。 在 API7 企业版 3.8.17 版本中可用。 * count integer | string 必填 有效值: 大于 0 *** 给定时间间隔内允许的最大请求数。 此参数还支持字符串数据类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)。 * time\_window integer | string 必填 有效值: 大于 0 *** 与速率限制 `count` 对应的时间间隔,以秒为单位。 此参数还支持字符串数据类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)。 * key string 必填 *** 用于计数请求的键。如果配置的键不存在,则不会执行该规则。 `key` 被解释为变量组合,例如 `$http_custom_a $http_custom_b`。 * header\_prefix string *** 所有速率限制响应头的前缀。在 API7 企业版 3.8.19 版本中可用。 配置后,前缀将插入到标题名称中的 `X-` 之后。例如,如果 `header_prefix` 设置为 `test`,则头部变为 `X-Test-RateLimit-Limit`、`X-Test-RateLimit-Remaining` 和 `X-Test-RateLimit-Reset`。 如果未配置,则使用规则在规则数组中的索引作为前缀。例如,第一条规则的头部将是 `X-1-RateLimit-Limit`、`X-1-RateLimit-Remaining` 和 `X-1-RateLimit-Reset`。 - show\_limit\_quota\_header boolean 默认值:`true` *** 如果为 true,则包含速率限制响应头。具体而言,未设置 `rules` 时,响应头为: * `X-RateLimit-Limit` 显示总配额。 * `X-RateLimit-Remaining` 显示剩余配额。 * `X-RateLimit-Reset` 显示计数器重置前的剩余秒数。
设置 `rules` 后,会在 `X-` 后插入一个前缀(后跟连字符)。有关详细信息,请参阅 `rules.header_prefix`。 - group string 有效值: 非空 *** 插件的 `group` ID,同一 `group` 的路由可以共享相同的速率限制计数器。 - redis\_host string *** Redis 节点的地址。当 `policy` 为 `redis` 时必填。 - redis\_port integer 默认值:`6379` 有效值: 大于或等于 1 *** Redis 节点的端口。当 `policy` 为 `redis` 时使用。 - redis\_username string *** 如果使用 Redis ACL,则为 Redis 的用户名。如果你使用传统的认证方法 `requirepass`,则只需配置 `redis_password`。当 `policy` 为 `redis` 时使用。 - redis\_password string *** Redis 节点的密码。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。 - redis\_database integer 默认值:`0` 有效值: 大于或等于 0 *** Redis 中的数据库编号。当 `policy` 为 `redis` 或 `redis-sentinel` 时使用。 - redis\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接到 Redis。 - redis\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。 - redis\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** Redis 超时时间(毫秒)。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。 - redis\_keepalive\_timeout integer 有效值: 对 `redis` 和 `redis-cluster` 大于或等于 1000;对 `redis-sentinel` 大于或等于 1 *** 空闲 Redis 连接在连接池中关闭前保持活动的时间(毫秒)。当 `policy` 为 `redis` 或 `redis-cluster` 时,默认值为 `10000`;当 `policy` 为 `redis-sentinel` 时,默认值为 `60000`。 对 `redis` 和 `redis-cluster`,此参数在 API7 企业版 3.9.16 和 3.10.3 中引入。 - redis\_keepalive\_pool integer 默认值:`100` 有效值: 大于或等于 1 *** 保活连接池中空闲 Redis 连接的最大数量。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。 此参数在 API7 企业版 3.9.16 和 3.10.3 中引入。 - redis\_cluster\_nodes array\[string] *** Redis 集群节点列表,至少包含两个地址。当 `policy` 为 `redis-cluster` 时必填。 - redis\_cluster\_name string *** Redis 集群的名称。当 `policy` 为 `redis-cluster` 时必填。 - redis\_cluster\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时使用 SSL 连接到 Redis 集群。 - redis\_cluster\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时验证服务器 SSL 证书。 - sync\_interval number 默认值:`-1` 有效值: 大于或等于 0.1,或者使用默认值 -1 *** 将计数器数据同步到 Redis 的频率。仅在 企业版 中可用。 `sync_interval` 值应小于 `time_window`。值 `1` 导致每秒同步计数器数据。值 `-1` 产生无变化同步行为,即每个请求都会同步计数器数据。 --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 该插件支持使用 `env://` 前缀从环境变量引用参数值,也支持使用 `secret://` 前缀从密钥管理器(例如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv))引用参数值。有关更多信息,请参阅[插件中的环境变量](https://docs.apiseven.com/apisix/reference/environment-variables.md#plugins)和[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * count integer | string 有效值: 大于 0 *** 给定时间间隔内允许的最大请求数。 字符串值可以通过在变量前添加美元符号(`$`)来引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.16.0 起引入。更早的版本仅接受整数值。 未配置 `rules` 时,此字段必须与 `time_window` 一起配置。不要同时配置 `count` 或 `time_window` 与 `rules`。 字符串值必须解析为不大于 `9007199254740991` 的正整数。无效值会返回 `500 Internal Server Error`,除非 `allow_degradation` 为 `true`。自 API7 企业版 3.9.16 和 3.10.2 以及 APISIX 3.18.0 起引入。 * time\_window integer | string 有效值: 大于 0 *** 与速率限制 `count` 对应的时间间隔,单位为秒。 字符串值可以通过在变量前添加美元符号(`$`)来引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.16.0 起引入。更早的版本仅接受整数值。 未配置 `rules` 时,此字段必须与 `count` 一起配置。不要同时配置 `count` 或 `time_window` 与 `rules`。 字符串值必须解析为不大于 `9007199254740991` 的正整数。无效值会返回 `500 Internal Server Error`,除非 `allow_degradation` 为 `true`。自 API7 企业版 3.9.16 和 3.10.2 以及 APISIX 3.18.0 起引入。 * key\_type string 默认值:`var` 有效值: `var`、`var_combination` 或 `constant` *** 密钥类型。 如果 `key_type` 为 `var`,则 `key` 将被解释为变量。 如果 `key_type` 为 `var_combination`,则 `key` 将被解释为变量组合。 如果 `key_type` 为 `constant`,则 `key` 将被解释为常量。 * key string 默认值:`remote_addr` *** 用于计数请求的密钥。 如果 `key_type` 为 `var`,则 `key` 将被解释为变量。变量不需要以美元符号(`$`)作为前缀。请参阅[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)以获取可用变量。 如果 `key_type` 为 `var_combination`,则 `key` 将被解释为变量组合。所有变量都应以美元符号(`$`)作为前缀。例如,要配置 `key` 使用两个请求头 `custom-a` 和 `custom-b` 的组合,则 `key` 应配置为 `$http_custom_a $http_custom_b`。 如果 `key_type` 为 `constant`,则 `key` 将被解释为常量值。 * rejected\_code integer 默认值:`503` 有效值: 介于 200 和 599 之间(含边界值) *** 当请求因超过阈值而被拒绝时返回的 HTTP 状态码。 * rejected\_msg string 有效值: 任意非空字符串 *** 当请求因超过阈值而被拒绝时返回的响应体。 * policy string 默认值:`local` 有效值: `local`、`redis`、`redis-cluster` 或 `redis-sentinel` *** 速率限制计数器的策略。API7 企业版中为必填项,APISIX 中为可选项。 限速计数器的策略。如果为 `local`,则计数器存储在本地内存中。如果为 `redis`,则计数器存储在 Redis 实例上。如果为 `redis-cluster`,则计数器存储在 Redis 集群中。如果为 `redis-sentinel`,则计数器存储在由 Redis Sentinel 管理的 Redis 节点上,以实现高可用。 `redis-sentinel` 通过由 Sentinel 管理的故障转移提供高可用性。自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起引入。 * window\_type string 默认值:`fixed` 有效值: `fixed` 或 `sliding` *** 限速窗口算法。如果为 `fixed`,则使用固定窗口算法,每个时间窗口独立地实施配额。如果为 `sliding`,则使用滑动窗口算法,在计算当前计数时对上一个窗口进行加权,从而平滑窗口边界处的突发流量。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起引入。 * sync\_interval number 默认值:`-1` 有效值: `-1`,或大于或等于 `0.1`;必须小于数值类型的顶层 `time_window` *** 将本地计数器同步到共享存储(Redis)的时间间隔(以秒为单位)。仅当 `policy` 为 `redis`、`redis-cluster` 或 `redis-sentinel` 时生效。取值为 `-1` 时禁用延迟同步,每个请求都直接同步。启用时,取值不应小于 `0.1` 且应小于 `time_window`。启用延迟同步可减少访问共享存储的往返次数,但代价是限速实施略微宽松。 运行时,如果适用的 `time_window` 小于或等于 `sync_interval`,网关会对该请求回退为直接同步。这可能发生在请求时求值的变量解析值或 `rules` 内的值上。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起引入。 * allow\_degradation boolean 默认值:`false` *** 如果为 true,则在计数器后端失败,或变量解析的 `count` 或 `time_window` 无效时,继续处理请求但不进行速率限制。如果为 false,这些失败会返回 `500 Internal Server Error`。 * show\_limit\_quota\_header boolean 默认值:`true` *** 如果为 true,则在响应中包含配额响应头。 使用默认名称时,`X-RateLimit-Limit` 表示总配额,`X-RateLimit-Remaining` 表示窗口内剩余的请求数,`X-RateLimit-Reset` 表示计数器重置前的秒数。 可以通过插件元数据重命名这些响应头。配置 `rules` 时,每条规则会在 `RateLimit-` 前插入其 `header_prefix`(省略时使用规则索引),使各规则的 Limit、Remaining 和 Reset 保持可区分。请参阅 `rules.header_prefix`。 * group string 有效值: 非空 *** 插件的 `group` ID,以便同一 `group` 的路由可以共享相同的限速计数器。 * redis\_host string *** Redis 节点的地址。当 `policy` 为 `redis` 时必填。 * redis\_port integer 默认值:`6379` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 时 Redis 节点的端口。 * redis\_username string *** 如果使用 Redis ACL,则为 Redis 用户名。如果你使用传统的身份验证方法 `requirepass`,请仅配置 `redis_password`。当 `policy` 为 `redis` 或 `redis-sentinel` 时使用。 * redis\_password string *** 当 `policy` 为 `redis`、`redis-cluster` 或 `redis-sentinel` 时 Redis 节点的密码。该密码在 API7 企业版中静态加密。在 APISIX 中,请[启用数据加密](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md),使其在存储到 etcd 前加密。加密功能自 API7 企业版 3.9.16 和 3.10.2 以及 APISIX 3.18.0 起引入。 * redis\_database integer 默认值:`0` 有效值: 大于或等于 0 *** 当 `policy` 为 `redis` 或 `redis-sentinel` 时 Redis 中的数据库编号。 * redis\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接到 Redis。 * redis\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。 * redis\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时的 Redis 超时值(以毫秒为单位)。 * redis\_keepalive\_timeout integer 有效值: 对 `redis` 和 `redis-cluster` 大于或等于 1000;对 `redis-sentinel` 大于或等于 1 *** Redis 连接的保活超时时间(毫秒)。当 `policy` 为 `redis` 或 `redis-cluster` 时,默认值为 `10000`,最小值为 `1000`;当 `policy` 为 `redis-sentinel` 时,默认值为 `60000`,最小值为 `1`。 自 API7 企业版 3.9.16 和 3.10.3 以及 APISIX 3.15.0 起引入。Sentinel 默认值自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起引入。 * redis\_keepalive\_pool integer 默认值:`100` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时的 Redis keepalive 连接池大小。 此参数自 API7 企业版 3.9.16 和 3.10.3 以及 APISIX 3.15.0 起可用。 * redis\_cluster\_nodes array\[string] *** Redis 集群节点列表,至少包含两个地址。当 `policy` 为 `redis-cluster` 时必填。 * redis\_cluster\_name string *** Redis 集群的名称。当 `policy` 为 `redis-cluster` 时必填。 * redis\_cluster\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时使用 SSL 连接到 Redis 集群。 * redis\_cluster\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时验证服务器 SSL 证书。 * redis\_sentinels array\[object] *** Redis Sentinel 节点列表,至少包含一个节点。当 `policy` 为 `redis-sentinel` 时必填。每个节点为一个对象,包含 `host`(字符串)和 `port`(介于 1 到 65535 之间的整数)。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起可用。 * redis\_master\_name string *** 由 Sentinel 监控的 Redis 主节点名称。当 `policy` 为 `redis-sentinel` 时必填。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起可用。 * redis\_role string 默认值:`master` 有效值: `master` 或 `slave` *** 当 `policy` 为 `redis-sentinel` 时要连接的 Redis 节点角色。使用 `master` 进行读写操作,或使用 `slave` 连接只读副本。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起可用。 * redis\_connect\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis-sentinel` 时的连接超时时间(以毫秒为单位)。 自 API7 企业版 3.9.14 和 3.10.1,以及 APISIX 3.18.0 起可用。 * redis\_read\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis-sentinel` 时的读取超时时间(以毫秒为单位)。 自 API7 企业版 3.9.14 和 3.10.1,以及 APISIX 3.18.0 起可用。 * sentinel\_username string *** 当 `policy` 为 `redis-sentinel` 时用于向 Redis Sentinel 节点进行身份验证的用户名。 自 API7 企业版 3.9.14 和 3.10.1,以及 APISIX 3.18.0 起可用。 * sentinel\_password string *** 当 `policy` 为 `redis-sentinel` 时用于向 Redis Sentinel 节点进行身份验证的密码。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.18.0 起引入。 该密码在 API7 企业版中静态加密。在 APISIX 中,请[启用数据加密](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md),使其在存储到 etcd 前加密。加密功能自 API7 企业版 3.9.16 和 3.10.2 以及 APISIX 3.18.0 起引入。 * rules array\[object] *** 按顺序应用的速率限制规则数组。不要同时配置 `rules` 与顶层 `count`、`time_window` 或 `group` 字段。规则模式不使用顶层 `key` 和 `key_type`。规则的键必须唯一。如果请求中不存在规则的 `key` 变量,则跳过该规则。 自 API7 企业版 3.9.14 和 3.10.1 以及 APISIX 3.16.0 起引入。 * count integer | string 必填 有效值: 大于 0 *** 给定 `time_window` 内允许的最大请求数。 此参数还支持字符串类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 字符串值必须解析为不大于 `9007199254740991` 的正整数。如果规则适用但值无效,请求会返回 `500 Internal Server Error`,除非 `allow_degradation` 为 `true`。自 API7 企业版 3.9.16 和 3.10.2 以及 APISIX 3.18.0 起引入。 * time\_window integer | string 必填 有效值: 大于 0 *** 速率限制 `count` 对应的时间间隔,单位为秒。 此参数还支持字符串类型,并允许使用以美元符号(`$`)为前缀的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 字符串值必须解析为不大于 `9007199254740991` 的正整数。如果规则适用但值无效,请求会返回 `500 Internal Server Error`,除非 `allow_degradation` 为 `true`。自 API7 企业版 3.9.16 和 3.10.2 以及 APISIX 3.18.0 起引入。 * key string 必填 *** 解析为此规则请求计数键的变量表达式。每个 APISIX [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)或 NGINX 变量都必须以美元符号(`$`)开头,例如 `$remote_addr` 或 `$remote_addr $http_x_tenant`。 顶层 `key_type` 不适用于规则。无法解析变量的规则会针对该请求被跳过。 * header\_prefix string *** 插入到此规则配额响应头中 `RateLimit-` 之前的前缀,使每条规则保持可区分。使用默认名称时,`foo` 会生成 `X-foo-RateLimit-Limit`、`X-foo-RateLimit-Remaining` 和 `X-foo-RateLimit-Reset`。这些响应头仍分别表示总配额、剩余配额和重置前秒数。省略时使用规则的数组索引,因此第一条规则会生成 `X-1-RateLimit-Limit`。仅在 `show_limit_quota_header` 为 `true` 时发送。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * limit\_header string 默认值:`X-RateLimit-Limit` *** 表示速率限制总配额的默认响应头名称。 * remaining\_header string 默认值:`X-RateLimit-Remaining` *** 表示速率限制剩余配额的默认响应头名称。 * reset\_header string 默认值:`X-RateLimit-Reset` *** 表示速率限制计数器重置前剩余秒数的默认响应头名称。 --- # limit-req `limit-req` 插件使用[漏桶](https://en.wikipedia.org/wiki/Leaky_bucket)算法来限制请求数量并允许进行流量整形。 ## 本地限速与基于 Redis 的限速[​](#本地限速与基于-redis-的限速 "本地限速与基于 Redis 的限速的直接链接") `limit-req` 插件支持两种限速模式: * **本地限速**:每个网关实例独立实施限速。每个实例维护自己的计数器,因此当流量分散到多个实例时,实际限额约为“限额 × 实例数”。未设置 `policy` 或将其设置为 `local` 时,这是默认模式。 * **基于 Redis 的限速**:所有网关实例通过 Redis 共享限额,因此配置的限额会应用到所有网关实例。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `limit-req`。 ### 基于远程地址进行速率限制[​](#基于远程地址进行速率限制 "基于远程地址进行速率限制的直接链接") 以下示例演示了如何通过单个变量 `remote_addr` 对 HTTP 请求进行速率限制。 创建一个启用了 `limit-req` 插件的路由,配置为每个远程地址允许 1 QPS: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d ' { "id": "limit-req-route", "uri": "/get", "plugins": { "limit-req": { "rate": 1, "burst": 0, "key": "remote_addr", "key_type": "var", "rejected_code": 429, "policy": "local", "nodelay": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-req-route plugins: limit-req: rate: 1 burst: 0 key: remote_addr key_type: var rejected_code: 429 policy: local nodelay: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-req-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-req-plugin-config spec: plugins: - name: limit-req config: rate: 1 burst: 0 key: remote_addr key_type: var rejected_code: 429 policy: local nodelay: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-req-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-req-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-req-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-req-route spec: ingressClassName: apisix http: - name: limit-req-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-req config: rate: 1 burst: 0 key: remote_addr key_type: var rejected_code: 429 policy: local nodelay: true ``` 应用配置: ``` kubectl apply -f limit-req-ic.yaml ``` ❶ `rate`:将 QPS 限制为 1。 ❷ `key`:设置为 `remote_addr`,以根据远程地址应用速率限制配额。 ❸ `key_type`:设置为 `var`,以将 `key` 解释为变量。 发送请求进行验证: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该会看到一个 `HTTP/1.1 200 OK` 响应。 该请求已消耗了时间窗口内允许的所有配额。如果你在同一秒内再次发送请求,应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应,表明请求超过了配额阈值。 ### 实现 API 流量整形[​](#实现-api-流量整形 "实现 API 流量整形的直接链接") 以下示例演示了如何配置 `burst` 以允许超过速率限制阈值的请求按配置值进行排队,从而实现请求流量整形。你还将看到与未实施流量整形时的比较。 创建一个启用了 `limit-req` 插件的路由,配置为每个远程地址允许 1 QPS,`burst` 为 1: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-req-route", "uri": "/get", "plugins": { "limit-req": { "rate": 1, "burst": 1, "key": "remote_addr", "rejected_code": 429, "policy": "local" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-req-route plugins: limit-req: rate: 1 burst: 1 key: remote_addr rejected_code: 429 policy: local upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD limit-req-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-req-plugin-config spec: plugins: - name: limit-req config: rate: 1 burst: 1 key: remote_addr rejected_code: 429 policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-req-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-req-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-req-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-req-route spec: ingressClassName: apisix http: - name: limit-req-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-req config: rate: 1 burst: 1 key: remote_addr rejected_code: 429 policy: local ``` 应用配置: ``` kubectl apply -f limit-req-ic.yaml ``` ❶ `burst`:允许 1 个超过 `rate` 的请求延迟处理。 生成三个请求到该路由: ``` resp=$(seq 3 | xargs -I{} curl -i "http://127.0.0.1:9080/get" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200 responses: $count_200 ; 429 responses: $count_429" ``` 你可能会看到所有三个请求都成功: ``` 200 responses: 3 ; 429 responses: 0 ``` 要查看没有 `burst` 的效果,请将 `burst` 更新为 0 或将 `nodelay` 设置为 `true`,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/limit-req-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "limit-req": { "nodelay": true } } }' ``` 在 ADC YAML 中设置 `nodelay: true`: adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: limit-req-route plugins: limit-req: rate: 1 burst: 1 # 或者,将 burst 设置为 0 key: remote_addr rejected_code: 429 policy: local nodelay: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将更新后的插件配置同步到网关: ``` adc sync -f adc.yaml ``` 按如下方式更新清单文件: * Gateway API * APISIX CRD limit-req-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-req-plugin-config spec: plugins: - name: limit-req config: rate: 1 burst: 1 # 或者,将 burst 设置为 0 key: remote_addr rejected_code: 429 policy: local nodelay: true ``` limit-req-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-req-route spec: ingressClassName: apisix http: - name: limit-req-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: limit-req config: rate: 1 burst: 1 # 或者,将 burst 设置为 0 key: remote_addr rejected_code: 429 policy: local nodelay: true ``` 应用更新后的配置: ``` kubectl apply -f limit-req-ic.yaml ``` 再次生成三个请求到该路由: ``` resp=$(seq 3 | xargs -I{} curl -i "http://127.0.0.1:9080/get" -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200 responses: $count_200 ; 429 responses: $count_429" ``` 你应该会看到类似于以下的响应,表明超过速率的请求已被拒绝: ``` 200 responses: 1 ; 429 responses: 2 ``` ### 基于远程地址和消费者名称进行速率限制[​](#基于远程地址和消费者名称进行速率限制 "基于远程地址和消费者名称进行速率限制的直接链接") 以下示例演示了如何通过变量组合 `remote_addr` 和 `consumer_name` 对请求进行速率限制。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建第二个消费者 `jane`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jane" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 创建一个启用了 `key-auth` 和 `limit-req` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "limit-req-route", "uri": "/get", "plugins": { "key-auth": {}, "limit-req": { "rate": 1, "burst": 0, "key": "$remote_addr $consumer_name", "key_type": "var_combination", "rejected_code": 429, "policy": "local" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建两个消费者和一个按消费者启用限速的路由: adc.yaml ``` consumers: - username: john credentials: - name: key-auth type: key-auth config: key: john-key - username: jane credentials: - name: key-auth type: key-auth config: key: jane-key services: - name: limit-req-service routes: - name: limit-req-route uris: - /get plugins: key-auth: {} limit-req: rate: 1 burst: 0 key: "$remote_addr $consumer_name" key_type: var_combination rejected_code: 429 policy: local upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建两个消费者和一个按消费者启用限速的路由: * Gateway API * APISIX CRD limit-req-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jane spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: jane-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: limit-req-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: limit-req config: rate: 1 burst: 0 key: "$remote_addr $consumer_name" key_type: var_combination rejected_code: 429 policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: limit-req-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: limit-req-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` limit-req-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: limit-req-route spec: ingressClassName: apisix http: - name: limit-req-route match: paths: - /get methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: key-auth config: _meta: disable: false - name: limit-req config: rate: 1 burst: 0 key: "$remote_addr $consumer_name" key_type: var_combination rejected_code: 429 policy: local ``` 应用配置: ``` kubectl apply -f limit-req-ic.yaml ``` ❶ `key-auth`:在路由上启用密钥认证。 ❷ `key`:设置为 `$remote_addr $consumer_name`,以根据远程地址和消费者应用速率限制配额。 ❸ `key_type`:设置为 `var_combination`,将 `key` 解释为变量组合。 同时发送两个请求,每个消费者一个: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key' & \ curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key' & ``` 你应该收到两个请求的 `HTTP/1.1 200 OK` 响应,表明每个消费者的请求均未超过阈值。 如果你在同一秒内作为任一消费者发送更多请求,你应该会收到一个 `HTTP/1.1 429 Too Many Requests` 响应。 这验证了插件是根据变量组合 `remote_addr` 和 `consumer_name` 进行速率限制的。 --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * rate number 必填 有效值: 大于 0 *** 每秒允许的最大请求数。超过此速率但低于 burst 的请求将被延迟。 * burst number 必填 有效值: 大于或等于 0 *** 每秒允许延迟处理的请求数(用于流量整形)。超过 rate 和 burst 总和的请求将被拒绝。 * key\_type string 默认值:`var` 有效值: `var` 或 `var_combination` *** 键的类型。 如果 `key_type` 为 `var`,则 `key` 被解释为变量。 如果 `key_type` 为 `var_combination`,则 `key` 被解释为变量组合。 * key string 必填 *** 用于计数请求的键。 如果 `key_type` 为 `var`,则 `key` 被解释为变量。变量不需要以美元符号(`$`)作为前缀。查看[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)以获取可用变量。 如果 `key_type` 为 `var_combination`,则 `key` 被解释为变量组合。所有变量都应以美元符号(`$`)作为前缀。例如,要将 `key` 配置为使用两个请求头 `custom-a` 和 `custom-b` 的组合,`key` 应配置为 `$http_custom_a $http_custom_b`。 * rejected\_code integer 默认值:`503` 有效值: 介于 200 和 599 之间(含边界值) *** 当请求因超过阈值而被拒绝时返回的 HTTP 状态码。 * rejected\_msg string 有效值: 任意非空字符串 *** 当请求因超过阈值而被拒绝时返回的响应体。 * nodelay boolean 默认值:`false` *** 如果为 true,则不延迟 burst 阈值内的请求。 * allow\_degradation boolean 默认值:`false` *** 如果为 true,则在插件或其依赖项不可用时,允许网关继续处理请求而不使用该插件。 * policy string 默认值:`local` 有效值: `local`、`redis` 或 `redis-cluster` *** 速率限制计数器的策略。如果为 `local`,则计数器存储在本地内存中。如果为 `redis`,则计数器存储在 Redis 实例中。如果为 `redis-cluster`,则计数器存储在 Redis 集群中。 如果你使用的是 API7 企业版,该选项从版本 3.9.0 开始可用。 * redis\_host string *** Redis 节点的地址。当 `policy` 为 `redis` 时必填。 * redis\_port integer 默认值:`6379` 有效值: 大于或等于 1 *** Redis 节点的端口。当 `policy` 为 `redis` 时使用。 * redis\_username string *** 如果使用 Redis ACL,则为 Redis 的用户名。如果你使用传统的认证方法 `requirepass`,则只需配置 `redis_password`。当 `policy` 为 `redis` 时使用。 * redis\_password string *** 当 `policy` 为 `redis` 或 `redis-cluster` 时 Redis 节点的密码。API7 企业版会对静态存储的该值进行加密;在 APISIX 中,请[启用数据加密](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md),以便在存入 etcd 前加密该值。加密能力自 API7 企业版 3.9.16 和 3.10.2,以及 APISIX 3.18.0 起可用。 * redis\_database integer 默认值:`0` 有效值: 大于或等于 0 *** Redis 中的数据库编号。当 `policy` 为 `redis` 时使用。 * redis\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时使用 SSL 连接到 Redis。 * redis\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis` 时验证服务器 SSL 证书。 * redis\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** Redis 超时时间(毫秒)。当 `policy` 为 `redis` 或 `redis-cluster` 时使用。 * redis\_keepalive\_timeout integer 默认值:`10000` 有效值: 大于或等于 1000 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 的 keepalive 超时时间(毫秒)。 此参数在 API7 企业版 3.9.x 系列中自 3.9.17 起可用,在 3.10.x 系列中自 3.10.4 起可用,并且在 APISIX 中自 3.15.0 起可用。 * redis\_keepalive\_pool integer 默认值:`100` 有效值: 大于或等于 1 *** 当 `policy` 为 `redis` 或 `redis-cluster` 时,Redis 的 keepalive 连接池大小。 此参数在 API7 企业版 3.9.x 系列中自 3.9.17 起可用,在 3.10.x 系列中自 3.10.4 起可用,并且在 APISIX 中自 3.15.0 起可用。 * redis\_cluster\_nodes array\[string] *** Redis 集群节点列表,至少包含两个地址。当 `policy` 为 `redis-cluster` 时必填。 * redis\_cluster\_name string *** Redis 集群的名称。当 `policy` 为 `redis-cluster` 时必填。 * redis\_cluster\_ssl boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时使用 SSL 连接到 Redis 集群。 * redis\_cluster\_ssl\_verify boolean 默认值:`false` *** 如果为 true,则在 `policy` 为 `redis-cluster` 时验证服务器 SSL 证书。 --- # loki-logger `loki-logger` 插件通过 [Loki HTTP API](https://grafana.com/docs/loki/latest/reference/loki-http-api/#loki-http-api) `/loki/api/v1/push` 将请求和响应日志分批推送到 [Grafana Loki](https://grafana.com/oss/loki/)。启用后,插件会将请求上下文信息序列化为 [JSON 对象](https://grafana.com/docs/loki/latest/api/#push-log-entries-to-loki) 并将其添加到队列中,然后再推送到 Loki。该插件还支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了如何在不同场景下配置 `loki-logger` 插件。 要跟随示例操作,请在 Docker 中启动一个 Loki 实例: * Docker * Kubernetes ``` wget https://raw.githubusercontent.com/grafana/loki/v3.0.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml docker run --name loki -d -v $(pwd):/mnt/config -p 3100:3100 grafana/loki:3.2.1 -config.file=/mnt/config/loki-config.yaml ``` 此外,启动一个 Grafana 实例来查看和可视化日志: ``` docker run -d --name=apisix-quickstart-grafana \ -p 3000:3000 \ grafana/grafana-oss ``` 要连接 Loki 和 Grafana,请访问 [`http://localhost:3000`](http://localhost:3000) 的 Grafana。在 **Connections > Data sources** 下,添加一个新的数据源并选择 Loki。你的连接 URL 应遵循 `http://{your_ip_address}:3100` 的格式。保存新数据源时,Grafana 还应该测试连接,你应该看到 Grafana 通知数据源已成功连接。 为 Loki Deployment 创建 Kubernetes 清单文件: loki-deployment.yaml ``` apiVersion: v1 kind: ConfigMap metadata: namespace: aic name: loki-config data: loki-config.yaml: | auth_enabled: false server: http_listen_port: 3100 grpc_listen_port: 9096 common: instance_addr: 127.0.0.1 path_prefix: /tmp/loki storage: filesystem: chunks_directory: /tmp/loki/chunks rules_directory: /tmp/loki/rules replication_factor: 1 ring: kvstore: store: inmemory schema_config: configs: - from: 2020-10-24 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h ruler: alertmanager_url: http://localhost:9093 --- apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: loki spec: replicas: 1 selector: matchLabels: app: loki template: metadata: labels: app: loki spec: containers: - name: loki image: grafana/loki:3.2.1 args: - -config.file=/mnt/config/loki-config.yaml ports: - containerPort: 3100 volumeMounts: - name: config mountPath: /mnt/config volumes: - name: config configMap: name: loki-config --- apiVersion: v1 kind: Service metadata: namespace: aic name: loki spec: selector: app: loki ports: - port: 3100 targetPort: 3100 type: ClusterIP ``` 将清单应用到集群: ``` kubectl apply -f loki-deployment.yaml ``` ### 使用默认日志格式记录请求和响应[​](#使用默认日志格式记录请求和响应 "使用默认日志格式记录请求和响应的直接链接") 以下示例展示了如何在路由上配置 `loki-logger` 插件,以记录经过该路由的请求和响应。 创建一个启用了 `loki-logger` 插件并配置了 Loki 地址的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "loki-logger-route", "uri": "/anything", "plugins": { "loki-logger": { "endpoint_addrs": ["http://192.168.1.5:3100"] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: loki-logger-route plugins: loki-logger: endpoint_addrs: - "http://192.168.1.5:3100" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD loki-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: loki-logger-plugin-config spec: plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: loki-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: loki-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` loki-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: loki-logger-route spec: ingressClassName: apisix http: - name: loki-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" ``` 应用配置: ``` kubectl apply -f loki-logger-ic.yaml ``` ❶ 替换为 Loki 地址。在 Kubernetes 中,请使用集群内 Service 地址 `http://loki.aic.svc:3100`。 发送几个请求到该路由以生成日志条目: ``` curl "http://127.0.0.1:9080/anything" ``` 你应该收到所有请求的 `HTTP/1.1 200 OK` 响应。 导航到 [Grafana explore 视图](http://localhost:3000/explore) 并运行查询 `job = apisix`。你应该看到许多与你的请求对应的日志,例如: ``` { "route_id": "loki-logger-route", "response": { "status": 200, "headers": { "date": "Fri, 03 Jan 2025 03:54:26 GMT", "server": "APISIX/3.13.0", "access-control-allow-credentials": "true", "content-length": "391", "access-control-allow-origin": "*", "content-type": "application/json", "connection": "close" }, "size": 619 }, "start_time": 1735876466, "client_ip": "192.168.65.1", "service_id": "", "apisix_latency": 5.0000038146973, "upstream": "34.197.122.172:80", "upstream_latency": 666, "server": { "hostname": "0b9a772e68f8", "version": "3.13.0" }, "request": { "headers": { "user-agent": "curl/8.6.0", "accept": "*/*", "host": "127.0.0.1:9080" }, "size": 85, "method": "GET", "url": "http://127.0.0.1:9080/anything", "querystring": {}, "uri": "/anything" }, "latency": 671.0000038147 } ``` 这证实了 Loki 已收到来自 APISIX 的日志。你也可以在 Grafana 中创建仪表板以进一步可视化和分析日志。 ### 使用插件元数据自定义日志格式[​](#使用插件元数据自定义日志格式 "使用插件元数据自定义日志格式的直接链接") 以下示例展示了如何使用 [插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md) 自定义日志格式。 创建一个启用了 `loki-logger` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "loki-logger-route", "uri": "/anything", "plugins": { "loki-logger": { "endpoint_addrs": ["http://192.168.1.5:3100"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: loki-logger-route plugins: loki-logger: endpoint_addrs: - "http://192.168.1.5:3100" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD loki-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: loki-logger-plugin-config spec: plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: loki-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: loki-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` loki-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: loki-logger-route spec: ingressClassName: apisix http: - name: loki-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" ``` 应用配置: ``` kubectl apply -f loki-logger-ic.yaml ``` 配置 `loki-logger` 的插件元数据,这将更新所有记录请求的路由的日志格式: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/loki-logger" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "log_format": { "host": "$host", "client_ip": "$remote_addr", "route_id": "$route_id", "@timestamp": "$time_iso8601" } }' ``` adc.yaml ``` plugin_metadata: - name: loki-logger log_format: host: "$host" client_ip: "$remote_addr" route_id: "$route_id" "@timestamp": "$time_iso8601" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: loki-logger: log_format: host: "$host" client_ip: "$remote_addr" route_id: "$route_id" "@timestamp": "$time_iso8601" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` 发送请求到该路由以生成新的日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 [Grafana explore 视图](http://localhost:3000/explore) 并运行查询 `job = apisix`。你应该看到与你的请求对应的日志条目,类似于: ``` { "@timestamp":"2025-01-03T21:11:34+00:00", "client_ip":"192.168.65.1", "route_id":"loki-logger-route", "host":"127.0.0.1" } ``` 如果路由上的插件指定了特定的日志格式,它将优先于插件元数据中指定的日志格式。例如,更新上一个路由上的插件如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/loki-logger-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "loki-logger": { "log_format": { "route_id": "$route_id", "client_ip": "$remote_addr", "@timestamp": "$time_iso8601" } } } }' ``` 更新 `adc.yaml`,为 `loki-logger` 插件添加路由级 `log_format`: adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: loki-logger-route plugins: loki-logger: endpoint_addrs: - "http://192.168.1.5:3100" log_format: route_id: "$route_id" client_ip: "$remote_addr" "@timestamp": "$time_iso8601" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `loki-logger-ic.yaml`,为 `PluginConfig` 添加路由级 `log_format`: loki-logger-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: loki-logger-plugin-config spec: plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" log_format: route_id: "$route_id" client_ip: "$remote_addr" "@timestamp": "$time_iso8601" ``` 更新 `loki-logger-ic.yaml`,为 `ApisixRoute` 添加路由级 `log_format`: loki-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: loki-logger-route spec: ingressClassName: apisix http: - name: loki-logger-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" log_format: route_id: "$route_id" client_ip: "$remote_addr" "@timestamp": "$time_iso8601" ``` 应用更新后的配置: ``` kubectl apply -f loki-logger-ic.yaml ``` 发送请求到该路由以生成新的日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 [Grafana explore 视图](http://localhost:3000/explore) 并重新运行查询 `job = apisix`。你应该看到与你的请求对应的日志条目,与路由上配置的格式一致,类似于: ``` { "client_ip":"192.168.65.1", "route_id":"loki-logger-route", "@timestamp":"2025-01-03T21:19:45+00:00" } ``` ### 有条件地记录请求体[​](#有条件地记录请求体 "有条件地记录请求体的直接链接") 以下示例展示了如何有条件地记录请求体。 创建一个启用了 `loki-logger` 的路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "loki-logger-route", "uri": "/anything", "plugins": { "loki-logger": { "endpoint_addrs": ["http://192.168.1.5:3100"], "include_req_body": true, "include_req_body_expr": [["arg_log_body", "==", "yes"]] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: loki-logger-route plugins: loki-logger: endpoint_addrs: - "http://192.168.1.5:3100" include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD loki-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: loki-logger-plugin-config spec: plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: loki-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: loki-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` loki-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: loki-logger-route spec: ingressClassName: apisix http: - name: loki-logger-route match: paths: - /anything methods: - GET - POST upstreams: - name: httpbin-external-domain plugins: - name: loki-logger config: endpoint_addrs: - "http://loki.aic.svc:3100" include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" ``` 应用配置: ``` kubectl apply -f loki-logger-ic.yaml ``` ❶ `include_req_body`: 设置为 true 以包含请求体。 ❷ `include_req_body_expr`: 仅当 URL 查询字符串 `log_body` 为 `yes` 时包含请求体。 使用满足条件的 URL 查询字符串发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}' ``` 导航到 [Grafana explore 视图](http://localhost:3000/explore) 并运行查询 `job = apisix`。你应该看到与你的请求对应的日志条目,其中记录了请求体: ``` { "route_id": "loki-logger-route", ..., "request": { "headers": { ... }, "body": "{\"env\": \"dev\"}", "size": 182, "method": "POST", "url": "http://127.0.0.1:9080/anything?log_body=yes", "querystring": { "log_body": "yes" }, "uri": "/anything?log_body=yes" }, "latency": 809.99994277954 } ``` 发送不带任何 URL 查询字符串的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}' ``` 导航到 [Grafana explore 视图](http://localhost:3000/explore) 并运行查询 `job = apisix`。你应该看到与你的请求对应的日志条目,其中未记录请求体: ``` { "route_id": "loki-logger-route", ..., "request": { "headers": { ... }, "size": 169, "method": "POST", "url": "http://127.0.0.1:9080/anything", "querystring": {}, "uri": "/anything" }, "latency": 557.00016021729 } ``` 信息 如果你在设置 `include_req_body` 或 `include_resp_body` 为 `true` 的同时自定义了 `log_format`,插件将不会在日志中包含请求体或响应体。 作为一种变通方法,你可以在日志格式中使用 NGINX 变量 `$request_body`,例如: ``` { "loki-logger": { ..., "log_format": {"body": "$request_body"} } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * endpoint\_addrs array\[string] 必填 *** Loki API 基础 URL,例如 `http://127.0.0.1:3100`。如果配置了多个端点,日志将推送到列表中随机确定的端点。 * endpoint\_uri string 默认值:`/loki/api/v1/push` *** Loki 摄取端点的 URI 路径。 * tenant\_id string 默认值:`fake` *** Loki 租户 ID。根据 Loki 的 [多租户文档](https://grafana.com/docs/loki/latest/operations/multi-tenancy/#multi-tenancy),在单租户模式下默认值为 `fake`。 * headers object *** 请求头的键值对,例如为非本地 Loki 服务设置 `Authorization` 请求头。此参数不能设置 `X-Scope-OrgID` 或 `Content-Type`。自 API7 企业版 3.9.0 起引入。请求头值加密自 API7 企业版 3.9.18、3.10.5 和 APISIX 3.18.0 起引入。启用数据加密时,这些值会在[存储前加密](https://docs.apiseven.com/apisix/production/security/data-encryption-with-keyring.md)。经授权的 Admin API `GET` 请求会返回完整的已解密请求头对象;静态加密不会在 API 响应中隐藏请求头名称或值。 * log\_labels object 默认值:`{job = "apisix"}` *** Loki 日志标签。支持值中的 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 和常量字符串。变量应以 `$` 符号为前缀。例如,标签可以是 `{"origin" = "apisix"}` 或 `{"origin" = "$remote_addr"}`。 * ssl\_verify boolean 默认值:`false` *** 如果为 true,则验证 Loki 的 SSL 证书。 * timeout integer 默认值:`3000` 有效值: 介于 1 和 60000 之间(含边界值) *** Loki 服务 HTTP 调用的超时时间(毫秒)。 * keepalive boolean 默认值:`true` *** 如果为 true,则在多个请求之间保持连接存活。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** Keepalive 超时时间(毫秒)。 * keepalive\_pool integer 默认值:`5` 有效值: 大于或等于 1 *** 连接池中的最大连接数。 * log\_format object *** 使用 JSON 格式键值对的自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 在 APISIX 3.15.0 及更高版本中,支持最多五层深度的日志格式嵌套结构。在 API7 企业版中,仅支持扁平的键值结构;尚不支持嵌套结构。 你还可以使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)在全局范围内配置日志格式,这将配置所有 `loki-logger` 插件实例的日志格式。如果单个插件实例上配置的日志格式与插件元数据上配置的日志格式不同,则单个插件实例上配置的日志格式优先。有关更多详细信息,请参阅此[示例](https://docs.apiseven.com/hub/loki-logger.md#使用插件元数据自定义日志格式)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * name string 默认值:`loki logger` *** 批处理器的插件唯一标识符。如果你使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,则名称将导出到 `apisix_batch_process_entries` 中。 * include\_req\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含请求体。请注意,如果请求体太大而无法保存在内存中,由于 NGINX 的限制,它可能无法被记录。 * include\_req\_body\_expr array\[array] *** 以 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的一个或多个条件的数组。当 `include_req_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 以 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的一个或多个条件的数组。当 `include_resp_body` 为 true 时使用。仅当此处配置的表达式计算结果为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 一个批次中允许的最大日志条目数。一旦达到,批次将被发送到日志服务。将此参数设置为 1 意味着立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前等待新日志的最长时间(秒)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 发送批次到日志服务之前,允许的最早条目的最长时间(秒)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送不成功,重试发送到日志服务的时间间隔(秒)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 丢弃日志条目之前允许的最大不成功重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式键值对的自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 在 APISIX 3.15.0 及更高版本中,支持最多五层深度的日志格式嵌套结构。在 API7 企业版中,仅支持扁平的键值结构;尚不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # mcp-tools-acl [企业版](https://api7.ai/enterprise) `mcp-tools-acl` 插件用于控制每个消费者在 [`openapi-to-mcp`](https://docs.apiseven.com/hub/openapi-to-mcp.md) 路由上可以调用或发现哪些 MCP 工具。该插件提供两种限制方式: * **`tools/call` 拦截** — 拒绝消费者调用被禁止的工具,返回 HTTP 错误响应。 * **`tools/list` 过滤** — 从返回给客户端的工具列表中移除被禁止的工具,使 MCP 客户端感知不到这些工具的存在。此过滤同时适用于 JSON 响应和 SSE(Server-Sent Events)流式响应。 该插件采用**基于规则**的配置方式,每条规则指定白名单或黑名单,并可选配表达式条件。规则按顺序执行——第一条条件匹配的规则生效,其余规则跳过。 此插件自 API7 企业版 3.9.8 起可用。 ## 示例[​](#示例 "示例的直接链接") ### 前提条件[​](#前提条件 "前提条件的直接链接") 使用此插件前,请确保: 1. 路由上已启用 [`openapi-to-mcp`](https://docs.apiseven.com/hub/openapi-to-mcp.md) 插件。 2. 路由上已配置身份认证插件(例如 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md))。如果请求中没有经过身份认证的消费者,`mcp-tools-acl` 会原样放行所有流量。 以下示例展示了如何在不同场景下使用 `mcp-tools-acl` 插件。 ### 使用白名单限制工具访问[​](#使用白名单限制工具访问 "使用白名单限制工具访问的直接链接") 以下示例展示了如何通过白名单配置,只允许消费者调用指定的 MCP 工具。 * Admin API * ADC * Ingress Controller 创建消费者 `alice`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "alice" }' ``` 为 `alice` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/alice/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-alice-key-auth", "plugins": { "key-auth": { "key": "alice-key" } } }' ``` 在消费者 `alice` 上配置 `mcp-tools-acl` 插件: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "alice", "plugins": { "mcp-tools-acl": { "rules": [ { "allow_tools": ["getPetById", "getUserByName"] } ] } } }' ``` ❶ 仅允许消费者 `alice` 调用 `getPetById` 和 `getUserByName`。其他所有工具都将被阻止,也不会出现在工具列表中。 提示 `mcp-tools-acl` 应配置在**消费者**(或**消费者组**)上,以实现按消费者粒度的工具访问控制。路由上只需配置 `openapi-to-mcp` 和认证插件。 当消费者和路由上同时配置了该插件时,**消费者配置优先生效**,路由级配置对该消费者不生效。若消费者未配置 `mcp-tools-acl`,则以路由上的配置作为兜底。 创建启用了 `openapi-to-mcp` 和 `key-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "mcp-tools-acl-route", "uri": "/mcp", "methods": ["GET", "POST"], "plugins": { "openapi-to-mcp": { "transport": "streamable_http", "openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json", "base_url": "https://petstore3.swagger.io/api/v3", "headers": { "Authorization": "special-key" } }, "key-auth": {} }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "petstore3.swagger.io:443": 1 } } }' ``` 以消费者 `alice` 的身份发送 `tools/list` 请求: ``` curl -s "http://127.0.0.1:9080/mcp" \ -H "apikey: alice-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }' ``` 响应中应该只包含 `getPetById` 和 `getUserByName`,其他所有工具均已被过滤。 调用允许的工具: ``` curl -i "http://127.0.0.1:9080/mcp" \ -H "apikey: alice-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "getPetById", "arguments": { "pathParameters": { "petId": 1 } } } }' ``` 你应该会看到包含 Petstore 宠物数据的 `HTTP/1.1 200 OK` 响应。 调用不在白名单中的工具: ``` curl -i "http://127.0.0.1:9080/mcp" \ -H "apikey: alice-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "deletePet", "arguments": { "pathParameters": { "petId": 1 } } } }' ``` 你应该看到 `HTTP/1.1 403 Forbidden` 响应,表明该工具调用被拦截。 创建一个配置了 `key-auth` 凭证和 `mcp-tools-acl` 的消费者,并创建一个启用了 `openapi-to-mcp` 和 `key-auth` 的路由: adc.yaml ``` consumers: - username: alice credentials: - name: cred-alice-key-auth type: key-auth config: key: alice-key plugins: mcp-tools-acl: rules: - allow_tools: - getPetById - getUserByName services: - name: mcp-tools-acl-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: mcp-tools-acl-route uris: - /mcp methods: - GET - POST plugins: key-auth: header: apikey openapi-to-mcp: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json ``` ❶ 仅允许消费者 `alice` 调用 `getPetById` 和 `getUserByName`。其他所有工具都将被阻止,也不会出现在工具列表中。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建消费者和路由,并按如下方式配置 `openapi-to-mcp`、`key-auth` 和 `mcp-tools-acl`: mcp-tools-acl-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: alice spec: gatewayRef: name: apisix credentials: - type: key-auth name: cred-alice-key-auth config: key: alice-key plugins: - name: mcp-tools-acl config: rules: - allow_tools: - getPetById - getUserByName --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: mcp-tools-acl-plugin-config spec: plugins: - name: key-auth config: header: apikey - name: openapi-to-mcp config: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: mcp-tools-acl-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /mcp method: GET - path: type: Exact value: /mcp method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: mcp-tools-acl-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: v1 kind: Service metadata: namespace: aic name: petstore-external-domain spec: type: ExternalName externalName: petstore3.swagger.io --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` ❶ 仅允许消费者 `alice` 调用 `getPetById` 和 `getUserByName`。 创建消费者和路由,并按如下方式配置 `openapi-to-mcp`、`key-auth` 和 `mcp-tools-acl`: mcp-tools-acl-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: alice spec: ingressClassName: apisix authParameter: keyAuth: value: key: alice-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mcp-tools-acl-route spec: ingressClassName: apisix http: - name: mcp-tools-acl-route match: paths: - /mcp methods: - GET - POST upstreams: - name: petstore-external-domain plugins: - name: key-auth enable: true config: header: apikey - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json - name: mcp-tools-acl enable: true config: rules: - allow_tools: - getPetById - getUserByName ``` ❶ 此路由仅允许调用 `getPetById` 和 `getUserByName`。 将配置应用到集群: ``` kubectl apply -f mcp-tools-acl-ic.yaml ``` ### 使用黑名单限制工具访问[​](#使用黑名单限制工具访问 "使用黑名单限制工具访问的直接链接") 以下示例展示如何通过黑名单配置,禁止消费者调用特定工具,其余工具均可正常访问。 * Admin API * ADC * Ingress Controller 基于上一个示例,为消费者 `bob` 配置黑名单: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "bob", "plugins": { "mcp-tools-acl": { "rules": [ { "deny_tools": ["deletePet"] } ] } } }' ``` ❶ 禁止消费者 `bob` 调用 `deletePet`,其他工具仍可访问。 为 `bob` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/bob/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-bob-key-auth", "plugins": { "key-auth": { "key": "bob-key" } } }' ``` 以消费者 `bob` 的身份发送 `tools/list` 请求: ``` curl -s "http://127.0.0.1:9080/mcp" \ -H "apikey: bob-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }' ``` 你应该会看到除 `deletePet` 之外的所有工具。 调用被禁止的工具: ``` curl -i "http://127.0.0.1:9080/mcp" \ -H "apikey: bob-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "deletePet", "arguments": { "pathParameters": { "petId": 1 } } } }' ``` 你应该看到 `HTTP/1.1 403 Forbidden` 响应。 更新 `adc.yaml` 中的消费者配置以更改 ACL 规则: adc.yaml ``` consumers: - username: bob credentials: - name: cred-bob-key-auth type: key-auth config: key: bob-key plugins: mcp-tools-acl: rules: - deny_tools: - deletePet services: - name: mcp-tools-acl-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: mcp-tools-acl-route uris: - /mcp methods: - GET - POST plugins: key-auth: header: apikey openapi-to-mcp: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json ``` ❶ 禁止消费者 `bob` 调用 `deletePet`,其他工具仍可访问。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新消费者或路由配置中的 ACL 规则: mcp-tools-acl-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: bob spec: gatewayRef: name: apisix credentials: - type: key-auth name: cred-bob-key-auth config: key: bob-key plugins: - name: mcp-tools-acl config: rules: - deny_tools: - deletePet ``` ❶ 禁止消费者 `bob` 调用 `deletePet`。 更新消费者或路由配置中的 ACL 规则: mcp-tools-acl-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mcp-tools-acl-route spec: ingressClassName: apisix http: - name: mcp-tools-acl-route match: paths: - /mcp methods: - GET - POST upstreams: - name: petstore-external-domain plugins: - name: key-auth enable: true config: header: apikey - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json - name: mcp-tools-acl enable: true config: rules: - deny_tools: - deletePet ``` ❶ 禁止调用 `deletePet`,同时允许访问路由上的其他工具。 将配置应用到集群: ``` kubectl apply -f mcp-tools-acl-ic.yaml ``` ### 基于路由条件应用不同规则[​](#基于路由条件应用不同规则 "基于路由条件应用不同规则的直接链接") 以下示例展示了如何使用表达式条件(`expr`),根据请求上下文(如访问的路由)应用不同的 ACL 规则。 * Admin API * ADC * Ingress Controller 此示例适用于 API7 企业版 3.9.8 及更高版本。 创建消费者 `grace`,配置条件规则: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "grace", "plugins": { "mcp-tools-acl": { "rules": [ { "expr": [["route_id", "==", "route-pets"]], "allow_tools": ["getPetById"] }, { "allow_tools": ["getUserByName"] } ] } } }' ``` ❶ 规则 1:当请求命中路由 `route-pets` 时,仅允许调用 `getPetById`。 ❷ 规则 2:一条兜底规则(没有 `expr`),对于其他所有路由,仅允许调用 `getUserByName`。仅当规则 1 不匹配时,才会执行此规则。 为 `grace` 创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/grace/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-grace-key-auth", "plugins": { "key-auth": { "key": "grace-key" } } }' ``` 创建两个配置了 `openapi-to-mcp` 和 `key-auth` 的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "route-pets", "uri": "/mcp", "methods": ["GET", "POST"], "plugins": { "openapi-to-mcp": { "transport": "streamable_http", "openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json", "base_url": "https://petstore3.swagger.io/api/v3", "headers": { "Authorization": "special-key" } }, "key-auth": {} }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "petstore3.swagger.io:443": 1 } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "route-inventory", "uri": "/mcp2", "methods": ["GET", "POST"], "plugins": { "openapi-to-mcp": { "transport": "streamable_http", "openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json", "base_url": "https://petstore3.swagger.io/api/v3", "headers": { "Authorization": "special-key" } }, "key-auth": {} }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "petstore3.swagger.io:443": 1 } } }' ``` 当 `grace` 调用 `route-pets` 时,规则 1 匹配,因此仅允许调用 `getPetById`: ``` curl -i "http://127.0.0.1:9080/mcp" \ -H "apikey: grace-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "getPetById", "arguments": { "pathParameters": { "petId": 1 } } } }' ``` 你应该会看到包含 Petstore 宠物数据的 `HTTP/1.1 200 OK` 响应。 当 `grace` 调用 `route-inventory` 时,规则 1 不匹配(`route_id` 不同),因此兜底规则 2 生效,仅允许调用 `getUserByName`: ``` curl -i "http://127.0.0.1:9080/mcp2" \ -H "apikey: grace-key" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "getUserByName", "arguments": { "pathParameters": { "username": "user1" } } } }' ``` 你应该会看到包含 Petstore 用户数据的 `HTTP/1.1 200 OK` 响应。 备注 规则从上到下依次匹配。第一条匹配的规则生效,后续规则均被跳过。应将更具体的规则(带 `expr`)放在前面,将范围更广的兜底规则(不带 `expr`)放在后面。 如果没有任何规则匹配(所有规则都设置了 `expr` 条件且均未求值为 true),插件不执行任何访问控制——所有工具均直接放行。 创建一个配置了条件规则的消费者以及两个路由: adc.yaml ``` consumers: - username: grace credentials: - name: cred-grace-key-auth type: key-auth config: key: grace-key plugins: mcp-tools-acl: rules: - expr: - - route_name - == - pets-route allow_tools: - getPetById - allow_tools: - getUserByName services: - name: pets-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: pets-route uris: - /mcp methods: - GET - POST plugins: key-auth: header: apikey openapi-to-mcp: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json - name: inventory-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: inventory-route uris: - /mcp2 methods: - GET - POST plugins: key-auth: header: apikey openapi-to-mcp: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json ``` ❶ 当请求命中 `pets-route` 时,仅允许调用 `getPetById`。 ❷ 其他所有路由的兜底规则。在此规则中仅允许调用 `getUserByName`。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 为不同的 MCP 路由配置条件规则: mcp-tools-acl-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: grace spec: gatewayRef: name: apisix credentials: - type: key-auth name: cred-grace-key-auth config: key: grace-key plugins: - name: mcp-tools-acl config: rules: - expr: - - route_name - == - pets-route allow_tools: - getPetById - allow_tools: - getUserByName --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: mcp-tools-acl-plugin-config spec: plugins: - name: key-auth config: header: apikey - name: openapi-to-mcp config: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: pets-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /mcp method: GET - path: type: Exact value: /mcp method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: mcp-tools-acl-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: inventory-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /mcp2 method: GET - path: type: Exact value: /mcp2 method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: mcp-tools-acl-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: v1 kind: Service metadata: namespace: aic name: petstore-external-domain spec: type: ExternalName externalName: petstore3.swagger.io --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` ❶ 仅当请求匹配 `pets-route` 时,才应用允许调用 `getPetById` 的规则。 ❷ 对其他所有匹配的路由应用允许调用 `getUserByName` 的规则。 为不同的 MCP 路由配置条件规则: mcp-tools-acl-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: grace spec: ingressClassName: apisix authParameter: keyAuth: value: key: grace-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mcp-tools-acl-routes spec: ingressClassName: apisix http: - name: pets-route match: paths: - /mcp methods: - GET - POST upstreams: - name: petstore-external-domain plugins: - name: key-auth enable: true config: header: apikey - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json - name: mcp-tools-acl enable: true config: rules: - expr: - - uri - == - /mcp allow_tools: - getPetById - allow_tools: - getUserByName - name: inventory-route match: paths: - /mcp2 methods: - GET - POST upstreams: - name: petstore-external-domain plugins: - name: key-auth enable: true config: header: apikey - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: https://petstore3.swagger.io/api/v3 headers: Authorization: special-key openapi_url: https://petstore3.swagger.io/api/v3/openapi.json - name: mcp-tools-acl enable: true config: rules: - expr: - - uri - == - /mcp allow_tools: - getPetById - allow_tools: - getUserByName ``` ❶ 仅当请求 URI 为 `/mcp` 时,才应用允许调用 `getPetById` 的规则。 ❷ 使用兜底规则,使 `/mcp2` 路由仅允许调用 `getUserByName`。 将配置应用到集群: ``` kubectl apply -f mcp-tools-acl-ic.yaml ``` ## 故障排除[​](#故障排除 "故障排除的直接链接") **插件不生效** 请检查同一路由上是否启用了 `openapi-to-mcp`,并确认已配置身份认证插件。如果请求中没有经过身份认证的消费者,`mcp-tools-acl` 会按设计原样放行所有流量。 **`tools/call` 返回 400** 请求体是合法的 JSON,但 `params` 字段缺失或 `params.name` 不是字符串,插件会返回 `{"message": "Invalid MCP tools/call request"}` 和 HTTP 400。这与配置的 `rejected_code`(针对被拒绝工具)不同,表明 MCP 客户端发送了格式错误的请求。 **`allow_tools: []` 导致所有工具均被拒绝** 空白名单符合 Schema,但会拒绝所有工具。每个 `tools/call` 请求都会被拒绝,`tools/list` 将返回空列表。如果希望消费者访问任何工具,请确保 `allow_tools` 数组不为空。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * rules array\[object] 必填 *** 按顺序执行的访问控制规则数组。第一条 `expr` 条件全部满足(或未设置 `expr`)的规则生效,其余规则跳过。每条规则必须且只能配置 `allow_tools` 或 `deny_tools` 其中之一。 * allow\_tools array\[string] *** 允许消费者调用和在 `tools/list` 中查看的 MCP 工具名称白名单。匹配方式为精确匹配,区分大小写。空数组(`[]`)将拒绝所有工具。 每条规则中 `allow_tools` 和 `deny_tools` 必须二选一,不能同时配置。 * deny\_tools array\[string] *** 禁止消费者调用的 MCP 工具名称黑名单。被拒绝的工具同样会从 `tools/list` 中隐藏。匹配方式为精确匹配,区分大小写。 每条规则中 `allow_tools` 和 `deny_tools` 必须二选一,不能同时配置。 * rejected\_code integer 默认值:`403` 有效值: 200 到 599 *** 此规则拒绝 `tools/call` 请求时返回的 HTTP 状态码。 * rejected\_msg string 默认值:`MCP tool is not allowed` 有效值: 非空字符串 *** 此规则拒绝 `tools/call` 请求时响应体中返回的错误消息。 * expr array *** 由一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)组成的匹配条件数组。仅当所有表达式求值为 true 时,此规则才生效。如未设置,则此规则无条件匹配(兜底规则)。 * max\_resp\_body\_size integer 默认值:`67108864` *** 进行工具过滤时缓冲到内存中的响应体最大字节数。超过该上限的响应体会被截断。自 API7 企业版 3.9.x 系列的 3.9.17 版本起可用,3.10.x 系列自 3.10.4 版本起可用。 --- # mocking `mocking` 插件允许你模拟 API 响应,而无需将请求转发到上游服务。该插件支持自定义响应状态码、响应体、响应头等。这在开发、测试或调试阶段特别有用,因为在这些阶段,实际的上游服务可能不可用、正在维护或调用成本高昂。通过以预定义格式提供模拟响应,该插件使你能够测试客户端集成、验证请求处理并调试问题,而无需依赖上游基础设施。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `mocking` 插件。 ### 生成特定的模拟响应[​](#生成特定的模拟响应 "生成特定的模拟响应的直接链接") 以下示例演示了如何配置插件以生成特定的模拟响应和响应状态码,而不将请求转发到上游服务。 创建一个使用 `mocking` 插件的路由,并为预期的模拟响应定义响应体: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "mocking-route", "uri": "/anything", "plugins": { "mocking": { "response_status":201, "response_example":"{\"Lastname\":\"Brown\",\"Age\":56}" } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: mocking-route uris: - /anything plugins: mocking: response_status: 201 response_example: '{"Lastname":"Brown","Age":56}' upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD mocking-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: mocking-plugin-config spec: plugins: - name: mocking config: response_status: 201 response_example: '{"Lastname":"Brown","Age":56}' --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: mocking-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: mocking-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f mocking-ic.yaml ``` mocking-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mocking-route spec: ingressClassName: apisix http: - name: mocking-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: mocking enable: true config: response_status: 201 response_example: '{"Lastname":"Brown","Age":56}' ``` 将配置应用到集群: ``` kubectl apply -f mocking-ic.yaml ``` ❶ 配置预期的模拟响应状态码为 `201`。 ❷ 配置预期的模拟响应体为 `{"Lastname":"Brown","Age":56}`。 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 201 Created` 模拟响应,并看到以下响应体: ``` {"Lastname":"Brown","Age":56} ``` ### 生成模拟响应头[​](#生成模拟响应头 "生成模拟响应头的直接链接") 以下示例演示了如何配置插件以生成模拟响应头,并在响应体中使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 创建一个使用 `mocking` 插件的路由,定义预期的模拟响应的响应头和响应体: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "mocking-route", "uri": "/anything", "plugins": { "mocking": { "response_headers": { "X-User-Id": 100, "X-Product-Id": "apac-398-472" }, "response_example":"Client IP: $remote_addr" } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: mocking-route uris: - /anything plugins: mocking: response_headers: X-User-Id: 100 X-Product-Id: apac-398-472 response_example: "Client IP: $remote_addr" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD mocking-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: mocking-plugin-config spec: plugins: - name: mocking config: response_headers: X-User-Id: 100 X-Product-Id: apac-398-472 response_example: "Client IP: $remote_addr" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: mocking-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: mocking-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f mocking-ic.yaml ``` mocking-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mocking-route spec: ingressClassName: apisix http: - name: mocking-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: mocking enable: true config: response_headers: X-User-Id: 100 X-Product-Id: apac-398-472 response_example: "Client IP: $remote_addr" ``` 将配置应用到集群: ``` kubectl apply -f mocking-ic.yaml ``` ❶ 配置预期的模拟响应头 `X-User-Id: 100`。 ❷ 配置预期的模拟响应头 `X-Product-Id: apac-398-472`。 ❸ 配置预期的模拟响应体以显示客户端 IP 地址。 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到类似以下的响应: ``` HTTP/1.1 200 OK ... X-Product-Id: apac-398-472 X-User-Id: 100 Client IP: 192.168.65.1 ``` ### 使用 JSON Schema 生成模拟响应[​](#使用-json-schema-生成模拟响应 "使用 JSON Schema �生成模拟响应的直接链接") 以下示例演示了如何配置插件以生成遵循特定 [JSON schema](https://json-schema.org) 的模拟响应。 创建一个使用 `mocking` 插件的路由,并为预期的模拟响应定义 JSON schema: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "mocking-route", "uri": "/anything", "plugins": { "mocking": { "response_schema": { "type": "object", "properties": { "id": { "type": "string", "example": "abcd" }, "ip": { "type": "number", "example": 192.168.0.10 }, "random_str_arr": { "type": "array", "items": { "type": "string" } }, "nested_obj": { "type": "object", "properties": { "random_str": { "type": "string" }, "child_nested_obj": { "type": "object", "properties": { "random_bool": { "type": "boolean", "example": true }, "random_int_arr": { "type": "array", "items": { "type": "integer", "example": 155 } } } } } } } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: mocking-route uris: - /anything plugins: mocking: response_schema: type: object properties: id: type: string example: abcd ip: type: number example: 192.168.0.10 random_str_arr: type: array items: type: string nested_obj: type: object properties: random_str: type: string child_nested_obj: type: object properties: random_bool: type: boolean example: true random_int_arr: type: array items: type: integer example: 155 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD mocking-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: mocking-plugin-config spec: plugins: - name: mocking config: response_schema: type: object properties: id: type: string example: abcd ip: type: number example: 192.168.0.10 random_str_arr: type: array items: type: string nested_obj: type: object properties: random_str: type: string child_nested_obj: type: object properties: random_bool: type: boolean example: true random_int_arr: type: array items: type: integer example: 155 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: mocking-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: mocking-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f mocking-ic.yaml ``` mocking-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mocking-route spec: ingressClassName: apisix http: - name: mocking-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: mocking enable: true config: response_schema: type: object properties: id: type: string example: abcd ip: type: number example: 192.168.0.10 random_str_arr: type: array items: type: string nested_obj: type: object properties: random_str: type: string child_nested_obj: type: object properties: random_bool: type: boolean example: true random_int_arr: type: array items: type: integer example: 155 ``` 将配置应用到集群: ``` kubectl apply -f mocking-ic.yaml ``` 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该看到类似以下的模拟响应,而没有来自上游服务的实际响应: ``` { "ip":192.168.0.10, "random_str_arr":[ "fb","lyquibkwc","r" ], "id":"abcd", "nested_obj":{ "random_str":"bzbb", "child_nested_obj":{ "random_bool":true, "random_int_arr":[155,155,155] } } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * delay integer 默认值:`0` *** 模拟响应延迟(秒)。 * response\_status integer 默认值:`200` *** 模拟响应的 HTTP 状态码。 * content\_type string 默认值:`application/json;charset=utf8` *** 模拟响应的 `Content-Type` 头。 * response\_example string *** 模拟响应的响应体。支持在响应体中使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 应至少配置 `response_example` 和 `response_schema` 中的一个。 * response\_schema object *** 响应 [JSON Schema](https://json-schema.org)。JSON schema 支持数据类型中的 `string`、`number`、`integer`、`boolean`、`object` 和 `array`。 应至少配置 `response_example` 和 `response_schema` 中的一个。`response_schema` 仅在未配置 `response_example` 时生效。 * with\_mock\_header boolean 默认值:`true` *** 如果为 true,则添加一个带有 APISIX 版本的响应头 `x-mock-by`。 * response\_headers object *** 添加到模拟响应中的头。 --- # mqtt-proxy `mqtt-proxy` 插件是一个 L4 插件,支持将 MQTT 请求代理和负载均衡到 MQTT 服务器。它支持 MQTT 版本 3.1.x 和 5.0。该插件必须在[流路由](https://docs.apiseven.com/apisix/key-concepts/stream-routes.md)上配置,并且 APISIX 需要启用 L4 流量代理。 ## 示例[​](#示例 "示例的直接链接") 默认情况下,APISIX 仅代理 L7 流量。在继续示例之前,请先启用 L4 流量代理。 * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` apisix: proxy_mode: http&stream # 同时启用 L4 和 L7 代理 stream_proxy: # 配置 L4 代理 tcp: - 9100 # 设置 TCP 代理监听端口 ``` 重新加载网关以使更改生效。网关现在应开始在 `9100` 端口监听 L4 流量。 对于 Helm 部署,请更新用于渲染 stream proxy 监听器的 Chart values,并保留 values 文件中的其他配置。 对于 APISIX Helm Chart,设置以下 values: values.yaml ``` service: stream: enabled: true tcp: - 9100 ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` gateway: stream: enabled: true tcp: - addr: 9100 ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 以下示例使用 Mosquitto 项目中的 MQTT 客户端来发布和订阅消息。你可以从[此处](https://mosquitto.org/download/)下载它,或使用你选择的任何其他 MQTT 客户端。 ### 代理到 MQTT 代理服务器[​](#代理到-mqtt-代理服务器 "代理到 MQTT 代理服务器的直接链接") 以下示例演示了如何配置流路由,将流量代理到托管的 MQTT 服务器,并验证 APISIX 能否成功代理 MQTT 消息。 创建一个指向 MQTT 服务器的流路由,并配置 `mqtt-proxy` 插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "mqtt-route", "plugins": { "mqtt-proxy": { "protocol_name": "MQTT", "protocol_level": 4 } }, "upstream": { "type": "roundrobin", "nodes": { "test.mosquitto.org:1883": 1 } } }' ``` adc.yaml ``` services: - name: mqtt-service upstream: name: default scheme: tcp nodes: - host: test.mosquitto.org port: 1883 weight: 1 stream_routes: - name: mqtt-route server_port: 9100 plugins: mqtt-proxy: protocol_name: MQTT protocol_level: 4 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 信息 Gateway API 目前不支持挂载 L4 插件,因此暂时无法使用 Gateway API 完成此示例。 使用 APISIX CRD 将 `mqtt-proxy` 插件挂载到流路由: mqtt-proxy-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: mqtt-broker spec: type: ExternalName externalName: test.mosquitto.org ports: - name: mqtt port: 1883 targetPort: 1883 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mqtt-route spec: ingressClassName: apisix stream: - name: mqtt-route protocol: TCP match: ingressPort: 9100 backend: serviceName: mqtt-broker servicePort: 1883 plugins: - name: mqtt-proxy enable: true config: protocol_name: MQTT protocol_level: 4 ``` 应用配置: ``` kubectl apply -f mqtt-proxy-ic.yaml ``` 打开两个终端会话。在第一个会话中,订阅测试主题: ``` mosquitto_sub -h test.mosquitto.org -p 1883 -t "test/apisix" ``` 在另一个会话中,向创建的路由发布一条示例消息: ``` mosquitto_pub -h 127.0.0.1 -p 9100 -t "test/apisix" -m "Hello APISIX" ``` 你应该会在第一个终端中看到消息 `Hello APISIX`。 ### 负载均衡 MQTT 流量[​](#负载均衡-mqtt-流量 "负载均衡 MQTT 流量的直接链接") 以下示例演示了如何配置流路由,将 MQTT 流量负载均衡到不同的 MQTT 服务器。 启用插件后,它会注册一个变量 `mqtt_client_id`,可用于负载均衡。具有不同客户端 ID 的 MQTT 连接将根据一致性哈希算法被转发到不同的上游节点。如果缺少客户端 ID,则将使用客户端 IP 代替。 创建一个指向两个 MQTT 服务器的流路由,并配置 `mqtt-proxy` 插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "mqtt-route", "plugins": { "mqtt-proxy": { "protocol_name": "MQTT", "protocol_level": 4 } }, "upstream": { "type": "chash", "key": "mqtt_client_id", "nodes": [ { "host": "test.mosquitto.org", "port": 1883, "weight": 1 }, { "host": "broker.mqtt.cool", "port": 1883, "weight": 1 } ] } }' ``` adc.yaml ``` services: - name: mqtt-service upstream: name: default scheme: tcp type: chash key: mqtt_client_id nodes: - host: test.mosquitto.org port: 1883 weight: 1 - host: broker.mqtt.cool port: 1883 weight: 1 stream_routes: - name: mqtt-route server_port: 9100 plugins: mqtt-proxy: protocol_name: MQTT protocol_level: 4 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 信息 Gateway API 目前不支持挂载 L4 插件,因此暂时无法使用 Gateway API 完成此示例。 mqtt-proxy-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: mqtt-brokers spec: ports: - name: mqtt port: 1883 protocol: TCP --- apiVersion: discovery.k8s.io/v1 kind: EndpointSlice metadata: namespace: aic name: mqtt-brokers-1 labels: kubernetes.io/service-name: mqtt-brokers addressType: FQDN ports: - name: mqtt protocol: TCP port: 1883 endpoints: - addresses: - test.mosquitto.org - addresses: - broker.mqtt.cool --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mqtt-brokers spec: ingressClassName: apisix loadbalancer: type: chash key: mqtt_client_id hashOn: vars --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: mqtt-route spec: ingressClassName: apisix stream: - name: mqtt-route protocol: TCP match: ingressPort: 9100 backend: serviceName: mqtt-brokers servicePort: 1883 plugins: - name: mqtt-proxy enable: true config: protocol_name: MQTT protocol_level: 4 ``` 应用配置: ``` kubectl apply -f mqtt-proxy-ic.yaml ``` 对于 Admin API 和 ADC 示例,请打开三个终端会话。在第一个会话中,订阅第一个 MQTT 代理上的测试主题: ``` mosquitto_sub -h test.mosquitto.org -p 1883 -t "test/apisix" ``` 在第二个终端中,订阅第二个 MQTT 代理上的相同主题: ``` mosquitto_sub -h broker.mqtt.cool -p 1883 -t "test/apisix" ``` 在第三个终端中,多次运行以下命令向路由发送示例消息: ``` mosquitto_pub -h 127.0.0.1 -p 9100 -i publisher-1 -t "test/apisix" -m "Hello from publisher-1" mosquitto_pub -h 127.0.0.1 -p 9100 -i publisher-2 -t "test/apisix" -m "Hello from publisher-2" ``` 你应该会在订阅者终端中看到已发布的消息,从而验证可以将不同的 `mqtt_client_id` 值路由到不同的上游 Broker。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * protocol\_name string 默认值:`MQTT` *** 协议名称,一般为 `MQTT`。 在 API7 Gateway 中,该参数必填且没有默认值。 * protocol\_level integer 必填 *** 协议版本。对于 MQTT 3.1.x 应设置为 `4`,对于 MQTT 5.0 应设置为 `5`。 --- # multi-auth `multi-auth` 插件允许使用不同认证方法的 Consumer 共享相同的路由或服务。它支持配置多个认证插件,只要请求成功通过任何配置的认证方法的认证,就会被允许通过。 ## 示例[​](#示例 "示例的直接链接") ### 在同一路由上允许不同的认证方式[​](#在同一路由上允许不同的认证方式 "在同一路由上允许不同的认证方式的直接链接") 以下示例演示了如何让一个 Consumer 使用 Basic Auth,而另一个 Consumer 使用 Key Auth,并且两者共享相同的路由。 * Admin API * ADC * Ingress Controller 创建两个 Consumer: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username":"consumer1" }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username":"consumer2" }' ``` 为 `consumer1` 配置 Basic Auth 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/consumer1/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "basic-auth": { "username":"consumer1", "password":"consumer1_pwd" } } }' ``` 为 `consumer2` 配置 Key Auth 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/consumer2/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key":"consumer2_pwd" } } }' ``` 创建一个启用了 `multi-auth` 的路由,并配置 Consumer 使用的两个认证插件: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "multi-auth-route", "uri": "/anything", "plugins": { "multi-auth":{ "auth_plugins":[ { "basic-auth":{} }, { "key-auth":{ "hide_credentials":true, "header":"apikey", "query":"apikey" } } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` 创建两个消费者及其各自的凭证,并创建启用了 `multi-auth` 的路由: adc.yaml ``` consumers: - username: consumer1 credentials: - name: cred-consumer1-basic-auth type: basic-auth config: username: consumer1 password: consumer1_pwd - username: consumer2 credentials: - name: cred-consumer2-key-auth type: key-auth config: key: consumer2_pwd services: - name: multi-auth-service routes: - name: multi-auth-route uris: - /anything plugins: multi-auth: auth_plugins: - basic-auth: {} - key-auth: hide_credentials: true header: apikey query: apikey upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD multi-auth-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: consumer1 spec: gatewayRef: name: apisix credentials: - type: basic-auth name: cred-consumer1-basic-auth config: username: consumer1 password: consumer1_pwd --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: consumer2 spec: gatewayRef: name: apisix credentials: - type: key-auth name: cred-consumer2-key-auth config: key: consumer2_pwd --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: multi-auth-plugin-config spec: plugins: - name: multi-auth config: auth_plugins: - basic-auth: {} - key-auth: hide_credentials: true header: apikey query: apikey --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: multi-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: multi-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f multi-auth-ic.yaml ``` multi-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: consumer1 spec: ingressClassName: apisix authParameter: basicAuth: value: username: consumer1 password: consumer1_pwd --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: consumer2 spec: ingressClassName: apisix authParameter: keyAuth: value: key: consumer2_pwd --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: multi-auth-route spec: ingressClassName: apisix http: - name: multi-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: multi-auth enable: true config: auth_plugins: - basic-auth: {} - key-auth: hide_credentials: true header: apikey query: apikey ``` 将配置应用到集群: ``` kubectl apply -f multi-auth-ic.yaml ``` 使用 `consumer1` 的 Basic Auth 凭据向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" -u consumer1:consumer1_pwd ``` 你应该收到一个 `HTTP/1.1 200 OK` 响应。 使用 `consumer2` 的 Key Auth 凭据向路由发送另一个请求: ``` curl -i "http://127.0.0.1:9080/anything" -H 'apikey: consumer2_pwd' ``` 你应该再次收到一个 `HTTP/1.1 200 OK` 响应。 向路由发送不带任何凭据的请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到一个 `HTTP/1.1 401 Unauthorized` 响应。 这表明使用不同认证方法的 Consumer 能够认证并访问同一路由背后的资源。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 ### 路由或服务[​](#路由或服务 "路由或服务的直接链接") 以下是可在[路由](https://docs.apiseven.com/apisix/key-concepts/routes.md)或[服务](https://docs.apiseven.com/apisix/key-concepts/services.md)上配置的插件属性。 * auth\_plugins array\[object] 必填 *** 包含至少两个认证插件的数组。 --- # oas-validator `oas-validator` 插件会在请求转发到上游服务前,根据 OpenAPI 3 规范校验传入的 HTTP 请求。它不会校验上游响应。 自 API7 企业版 3.9.8 和 APISIX 3.17.0 起支持 OpenAPI 3.1,包括数值形式的 `exclusiveMinimum` 和 `exclusiveMaximum`、`if`/`then`/`else` 条件 Schema、通过 `["string", "null"]` 定义的可空类型,以及 `const`、`patternProperties`、`prefixItems` 和 JSON Schema `$dynamicRef`/`$dynamicAnchor` 等功能。 ## 示例[​](#示例 "示例的直接链接") 继续之前,请获取 Swagger Petstore 的 [OpenAPI 规范](https://petstore3.swagger.io/api/v3/openapi.json),后续示例将使用该规范。 * Admin API * ADC * Ingress Controller ``` export OPEN_API_SPEC=$(curl -s "https://petstore3.swagger.io/api/v3/openapi.json" | sed 's/"/\\"/g') ``` ``` export OPEN_API_SPEC=$(curl -s "https://petstore3.swagger.io/api/v3/openapi.json") ``` ``` curl -s "https://petstore3.swagger.io/api/v3/openapi.json" ``` 请在清单中将 `` 替换为实际的 OpenAPI JSON。 ### 验证请求体[​](#验证请求体 "验证请求体的直接链接") 此示例演示了如何根据给定规范验证请求体。 创建一个使用 OAS validator 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-validation spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: oas-validator-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` oas-validator-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-validation spec: ingressClassName: apisix http: - name: body-validation match: paths: - /* upstreams: - name: petstore-external-domain plugins: - name: oas-validator config: spec: ``` 应用配置: ``` kubectl apply -f oas-validator-ic.yaml ``` #### 验证失败[​](#验证失败 "验证失败的直接链接") 使用不满足定义的 Open API 规范的请求体向上述路由发送请求: ``` curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"invalid-body": "this is an invalid body"}' ``` 你应该会看到 `HTTP/1.1 400 Bad Request` 响应,其响应体类似于以下内容: ``` {"message":"failed to validate request."} ``` #### 验证成功[​](#验证成功 "验证成功的直接链接") 使用有效的请求体向路由发送请求: ``` curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "id": 1, "name": "doggie", "category": { "id": 1, "name": "Dogs" }, "photoUrls": ["string"], "tags": [{ "id": 1, "name": "tag1" }], "status": "available" }' ``` 你应该会看到 `HTTP/1.1 200 OK` 响应,其响应体类似于以下内容: ``` { "id": 1, "category": { "id": 1, "name": "Dogs" }, "name": "doggie", "photoUrls": ["string"], "tags": [{ "id": 1, "name": "tag1" }], "status": "available" } ``` ### 获取详细的错误响应[​](#获取详细的错误响应 "获取详细的错误响应的直接链接") 此示例演示了如何在验证失败时获取详细的错误响应。 创建一个从 URL 获取规范的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < verbose_errors: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-validation spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: oas-validator-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` oas-validator-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-validation spec: ingressClassName: apisix http: - name: body-validation match: paths: - /* upstreams: - name: petstore-external-domain plugins: - name: oas-validator config: spec: verbose_errors: true ``` 应用配置: ``` kubectl apply -f oas-validator-ic.yaml ``` 使用无效的请求体向上面创建的路由发送请求: ``` curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"invalid-body": "this is an invalid body"}' ``` 你应该会看到 `HTTP/1.1 400 Bad Request` 响应,其响应体类似于以下内容: ``` doesn't match schema #/components/schemas/Pet: Error at "/name": property "name" is missing Schema: { "properties": { "category": { "$ref": "#/components/schemas/Category" }, "id": { "example": 10, "format": "int64", "type": "integer" }, ... } Value: { "invalid-body": "this is an invalid body" } | Error at "/photoUrls": property "photoUrls" is missing Schema: { "properties": { "category": { "$ref": "#/components/schemas/Category" }, ... } Value: { "invalid-body": "this is an invalid body" } ``` ### 监控违规请求而不阻断流量[​](#监控违规请求而不阻断流量 "监控违规请求而不阻断流量的直接链接") 使用 `reject_if_not_match` 控制是不合规请求被阻止还是继续放行。该选项自 API7 企业版 3.9.6 和 APISIX 3.17.0 起可用。 #### 拒绝不符合规范的请求[​](#拒绝不符合规范的请求 "拒绝不符合规范的请求的直接链接") 当 `reject_if_not_match` 设置为 `true`(默认值)时,未通过 OAS 验证的请求会被拦截,并返回 `HTTP/1.1 400 Bad Request` 响应。 创建一个从 URL 获取规范的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < reject_if_not_match: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-validation spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: oas-validator-plugin-config backendRefs: - name: petstore-external-domain port: 443 ``` oas-validator-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-validation spec: ingressClassName: apisix http: - name: body-validation match: paths: - /* upstreams: - name: petstore-external-domain plugins: - name: oas-validator config: spec: reject_if_not_match: true ``` 应用配置: ``` kubectl apply -f oas-validator-ic.yaml ``` 发送带有无效请求体的请求: ``` curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"invalid-body": "this is an invalid body"}' ``` 你应该会看到 `HTTP/1.1 400 Bad Request` 响应,其响应体类似于以下内容: ``` {"message":"failed to validate request."} ``` #### 允许不符合规范的请求通过[​](#允许不符合规范的请求通过 "允许不符合规范的请求通过的直接链接") 当 `reject_if_not_match` 设置为 `false` 时,不符合规范的请求不会被拦截,而是转发到上游,同时验证错误会记录到错误日志中。 更新路由,将 `reject_if_not_match` 设置为 `false`: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ --data-binary @- < reject_if_not_match: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: body-validation spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: oas-validator-plugin-config backendRefs: - name: petstore-external-domain port: 443 ``` oas-validator-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: body-validation spec: ingressClassName: apisix http: - name: body-validation match: paths: - /* upstreams: - name: petstore-external-domain plugins: - name: oas-validator config: spec: reject_if_not_match: false ``` 应用配置: ``` kubectl apply -f oas-validator-ic.yaml ``` 发送带有无效请求体的请求: ``` curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"invalid-body": "this is an invalid body"}' ``` 你应该会看到 `HTTP/1.1 500 Internal Server Error` 响应,因为 `petstore3.swagger.io` 无法正确处理无效请求体。不过,可以确认该请求已成功转发到上游。 你还应该会看到类似以下的错误日志,其中记录了请求方法、URI 和验证错误: ``` [error] error occurred while validating request [POST /api/v3/pet], err: ... ``` 这样便可以在不影响现有客户端的情况下,通过日志审计不合规流量。 ### 使用远程规范 URL 进行验证[​](#使用远程规范-url-进行验证 "使用远程规范 URL 进行验证的直接链接") 本示例适用于 API7 企业版 3.9.12 及更高版本和 APISIX 3.17.0 及更高版本。 当 OpenAPI 规范过大而无法内嵌(`spec` 字段大小上限为 2 MB),或希望定期自动刷新规范时,请使用 `spec_url` 从远程 URL 加载规范。 插件会缓存编译后的规范。缓存过期后,APISIX 在后台刷新规范期间,旧缓存仍会继续处理请求。 如果首次获取或编译失败且没有可用缓存,插件返回 `500 Internal Server Error`。 为兼容既有环境,`spec_url` 默认不验证 TLS 证书。生产环境中请将 `ssl_verify` 设置为 `true`,并配置可信证书链。 创建一条从 URL 获取规范的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "url_validation", "uri": "/*", "plugins": { "oas-validator": { "spec_url": "https://petstore3.swagger.io/api/v3/openapi.json", "timeout": 5000 } }, "upstream": { "type": "roundrobin", "nodes": { "petstore3.swagger.io:443": 1 }, "scheme": "https", "pass_host": "node" } }' ``` adc.yaml ``` services: - name: petstore routes: - name: url-validation uris: - /* plugins: oas-validator: spec_url: https://petstore3.swagger.io/api/v3/openapi.json timeout: 5000 upstream: type: roundrobin nodes: - host: petstore3.swagger.io port: 443 weight: 1 scheme: https pass_host: node ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD oas-validator-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: petstore-external-domain spec: type: ExternalName externalName: petstore3.swagger.io --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: oas-validator-plugin-config spec: plugins: - name: oas-validator config: spec_url: https://petstore3.swagger.io/api/v3/openapi.json timeout: 5000 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: url-validation spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: oas-validator-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` oas-validator-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: url-validation spec: ingressClassName: apisix http: - name: url-validation match: paths: - /* upstreams: - name: petstore-external-domain plugins: - name: oas-validator enable: true config: spec_url: https://petstore3.swagger.io/api/v3/openapi.json timeout: 5000 ``` 应用配置: ``` kubectl apply -f oas-validator-ic.yaml ``` 如果规范端点需要身份认证,请使用相同的配置结构,并将占位 URL、后端和 Token 替换为实际环境中的值: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "url_validation", "uri": "/*", "plugins": { "oas-validator": { "spec_url": "https://internal-api.example.com/openapi.json", "spec_url_request_headers": { "Authorization": "Bearer " }, "timeout": 5000 } }, "upstream": { "type": "roundrobin", "nodes": { "internal-api.example.com:443": 1 }, "scheme": "https", "pass_host": "node" } }' ``` adc.yaml ``` services: - name: internal-api routes: - name: url-validation uris: - /* plugins: oas-validator: spec_url: https://internal-api.example.com/openapi.json spec_url_request_headers: Authorization: Bearer timeout: 5000 upstream: type: roundrobin nodes: - host: internal-api.example.com port: 443 weight: 1 scheme: https pass_host: node ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD oas-validator-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: internal-api-external-domain spec: type: ExternalName externalName: internal-api.example.com --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: oas-validator-plugin-config spec: plugins: - name: oas-validator config: spec_url: https://internal-api.example.com/openapi.json spec_url_request_headers: Authorization: Bearer timeout: 5000 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: url-validation spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: oas-validator-plugin-config backendRefs: - name: internal-api-external-domain port: 443 --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: internal-api-external-domain spec: targetRefs: - group: "" kind: Service name: internal-api-external-domain passHost: node scheme: https ``` oas-validator-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: internal-api-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: internal-api.example.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: url-validation spec: ingressClassName: apisix http: - name: url-validation match: paths: - /* upstreams: - name: internal-api-external-domain plugins: - name: oas-validator enable: true config: spec_url: https://internal-api.example.com/openapi.json spec_url_request_headers: Authorization: Bearer timeout: 5000 ``` 应用配置: ``` kubectl apply -f oas-validator-ic.yaml ``` 若要配置所获取规范的缓存 TTL(默认为 3600 秒),请设置插件元数据: * Admin API * ADC ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/oas-validator" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "spec_url_ttl": 1800 }' ``` adc.yaml ``` plugin_metadata: oas-validator: spec_url_ttl: 1800 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * spec string *** 包含 OpenAPI 规范的字符串。与 `spec_url` 互斥。 内联规范受控制面 2 MB 大小限制。如果你的 OpenAPI 规范超过此限制,请改用 `spec_url` 从远程 URL 加载。 * spec\_url string *** 用于获取 OpenAPI 规范的 URL(必须以 `http://` 或 `https://` 开头)。与 `spec` 互斥。获取的规范使用可配置的 TTL 缓存(参见插件元数据 `spec_url_ttl`),过期条目在后台异步刷新期间继续提供服务。 自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用。 * spec\_url\_request\_headers object *** 获取 `spec_url` 时包含的自定义 HTTP 头(例如用于认证)。 自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用。 * ssl\_verify boolean 默认值:`false` *** 获取 `spec_url` 时是否验证 SSL 证书。 自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用。 * timeout integer 默认值:`10000` 有效值: 1000–60000 *** 获取 `spec_url` 时的 HTTP 请求超时(毫秒)。 自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用。 * verbose\_errors boolean 默认值:`false` *** 如果为 true,则在验证失败时响应详细错误。 * skip\_request\_body\_validation boolean 默认值:`false` *** 如果为 true,则跳过请求体验证。 * skip\_request\_header\_validation boolean 默认值:`false` *** 如果为 true,则跳过请求头验证。 * skip\_query\_param\_validation boolean 默认值:`false` *** 跳过查询参数验证。 * skip\_path\_params\_validation boolean 默认值:`false` *** 跳过路径参数验证。 * reject\_if\_not\_match boolean 默认值:`true` *** 如果为 false,OAS 验证失败的请求仅记录错误日志,但仍会转发到上游服务。 自 API7 企业版 3.9.6 和 APISIX 3.17.0 起可用。 * rejection\_status\_code integer 默认值:`400` 有效值: 400–599 *** 请求验证失败时返回的 HTTP 状态码。例如,设置为 `422` 以区分语义验证错误(Unprocessable Entity)和格式错误的请求语法(`400` Bad Request)。仅在 `reject_if_not_match` 为 `true` 时生效。 自 API7 企业版 3.9.8 和 APISIX 3.17.0 起可用。 * max\_req\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** OpenAPI 验证时读取的请求体最大字节数。超过该大小的请求体会返回 `500 Internal Server Error`。`skip_request_body_validation` 为 `true` 时,此字段无效。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 备注 必须配置 `spec` 或 `spec_url` 之一,两者互斥。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * spec\_url\_ttl integer 默认值:`3600` *** 从 `spec_url` 获取的规范缓存的 TTL(秒)。过期后,过期条目在后台异步刷新时继续提供服务。 自 API7 企业版 3.9.12 和 APISIX 3.17.0 起可用。 --- # OPA `opa` 插件支持与 [Open Policy Agent (OPA)](https://www.openpolicyagent.org) 集成,OPA 是一个统一的策略引擎和框架,有助于定义和强制执行授权策略。授权逻辑在 [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) 中定义并存储在 OPA 中。 配置后,OPA 引擎将评估对受保护路由的客户端请求,根据定义的策略确定请求是否有权访问上游资源。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下使用 `opa` 插件。 在继续之前,你应该拥有一个正在运行的 OPA 服务器,或者在 Docker 中启动一个新的: * Docker * Kubernetes ``` docker run -d --name opa-server -p 8181:8181 openpolicyagent/opa:1.6.0 run --server --addr :8181 --log-level debug ``` * `run -s` 将 OPA 作为服务器启动。 * `--log-level debug` 打印调试信息,以检查 APISIX 推送到 OPA 的数据。 要验证 OPA 服务器是否已安装且端口正确暴露,请运行: ``` curl "http://127.0.0.1:8181" | grep Version ``` 你应该看到类似以下的响应: ``` Version: 1.6.0 ``` 在集群中为 OPA 创建 `Deployment` 和 `Service`: opa-server.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: opa spec: replicas: 1 selector: matchLabels: app: opa template: metadata: labels: app: opa spec: containers: - name: opa image: openpolicyagent/opa:1.6.0 args: - run - --server - --addr=:8181 - --log-level=debug ports: - containerPort: 8181 --- apiVersion: v1 kind: Service metadata: namespace: aic name: opa spec: selector: app: opa ports: - port: 8181 targetPort: 8181 ``` 将配置应用到集群: ``` kubectl apply -f opa-server.yaml ``` 等待 OPA Pod 就绪。就绪后,可以在集群内通过 `http://opa.aic.svc.cluster.local:8181` 访问 OPA 服务器。要从集群外向其推送策略,请设置端口转发: ``` kubectl port-forward -n aic svc/opa 8181:8181 & ``` ### 实现基本策略[​](#implement-a-basic-policy "实现基本策略的直接链接") 以下示例在 OPA 中实现了一个基本的授权策略,仅允许 GET 请求。 创建一个仅允许 HTTP GET 请求的 OPA 策略: ``` curl "http://127.0.0.1:8181/v1/policies/getonly" -X PUT \ -H "Content-Type: text/plain" \ -d ' package getonly default allow = false allow if { input.request.method == "GET" }' ``` 创建一个使用 `opa` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "opa-route", "uri": "/anything", "plugins": { "opa": { "host": "http://192.168.2.104:8181", "policy": "getonly" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 配置 OPA 服务器地址。请替换为你的 IP 地址。 ❷ 将授权策略设置为 `getonly`。 adc.yaml ``` services: - name: opa-service routes: - name: opa-route uris: - /anything plugins: opa: host: "http://192.168.2.104:8181" policy: getonly upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 配置 OPA 服务器地址。请替换为你的 IP 地址。 ❷ 将授权策略设置为 `getonly`。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD opa-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: opa-plugin-config spec: plugins: - name: opa config: host: "http://opa.aic.svc.cluster.local:8181" policy: getonly --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: opa-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: opa-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 配置 OPA 服务器地址。 ❷ 将授权策略设置为 `getonly`。 将配置应用到集群: ``` kubectl apply -f opa-ic.yaml ``` opa-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: opa-route spec: ingressClassName: apisix http: - name: opa-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: opa enable: true config: host: "http://opa.aic.svc.cluster.local:8181" policy: getonly ``` ❶ 配置 OPA 服务器地址。 ❷ 将授权策略设置为 `getonly`。 将配置应用到集群: ``` kubectl apply -f opa-ic.yaml ``` 要验证该策略,向路由发送一个 GET 请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 向路由发送另一个使用 PUT 的请求: ``` curl -i "http://127.0.0.1:9080/anything" -X PUT ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应。 ### 理解数据格式[​](#理解数据格式 "理解数据格式的直接链接") 以下示例有助于你理解 APISIX 推送到 OPA 以支持授权逻辑编写的数据及其格式。该示例沿用[上一个示例](#implement-a-basic-policy)中的策略和路由。 假设你的 OPA 服务器已使用 `--log-level debug` 启动,并且你已完成[上一个示例](#implement-a-basic-policy)中的验证步骤,向示例路由发送了请求。 查看 OPA 服务器日志。你应该看到类似以下的条目: ``` { "client_addr": "192.168.215.1:58467", "level": "info", "msg": "Received request.", "req_body": "{\"input\":{\"type\":\"http\",\"var\":{\"server_port\":\"9080\",\"timestamp\":1752400020,\"server_addr\":\"192.168.107.3\",\"remote_port\":\"58544\",\"remote_addr\":\"192.168.107.1\"},\"request\":{\"host\":\"127.0.0.1\",\"path\":\"/anything\",\"headers\":{\"host\":\"127.0.0.1:9080\",\"accept\":\"*/*\",\"user-agent\":\"curl/8.6.0\"},\"query\":{},\"port\":9080,\"scheme\":\"http\",\"method\":\"PUT\"}}}", "req_id": 12, "req_method": "POST", "req_params": {}, "req_path": "/v1/data/getonly", "time": "2025-07-14T15:07:00Z" } ``` 其中 `req_body` 显示了 APISIX 推送的数据: ``` { "input": { "type": "http", "var": { "server_port": "9080", "timestamp": 1752400020, "server_addr": "192.168.107.3", "remote_port": "58544", "remote_addr": "192.168.107.1" }, "request": { "host": "127.0.0.1", "path": "/anything", "headers": { "host": "127.0.0.1:9080", "accept": "*/*", "user-agent": "curl/8.6.0" }, "query": {}, "port": 9080, "scheme": "http", "method": "PUT" } } } ``` 现在,更新[之前创建的路由](#implement-a-basic-policy)上的插件以包含路由信息: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/opa-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "opa": { "with_route": true } } }' ``` 更新 `adc.yaml`,添加 `with_route: true`: adc.yaml ``` services: - name: opa-service routes: - name: opa-route uris: - /anything plugins: opa: host: "http://192.168.2.104:8181" policy: getonly with_route: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `opa-ic.yaml`,添加 `with_route: true`: opa-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: opa-plugin-config spec: plugins: - name: opa config: host: "http://opa.aic.svc.cluster.local:8181" policy: getonly with_route: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: opa-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: opa-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将更新后的配置应用到集群: ``` kubectl apply -f opa-ic.yaml ``` 更新 `opa-ic.yaml`,添加 `with_route: true`: opa-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: opa-route spec: ingressClassName: apisix http: - name: opa-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: opa enable: true config: host: "http://opa.aic.svc.cluster.local:8181" policy: getonly with_route: true ``` 将更新后的配置应用到集群: ``` kubectl apply -f opa-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 在 OPA 服务器日志中,你应该看到一个新的条目: ``` { "client_addr": "192.168.215.1:43706", "level": "info", "msg": "Received request.", "req_body": "{\"input\":{\"route\":{\"id\":\"opa-route\",\"uri\":\"/anything\",\"update_time\":1752395758,\"plugins\":{\"opa\":{\"keepalive_pool\":5,\"keepalive_timeout\":60000,\"host\":\"http://172.17.1.196:8181\",\"ssl_verify\":true,\"with_route\":true,\"with_service\":false,\"with_consumer\":false,\"timeout\":3000,\"keepalive\":true,\"policy\":\"getonly\"}},\"priority\":0,\"status\":1,\"create_time\":1752393063},\"type\":\"http\",\"var\":{\"server_port\":\"9080\",\"timestamp\":1752396233,\"server_addr\":\"192.168.107.3\",\"remote_port\":\"47838\",\"remote_addr\":\"192.168.107.1\"},\"request\":{\"host\":\"127.0.0.1\",\"path\":\"/anything\",\"headers\":{\"host\":\"127.0.0.1:9080\",\"accept\":\"*/*\",\"user-agent\":\"curl/8.6.0\"},\"query\":{},\"port\":9080,\"scheme\":\"http\",\"method\":\"GET\"}}}", "req_id": 14, "req_method": "POST", "req_params": {}, "req_path": "/v1/data/getonly", "time": "2025-07-13T08:43:53Z" } ``` `req_body` 现在包含了路由信息: ``` { "input": { "route": { "id": "opa-route", "uri": "/anything", "update_time": 1752395758, "plugins": { "opa": { "keepalive_pool": 5, "keepalive_timeout": 60000, "host": "http://172.17.1.196:8181", "ssl_verify": true, "with_route": true, "with_service": false, "with_consumer": false, "timeout": 3000, "keepalive": true, "policy": "getonly" } }, "priority": 0, "status": 1, "create_time": 1752393063 }, "type": "http", "var": { "server_port": "9080", "timestamp": 1752396233, "server_addr": "192.168.107.3", "remote_port": "47838", "remote_addr": "192.168.107.1" }, "request": { "host": "127.0.0.1", "path": "/anything", "headers": { "host": "127.0.0.1:9080", "accept": "*/*", "user-agent": "curl/8.6.0" }, "query": {}, "port": 9080, "scheme": "http", "method": "GET" } } } ``` ### 返回自定义响应[​](#返回自定义响应 "返回自定义响应的直接链接") 以下示例展示了如何在请求未获授权时返回自定义响应代码和消息。 创建一个仅允许 HTTP GET 请求并在未获授权时返回 `302` 和自定义消息的 OPA 策略: ``` curl "http://127.0.0.1:8181/v1/policies/customresp" -X PUT \ -H "Content-Type: text/plain" \ -d ' package customresp default allow = false allow if { input.request.method == "GET" } reason := "The resource has temporarily moved. Please follow the new URL." if { not allow } headers := { "Location": "http://example.com/auth" } if { not allow } status_code := 302 if { not allow } ' ``` 创建一个使用 `opa` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "opa-route", "uri": "/anything", "plugins": { "opa": { "host": "http://192.168.2.104:8181", "policy": "customresp" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 配置 OPA 服务器地址。请替换为你的 IP 地址。 ❷ 将授权策略设置为 `customresp`。 adc.yaml ``` services: - name: opa-service routes: - name: opa-route uris: - /anything plugins: opa: host: "http://192.168.2.104:8181" policy: customresp upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 配置 OPA 服务器地址。请替换为你的 IP 地址。 ❷ 将授权策略设置为 `customresp`。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD opa-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: opa-customresp-plugin-config spec: plugins: - name: opa config: host: "http://opa.aic.svc.cluster.local:8181" policy: customresp --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: opa-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: opa-customresp-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 配置 OPA 服务器地址。 ❷ 将授权策略设置为 `customresp`。 将配置应用到集群: ``` kubectl apply -f opa-ic.yaml ``` opa-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: opa-route spec: ingressClassName: apisix http: - name: opa-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: opa enable: true config: host: "http://opa.aic.svc.cluster.local:8181" policy: customresp ``` ❶ 配置 OPA 服务器地址。 ❷ 将授权策略设置为 `customresp`。 将配置应用到集群: ``` kubectl apply -f opa-ic.yaml ``` 向路由发送一个 GET 请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 向路由发送一个 POST 请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST ``` 你应该收到 `HTTP/1.1 302 Moved Temporarily` 响应: ``` HTTP/1.1 302 Moved Temporarily ... Location: http://example.com/auth The resource has temporarily moved. Please follow the new URL. ``` ### 实现 RBAC[​](#实现-rbac "实现 RBAC的直接链接") 以下示例展示了如何使用 [`jwt-auth`](https://docs.apiseven.com/hub/jwt-auth.md) 和 `opa` 插件实现身份认证和 RBAC。你将实现以下 RBAC 逻辑: * `user` 角色只能读取上游资源。 * `admin` 角色可以读取和写入上游资源。 为两个示例消费者创建 RBAC 的 OPA 策略,其中 `john` 拥有 `user` 角色,`jane` 拥有 `admin` 角色: ``` curl "http://127.0.0.1:8181/v1/policies/rbac" -X PUT \ -H "Content-Type: text/plain" \ -d ' package rbac # 为用户分配角色 user_roles := { "john": ["user"], "jane": ["admin"] } # 将权限映射到 HTTP 方法 permission_methods := { "read": "GET", "write": "POST" } # 分配角色权限 role_permissions := { "user": ["read"], "admin": ["read", "write"] } # 获取 JWT 授权令牌 bearer_token := t if { t := input.request.headers.authorization } # 解码令牌以获取角色和权限 token := {"payload": payload} if { [_, payload, _] := io.jwt.decode(bearer_token) } # 将权限规范化为列表 normalized_permissions := ps if { ps := token.payload.permission not is_string(ps) } normalized_permissions := [ps] if { ps := token.payload.permission is_string(ps) } # 实现 RBAC 逻辑 default result := {"allow": false} result := {"allow": true} if { # 查找用户的角色列表 roles := user_roles[input.consumer.username] # 遍历列表中的每个角色 r := roles[_] # 查找角色的权限列表 permissions := role_permissions[r] # 遍历每项权限 p := permissions[_] # 检查权限是否与请求方法匹配 permission_methods[p] == input.request.method # 检查规范化后的权限是否包含该权限 p in normalized_permissions } ' ``` 在 APISIX 中创建两个消费者 `john` 和 `jane`,并配置其 `jwt-auth` 凭证: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" \ -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "username": "john" }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" \ -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "username": "jane" }' ``` 使用默认算法 `HS256` 为消费者配置 `jwt-auth` 凭据: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-jwt-auth", "plugins": { "jwt-auth": { "key": "john-key", "secret": "john-hs256-secret-that-is-very-long" } } }' ``` ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-jwt-auth", "plugins": { "jwt-auth": { "key": "jane-key", "secret": "jane-hs256-secret-that-is-very-long" } } }' ``` adc.yaml ``` consumers: - username: john credentials: - name: cred-john-jwt-auth type: jwt-auth config: key: john-key secret: john-hs256-secret-that-is-very-long - username: jane credentials: - name: cred-jane-jwt-auth type: jwt-auth config: key: jane-key secret: jane-hs256-secret-that-is-very-long ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD opa-consumers-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: cred-john-jwt-auth config: key: john-key secret: john-hs256-secret-that-is-very-long --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jane spec: gatewayRef: name: apisix credentials: - type: jwt-auth name: cred-jane-jwt-auth config: key: jane-key secret: jane-hs256-secret-that-is-very-long ``` 将配置应用到集群: ``` kubectl apply -f opa-consumers-ic.yaml ``` opa-consumers-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: jwtAuth: value: key: john-key secret: john-hs256-secret-that-is-very-long --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane spec: ingressClassName: apisix authParameter: jwtAuth: value: key: jane-key secret: jane-hs256-secret-that-is-very-long ``` 将配置应用到集群: ``` kubectl apply -f opa-consumers-ic.yaml ``` 创建一个路由并配置 `jwt-auth` 和 `opa` 插件,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "opa-route", "methods": ["GET", "POST"], "uris": ["/get","/post"], "plugins": { "jwt-auth": {}, "opa": { "host": "http://192.168.2.104:8181", "policy": "rbac/result", "with_consumer": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` ❶ 在路由上启用 `jwt-auth` 插件。 ❷ 配置 OPA 服务器地址。请替换为你的 IP 地址。 ❸ 将授权策略设置为 `rbac/result`。 ❹ 将 `with_consumer` 设置为 `true`,以发送消费者信息。 更新 `adc.yaml`,添加启用了 `jwt-auth` 和 `opa` 插件的路由: adc.yaml ``` consumers: - username: john credentials: - name: cred-john-jwt-auth type: jwt-auth config: key: john-key secret: john-hs256-secret-that-is-very-long - username: jane credentials: - name: cred-jane-jwt-auth type: jwt-auth config: key: jane-key secret: jane-hs256-secret-that-is-very-long services: - name: opa-service routes: - name: opa-route uris: - /get - /post methods: - GET - POST plugins: jwt-auth: {} opa: host: "http://192.168.2.104:8181" policy: rbac/result with_consumer: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` ❶ 在路由上启用 `jwt-auth` 插件。 ❷ 配置 OPA 服务器地址。请替换为你的 IP 地址。 ❸ 将授权策略设置为 `rbac/result`。 ❹ 将 `with_consumer` 设置为 `true`,以发送消费者信息。 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD opa-route-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: opa-rbac-plugin-config spec: plugins: - name: jwt-auth config: _meta: disable: false - name: opa config: host: "http://opa.aic.svc.cluster.local:8181" policy: rbac/result with_consumer: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: opa-rbac-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get method: GET filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: opa-rbac-plugin-config backendRefs: - name: httpbin-external-domain port: 80 - matches: - path: type: Exact value: /post method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: opa-rbac-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` ❶ 配置 OPA 服务器地址。 ❷ 将授权策略设置为 `rbac/result`。 ❸ 将 `with_consumer` 设置为 `true`,以发送消费者信息。 将配置应用到集群: ``` kubectl apply -f opa-route-ic.yaml ``` 备注 使用 Ingress Controller 时,APISIX 会为消费者名称添加 Kubernetes 命名空间前缀。例如,`aic` 命名空间中名为 `john` 的消费者会变为 `aic_john`。请更新 OPA RBAC 策略以使用带前缀的名称: ``` curl "http://127.0.0.1:8181/v1/policies/rbac" -X PUT \ -H "Content-Type: text/plain" \ -d ' package rbac # 为用户分配角色 user_roles := { "aic_john": ["user"], "aic_jane": ["admin"] } # 将权限映射到 HTTP 方法 permission_methods := { "read": "GET", "write": "POST" } # 分配角色权限 role_permissions := { "user": ["read"], "admin": ["read", "write"] } # 获取 JWT 授权令牌 bearer_token := t if { t := input.request.headers.authorization } # 解码令牌以获取角色和权限 token := {"payload": payload} if { [_, payload, _] := io.jwt.decode(bearer_token) } # 将权限规范化为列表 normalized_permissions := ps if { ps := token.payload.permission not is_string(ps) } normalized_permissions := [ps] if { ps := token.payload.permission is_string(ps) } # 实现 RBAC 逻辑 default result := {"allow": false} result := {"allow": true} if { # 查找用户的角色列表 roles := user_roles[input.consumer.username] # 遍历列表中的每个角色 r := roles[_] # 查找角色的权限列表 permissions := role_permissions[r] # 遍历每项权限 p := permissions[_] # 检查权限是否与请求方法匹配 permission_methods[p] == input.request.method # 检查规范化后的权限是否包含该权限 p in normalized_permissions } ' ``` opa-route-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: opa-rbac-route spec: ingressClassName: apisix http: - name: get-route match: methods: - GET paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: _meta: disable: false - name: opa enable: true config: host: "http://opa.aic.svc.cluster.local:8181" policy: rbac/result with_consumer: true - name: post-route match: methods: - POST paths: - /post upstreams: - name: httpbin-external-domain plugins: - name: jwt-auth enable: true config: _meta: disable: false - name: opa enable: true config: host: "http://opa.aic.svc.cluster.local:8181" policy: rbac/result with_consumer: true ``` 将配置应用到集群: ``` kubectl apply -f opa-route-ic.yaml ``` 备注 使用 Ingress Controller 时,APISIX 会为消费者名称添加 Kubernetes 命名空间前缀。例如,`aic` 命名空间中名为 `john` 的消费者会变为 `aic_john`。请更新 OPA RBAC 策略以使用带前缀的名称: ``` curl "http://127.0.0.1:8181/v1/policies/rbac" -X PUT \ -H "Content-Type: text/plain" \ -d ' package rbac user_roles := { "aic_john": ["user"], "aic_jane": ["admin"] } permission_methods := { "read": "GET", "write": "POST" } role_permissions := { "user": ["read"], "admin": ["read", "write"] } bearer_token := t if { t := input.request.headers.authorization } token := {"payload": payload} if { [_, payload, _] := io.jwt.decode(bearer_token) } normalized_permissions := ps if { ps := token.payload.permission not is_string(ps) } normalized_permissions := [ps] if { ps := token.payload.permission is_string(ps) } default result := {"allow": false} result := {"allow": true} if { roles := user_roles[input.consumer.username] r := roles[_] permissions := role_permissions[r] p := permissions[_] permission_methods[p] == input.request.method p in normalized_permissions } ' ``` #### 验证 `john`[​](#验证-john "验证-john的直接链接") 要为 `john` 颁发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io)或其他工具。如果你使用 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 将算法填写为 `HS256`。 * 将 **Valid secret** 部分中的密钥更新为 `john-hs256-secret-that-is-very-long`。 * 更新 payload,角色为 `user`,权限为 `read`,消费者密钥为 `john-key`;以及 `exp` 或 `nbf` 为 UNIX 时间戳。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "role": "user", "permission": "read", "key": "john-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量: ``` export john_jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsInBlcm1pc3Npb24iOiJyZWFkIiwia2V5Ijoiam9obi1rZXkiLCJuYmYiOjE3MjkxMzIyNzF9.rAHMTQfnnGFnKYc3am_lpE9pZ9E8EaOT_NBQ5Ss8pk4 ``` 使用 `john` 的 JWT 向路由发送 GET 请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${john_jwt_token}" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 使用相同的 JWT 向路由发送 POST 请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST -H "Authorization: ${john_jwt_token}" ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应。 #### 验证 `jane`[​](#验证-jane "验证-jane的直接链接") 同样,要为 `jane` 颁发 JWT,你可以使用 [JWT.io 的 JWT 编码器](https://jwt.io)或其他工具。如果你使用 [JWT.io 的 JWT 编码器](https://jwt.io),请执行以下操作: * 将算法填写为 `HS256`。 * 将 **Valid secret** 部分中的密钥更新为 `jane-hs256-secret-that-is-very-long`。 * 更新 payload,角色为 `admin`,权限为 `["read","write"]`,消费者密钥为 `jane-key`;以及 `exp` 或 `nbf` 为 UNIX 时间戳。 备注 当 `claims_to_verify` 为非空列表时,列表中的每个 Claim 都必须存在并通过验证。未设置或设置为空列表时,如果 `exp` 和 `nbf` 存在,则会对其进行验证,但不会强制要求这两个 Claim 存在。 你的 payload 应该类似于以下内容: ``` { "role": "admin", "permission": ["read","write"], "key": "jane-key", "nbf": 1729132271 } ``` 复制生成的 JWT 并保存到变量: ``` export jane_jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJwZXJtaXNzaW9uIjpbInJlYWQiLCJ3cml0ZSJdLCJrZXkiOiJqYW5lLWtleSIsIm5iZiI6MTcyOTEzMjI3MX0.meZ-AaGHUPwN_GvVOE3IkKuAJ1wqlCguaXf3gm3Ww8s ``` 使用 `jane` 的 JWT 向路由发送 GET 请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jane_jwt_token}" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 使用相同的 JWT 向路由发送 POST 请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST -H "Authorization: ${jane_jwt_token}" ``` 你应该也收到 `HTTP/1.1 200 OK` 响应。 提示 如果你设置了 `--log-level debug`,要检查授权决策是否来自 OPA,你应该在 OPA 服务器中观察到以下日志: ``` { "result":{ "allow": true, "bearer_token": "eyJ...", ... } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件可用的配置选项。 * host string 必填 *** OPA 服务器的地址。 * policy string 必填 *** 要评估的策略。 例如,如果你想评估名为 `rbac` 的包中的所有规则,请将策略配置为 `rbac`。 如果你想评估包中的特定规则,可以在包后面指定规则名称,例如 `rbac/allow`。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则验证 OPA 服务器的 SSL 证书。 * timeout integer 默认值:`3000` 有效值: 介于 1 和 60000 之间(含边界值) *** HTTP 调用的超时时间(毫秒)。 * keepalive boolean 默认值:`true` *** 如果为 true,则在多个请求之间保持连接。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** 连接关闭前的空闲时间(毫秒)。 * keepalive\_pool integer 默认值:`5` 有效值: 大于或等于 1 *** 空闲连接数。 * with\_route boolean 默认值:`false` *** 如果为 true,则发送当前路由的信息。 * with\_service boolean 默认值:`false` *** 如果为 true,则发送当前服务的信息。 * with\_consumer boolean 默认值:`false` *** 如果为 true,则发送当前消费者的信息。 注意,消费者信息可能包含敏感信息,如 API 密钥。仅当你确定安全时才将此选项设置为 `true`。 * send\_headers\_upstream array\[string] *** 请求被允许时,由 OPA 响应控制的请求头名称。当 OPA 返回已配置的请求头时,网关会将其转发;当 OPA 未返回该请求头时,网关会清除客户端提供的同名值。 --- # openapi-to-mcp [企业版](https://api7.ai/enterprise) `openapi-to-mcp` 插件使网关能够充当 OpenAPI 规范与模型上下文协议(MCP)服务器之间的桥梁。通过此插件,你可以通过 MCP 接口暴露现有的基于 OpenAPI 的服务,使其可供 AI 模型和客户端访问。 该插件会将 OpenAPI 规范转换为 MCP 格式,并通过 MCP 服务器接口提供服务。随后,来自 AI 客户端的请求会被代理到上游服务。插件支持自定义请求头,并支持两种用于流式响应的传输方式:Streamable HTTP 和服务器发送事件(SSE),从而实现灵活、可靠的实时通信。 下图展示了 MCP 客户端、API7 网关与上游 OpenAPI 服务之间的交互。图中的路径和数据仅为演示示例。
## 演示[​](#演示 "演示的直接链接") 以下示例演示如何[启用对 Petstore API 的 MCP 访问](#%E5%90%AF%E7%94%A8%E5%AF%B9-petstore-api-%E7%9A%84-mcp-%E8%AE%BF%E9%97%AE),使 AI 模型和客户端能够与 Petstore 服务交互。正确配置后,AI 客户端应立即显示可用的 Petstore 工具;如果工具未显示,请确认 OpenAPI 规范 URL 可访问,且 AI 客户端环境能够连接网关地址。
## 部署与兼容性[​](#deployment-and-compatibility "部署与兼容性的直接链接") ### 部署前置条件[​](#部署前置条件 "部署前置条件的直接链接") 从 API7 企业版 **3.9.10** 起,OpenAPI-to-MCP 服务不再内置于网关镜像中,必须与网关一起部署在同一网络命名空间中。 * **Kubernetes(Helm)**:在网关 Chart values 中设置 `openapiToMcp.enabled: true`,以边车方式运行该服务。 * **Docker / 裸机**:将 `api7/openapi-to-mcp` 镜像作为独立容器运行,并与网关共享网络命名空间(例如使用 `--network=container:` 或主机网络),使插件可以通过 `127.0.0.1:`(默认端口为 `3000`)访问该服务。插件将 `127.0.0.1` 硬编码为目标地址,因此两个容器必须共享网络命名空间;仅共享 Docker bridge 网络并不足够。 如果无法访问该服务,插件将返回 503 错误。`mcp-tools-acl` 插件同样如此。若要让服务在其他端口运行,请参阅[静态配置](https://docs.apiseven.com/hub/openapi-to-mcp/configuration.md#%E9%9D%99%E6%80%81%E9%85%8D%E7%BD%AE)。 ### 边车镜像标签与网关版本兼容性[​](#边车镜像标签与网关版本兼容性 "边车镜像标签与网关版本兼容性的直接链接") 插件与 OpenAPI-to-MCP 服务通过很少变更的稳定内部契约进行通信,因此一个边车镜像标签可兼容多个网关版本。下表列出了各网关版本范围应使用的边车标签。仅当两者之间的协议发生变化(即下表新增一行)时,才需要更新边车。 此指南适用于需要自行选择边车镜像标签的 **Docker 和裸机**部署。Helm Chart 已为配套的网关版本固定经过验证的边车标签,因此 Helm 用户无需参考此表。 | 网关版本 | 边车镜像标签(`api7/openapi-to-mcp`) | | ------------------- | ------------------------------------- | | `3.9.10` 及更高版本 | `1.0.2` 或更高版本 | ### OpenAPI 文档缓存[​](#openapi-document-caching "OpenAPI 文档缓存的直接链接") 在 `api7/openapi-to-mcp:1.0.2` 中,服务会缓存解析后的 OpenAPI 文档及据此生成的工具定义。缓存键根据 `openapi_url`、`base_url`、三个鉴权请求头(`Authorization`、`X-API-Key`、`X-Auth-Token`)值的摘要,以及 `flatten_parameters` 设置生成。缓存默认开启,条目自写入起保留 3600 秒,命中缓存不会延长有效期。服务会在条目过期后下一次需要加载规范时重新下载并解析文档;文档内容或 HTTP 缓存头的变化不会主动使缓存失效。缓存过期不会自动更新已有 SSE 或有状态 HTTP 会话中注册的工具。 如需跳过旧缓存,请修改 `openapi_url`(例如添加或更新查询参数 `?v=2`),确保新 URL 仍能返回所需规范,并保存插件。服务下一次加载规范时会使用新 URL 对应的缓存键;若该键尚无缓存,则重新拉取文档。已有会话需要重新建立连接并加载工具。 **Docker 和裸机**部署可以通过 `api7/openapi-to-mcp` 容器的环境变量调整缓存: | 变量 | 默认值 | 说明 | | --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `CACHE_ENABLED` | `true` | 设为小写 `false` 可关闭缓存。关闭后,每次需要加载 OpenAPI 规范时都会重新下载并解析文档,延迟会上升;已有会话中的工具请求不会因此重新加载规范。 | | `CACHE_TTL` | `3600` | 缓存条目的保留秒数,建议使用正整数。 | Helm Chart 目前未为边车暴露这些变量,Helm 部署使用默认值。 ## 使用 Docker Compose 部署[​](#deploy-with-docker-compose "使用 Docker Compose 部署的直接链接") 以下 `docker-compose.yaml` 会同时运行 API7 企业版网关和 OpenAPI-to-MCP 服务。MCP 服务会加入网关的网络命名空间,使插件可以通过 `127.0.0.1:3000` 访问它。 在控制台中添加网关实例时,系统会自动生成可直接使用的 `docker-compose.yaml`。若要启用 `openapi-to-mcp` 插件,请将下方所示的 `openapi-to-mcp` 服务添加到该文件中: docker-compose.yaml ``` services: gateway: image: api7/api7-ee-3-gateway:3.9.12 container_name: gateway hostname: gateway restart: always ports: - "9080:9080" - "9443:9443" environment: API7_DP_MANAGER_ENDPOINTS: '["https://:7943"]' API7_GATEWAY_GROUP_SHORT_ID: "" API7_DP_MANAGER_CERT: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- API7_DP_MANAGER_KEY: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- API7_CONTROL_PLANE_CA: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- openapi-to-mcp: image: api7/openapi-to-mcp:1.0.2 network_mode: "service:gateway" restart: always ``` ❶ DP Manager 端点,请替换为控制台中提供的地址。 ❷ 网关组短 ID,请替换为控制台中显示的值。 ❸ TLS 客户端证书、私钥和 CA 证书。从控制台复制生成的 Compose 文件时,系统会自动填充这些值。 ❹ `network_mode: "service:gateway"` 让 MCP 容器共享网关的网络栈,使插件可以通过 `127.0.0.1:3000` 访问 MCP 服务。仅共享 Docker bridge 网络**并不足够**,因为插件将 `127.0.0.1` 硬编码为目标地址。 启动服务: ``` docker compose up -d ``` ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `openapi-to-mcp` 插件。 ### 启用对 Petstore API 的 MCP 访问[​](#启用对-petstore-api-的-mcp-访问 "启用对 Petstore API 的 MCP 访问的直接��链接") 以下示例演示了如何通过 MCP 协议暴露 Petstore API,允许 AI 模型和客户端与 Petstore 服务进行交互。 * Admin API * ADC * Ingress Controller 创建一个使用 `openapi-to-mcp` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "openapi-to-mcp-route", "uri": "/mcp", "methods": ["GET", "POST"], "plugins": { "openapi-to-mcp": { "transport": "streamable_http", "base_url": "https://petstore3.swagger.io/api/v3", "headers": { "Authorization": "special-key" }, "openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json" } } }' ``` ❶ 配置路由允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行和操作能力(messages)。 ❷ 将传输方式配置为 `streamable_http`(建议用于生产环境)。 ❸ 配置 Petstore API 地址。 ❹ 配置 Petstore API 凭证。 ❺ 配置 Petstore OpenAPI 文档 URL。 创建一个路由,并按如下方式配置 `openapi-to-mcp` 插件: adc.yaml ``` services: - name: openapi-to-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: openapi-to-mcp-route uris: - /mcp methods: - GET - POST plugins: openapi-to-mcp: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ 配置路由允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行和操作能力(messages)。 ❷ 将传输方式配置为 `streamable_http`(建议用于生产环境)。 ❸ 配置 Petstore API 地址。 ❹ 配置 Petstore API 凭证。 ❺ 配置 Petstore OpenAPI 文档 URL。 * Gateway API * APISIX CRD 创建一个路由,并按如下方式配置 `openapi-to-mcp` 插件: openapi-to-mcp-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: openapi-to-mcp-plugin-config spec: plugins: - name: openapi-to-mcp config: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: openapi-to-mcp-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /mcp method: GET - path: type: Exact value: /mcp method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: openapi-to-mcp-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: v1 kind: Service metadata: namespace: aic name: petstore-external-domain spec: type: ExternalName externalName: petstore3.swagger.io --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` 将配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` ❶ 将传输方式配置为 `streamable_http`(推荐用于生产环境)。 ❷ 配置 Petstore API 地址。 ❸ 配置 Petstore API 凭证。 ❹ 配置 Petstore OpenAPI 文档 URL。 ❺ 配置路由以允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行操作(消息)。 创建一个路由,并按如下方式配置 `openapi-to-mcp` 插件: openapi-to-mcp-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: openapi-to-mcp-route spec: ingressClassName: apisix http: - name: openapi-to-mcp-route match: paths: - /mcp methods: - GET - POST plugins: - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` ❶ 配置路由允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行和操作能力(messages)。 ❷ 将传输方式配置为 `streamable_http`(建议用于生产环境)。 ❸ 配置 Petstore API 地址。 ❹ 配置 Petstore API 凭证。 ❺ 配置 Petstore OpenAPI 文档 URL。 应用 Admin API、ADC 或 APISIX CRD 配置后,在 MCP 设置中填写 API7 网关地址,并追加之前创建的路由路径。例如: mcp.json ``` { "mcpServers": { "api7-petstore-mcp": { "url": "http://123.123.123.123:9080/mcp" } } } ``` 如果配置成功,你应该会看到可用工具,即通过 MCP 向 AI 客户端公开的外部函数或服务。 现在,你可以直接在 AI 客户端的聊天窗口中与 Petstore 服务交互。例如,可以尝试询问:“显示 Petstore 中编号为 1 的宠物。” ![AI 客户端与 Petstore 交互](https://static.api7.ai/uploads/2025/09/22/6TE6DgXy_oet.png) ### 为 MCP 路由配置身份验证[​](#为-mcp-路由配置身份验证 "为 MCP 路由配置身份验证的直接链接") 以下示例演示了当路由受到身份验证方法(如 `key-auth`)保护时,如何通过 MCP 协议暴露 Petstore API。 * Admin API * ADC * Ingress Controller 创建一个消费者 `johndoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "johndoe" }' ``` 为 `johndoe` 配置 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建一个包含 `openapi-to-mcp` 和 `key-auth` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "openapi-to-mcp-route", "uri": "/mcp", "methods": ["GET", "POST"], "plugins": { "openapi-to-mcp": { "transport": "streamable_http", "base_url": "https://petstore3.swagger.io/api/v3", "headers": { "Authorization": "special-key" }, "openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json" }, "key-auth": { "header": "apikey" } } }' ``` 创建一个消费者和一条路由,并按如下方式配置 `openapi-to-mcp` 和 `key-auth` 插件: adc.yaml ``` consumers: - username: johndoe credentials: - name: primary-key type: key-auth config: key: john-key services: - name: openapi-to-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: openapi-to-mcp-route uris: - /mcp methods: - GET - POST plugins: key-auth: header: apikey openapi-to-mcp: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 创建一个消费者和一条路由,并按如下方式配置 `openapi-to-mcp` 和 `key-auth` 插件: openapi-to-mcp-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: openapi-to-mcp-plugin-config spec: plugins: - name: key-auth config: header: apikey - name: openapi-to-mcp config: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: openapi-to-mcp-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /mcp method: GET - path: type: Exact value: /mcp method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: openapi-to-mcp-plugin-config backendRefs: - name: petstore-external-domain port: 443 --- apiVersion: v1 kind: Service metadata: namespace: aic name: petstore-external-domain spec: type: ExternalName externalName: petstore3.swagger.io --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: petstore-external-domain spec: targetRefs: - group: "" kind: Service name: petstore-external-domain passHost: node scheme: https ``` 创建一个 `ApisixConsumer` 和一条路由,并按如下方式配置 `openapi-to-mcp` 和 `key-auth` 插件: openapi-to-mcp-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: petstore-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: petstore3.swagger.io port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: openapi-to-mcp-route spec: ingressClassName: apisix http: - name: openapi-to-mcp-route match: paths: - /mcp methods: - GET - POST upstreams: - name: petstore-external-domain plugins: - name: key-auth enable: true config: header: apikey - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` 当 MCP 服务器需要身份验证时,你可以在 `mcp.json` 配置中指定请求头。请参阅你的 AI 客户端文档以确认是否支持请求头。 #### 如果支持请求头[​](#如果支持请求头 "如果支持请求头的直接链接") 例如,在应用 Admin API、ADC 或 APISIX CRD 配置后,可以在 Cursor 的 MCP 设置中填写 API7 网关地址、追加之前创建的路由路径,并添加 `key-auth` 所需的请求头: mcp.json ``` { "mcpServers": { "api7-petstore-mcp": { "url": "http://123.123.123.123:9080/mcp", "headers": { "apikey": "john-key" } } } } ``` 配置的请求头将被添加到 GET 和 POST 请求中。 如果配置成功,你应该会看到可用工具,即通过 MCP 向 AI 客户端公开的外部函数或服务。随后便可直接在 AI 客户端的聊天窗口中与 Petstore 交互。 如果未在 `mcp.json` 中配置身份验证头,AI 客户端将无法从 MCP 服务器加载工具。 #### 如果不支持请求头[​](#如果不支持请求头 "如果不支持请求头的直接链接") 如果你的 AI 客户端不支持在 `mcp.json` 中配置请求头,你可以将身份验证凭证包含在 MCP URL 查询参数中,因为 `key-auth` 支持从 URL 查询中获取凭证。 更新路由上的 `key-auth` 配置如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/openapi-to-mcp-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "key-auth": { "_meta": { "filter": [ [ "request_method", "==", "GET" ] ] }, "query": "apikey" } } }' ``` adc.yaml ``` # 其他配置 # ... services: - name: openapi-to-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: openapi-to-mcp-route uris: - /mcp methods: - GET - POST plugins: key-auth: _meta: filter: - - request_method - "==" - GET query: apikey openapi-to-mcp: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `PluginConfig`: openapi-to-mcp-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: openapi-to-mcp-plugin-config spec: plugins: - name: key-auth config: _meta: filter: - - request_method - "==" - GET query: apikey - name: openapi-to-mcp config: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将更新后的配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` 更新 `ApisixRoute`: openapi-to-mcp-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: openapi-to-mcp-route spec: ingressClassName: apisix http: - name: openapi-to-mcp-route match: paths: - /mcp methods: - GET - POST plugins: - name: key-auth enable: true config: _meta: filter: - - request_method - "==" - GET query: apikey - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将更新后的配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` ❶ 仅将 `key-auth` 应用于 GET 请求。这是因为查询参数中配置的 `apikey` 仅随 GET 请求发送到 SSE 端点,而不会包含在后续的 POST 消息请求中。因此,如果未应用过滤器,消息请求将被 `key-auth` 插件阻止。 ❷ 配置插件从查询参数中获取身份验证密钥。 应用 Admin API、ADC 或 APISIX CRD 配置后,在 API7 网关地址的查询参数中包含凭证: mcp.json ``` { "mcpServers": { "api7-petstore-mcp": { "url": "http://123.123.123.123:9080/mcp?apikey=john-key" } } } ``` 如果配置成功,你应该会看到可用工具,即通过 MCP 向 AI 客户端公开的外部函数或服务。随后便可直接在 AI 客户端的聊天窗口中与 Petstore 交互。 如果未在 MCP 服务器 URL 的查询参数中配置身份认证凭证,AI 客户端将无法从 MCP 服务器加载工具。 ### 将动态请求头传递到上游[​](#将动态请求头传递到上游 "将动态请求头传递到上游的直接链接") 当上游 API 需要随请求和 MCP 客户端变化的凭证或上下文(例如用户专属 API Token、租户标识符或会话 ID)时,可以使用 `x-openapi2mcp-header-*` 约定,将这些值从 MCP 客户端动态传递到上游。 发送到网关且匹配 `x-openapi2mcp-header-{name}` 模式的 HTTP 请求头会由 OpenAPI-to-MCP 边车提取并移除前缀,再以 `{name}` 请求头的形式转发到上游 API。 例如,客户端请求中的 `x-openapi2mcp-header-my-token: abc123` 请求头会转换为上游 API 请求中的 `my-token: abc123`。 #### 工作原理[​](#工作原理 "工作原理的直接链接") 网关插件与 OpenAPI-to-MCP 边车协同转发请求头: 1. **插件级请求头**:在插件 `headers` 字段中配置的请求头会在网关中解析,并以 `x-openapi2mcp-header-{name}` 的形式转发给边车。这些请求头由所有客户端共享;使用[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)时,其值可以随请求变化。 2. **客户端级请求头**(动态):MCP 客户端在 `mcp.json` 中使用 `x-openapi2mcp-header-*` 前缀设置的请求头会经网关传递到边车,再转发到上游。这些值可以随客户端变化。 静态插件请求头与动态客户端请求头同时存在时,系统会合并两者。如果客户端请求头与插件请求头同名,则插件请求头优先,客户端提供的值会被忽略。 #### 不同传输方式的行为[​](#不同传输方式的行为 "不同传输方式的行为的直接链接") 动态请求头的行为取决于插件中配置的传输方式: * **`streamable_http`(推荐)**:每个 MCP 请求都相互独立且无状态。边车会在每次请求时读取 `x-openapi2mcp-header-*` 请求头,因此动态请求头真正按请求生效。建议使用此传输方式透传动态请求头。 * **`sse`**:仅在建立 SSE 连接的初始 `GET` 请求期间读取 `x-openapi2mcp-header-*` 请求头。同一会话中的后续 POST 请求不会重新读取这些请求头。因此,动态请求头在整个会话期间保持不变,无法在会话中途更改。 如果用例要求请求之间使用不同的请求头值(例如会变化的用户专属 Token),请使用 `streamable_http` 传输方式。 #### 配置客户端请求头[​](#配置客户端请求头 "配置客户端请求头的直接链接") 如果 MCP 客户端支持自定义请求头(例如 Cursor 或 Claude Desktop),请在 `mcp.json` 的 `headers` 字段中添加 `x-openapi2mcp-header-*` 条目: mcp.json ``` { "mcpServers": { "my-api-mcp": { "url": "http://123.123.123.123:9080/mcp", "headers": { "x-openapi2mcp-header-authorization": "Bearer ", "x-openapi2mcp-header-x-tenant-id": "tenant-42" } } } } ``` MCP 客户端发送 `tools/call` 请求时,边车会提取这些请求头,并按如下形式转发到上游 API: ``` authorization: Bearer x-tenant-id: tenant-42 ``` #### 请求头名称映射[​](#请求头名称映射 "请求头名称映射的直接链接") HTTP 基础设施(例如 Nginx 和 Fastify)会将请求头名称规范化为小写。因此,从 `x-openapi2mcp-header-` 前缀后提取的请求头名称在上游请求中始终为小写。下表汇总了映射关系: | 客户端请求头 | 上游请求头 | | ------------------------------------ | --------------- | | `x-openapi2mcp-header-authorization` | `authorization` | | `x-openapi2mcp-header-x-api-key` | `x-api-key` | | `x-openapi2mcp-header-my-token` | `my-token` | 备注 `x-openapi2mcp-header-*` 请求头由边车处理,不会原样转发到上游。只有提取后的请求头名称和值会发送到上游。 #### 安全注意事项[​](#安全注意事项 "安全注意事项的直接链接") MCP 客户端发送的任何 `x-openapi2mcp-header-*` 请求头在移除前缀后都会转发到上游 API。这意味着客户端可以向上游请求注入任意请求头。为降低风险: * 使用网关级身份认证插件(例如 `key-auth` 或 `jwt-auth`)限制对 MCP 路由的访问,确保只有经过授权的客户端才能发送请求。 * 如果上游 API 依赖特定请求头进行身份认证或鉴权,请在插件级 `headers` 配置中设置这些请求头,不要依赖客户端提供的值,因为插件级请求头的优先级高于客户端级请求头。 ### 扁平化工具架构参数[​](#扁平化工具架构参数 "扁平化工具架构参数的直接链接") 以下示例演示了 `flatten_parameters` 如何影响生成的 MCP 工具输入架构中查询和路径参数的结构。 使用 Admin API、ADC 或 APISIX CRD 完成[上一个示例](#%E5%90%AF%E7%94%A8%E5%AF%B9-petstore-api-%E7%9A%84-mcp-%E8%AE%BF%E9%97%AE),为 Petstore API 配置 MCP 访问。尽管配置中未显式设置 `flatten_parameters`,该参数的默认值为 `false`。 在你的 AI 客户端(如 Cursor)中,检查工具输入架构。你应该看到参数嵌套在 `pathParameters` 和 `queryParameters` 下: ``` { "operations": { ..., "getPetById": { "method": "GET", "path": "/pet/{petId}", "pathParameters": { "type": "object", "required": ["petId"], "properties": { "petId": { "type": "integer", "description": "ID of pet to return" } }, "additionalProperties": false } }, "findPetsByStatus": { "method": "GET", "path": "/pet/findByStatus", "queryParameters": { "type": "object", "properties": { "status": { "type": "string", "enum": ["available", "pending", "sold"], "description": "Status values that need to be considered for filter", "default": "available" } }, "additionalProperties": false } } } } ``` 更新插件以扁平化查询和路径参数: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/openapi-to-mcp-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "openapi-to-mcp": { "flatten_parameters": true } } }' ``` adc.yaml ``` services: - name: openapi-to-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: petstore3.swagger.io port: 443 weight: 1 routes: - name: openapi-to-mcp-route uris: - /mcp methods: - GET - POST plugins: openapi-to-mcp: flatten_parameters: true transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `PluginConfig`: openapi-to-mcp-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: openapi-to-mcp-plugin-config spec: plugins: - name: openapi-to-mcp config: flatten_parameters: true transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将更新后的配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` 更新 `ApisixRoute`: openapi-to-mcp-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: openapi-to-mcp-route spec: ingressClassName: apisix http: - name: openapi-to-mcp-route match: paths: - /mcp methods: - GET - POST plugins: - name: openapi-to-mcp enable: true config: flatten_parameters: true transport: streamable_http base_url: "https://petstore3.swagger.io/api/v3" headers: Authorization: "special-key" openapi_url: "https://petstore3.swagger.io/api/v3/openapi.json" ``` 将更新后的配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` 在你的 AI 客户端(如 Cursor)中,检查工具输入架构。你应该看到像 `status` 这样的参数不再嵌套在 `pathParameters` 或 `queryParameters` 下: ``` { "operations": { ..., "getPetById": { "parameters": { "type": "object", "required": ["petId"], "properties": { "petId": { "type": "integer", "description": "ID of pet to return" } }, "additionalProperties": false } }, "findPetsByStatus": { "parameters": { "type": "object", "properties": { "status": { "type": "string", "enum": ["available", "pending", "sold"], "description": "Status values that need to be considered for filter", "default": "available" } }, "additionalProperties": false } } } } ``` ### 自定义 MCP 工具注解[​](#自定义-mcp-工具注解 "自定义 MCP 工具注解的直接链接") 可用性 MCP 工具注解自 API7 企业版 3.9.7 起可用。 以下示例演示了如何为 `openapi-to-mcp` 插件公开的 OpenAPI 操作添加 MCP 工具注解。 如果没有这些注解,AI 客户端只能收到生成的工具名称、描述和输入 Schema,无法可靠判断工具是否只读、是否具有破坏性或是否幂等,因而更难正确排列工具并安全使用它们。 内置 OpenAPI-to-MCP 转换器通过以下两种方式实现此功能: 1. 根据 HTTP 方法推断工具的默认行为。 2. 从 OpenAPI 厂商扩展 `x-mcp-annotations` 中读取显式的操作级配置。 两者同时存在时,显式的 `x-mcp-annotations` 值会覆盖推断出的默认值。 使用 Admin API、ADC 或 APISIX CRD 完成[上一个示例](#%E5%90%AF%E7%94%A8%E5%AF%B9-petstore-api-%E7%9A%84-mcp-%E8%AE%BF%E9%97%AE),通过 `openapi-to-mcp` 插件公开 OpenAPI 文档,然后为 OpenAPI 操作添加注解: 上一个 Petstore 示例使用无法直接编辑的公开 OpenAPI 文档。若要应用 `x-mcp-annotations`,请自行托管 OpenAPI 文档,并更新 `openapi-to-mcp` 插件配置中的 `openapi_url` 字段,使其指向该文档。 openapi.yaml ``` paths: /users/{id}: get: operationId: getUser summary: Get user information x-mcp-annotations: title: Get User readOnlyHint: true openWorldHint: false delete: operationId: deleteUser summary: Delete a user x-mcp-annotations: title: Delete User destructiveHint: true ``` 支持以下注解字段: * `title` * `readOnlyHint` * `destructiveHint` * `idempotentHint` * `openWorldHint` 如果未配置 `x-mcp-annotations`,转换器仍会应用以下默认推断规则: * `GET`、`HEAD` 和 `OPTIONS` 映射为 `readOnlyHint: true` * `DELETE` 映射为 `destructiveHint: true` 和 `idempotentHint: true` * `PUT` 映射为 `idempotentHint: true` 更新托管的 OpenAPI 文档后,让 MCP 客户端列出工具。以下代码片段展示了 `tools/list` 响应的 `result.tools` 部分: ``` { "tools": [ { "name": "getUser", "annotations": { "title": "Get User", "readOnlyHint": true, "openWorldHint": false } }, { "name": "deleteUser", "annotations": { "title": "Delete User", "destructiveHint": true, "idempotentHint": true } } ] } ``` 注意事项: * 仅支持操作级 `x-mcp-annotations`。 * 无效值和不支持的字段会被忽略。 * `summary` 和 `description` 仍用于控制生成的工具描述。 * `title` 仅从 `x-mcp-annotations.title` 读取。 ### 启用对 API7 企业版 API 的 MCP 访问[​](#启用对-api7-企业版-api-的-mcp-访问 "启用对 API7 企业版 API 的 MCP 访问的直接链接") 以下示例说明如何通过 MCP 协议公开 API7 企业版 API,使 AI 模型和客户端能够与你的 API7 企业版配置交互。 创建一个使用 `openapi-to-mcp` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "openapi-to-mcp-route", "uri": "/mcp", "methods": ["GET", "POST"], "plugins": { "openapi-to-mcp": { "transport": "streamable_http", "base_url": "https://your-dashboard.com", "headers": { "X-API-KEY": "" }, "openapi_url": "https://run.api7.ai/api7-ee/openapi-latest.json" } } }' ``` adc.yaml ``` services: - name: openapi-to-mcp-service upstream: type: roundrobin scheme: https pass_host: node nodes: - host: your-dashboard.com port: 443 weight: 1 routes: - name: openapi-to-mcp-route uris: - /mcp methods: - GET - POST plugins: openapi-to-mcp: transport: streamable_http base_url: "https://your-dashboard.com" headers: X-API-KEY: "" openapi_url: "https://run.api7.ai/api7-ee/openapi-latest.json" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD openapi-to-mcp-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: openapi-to-mcp-plugin-config spec: plugins: - name: openapi-to-mcp config: transport: streamable_http base_url: "https://your-dashboard.com" headers: X-API-KEY: "" openapi_url: "https://run.api7.ai/api7-ee/openapi-latest.json" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: openapi-to-mcp-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /mcp method: GET - path: type: Exact value: /mcp method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: openapi-to-mcp-plugin-config backendRefs: - name: api7-enterprise-external-domain port: 443 --- apiVersion: v1 kind: Service metadata: namespace: aic name: api7-enterprise-external-domain spec: type: ExternalName externalName: your-dashboard.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: api7-enterprise-external-domain spec: targetRefs: - group: "" kind: Service name: api7-enterprise-external-domain passHost: node scheme: https ``` 将配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` openapi-to-mcp-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: openapi-to-mcp-route spec: ingressClassName: apisix http: - name: openapi-to-mcp-route match: paths: - /mcp methods: - GET - POST plugins: - name: openapi-to-mcp enable: true config: transport: streamable_http base_url: "https://your-dashboard.com" headers: X-API-KEY: "" openapi_url: "https://run.api7.ai/api7-ee/openapi-latest.json" upstreams: - name: api7-enterprise-external-domain --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: api7-enterprise-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: your-dashboard.com port: 443 passHost: node scheme: https ``` 将配置应用到集群: ``` kubectl apply -f openapi-to-mcp-ic.yaml ``` ❶ 配置路由允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行和操作能力(messages)。 ❷ 将传输方式配置为 `streamable_http`(建议用于生产环境)。 ❸ 替换为你的 API7 企业版地址,请求将转发到该地址。 ❹ 将 `X-API-KEY` 请求头替换为用于 API7 企业版身份验证的凭证。 ❺ 配置 API7 企业版 OpenAPI 文档的 URL。 在 Cursor 等 AI 客户端中,使用你的 API7 网关地址更新 MCP 设置,并追加之前创建的路由路径。例如: mcp.json ``` { "mcpServers": { "api7-enterprise-mcp": { "url": "http://123.123.123.123:9080/mcp" } } } ``` 配置成功后,你应能看到可用工具(通过 MCP 向 AI 客户端公开的外部函数或服务)。 现在,你可以直接在 AI 客户端的聊天窗口中与 API7 企业版交互。例如,可以尝试询问:“API7 企业版中有多少个网关组?” ![AI 客户端与 API7 企业版交互](https://static.api7.ai/uploads/2025/09/19/vUBryakn_cursor.png) ## 故障排除[​](#故障排除 "故障排除的直接链接") 要诊断问题,请检查网关容器或 Pod 中 `/usr/local/openapi2mcp/error.log` 处的 `openapi-to-mcp` 错误日志。请注意,此日志与网关的错误日志是分开的。 ### 已知问题[​](#已知问题 "已知问题的直接链接") 1. 错误 `Cannot use 'in' operator to search for '$ref' in undefined` 通常发生在 `openapi_url` 中使用 OpenAPI v2 文档时。该插件仅支持 `openapi_url` 中的 OpenAPI v3 文档。 2. 该插件在处理从 `openapi_url` 获取的 OpenAPI v3 文档中的 `oneOf` 架构时存在已知的解析问题。在这种情况下,MCP 客户端将在加载工具时卡住。 --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 默认情况下,该插件将 MCP 流量代理到位于 `127.0.0.1:3000` 的 OpenAPI-to-MCP 服务。 需要更新的文件取决于网关的部署方式: * 主机或 Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` plugin_attr: openapi-to-mcp: port: 4000 ``` 然后重新加载网关,使静态配置更改生效。 对于 Helm 部署,请在 API7 网关 Helm Chart 中设置以下值。请确保插件属性中的端口与 Chart 管理的边车端口一致。 values.yaml ``` openapiToMcp: enabled: true port: 4000 pluginAttrs: openapi-to-mcp: port: 4000 ``` 然后将 Helm 配置值文件应用到现有网关发布版本: ``` helm upgrade api7/gateway -n -f values.yaml ``` 在 Helm 之外更改此值时,还必须更新 OpenAPI-to-MCP 服务,使其监听同一端口,否则插件将返回 503 错误。 ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * transport string 默认值:`sse` 有效值: `sse` 或 `streamable_http` *** 客户端与服务器之间的传输方式。生产部署建议使用 `streamable_http`,因为它支持适用于多个网关实例的无状态通信。`sse` 是有状态传输,在部署多个网关时可能出现非预期行为。 `streamable_http` 传输方式自 API7 企业版 3.8.15 起可用。 * openapi\_url string 必填 *** 定义要通过 MCP 暴露的 API 结构的 OpenAPI 规范文档的 URL。 请注意,该插件仅支持 OpenAPI Specification (OAS) 3 版本。不支持 OpenAPI v2 (Swagger)。 此外,该插件在处理从 `openapi_url` 获取的 OpenAPI v3 文档中的 `oneOf` 架构时存在已知的解析问题。在这种情况下,MCP 客户端将在加载工具时卡住。 `api7/openapi-to-mcp:1.0.2` 默认缓存文档及生成的工具定义 3600 秒;该 URL 是缓存键的组成部分。修改 URL 可在下次加载规范时避开旧缓存,但不会自动更新已有会话中的工具。参见 [OpenAPI 文档缓存](https://docs.apiseven.com/hub/openapi-to-mcp.md#openapi-document-caching)。 * base\_url string 必填 *** 请求转发到的 API 服务的基础 URL。支持在值中使用[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md)(从 API7 企业版 3.8.19 版本开始可用),例如 `https://${http_baseurl}.swagger.io`。 * allowed\_hosts array\[string] 有效值: 精确主机名或通配符主机名,例如 `api.example.com` 和 `*.example.com` *** 可选的主机允许列表,用于限制解析后的 `base_url` 可访问的目标主机。设置后,解析后的主机不在列表中的请求会被拒绝并返回 HTTP 400。自 API7 企业版 3.9.13 起可用,APISIX 中暂不可用。 * headers object *** 包含在发往上游服务的请求中的请求头。支持在值中使用[内置变量](https://docs.apiseven.com/api7-gateway/reference/built-in-variables.md),例如 `$arg_username-$http_apikey`。 * flatten\_parameters boolean 默认值:`false` *** 是否在工具 Schema 中扁平化参数。查询参数和路径参数扁平化自 API7 企业版 3.8.21 起可用;对 OpenAPI 规范中定义的请求头参数(`in: header`)的支持自 3.9.8 起可用。APISIX 暂不支持。 设置为 `false` 时,查询参数嵌套在 `queryParameters` 下,路径参数嵌套在 `pathParameters` 下;自 API7 企业版 3.9.8 起,请求头参数嵌套在 `headerParameters` 下。设置为 `true` 时,查询参数和路径参数直接放在 `properties` 下;自 3.9.8 起,请求头参数也直接放在 `properties` 下。 将此参数设置为 `true` 可降低 Schema 复杂度,简化 AI 模型交互。当查询参数、路径参数和请求头参数存在同名项时,请保持为 `false` 以避免冲突。 --- # openid-connect `openid-connect` 插件支持与 [OpenID Connect (OIDC)](https://openid.net/connect/) 身份提供商(IdP)集成,例如 [Keycloak](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md)、[Auth0](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-auth0.md)、[Microsoft Entra ID](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-azure-ad.md)、[Google](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-google.md)、[Amazon Cognito](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-amazon-cognito.md)、[Okta](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-okta.md) 等。它允许 APISIX 在允许或拒绝客户端访问上游受保护资源之前,对其进行身份认证并从身份提供商获取其信息。 ## 示例[​](#示例 "示例的直接链接") ### 授权码流程[​](#authorization-code-flow "授权码流程的直接链接") 授权码流程在 [RFC 6749, Section 4.1](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1) 中定义。它涉及将临时授权码交换为访问令牌,通常用于机密客户端和公共客户端。 下图说明了在实现授权码流程时不同实体之间的交互:
当传入请求的请求头或相应的会话 Cookie 中不包含访问令牌时,插件将充当依赖方,并重定向到授权服务器以继续授权码流程。 身份认证成功后,插件将令牌保存在会话 Cookie 中,后续请求将使用存储在 Cookie 中的令牌。 参见 [实施授权码授予](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md#implement-authorization-code-grant) 了解如何使用 `openid-connect` 插件通过授权码流程与 Keycloak 集成的示例。 参见[使用 PAR 和 DPoP 保护 OIDC](https://docs.apiseven.com/apisix/how-to-guide/authentication/secure-oidc-with-par-and-dpop.md),了解如何使用 `openid-connect` 插件通过 PAR、DPoP、PKCE 和 `private_key_jwt` 客户端身份认证与 Keycloak 集成。 ### 用于代码交换的证明密钥 (PKCE)[​](#用于代码交换的证明密钥-pkce "用于代码交换的证明密钥 (PKCE)的直接链接") 用于代码交换的证明密钥 (PKCE) 在 [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) 中定义。PKCE 通过添加代码挑战和验证器来增强授权码流程,以防止授权码拦截攻击。 下图说明了在实现带有 PKCE 的授权码流程时不同实体之间的交互:
参见 [实施授权码授予](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md#implement-authorization-code-grant) 了解如何使用 `openid-connect` 插件通过带有 PKCE 的授权码流程与 Keycloak 集成的示例。 ### 结合 PAR 和 DPoP 的授权码流程[​](#结合-par-和-dpop-的授权码流程 "结合 PAR 和 DPoP 的授权码流程的直接链接") PAR、PKCE、`private_key_jwt` 和 DPoP 可以组合在同一个授权码流程中。请分别配置用于客户端身份认证和 DPoP 的签名密钥。此工作流自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起支持。
在此工作流中,网关是向授权服务器发起令牌请求和用户信息请求的 DPoP 客户端。它不会验证外部客户端调用受保护路由时提交的 DPoP 证明。 对于 APISIX 部署,请参阅[使用 PAR 和 DPoP 保护 OIDC](https://docs.apiseven.com/apisix/how-to-guide/authentication/secure-oidc-with-par-and-dpop.md),其中提供了经过验证的 Keycloak 示例,涵盖密钥生成、配置和验证。 ### 客户端凭据流程[​](#客户端凭据流程 "客户端凭据流程的直接链接") 客户端凭据流程在 [RFC 6749, Section 4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4) 中定义。它涉及客户端使用自己的凭据请求访问令牌以访问受保护资源,通常用于机器对机器的身份认证,不代表特定用户。 下图说明了使用本地 JWT 验证(例如配置 `public_key` 或 `use_jwks`)实现客户端凭据流程时,不同实体之间的交互:
参见 [实施客户端凭据授予](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md#implement-client-credentials-grant) 了解如何使用 `openid-connect` 插件通过客户端凭据流程与 Keycloak 集成的示例。 ### 内省流程[​](#内省流程 "内省流程的直接链接") 内省流程在 [RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662) 中定义。它涉及通过查询授权服务器的内省端点来验证访问令牌的有效性和详细信息。 在此流程中,当客户端向资源服务器出示访问令牌时,资源服务器向授权服务器的内省端点发送请求,如果令牌处于活动状态,该端点将响应令牌详细信息,包括令牌过期时间、关联的范围以及它所属的用户或客户端等信息。 下图说明了在实现带有令牌内省的授权码流程时不同实体之间的交互:
参见 [实施客户端凭据授予](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md#implement-client-credentials-grant) 了解如何使用 `openid-connect` 插件通过带有令牌内省的客户端凭据流程与 Keycloak 集成的示例。 ### 密码流程[​](#密码流程 "密码流程的直接链接") 密码流程在 [RFC 6749, Section 4.3](https://datatracker.ietf.org/doc/html/rfc6749#section-4.3) 中定义。它专为受信任的应用程序设计,允许它们直接使用用户的用户名和密码获取访问令牌。在这种授予类型中,客户端应用程序将用户的凭据连同其自己的客户端 ID 和密钥发送到授权服务器,授权服务器随后对用户进行身份认证,如果验证通过,则颁发访问令牌。 虽然效率很高,但此流程仅适用于高度受信任的第一方应用程序,因为它要求应用程序直接处理敏感的用户凭据,如果在第三方上下文中使用,会带来重大的安全风险。 下图说明了在实现密码流程时不同实体之间的交互:
参见 [实施密码授予](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md#implement-password-grant) 了解如何使用 `openid-connect` 插件通过密码流程与 Keycloak 集成的示例。 ### 刷新令牌授予[​](#刷新令牌授予 "刷新令牌授予的直接链接") 刷新令牌授予在 [RFC 6749, Section 6](https://datatracker.ietf.org/doc/html/rfc6749#section-6) 中定义。它使客户端能够在无需用户重新身份认证的情况下,使用以前颁发的刷新令牌请求新的访问令牌。此流程通常在访问令牌过期时使用,允许客户端在无需用户干预的情况下保持对资源的持续访问。刷新令牌在某些 OAuth 流程中与访问令牌一起颁发,其生命周期和安全要求取决于授权服务器的配置。 下图说明了在实现带有刷新令牌流程的密码流程时不同实体之间的交互:
参见 [刷新令牌](https://docs.apiseven.com/apisix/how-to-guide/authentication/set-up-sso-with-keycloak.md#refresh-token) 了解如何使用 `openid-connect` 插件通过带有令牌刷新的密码流程与 Keycloak 集成的示例。 ### 用户信息[​](#用户信息 "用户信息的直接链接") OpenID Connect (OIDC) 中的 UserInfo 端点在 [OpenID Connect Core 1.0, Section 5.3](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) 中定义。它使客户端能够通过出示有效的访问令牌来检索有关已认证用户的其他 Claim。此端点对于在用户通过身份认证后获取用户个人资料信息(如姓名、电子邮件和其他属性)特别有用。UserInfo 端点返回的数据取决于访问令牌的范围和授权服务器配置的 Claim。 下图说明了当 APISIX 验证用户信息时不同实体之间的交互:
参见[通过检查外部身份提供商的用户信息控制访问](https://docs.apiseven.com/hub/acl.md#%E9%80%9A%E8%BF%87%E6%A3%80%E6%9F%A5%E5%A4%96%E9%83%A8%E8%BA%AB%E4%BB%BD%E6%8F%90%E4%BE%9B%E5%95%86%E7%9A%84%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF%E6%8E%A7%E5%88%B6%E8%AE%BF%E9%97%AE),了解如何使用 `openid-connect` 插件与 Keycloak 集成,并基于用户信息使用 API7 企业版 `acl` 插件实现访问控制。 ## 故障排除[​](#故障排除 "故障排除的直接链接") 本节涵盖了在使用此插件时常见的一些问题,以帮助您进行故障排除。 ### APISIX 无法连接到 OpenID 提供商[​](#apisix-无法连接到-openid-提供商 "APISIX 无法连接到 OpenID 提供商的直接链接") 如果 APISIX 无法解析或无法连接到 OpenID 提供商,请仔细检查配置文件 `config.yaml` 中的 DNS 设置,并根据需要进行修改。 ### 授权回调中的 State 不匹配[​](#授权回调中的-state-不匹配 "授权回调中的 State 不匹配的直接链接") 授权状态完成、被重放或被删除后,回调仍可能到达。自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起,Multi Auth 之外过期的 `GET` 回调会重定向到最初请求的 URL,从而启动新的身份认证流程。如果身份提供商中仍存在 SSO 会话,该流程可以在无需再次提示用户的情况下完成。 使用其他 HTTP 方法、无法恢复目标 URL 或在 Multi Auth 中运行的回调仍会失败,而不会重定向。 ### 身份提供商暂时不可用[​](#身份提供商暂时不可用 "身份提供商暂时不可用的直接链接") 在 APISIX 3.18.0 中,如果授权回调包含 OAuth 错误 `temporarily_unavailable`,且其 state 可以验证,则回调会重定向到最初请求的 URL。这样会重新启动身份认证流程,而不是返回 `500 Internal Server Error`。 其他 OAuth 错误、缺失或无效的 state,以及非 `GET` 回调不会自动重试。 ### 找不到会话状态[​](#找不到会话状态 "找不到会话状态的直接链接") 如果您在使用 [授权码流程](#authorization-code-flow) 时遇到 `500 internal server error` 并在日志中看到以下消息,可能有多种原因。 ``` the error request to the redirect_uri path, but there's no session state found ``` #### 1. 重定向 URI 错误[​](#1-重定向-uri-错误 "1. 重定向 URI 错误的直接链接") 一种常见配置错误是将 `redirect_uri` 设置为与路由 URI 相同。当用户请求受保护资源时,请求会在不携带会话 Cookie 的情况下直接到达重定向 URI,从而产生 `no session state found` 错误。 请把 `redirect_uri` 配置为完全限定 URI,其路径应当匹配路由,但不能与受保护的请求路径完全相同。例如,如果路由 `uri` 为 `/api/v1/*`,请把 `redirect_uri` 设为 `https://gateway.example.com/api/v1/redirect`。同时,请在 OpenID 提供商中把同一 URI 配置为允许的重定向 URI。 如果未配置 `redirect_uri`,或其值是以 `/` 开头的根相对路径,网关会根据请求的协议方案和主机构建 URI。完全限定 URI 可以避免依赖这个从请求推导的来源。 #### 2. 缺少 Session Secret[​](#2-缺少-session-secret "2. 缺少 Session Secret的直接链接") 当 `bearer_only` 为 `false` 时,请显式配置 `session.secret`。无论配置存储在 etcd 中,还是从 [Standalone YAML](https://docs.apiseven.com/apisix/production/deployment-modes.md#standalone-mode) 加载,缺少此字段时 APISIX 都会拒绝插件配置。密钥应至少包含 16 个字符;在多实例部署中,需要读取加密会话 Cookie 的每个网关实例都应使用相同的密钥。 #### 3. Cookie 未发送或缺失[​](#3-cookie-未发送或缺失 "3. Cookie 未发送或缺失的直接链接") 检查 [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value) Cookie 属性是否设置正确(即,如果您的应用程序需要跨站点发送 Cookie),以查看这是否是阻止 Cookie 保存到浏览器 Cookie 存储或从浏览器发送的因素。 #### 4. 身份认证会话已过期[​](#4-身份认证会话已过期 "4. 身份认证会话已过期的直接链接") APISIX 在将浏览器重定向到身份提供商前,会把 `state` 参数和原始请求 URL 存入会话。如果浏览器返回重定向 URI 前该会话已过期,APISIX 将无法验证回调或恢复原始 URL。 请重新访问受保护的 URL,以发起新的身份认证流程。如果用户需要更多时间完成身份认证,请为 [`session.idling_timeout`](https://docs.apiseven.com/hub/openid-connect/configuration.md) 配置合适的值。默认空闲超时时间为 900 秒。 #### 5. 上游发送的响应头过大[​](#5-上游发送的响应头过大 "5. 上游发送的响应头过大的直接链接") 如果您的 APISIX 前面有 NGINX 代理客户端流量,请查看 NGINX 的 `error.log` 中是否观察到以下错误: ``` upstream sent too big header while reading response header from upstream ``` 如果是这样,请尝试将 `proxy_buffers`、`proxy_buffer_size` 和 `proxy_busy_buffers_size` 调整为更大的值。 或者,调整插件的 `session_contents` 参数以仅包含必要的信息。例如,要仅包含访问令牌和刷新令牌,您可以按如下方式配置插件: ``` { ... "plugins": { "openid-connect": { ..., "session_contents": { "access_token": true } } } } ``` 可用选项包括 `id_token`、`user`、`enc_id_token` 和 `access_token`(其中包括刷新令牌)。未配置时,所有内容都包含在会话中。 #### 6. 无效的客户端密钥[​](#6-无效的客户端密钥 "6. 无效的客户端密钥的直接链接") 对于使用共享密钥向身份提供商认证的流程(例如令牌内省,或未使用 PKCE 的授权码流程),请验证 `client_secret`。在仅使用 Bearer Token 的本地 JWT/JWKS 验证、非 Bearer Token 的 PKCE 流程,以及适用的 `private_key_jwt` 模式下,此字段为可选。在需要密钥的流程中,无效值会导致认证失败,且不会在会话中存储令牌。 `introspection_endpoint_auth_method` 默认为 `client_secret_basic`,它通过 `Authorization` 请求头发送客户端凭证。如果身份提供商要求在内省请求体中发送凭证,请将该方法设为 `client_secret_post`。 #### 7. PKCE IdP 配置[​](#7-pkce-idp-配置 "7. PKCE IdP 配置的直接链接") 如果您正在启用带有授权码流程的 PKCE,请确保您已将 IdP 客户端配置为使用 PKCE。例如,在 Keycloak 中,您应该在客户端的高级设置中配置 PKCE 挑战方法: ![PKCE keycloak configuration](https://static.api7.ai/uploads/2024/11/04/xvnCNb20_pkce-keycloak-revised.jpeg) --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 该插件支持使用 `env://` 前缀引用环境变量中的敏感参数值,或使用 `secret://` 前缀引用 Secret 管理器(如 HashiCorp Vault 的 [KV 密钥引擎](https://developer.hashicorp.com/vault/docs/secrets/kv))中的值。更多信息,请参阅环境变量中的[插件](https://docs.apiseven.com/apisix/reference/environment-variables.md#plugins)和[密钥](https://docs.apiseven.com/apisix/key-concepts/secrets.md)。 * client\_id string 必填 *** 客户端 ID。 * client\_secret string *** 客户端密钥。该值在存储到 etcd 之前会使用 AES 加密。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起,对于不与 OpenID 提供商通信的本地 JWT 验证模式(例如将 `bearer_only` 与 `public_key` 或 `use_jwks` 组合使用),客户端密钥是可选的。使用 `private_key_jwt` 进行客户端身份认证,或授权码流程使用 PKCE 时,客户端密钥也是可选的。对于使用客户端密钥向提供商进行身份认证的流程(例如令牌内省或不使用 PKCE 的授权码流程),客户端密钥仍为必填项。 * discovery string 必填 *** OpenID 提供商的 well-known 发现文档的 URL,其中包含 [OP API 端点](https://samples.auth0.com/.well-known/openid-configuration) 列表。插件可以直接使用发现文档中的端点。你也可以单独配置这些端点,这将优先于发现文档中提供的端点。 * scope string 默认值:`openid` *** 对应于应返回的有关已认证用户信息的 OIDC 范围,也称为 [claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)。这用于通过适当的权限对用户进行授权。默认值为 `openid`,这是 OIDC 返回唯一标识已认证用户的 `sub` claim 所需的范围。 其他范围可以追加并用空格分隔,例如 `openid email profile`。 * required\_scopes array\[string] *** 授权所需的范围。如果缺少任一必需范围,插件将以 `403 Forbidden` 拒绝请求。 使用 Bearer 令牌内省时,范围从内省响应中读取。在 APISIX 3.18.0 中,授权码会话也会接受检查:范围先从访问令牌读取,再从 ID 令牌读取;如果无法确定会话获授的范围,则拒绝该会话。API7 企业版 3.9.18 和 3.10.5 仅在 Bearer 令牌内省时强制执行此字段。 * realm string 默认值:`apisix` *** 因身份认证失败而返回 `401 Unauthorized` 响应时,[`WWW-Authenticate`](https://www.rfc-editor.org/rfc/rfc6750#section-3) 响应头中的 Realm。例如: * 如果 `realm` 设置为 `apisix-oidc`,401 响应将包含以下响应头: ``` WWW-Authenticate: Bearer realm="apisix-oidc" ``` * 如果未配置 `realm`,401 响应将包含以下响应头: ``` WWW-Authenticate: Bearer realm="apisix" ``` * claim\_validator object *** JWT Claim 验证配置。 * issuer object *** Claim 颁发者验证配置。 * valid\_issuers array\[string] *** 受信任的 JWT 颁发者数组。如果未配置,则使用发现文档中的颁发者。在 APISIX 3.18.0 中,如果发现服务不可用,Bearer JWT 验证会以关闭方式失败,因为无法确定受信任的颁发者。API7 企业版 3.9.18 和 3.10.5 在该失败场景下会跳过颁发者验证,除非显式配置了 `valid_issuers`。 * audience object *** 受众 Claim 验证配置。 * claim string 默认值:`aud` *** 包含受众的 Claim 名称。 * required boolean 默认值:`false` *** 如果为 true,则受众 Claim 是必需的,且 Claim 名称将是在 `claim` 中定义的名称。 例如,假设 `claim_validator` 配置如下: `json { "audience": { "claim": "custom_claim", "required": true } }` 如果请求中不存在 Claim `custom_claim`,你将收到 `required audience claim not present` 错误。 * match\_with\_client\_id boolean 默认值:`false` *** 如果为 true,则要求受众与客户端 ID 匹配。如果受众是字符串,则必须与客户端 ID 完全匹配;如果受众是字符串数组,则必须至少有一个值匹配。在 APISIX 3.18.0 中,此选项也会拒绝缺少受众 Claim 的令牌。API7 企业版 3.9.18 和 3.10.5 仅在该 Claim 存在时进行匹配;如需拒绝缺少 Claim 的令牌,请同时将 `required` 设置为 `true`。 此要求在 [OpenID Connect 规范](https://openid.net/specs/openid-connect-core-1_0-final.html) 中说明,以确保令牌是针对特定客户端的。 * claim\_schema object *** 用于验证 OIDC 响应中返回的 Claim 的 JSON Schema。例如,schema `{"type":"object","properties":{"access_token":{"type":"string"}},"required":["access_token"]}` 确保响应包含名为 `access_token` 的必需字符串字段。 从 APISIX 3.14.0 和 API7 企业版 3.9.2 起可用。 * bearer\_only boolean 默认值:`false` *** 如果为 true,则严格要求请求中包含 Bearer 访问令牌以进行身份认证。 * logout\_path string 默认值:`/logout` *** 激活注销的路径。 * post\_logout\_redirect\_uri string *** `logout_path` 收到注销请求后将用户重定向到的 URL。 * redirect\_uri string 默认值:`` `${ngx.var.request_uri}/.apisix/redirect` `` *** 与 OpenID 提供商认证后重定向到的 URI。 请配置包含协议方案和主机的完全限定 URI。其路径应当匹配路由,但不能与受保护的请求路径完全相同。例如,如果路由 `uri` 为 `/api/v1/*`,请把 `redirect_uri` 设为 `https://gateway.example.com/api/v1/redirect`。 如果未配置 `redirect_uri`,或其值是以 `/` 开头的根相对路径,网关会根据请求的协议方案和主机构建 URI。它会保留请求中显式指定的端口,并且仅当直接代理位于 `apisix.trusted_addresses` 中时才使用转发的来源请求头。 完全限定 URI 不依赖从请求推导的来源。请在 OpenID 提供商中把同一 URI 配置为允许的重定向 URI。 * timeout integer 默认值:`3` 有效值: 大于 0 *** 请求超时时间(秒)。 * ssl\_verify boolean 默认值:`true` *** 如果为 `true`,则验证 OpenID 提供商的 SSL 证书。 自 APISIX 3.16.0 和 API7 企业版 3.9.8 起,默认值由 `false` 更改为 `true`。这是一个不兼容变更。 * introspection\_endpoint string *** OpenID 提供商用于内省访问令牌的[令牌内省](https://datatracker.ietf.org/doc/html/rfc7662)端点 URL。如果未设置,则使用 well-known 发现文档中提供的内省端点作为后备。 * introspection\_endpoint\_auth\_method string 默认值:`client_secret_basic` *** 令牌内省端点的身份认证方法。该值应为 well-known 发现文档中 `introspection_endpoint_auth_methods_supported` [授权服务器元数据](https://www.rfc-editor.org/rfc/rfc8414.html)指定的身份认证方法之一,例如 `client_secret_basic`、`client_secret_post`、`private_key_jwt` 和 `client_secret_jwt`。 使用默认的 `client_secret_basic` 时,客户端凭据仅通过 `Authorization` 请求头发送。如果身份提供商要求在内省请求体中接收凭据,请将此字段设置为 `client_secret_post`。 * token\_endpoint\_auth\_method string 默认值:`client_secret_basic` *** 令牌端点的身份认证方法。该值应为 well-known 发现文档中 `token_endpoint_auth_methods_supported` [授权服务器元数据](https://www.rfc-editor.org/rfc/rfc8414.html) 指定的身份认证方法之一,例如 `client_secret_basic`、`client_secret_post`、`private_key_jwt` 和 `client_secret_jwt`。 如果插件不支持配置的方法,则忽略该配置,并使用 OpenID 提供商公布的第一个可用方法。如果插件支持配置的方法,但 `token_endpoint_auth_methods_supported` 已提供且不包含该方法,则令牌端点身份认证失败。 * client\_rsa\_private\_key string *** 用于签署客户端断言 JWT 的私钥。当令牌、内省或 PAR 端点选择 `private_key_jwt` 时必填。密钥类型必须与 `client_jwt_assertion_alg` 匹配:`RS*` 使用 RSA 密钥,`ES*` 使用对应曲线上的 EC 密钥。 该值在存储到 etcd 前会使用 AES 加密。 * client\_rsa\_private\_key\_id string *** 端点选择 `private_key_jwt` 时,签名客户端断言 JWT 中使用的可选密钥 ID。 * client\_jwt\_assertion\_expires\_in integer 默认值:`60` *** 令牌、内省或 PAR 端点使用 `private_key_jwt` 或 `client_secret_jwt` 时,客户端断言 JWT 的生命周期(秒)。 * public\_key string *** 如果使用非对称算法,则用于验证 JWT 签名的公钥。提供此值以执行令牌验证将跳过客户端凭据流程中的令牌内省。 你可以使用 `-----BEGIN PUBLIC KEY----- …… -----END PUBLIC KEY-----` 格式传递公钥。 * token\_signing\_alg\_values\_expected string *** 用于签署 JWT 的算法,例如 `RS256`。 * set\_access\_token\_header boolean 默认值:`true` *** 如果为 `true`,则在请求头中设置已认证请求所使用的访问令牌。默认使用 `X-Access-Token` 请求头。网关会先清除客户端提供的同名值,再设置该令牌。 * access\_token\_in\_authorization\_header boolean 默认值:`false` *** 如果为 `true` 且 `set_access_token_header` 也为 `true`,则在 `Authorization` 请求头中设置访问令牌。 * accept\_none\_alg boolean 默认值:`false` *** 如果 OpenID 提供商不对其 ID 令牌进行签名(例如当签名算法设置为 `none` 时),则设置为 true。 * use\_jwks boolean 默认值:`false` *** 如果为 true 且未设置 `public_key`,则使用 JWKS 验证 JWT 签名并跳过客户端凭据流程中的令牌内省。JWKS 端点从发现文档中解析。 * jwk\_expires\_in integer 默认值:`86400` *** JWK 缓存的过期时间(秒)。 * jwt\_verification\_cache\_ignore boolean 默认值:`false` *** 如果为 true,则强制重新验证 Bearer 令牌并忽略任何现有的缓存验证结果。 * cache\_segment string *** 缓存段的可选名称,用于分隔和区分令牌内省或 JWT 验证使用的缓存。 * use\_pkce boolean 默认值:`false` *** 如果为 true,则对授权码流程使用用于代码交换的证明密钥 (PKCE),如 [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) 中所定义。 * set\_id\_token\_header boolean 默认值:`true` *** 如果为 true 且经过验证的 ID 令牌可用,则在 `X-ID-Token` 请求头中设置经过 Base64 编码的解码后 Claim。该值不是签名 JWT,无法使用身份提供商的 JWKS 进行验证。网关会先清除客户端提供的同名值。 * set\_userinfo\_header boolean 默认值:`true` *** 如果为 true 且用户信息数据可用,则在 `X-Userinfo` 请求头中设置该值。网关会先清除客户端提供的同名值。 * set\_raw\_id\_token\_header boolean 默认值:`false` *** 如果为 true 且原始 ID Token 可用,则把身份提供商签发的原始签名 JWT 添加到 `X-Raw-ID-Token` 请求头中。该 Token 会持久化到会话,以便上游服务使用身份提供商的 JWKS 进行验证。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起可用。 原始 ID Token 属于 bearer 凭证。请仅对可信上游启用,并确保该请求头不会被写入访问日志或回显给客户端。 * set\_refresh\_token\_header boolean 默认值:`false` *** 如果为 true 且从身份提供商获取的刷新令牌可用,则在 `X-Refresh-Token` 请求头中设置该值。网关会先清除客户端提供的同名值。 * session object *** 当 `bearer_only` 为 `false` 且插件使用授权码流程时使用的会话配置。 * secret string 有效值: 至少 16 个字符 *** 当 `bearer_only` 为 `false` 时,用于会话加密和 HMAC 操作的密钥。 当 `bearer_only` 为 `false` 时,此字段为必填项。该要求自 API7 企业版 3.9.2 和 APISIX 3.14.0 起生效。 API7 网关使用 AES 对该值进行静态加密;当启用 `apisix.data_encryption.enable_encrypt_fields` 时,APISIX 会在写入 etcd 前对其加密。 * cookie\_name string *** 会话 Cookie 的名称。对应 lua-resty-session 的 `cookie_name` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * cookie\_path string *** 会话 Cookie 的路径范围。对应 lua-resty-session 的 `cookie_path` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * cookie\_domain string *** 会话 Cookie 的域范围。对应 lua-resty-session 的 `cookie_domain` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * cookie\_secure boolean *** 如果为 true,则在会话 Cookie 上设置 `Secure` 属性。对应 lua-resty-session 的 `cookie_secure` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * cookie\_http\_only boolean *** 如果为 true,则在会话 Cookie 上设置 `HttpOnly` 属性。对应 lua-resty-session 的 `cookie_http_only` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * cookie\_same\_site string 有效值: `Strict`、`Lax`、`None` 或 `Default` *** 会话 Cookie 的 SameSite 属性。对应 lua-resty-session 的 `cookie_same_site` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * idling\_timeout integer *** 空闲超时时间(秒),超过该时间后空闲会话将被重新生成。对应 lua-resty-session 的 `idling_timeout` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * rolling\_timeout integer *** 滚动超时时间(秒),超过该时间后会话将被续期。对应 lua-resty-session 的 `rolling_timeout` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * absolute\_timeout integer *** 会话的绝对生命周期(秒),超过该时间后无论是否活跃,会话都会过期。对应 lua-resty-session 的 `absolute_timeout` 选项。 自 API7 企业版 3.9.14 和 APISIX 3.17.0 起可用。 * cookie object *** Cookie 配置。已废弃,仅为与 lua-resty-session 3.x schema 向后兼容而保留。请改用扁平的 `session.*` 选项,例如 `cookie_name` 和 `absolute_timeout`。 * lifetime integer 默认值:`3600` *** Cookie 生命周期(秒)。已废弃。当未设置 `absolute_timeout` 时,在运行时映射到 `absolute_timeout`。 * storage string 默认值:`cookie` 有效值: `cookie` 或 `redis` *** 会话存储后端。当设置为 `redis` 时,会话存储在 Redis 中而非 Cookie 中。 自 API7 企业版 3.9.15 和 APISIX 3.16.0 起可用。 * redis object *** Redis 连接配置。当 `storage` 为 `redis` 时必填。 自 API7 企业版 3.9.15 和 APISIX 3.16.0 起可用。 * host string 默认值:`127.0.0.1` *** Redis 主机。 * port integer 默认值:`6379` 有效值: 大于或等于 1 *** Redis 端口。 * username string *** Redis 用户名。 * password string *** Redis 密码。该值在存储到 etcd 前会使用 AES 加密。 * database integer 默认值:`0` 有效值: 大于或等于 0 *** Redis 数据库索引。 * prefix string 默认值:`sessions` *** Redis 会话 key 的前缀。 * ssl boolean 默认值:`false` *** 如果为 true,则使用 SSL 连接 Redis。 * ssl\_verify boolean 默认值:`true` *** 如果为 true,则校验 Redis 服务器的 SSL 证书。 * server\_name string *** 连接 Redis 时用于 TLS SNI 的服务器名称。 * connect\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** Redis 连接超时时间(毫秒)。 * send\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** Redis 发送超时时间(毫秒)。 * read\_timeout integer 默认值:`1000` 有效值: 大于或等于 1 *** Redis 读取超时时间(毫秒)。 * keepalive\_timeout integer 默认值:`10000` 有效值: 大于或等于 1000 *** Redis keepalive 超时时间(毫秒)。 * unauth\_action string 默认值:`auth` 有效值: `auth`、`deny` 或 `pass` *** 未经身份认证的请求的操作。 当设置为 `auth` 时,重定向到 OpenID 提供商的身份认证端点。 当设置为 `pass` 时,允许请求通过而无需身份认证。 当设置为 `deny` 时,返回 401 未经身份认证的响应,而不是启动授权码授予流程。 * proxy\_opts object *** OpenID 提供商所在的代理服务器的配置。 * http\_proxy string *** HTTP 请求的代理服务器地址,例如 `http://:`。 * https\_proxy string *** HTTPS 请求的代理服务器地址,例如 `http://:`。 * http\_proxy\_authorization string *** 用于 `http_proxy` 的默认 `Proxy-Authorization` 请求头值。可以使用自定义 `Proxy-Authorization` 请求头覆盖。 * https\_proxy\_authorization string *** 用于 `https_proxy` 的默认 `Proxy-Authorization` 请求头值。不能使用自定义 `Proxy-Authorization` 请求头覆盖,因为对于 HTTPS,授权在建立连接时完成。 * no\_proxy string *** 不应被代理的主机的逗号分隔列表。 * authorization\_params object *** 发送到授权端点的请求中的附加参数。 * renew\_access\_token\_on\_expiry boolean 默认值:`true` *** 如果为 true,则在访问令牌过期或刷新令牌可用时尝试静默更新访问令牌。如果令牌更新失败,则重定向用户以重新进行身份认证。 * access\_token\_expires\_in integer 默认值:`3600` *** 如果令牌端点响应中不存在 `expires_in` 属性,则为访问令牌的生命周期(秒)。 * refresh\_session\_interval integer *** 无需重新身份认证即可刷新用户 ID 令牌的时间间隔。在 APISIX 中,未设置时插件不会尝试静默更新。 在 API7 Gateway 中,默认值为 `900`。 * iat\_slack integer 默认值:`120` *** ID 令牌中 `iat` Claim 的时钟偏差容差(秒)。 * introspection\_expiry\_claim string 默认值:`exp` *** 过期时间 Claim 的名称,用于控制缓存和内省的访问令牌的 TTL。 * introspection\_interval integer *** 缓存和内省的访问令牌的 TTL(秒)。 默认值为 0,表示不使用此选项,插件默认使用由 `introspection_expiry_claim` 中定义的过期时间 Claim 传递的 TTL。 如果 `introspection_interval` 大于 0 且小于由 `introspection_expiry_claim` 中定义的过期时间 Claim 传递的 TTL,则使用 `introspection_interval`。 * introspection\_addon\_headers array\[string] *** 用于向内省 HTTP 请求附加额外的请求头值。如果原始请求中不存在指定的请求头,则不会附加该值。 * accept\_unsupported\_alg boolean 默认值:`true` *** 如果 ID 令牌使用了网关不支持的预期签名算法,设置为 true 会在不验证签名的情况下继续;设置为 false 会拒绝该令牌。 对于安全敏感的部署,请将其设置为 false,除非你明确接受 ID 令牌签名未验证的风险。设置为 false 不会增加对其他签名算法的支持。 在 APISIX 3.18.0 以及 API7 网关 3.9.18 和 3.10.5 中,ID 令牌验证路径支持 `RS256`、`RS512`、`HS256` 和 `HS512`,不验证 `PS*`、`ES*` 或 `EdDSA` 签名。 * access\_token\_expires\_leeway integer *** 访问令牌更新的过期回旋余地(秒)。当设置为大于 0 的值时,令牌更新将在令牌过期前的设定时间进行。这避免了在到达资源服务器时访问令牌刚好过期的情况。 * force\_reauthorize boolean 默认值:`false` *** 如果为 true,即使已缓存令牌,也执行授权流程。 * use\_nonce boolean 默认值:`false` *** 如果为 true,则在授权请求中启用 nonce 参数。 * revoke\_tokens\_on\_logout boolean 默认值:`false` *** 如果为 true,则在撤销端点通知授权服务器不再需要先前获取的刷新或访问令牌。 * session\_contents object *** 应存储在会话中的内容,用于最小化会话数据的大小。未设置时,所有内容都包含在会话中。 * id\_token boolean *** 如果为 true,则在会话中存储 ID 令牌。 * access\_token boolean *** 如果为 true,则在会话中存储访问令牌和刷新令牌。 * enc\_id\_token boolean *** 如果为 true,则在会话中存储加密的 ID 令牌。 * user boolean *** 如果为 true,则在会话中存储用户信息。 * par object *** 推送式授权请求(PAR)配置,定义见 [RFC 9126](https://datatracker.ietf.org/doc/html/rfc9126)。启用 PAR 后,网关通过后通道把授权请求参数发送给身份提供商,并只用返回的 `request_uri` 重定向用户代理,因此这些参数不会经过浏览器。 请通过此嵌套对象配置 PAR。插件会拒绝扁平选项 `use_par`、`pushed_authorization_request_endpoint` 和 `pushed_authorization_request_endpoint_auth_method`,以便验证端点和身份认证方法。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * enabled boolean 默认值:`false` *** 如果为 true,则把授权请求推送到 PAR 端点,而不是在重定向到授权端点时携带其参数。 * endpoint string *** 身份提供商 PAR 端点的 URL。未设置时使用其发现文档中声明的端点。 * endpoint\_auth\_method string 有效值: `client_secret_basic`、`client_secret_post`、`client_secret_jwt` 或 `private_key_jwt` *** PAR 端点使用的客户端身份认证方法。未设置时沿用令牌端点配置的方法。`private_key_jwt` 需要 `client_rsa_private_key`,`client_secret_jwt` 需要 `client_secret`。如果所选方法无法使用,PAR 请求将失败。 * dpop object *** 发送方约束令牌(DPoP)配置,定义见 [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)。网关会为每次令牌请求签发 proof JWT,把签发的令牌绑定到所配置的密钥上,令牌即使被窃取也无法由其它客户端重放。同时设置 `par.enabled` 时,密钥指纹会以 `dpop_jkt` 随推送请求一并发送。 网关充当向身份提供商发起令牌请求和用户信息请求的 DPoP 客户端。此配置不会验证外部 API 客户端入站请求中的 DPoP 证明。 如果令牌响应的 `token_type` 不是 `DPoP`,网关会拒绝该响应。令牌请求收到携带 `DPoP-Nonce` 请求头的 `400` 或 `401` 响应时会重试一次;用户信息请求收到携带该请求头的 `401` 响应时也会重试一次。 请通过此嵌套对象配置 DPoP。插件会拒绝扁平选项 `use_dpop`、`dpop_signing_alg`、`dpop_private_key` 和 `dpop_public_jwk`,以便应用 DPoP 验证和加密字段处理。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * enabled boolean 默认值:`false` *** 如果为 true,则在令牌请求中携带 DPoP proof JWT。启用时 `private_key` 与 `public_jwk` 均为必填。 * private\_key string *** 用于签名 DPoP proof JWT 的 PEM 格式私钥。启用数据面数据加密时,该字段会落盘加密。 * public\_jwk object *** 与 `private_key` 匹配的公开 JWK,会嵌入 proof JWT 的头部。其中不得包含私钥参数。 * signing\_alg string 默认值:`ES256` 有效值: `ES256`、`RS256` 或 `PS256` *** 用于签署 DPoP proof JWT 的算法。该算法必须与所配置密钥的类型匹配;如果发现文档列出了支持的 DPoP 算法,还必须是身份提供商接受的算法。 * client\_jwt\_assertion\_alg string 有效值: `HS256`、`HS512`、`RS256`、`RS512`、`ES256` 或 `ES512` *** 当端点认证方法为 `client_secret_jwt` 或 `private_key_jwt` 时,用于签名客户端断言 JWT 的算法。 `client_secret_jwt` 应使用 `HS*` 算法,`private_key_jwt` 应使用 `RS*` 或 `ES*` 算法。算法必须与 `client_rsa_private_key` 匹配;如果发现文档列出了支持的客户端断言算法,还必须是身份提供商接受的算法。所有端点共用一个配置的算法。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 * client\_jwt\_assertion\_audience string *** 客户端断言 JWT 的 audience Claim。未设置时使用正在调用的端点 URL。当网关访问的是内部端点 URL,而身份提供商要求 audience 使用其外部 URL 时,请配置此字段。 自 API7 企业版 3.9.18 和 3.10.5 以及 APISIX 3.18.0 起可用。 --- # OpenTelemetry `opentelemetry` 插件对 APISIX 进行插桩,并根据 [OpenTelemetry 规范](https://opentelemetry.io/docs/reference/specification/),以二进制编码的 [OTLP over HTTP](https://opentelemetry.io/docs/reference/specification/protocol/otlp/#otlphttp) 将追踪信息发送到 OpenTelemetry 收集器。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了如何在不同场景下使用 `opentelemetry` 插件。 ### 启用 `opentelemetry` 插件[​](#启用-opentelemetry-插件 "启用-opentelemetry-插件的直接链接") 在 API7 网关中,`opentelemetry` 默认可通过 Dashboard 和 Admin API 使用。对于 APISIX 部署,在配置使用该插件的路由前,请先在网关静态配置中加载该插件。 * Host or Docker * Kubernetes (Helm) 对于 APISIX 宿主机或 Docker 部署,请保留 `config.yaml` 中现有插件列表,并加入 `opentelemetry`: config.yaml ``` plugins: # 保留当前网关使用的完整插件列表。 - opentelemetry ``` 重新加载网关以使更改生效。 对于 APISIX Helm Chart,`apisix.plugins` 会替换已加载插件列表。请从当前网关使用的完整插件列表开始,并加入 `opentelemetry`: values.yaml ``` apisix: plugins: # 保留当前网关使用的完整插件列表。 - opentelemetry ``` API7 网关 Helm 部署在本节不需要修改 Helm values,可继续配置插件元数据和路由。 使用 APISIX Helm Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ### 发送追踪到 OpenTelemetry[​](#发送追踪到-opentelemetry "发送追踪到 OpenTelemetry的直接链接") 以下示例展示了如何追踪对路由的请求并将追踪信息发送到 OpenTelemetry。 在 Docker 中启动一个 OpenTelemetry 收集器实例: * Docker * Kubernetes ``` docker run -d --name otel-collector -p 4318:4318 otel/opentelemetry-collector-contrib ``` otel-collector.yaml ``` apiVersion: v1 kind: ConfigMap metadata: namespace: aic name: otel-collector-config data: config.yaml: | receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 exporters: debug: verbosity: detailed service: pipelines: traces: receivers: [otlp] exporters: [debug] --- apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: otel-collector spec: replicas: 1 selector: matchLabels: app: otel-collector template: metadata: labels: app: otel-collector spec: containers: - name: otel-collector image: otel/opentelemetry-collector-contrib args: - "--config=/conf/config.yaml" ports: - containerPort: 4318 volumeMounts: - name: config mountPath: /conf volumes: - name: config configMap: name: otel-collector-config --- apiVersion: v1 kind: Service metadata: namespace: aic name: otel-collector spec: selector: app: otel-collector ports: - name: otlp-http port: 4318 targetPort: 4318 type: ClusterIP ``` 应用清单: ``` kubectl apply -f otel-collector.yaml ``` 收集器应开始监听 `127.0.0.1:4318`(Docker)或 `otel-collector.aic.svc.cluster.local:4318`(Kubernetes)。配置插件元数据以设置收集器地址: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/opentelemetry" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "collector": { "address": "127.0.0.1:4318" } }' ``` adc.yaml ``` plugin_metadata: - name: opentelemetry collector: address: "127.0.0.1:4318" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 更新现有 `GatewayProxy` 资源中的 `pluginMetadata` 字段: gateway-proxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # 控制面连接配置 # .... pluginMetadata: opentelemetry: collector: address: "otel-collector.aic.svc.cluster.local:4318" ``` 将配置应用到集群: ``` kubectl apply -f gateway-proxy.yaml ``` 创建一个带有 `opentelemetry` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "otel-tracing-route", "uri": "/anything", "plugins": { "opentelemetry": { "sampler": { "name": "always_on" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: otel-tracing-route plugins: opentelemetry: sampler: name: always_on upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD otel-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: otel-plugin-config spec: plugins: - name: opentelemetry config: sampler: name: always_on --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: otel-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: otel-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` otel-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: otel-route spec: ingressClassName: apisix http: - name: otel-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: opentelemetry enable: true config: sampler: name: always_on ``` 将配置应用到集群: ``` kubectl apply -f otel-ic.yaml ``` 发送请求到该路由: ``` curl "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 在 OpenTelemetry 收集器的日志中,你应该看到类似于以下的信息: ``` 2024-02-18T17:14:03.825Z info ResourceSpans #0 Resource SchemaURL: Resource attributes: -> telemetry.sdk.language: Str(lua) -> telemetry.sdk.name: Str(opentelemetry-lua) -> telemetry.sdk.version: Str(0.1.1) -> hostname: Str(e34673e24631) -> service.name: Str(APISIX) ScopeSpans #0 ScopeSpans SchemaURL: InstrumentationScope opentelemetry-lua Span #0 Trace ID : fbd0a38d4ea4a128ff1a688197bc58b0 Parent ID : ID : af3dc7642104748a Name : GET /anything Kind : Server Start time : 2024-02-18 17:14:03.763244032 +0000 UTC End time : 2024-02-18 17:14:03.920229888 +0000 UTC Status code : Unset Status message : Attributes: -> net.host.name: Str(127.0.0.1) -> http.method: Str(GET) -> http.scheme: Str(http) -> http.target: Str(/anything) -> http.user_agent: Str(curl/7.64.1) -> apisix.route_id: Str(otel-tracing-route) -> apisix.route_name: Empty() -> apisix.response_source: Str(upstream) -> http.route: Str(/anything) -> http.status_code: Int(200) {"kind": "exporter", "data_type": "traces", "name": "debug"} ``` 要可视化这些追踪,你可以将遥测数据导出到后端服务,例如 Zipkin 和 Prometheus。有关更多详细信息,请参阅 [exporters](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter)。 自 API7 企业版 3.9.10 和 APISIX 3.17.0 起,每个请求跨度都包含 `apisix.response_source` 属性,用于分类 HTTP 响应的来源: * `apisix` — 响应由 APISIX 自身生成,例如插件拒绝、认证失败或路由未找到错误。 * `nginx` — 响应由 NGINX 代理层生成,例如连接被拒绝或上游超时错误。 * `upstream` — 响应来自实际的上游服务。 此属性可在追踪分析中实现更精确的错误归因,例如区分网关侧拒绝和真实的上游错误。 ### 在日志记录中使用追踪变量[​](#在日志记录中使用追踪变量 "在日志记录中使用追踪变量的直接链接") 以下示例展示了如何配置 `opentelemetry` 插件以设置以下内置变量,这些变量可用于日志插件或访问日志: * `opentelemetry_context_traceparent`:[父级链路](https://www.w3.org/TR/trace-context/#trace-context-http-headers-format) ID - `opentelemetry_trace_id`:当前跨度的链路 ID - `opentelemetry_span_id`:当前跨度的跨度 ID 配置插件元数据以将 `set_ngx_var` 设置为 true: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/opentelemetry" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "set_ngx_var": true }' ``` adc.yaml ``` plugin_metadata: - name: opentelemetry set_ngx_var: true ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 更新现有 `GatewayProxy` 资源中的 `pluginMetadata` 字段,并保留收集器配置: gateway-proxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # 控制面连接配置 # .... pluginMetadata: opentelemetry: collector: address: "otel-collector.aic.svc.cluster.local:4318" set_ngx_var: true ``` 将配置应用到集群: ``` kubectl apply -f gateway-proxy.yaml ``` OpenTelemetry Collector 可访问后,请根据网关部署方式配置网关。 * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置,以使用 `opentelemetry` 插件变量: config.yaml ``` nginx_config: http: enable_access_log: true access_log_format: '{"time": "$time_iso8601","opentelemetry_context_traceparent": "$opentelemetry_context_traceparent","opentelemetry_trace_id": "$opentelemetry_trace_id","opentelemetry_span_id": "$opentelemetry_span_id","remote_addr": "$remote_addr"}' access_log_format_escape: json ``` ❶ `access_log_format`:自定义访问日志格式以使用 `opentelemetry` 插件变量。 重新加载网关以使配置更改生效。 对于 Helm 部署,请更新用于渲染网关访问日志格式的 values,并保留 values 文件中的其他配置。 对于 APISIX Helm Chart,设置以下 values: values.yaml ``` apisix: nginx: logs: enableAccessLog: true accessLogFormat: '{"time": "$time_iso8601","opentelemetry_context_traceparent": "$opentelemetry_context_traceparent","opentelemetry_trace_id": "$opentelemetry_trace_id","opentelemetry_span_id": "$opentelemetry_span_id","remote_addr": "$remote_addr"}' accessLogFormatEscape: json ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` logs: enableAccessLog: true accessLogFormat: '{"time": "$time_iso8601","opentelemetry_context_traceparent": "$opentelemetry_context_traceparent","opentelemetry_trace_id": "$opentelemetry_trace_id","opentelemetry_span_id": "$opentelemetry_span_id","remote_addr": "$remote_addr"}' accessLogFormatEscape: json ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 生成请求时,你应该看到类似于以下的访问日志条目: ``` {"time": "18/Feb/2024:15:09:00 +0000","opentelemetry_context_traceparent": "00-fbd0a38d4ea4a128ff1a688197bc58b0-8f4b9d9970a02629-01","opentelemetry_trace_id": "fbd0a38d4ea4a128ff1a688197bc58b0","opentelemetry_span_id": "af3dc7642104748a","remote_addr": "172.10.0.1"} ``` --- ## 参数[​](#parameters "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * sampler object *** 采样配置。 * name string 默认值:`always_off` 有效值: `always_on`、`always_off`、`trace_id_ratio` 或 `parent_base` *** 采样策略。 要始终采样,请使用 `always_on`。 要从不采样,请使用 `always_off`。 要根据给定比例随机采样,请使用 `trace_id_ratio`。 要使用父跨度的采样决策,请使用 `parent_base`。如果没有父跨度,则使用根采样器。 * options object *** 采样策略的参数。 * fraction number 默认值:`0` 有效值: 介于 0 和 1 之间(含边界值) *** 采样策略为 `trace_id_ratio` 时的采样率。 * root object *** 采样策略为 `parent_base` 时的根采样器。 * name string 默认值:`always_off` 有效值: `always_on`、`always_off` 或 `trace_id_ratio` *** 根采样策略。 * options object *** 根采样策略参数。 * fraction number 默认值:`0` 有效值: 介于 0 和 1 之间(含边界值) *** 根采样策略为 `trace_id_ratio` 时的根采样率。 * additional\_attributes array\[string] *** 要作为字符串属性附加到链路跨度的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)名称。变量值在日志阶段解析,因此可以使用请求处理后期才填充的变量。数字和布尔值会转换为字符串;布尔值 `false` 不会被丢弃。 * additional\_header\_prefix\_attributes array\[string] *** 在日志阶段作为字符串属性附加到链路跨度的请求头或请求头前缀。例如,使用 `x-my-header` 或 `x-my-headers-*` 来包含所有前缀为 `x-my-headers-` 的请求头。同一请求头的多个值使用 `,` 连接。 ## 插件元数据[​](#plugin-metadata "插件元数据的直接链接") * tracing boolean 默认值:`true` *** 用于启用或禁用追踪的全局开关。设置为 `false` 时,无论路由级采样器如何配置,都不会发出跨度。 * trace\_id\_source string 默认值:`random` 有效值: `x-request-id` 或 `random` *** 链路 ID 的来源。当设置为 `x-request-id` 时,`x-request-id` 请求头的值将用作链路 ID。 * resource object *** 附加到链路的额外资源,例如 `{"service_name": "APISIX"}`。 * collector object *** 收集器配置。 * address string 默认值:`127.0.0.1:4318` *** 发送追踪的 OpenTelemetry 收集器地址。 * request\_timeout integer 默认值:`3` *** OpenTelemetry 收集器的请求超时时间(秒)。 * request\_headers object *** 包含在发往 OpenTelemetry 收集器的请求中的请求头,例如 `{"Authorization": "token"}`。 * batch\_span\_processor object *** 批量跨度处理器配置。 * drop\_on\_queue\_full boolean *** 如果为 true,则在队列已满时丢弃跨度;否则强制处理批次。 * max\_queue\_size integer *** 为延迟处理缓冲跨度的最大队列大小。 * batch\_timeout number *** 跨度批次在发送前可在导出队列中等待的最长时间(秒)。 * inactive\_timeout number *** 如果队列未满,跨度在发送前可在导出队列中等待的最长时间(秒)。 * max\_export\_batch\_size integer *** 发送到 OpenTelemetry 收集器的单个批次中可包含的最大跨度数。 * set\_ngx\_var boolean 默认值:`false` *** 将 `opentelemetry` 变量导出到 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 --- # Prometheus `prometheus` 插件提供了将 APISIX 与 [Prometheus](https://prometheus.io) 集成的能力。 启用插件后,APISIX 将开始收集相关指标,例如 API 请求和延迟,并以[基于文本的展示格式](https://prometheus.io/docs/instrumenting/exposition_formats/#exposition-formats)将它们导出到 Prometheus。然后,你可以在 Prometheus 中创建监控规则和告警,以监控 API 网关和 API 的健康状况。 []() ## 指标[​](#指标 "指标的直接链接") Prometheus 中有不同类型的指标。要了解它们的区别,请参阅 [指标类型](https://prometheus.io/docs/concepts/metric_types/)。 默认情况下,`prometheus` 插件会导出以下指标。有关示例,请参阅 [获取 APISIX 指标](#%E8%8E%B7%E5%8F%96-apisix-%E6%8C%87%E6%A0%87)。请注意,如果没有数据,某些指标(如 `apisix_batch_process_entries`)可能不会立即显示。 | 名称 | 类型 | 描述 | | ----------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | apisix\_bandwidth | counter | 流经 APISIX 的总流量(以字节为单位)。 | | apisix\_etcd\_modify\_indexes | gauge | APISIX 键对 etcd 的更改次数。 | | apisix\_batch\_process\_entries | gauge | 批量发送数据时批次中的剩余条目数,例如使用 `http logger` 和其他日志插件时。 | | apisix\_etcd\_reachable | gauge | APISIX 是否可以连接到 etcd。值 `1` 表示可达,`0` 表示不可达。 | | apisix\_http\_status | counter | 返回给客户端的 HTTP 状态码。这是经过插件处理和代理后客户端实际收到的状态,可能与上游状态不同。 | | apisix\_http\_requests\_total | gauge | 来自客户端的 HTTP 请求数。 | | apisix\_nginx\_http\_current\_connections | gauge | 当前与客户端的连接数。 | | apisix\_nginx\_metric\_errors\_total | counter | `nginx-lua-prometheus` 错误总数。 | | apisix\_http\_latency | histogram | HTTP 请求延迟(以毫秒为单位)。 | | apisix\_node\_info | gauge | 有关 APISIX 节点的信息,例如主机名和 APISIX 版本。 | | apisix\_shared\_dict\_capacity\_bytes | gauge | [NGINX 共享字典](https://github.com/openresty/lua-nginx-module#ngxshareddict) 的总容量。 | | apisix\_shared\_dict\_free\_space\_bytes | gauge | [NGINX 共享字典](https://github.com/openresty/lua-nginx-module#ngxshareddict) 中的剩余空间。 | | apisix\_upstream\_status | gauge | 上游节点的健康检查状态,如果在上游配置了健康检查则可用。值 `1` 表示健康,`0` 表示不健康。 | | apisix\_stream\_connection\_total | counter | 每个流路由处理的连接总数。 | | apisix\_stream\_active\_connections | gauge | 每个流监听地址上活动的 TCP 连接与 UDP 会话数。需要 APISIX-Runtime。在 API7 企业版 3.9.x 系列中自 3.9.19 起支持,在 3.10.x 系列中自 3.10.6 起支持,并且在 APISIX 中自 3.18.0 起支持。 | | apisix\_stream\_status | counter | 按终止状态、监听地址和上游节点统计的已结束流会话数。在 API7 企业版 3.9.x 系列中自 3.9.19 起支持,在 3.10.x 系列中自 3.10.6 起支持,并且在 APISIX 中自 3.18.0 起支持。 | | apisix\_stream\_bandwidth | counter | 流子系统按监听地址、方向和连接侧代理的字节数。需要 APISIX-Runtime。在 API7 企业版 3.9.x 系列中自 3.9.19 起支持,在 3.10.x 系列中自 3.10.6 起支持,并且在 APISIX 中自 3.18.0 起支持。 | | apisix\_llm\_prompt\_tokens | counter | 提示词 Token 数量。仅对 AI 请求类型导出。自 API7 企业版 3.9.7 和 APISIX 3.17.0 起支持。 | | apisix\_llm\_completion\_tokens | counter | 补全 Token 数量。仅对 AI 请求类型导出。自 API7 企业版 3.9.7 和 APISIX 3.17.0 起支持。 | | apisix\_llm\_latency | histogram | LLM 请求延迟,单位为毫秒。仅对 AI 请求类型导出。自 API7 企业版 3.9.7 和 APISIX 3.17.0 起支持。`type` 标签用于区分完整响应延迟(`total`)与流式请求的首 Token 时间(`ttft`),自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。未指定 `type` 的查询会同时匹配两类观测值;如需保留此前的总延迟语义,请筛选 `type="total"`。每个流式请求会记录一个 `total` 样本和一个 `ttft` 样本。 | | apisix\_llm\_active\_connections | gauge | 正在处理的 LLM 上游请求数。仅对 AI 请求类型导出。自 API7 企业版 3.9.7 和 APISIX 3.17.0 起支持。 | | apisix\_llm\_prompt\_tokens\_dist | histogram | 单个请求的提示词 Token 数量分布。仅对 AI 请求类型导出。自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起支持。 | | apisix\_llm\_completion\_tokens\_dist | histogram | 单个请求的补全 Token 数量分布。仅对 AI 请求类型导出。自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起支持。 | | apisix\_ai\_cache\_hits\_total | counter | 由 AI Cache 返回的请求数,按精确缓存层或语义缓存层区分。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起支持。 | | apisix\_ai\_cache\_misses\_total | counter | 未返回缓存响应的 AI Cache 查找次数。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起支持。 | | apisix\_ai\_cache\_bypasses\_total | counter | 绕过 AI Cache 查找的请求数。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起支持。 | | apisix\_ai\_cache\_embedding\_latency | histogram | 语义缓存层调用嵌入模型服务提供方的延迟,单位为毫秒。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起支持。 | 备注 仅当请求由 AI 插件(例如 [AI Proxy](https://docs.apiseven.com/hub/ai-proxy.md))处理时,才会导出 LLM 指标(`apisix_llm_prompt_tokens`、`apisix_llm_completion_tokens`、`apisix_llm_latency`、`apisix_llm_prompt_tokens_dist` 和 `apisix_llm_completion_tokens_dist`)。未启用 AI 插件的路由不会生成这些指标。`apisix_llm_active_connections` 由 AI 插件直接管理,也仅存在于启用了 AI 的路由中。 当一次 LLM 上游尝试开始时,该 gauge 增加;请求进入日志阶段后,该 gauge 减少。对于单次尝试,它表示正在处理的 LLM 上游请求。使用 `ai-proxy-multi` 回退重试时,每次重试都会增加一个新的实例级时序,而请求只会使用最终实例的标签减少一次。因此,失败实例的时序可能会一直高于真实活动请求数,直到指标过期或存储被重置。 要减少 LLM 指标中的高基数标签,请使用[插件元数据](https://docs.apiseven.com/hub/prometheus/configuration.md#%E6%8F%92%E4%BB%B6%E5%85%83%E6%95%B0%E6%8D%AE)中的 `disabled_labels`,有选择地禁用 `consumer` 或 `node` 等标签。 提示词和补全 Token 直方图使用可配置的桶。有关默认值和配置方式,请参阅[静态插件属性](https://docs.apiseven.com/hub/prometheus/configuration.md#%E9%9D%99%E6%80%81%E9%85%8D%E7%BD%AE)。 ## 标签[​](#标签 "标签的直接链接") [标签](https://prometheus.io/docs/practices/naming/#labels) 是指标的属性,用于区分指标。 例如,`apisix_http_status` 指标可以用 `route` 信息进行标记,以识别 HTTP 状态源自哪个路由。 以下是非详尽的 APISIX 指标及其描述的标签列表。 ### `apisix_http_status` 的标签[​](#apisix_http_status-的标签 "apisix_http_status-的标签的直接链接") 以下标签用于区分 `apisix_http_status` 指标。 | 名称 | 描述 | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | code | 上游节点返回的 HTTP 响应代码。 | | route | 当 `prefer_name` 为 `false`(默认值)时,为 HTTP 状态源自的路由 ID;当 `prefer_name` 为 `true` 时,为路由名称。如果请求不匹配任何路由,则默认为空字符串。 | | route\_id | 仅在 Enterprise 中可用。无论 `prefer_name` 设置如何,HTTP 状态源自的路由 ID。 | | matched\_uri | 匹配请求的路由 URI。如果请求不匹配任何路由,则默认为空字符串。 | | matched\_host | 匹配请求的路由主机。如果请求不匹配任何路由,或者路由上未配置主机,则默认为空字符串。 | | service | 当 `prefer_name` 为 `false`(默认值)时,为 HTTP 状态源自的服务 ID;当 `prefer_name` 为 `true` 时,为服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 | | service\_id | 仅在 Enterprise 中可用。无论 `prefer_name` 设置如何,HTTP 状态源自的服务 ID。 | | consumer | 与请求关联的消费者名称。如果请求没有关联消费者,则默认为空字符串。 | | node | 上游节点的 IP 地址。 | | gateway\_group\_id | HTTP 状态源自的网关组 ID。仅 API7 企业版可用。 | | instance\_id | HTTP 状态源自的网关实例 ID。仅 API7 企业版可用。 | | api\_product\_id | HTTP 状态源自的产品 ID。仅 API7 企业版可用。 | | request\_type | 与 HTTP 状态关联的请求类型:`traditional_http`、`websocket`、`ai_chat` 或 `ai_stream`。以 `101 Switching Protocols` 应答的请求为 `websocket`,自 API7 企业版 3.10.7 起引入。 | | request\_llm\_model | 客户端请求中指定的 LLM 模型。 | | llm\_model | 处理请求的 LLM 模型。 | | response\_source | HTTP 响应的来源:`apisix`(由 APISIX 生成,如插件拒绝或路由未找到)、`nginx`(NGINX 代理错误,如连接被拒绝或上游超时)或 `upstream`(来自上游服务的真实响应)。该标签自 API7 企业版 3.9.10 和 APISIX 3.17.0 起提供。 | | mcp\_request\_type | MCP 请求类型,例如 `tools/list` 或 `tools/call`。非 MCP 请求为空。自 API7 企业版 3.9.14 起支持。 | | mcp\_tool\_name | `tools/call` 请求中的 MCP 工具名称,其他请求为空。自 API7 企业版 3.9.14 起支持。 | `response_source` 是 `apisix_http_status` 的必需标签,每个既有状态标签组合最多可能新增三个时序。发布前请更新匹配完整标签集的 PromQL join、记录规则、告警和 Dashboard,并评估新增基数。 ### `apisix_bandwidth` 的标签[​](#apisix_bandwidth-的标签 "apisix_bandwidth-的标签的直接链接") 以下标签用于区分 `apisix_bandwidth` 指标。 | 名称 | 描述 | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | 流量类型,`egress`(出口)或 `ingress`(入口)。 | | route | 当 `prefer_name` 为 `false`(默认值)时,为带宽对应的路由 ID;当 `prefer_name` 为 `true` 时,为路由名称。如果请求不匹配任何路由,则默认为空字符串。 | | route\_id | 仅在 Enterprise 中可用。无论 `prefer_name` 设置如何,带宽对应的路由 ID。 | | service | 当 `prefer_name` 为 `false`(默认值)时,为带宽对应的服务 ID;当 `prefer_name` 为 `true` 时,为服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 | | service\_id | 仅在 Enterprise 中可用。无论 `prefer_name` 设置如何,带宽对应的服务 ID。 | | consumer | 与请求关联的消费者名称。如果请求没有关联消费者,则默认为空字符串。 | | node | 上游节点的 IP 地址。 | | gateway\_group\_id | 仅在 Enterprise 中可用。带宽对应的网关组 ID。 | | instance\_id | 仅在 Enterprise 中可用。带宽对应的网关实例 ID。 | | api\_product\_id | 仅在 Enterprise 中可用。带宽对应的产品 ID。 | | request\_type | 带宽对应的请求类型:`traditional_http`、`websocket`、`ai_chat` 或 `ai_stream`。以 `101 Switching Protocols` 应答的请求为 `websocket`,自 API7 企业版 3.10.7 起引入。 | | request\_llm\_model | 仅在企业版(自 3.9.7 起)可用。客户端请求中指定的 LLM 模型。 | | llm\_model | 仅在 Enterprise 中可用。带宽对应的 LLM 模型。 | | mcp\_request\_type | 仅在企业版(自 3.9.14 版本起)可用。MCP 请求类型,例如 `tools/list` 或 `tools/call`。非 MCP 请求为空。 | | mcp\_tool\_name | 仅在企业版(自 3.9.14 版本起)可用。`tools/call` 请求中的 MCP 工具名称,其他请求为空。 | ### `apisix_http_latency` 的标签[​](#apisix_http_latency-的标签 "apisix_http_latency-的标签的直接链接") 以下标签用于区分 `apisix_http_latency` 指标。 | 名称 | 描述 | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | 延迟类型。有关详细信息,请参阅 [延迟类型](#%E5%BB%B6%E8%BF%9F%E7%B1%BB%E5%9E%8B)。 | | route | 当 `prefer_name` 为 `false`(默认值)时,为延迟对应的路由 ID;当 `prefer_name` 为 `true` 时,为路由名称。如果请求不匹配任何路由,则默认为空字符串。 | | route\_id | 仅在 Enterprise 中可用。无论 `prefer_name` 设置如何,延迟对应的路由 ID。 | | service | 当 `prefer_name` 为 `false`(默认值)时,为延迟对应的服务 ID;当 `prefer_name` 为 `true` 时,为服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 | | service\_id | 仅在 Enterprise 中可用。无论 `prefer_name` 设置如何,延迟对应的服务 ID。 | | consumer | 与延迟关联的消费者名称。如果请求没有关联消费者,则默认为空字符串。 | | node | 与延迟关联的上游节点的 IP 地址。 | | gateway\_group\_id | 仅在 Enterprise 中可用。延迟对应的网关组 ID。 | | instance\_id | 仅在 Enterprise 中可用。延迟对应的网关实例 ID。 | | api\_product\_id | 仅在 Enterprise 中可用。延迟对应的产品 ID。 | | request\_type | 延迟对应的请求类型:`traditional_http`、`websocket`、`ai_chat` 或 `ai_stream`。以 `101 Switching Protocols` 应答的请求为 `websocket`,自 API7 企业版 3.10.7 起引入。 | | request\_llm\_model | 仅在企业版(自 3.9.7 起)可用。客户端请求中指定的 LLM 模型。 | | llm\_model | 仅在 Enterprise 中可用。延迟对应的 LLM 模型。 | | mcp\_request\_type | 仅在企业版(自 3.9.14 版本起)可用。MCP 请求类型,例如 `tools/list` 或 `tools/call`。非 MCP 请求为空。 | | mcp\_tool\_name | 仅在企业版(自 3.9.14 版本起)可用。`tools/call` 请求中的 MCP 工具名称,其他请求为空。 | #### 延迟类型[​](#延迟类型 "延迟类型的直接链接") `apisix_http_latency` 可以用以下三种类型之一进行标记: * `request` 表示从客户端读取第一个字节到向客户端发送最后一个字节后的日志写入之间经过的时间。 * `upstream` 表示等待上游服务响应所经过的时间。 * `apisix` 表示 `request` 延迟与 `upstream` 延迟之间的差值。 对于 WebSocket 会话,`request` 和 `upstream` 延迟衡量的是升级后的连接保持打开的时长,而不是一次请求-响应往返。自 API7 企业版 3.10.7 起,这类请求带有 `request_type="websocket"`,因此可以用 `request_type!="websocket"` 把它们排除在延迟查询之外。 换句话说,APISIX 延迟不仅仅归因于 Lua 处理。它应该理解如下: ``` APISIX latency = downstream request time - upstream response time = downstream traffic latency + NGINX latency ``` ### `apisix_upstream_status` 的标签[​](#apisix_upstream_status-的标签 "apisix_upstream_status-的标签的直接链接") 以下标签用于区分 `apisix_upstream_status` 指标。 | 名称 | 描述 | | ---- | ------------------------------------------------------------------------------------- | | name | 配置了健康检查的上游对应的资源 ID,例如 `/apisix/routes/1` 和 `/apisix/upstreams/1`。 | | ip | 上游节点的 IP 地址。 | | port | 节点的端口号。 | ### 流指标的标签[​](#流指标的标签 "流指标的标签的直接链接") `apisix_stream_active_connections` 以流监听地址作为标签: | 名称 | 描述 | | ------------- | -------------------------------------------------------------- | | `listen_addr` | APISIX 接受该 TCP 连接或 UDP 会话的地址,例如 `0.0.0.0:9100`。 | `apisix_stream_status` 在每个流会话结束时记录一次: | 名称 | 描述 | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `code` | 会话的结束方式。`200` 表示正常关闭。`400` 表示客户端侧的问题,例如客户端重置连接或发送了无效数据。`403` 表示被访问规则拒绝。`500` 表示内部错误。`502` 表示上游或传输层问题,例如连接失败、重置或空闲超时。`503` 表示被连接数限制拒绝。 | | `listen_addr` | APISIX 接受该会话的地址。 | | `node` | 选中的上游地址,形式为 `IP:端口`。会话在 APISIX 选出上游之前结束时为空。 | 对于上游连接建立之后发生的部分失败,NGINX 报告的 Stream `$status` 仍为 200。该指标改用会话终止原因来区分正常关闭与之后的超时或重置。worker 关闭以及未记录到可识别原因时同样使用 `200`。 `apisix_stream_bandwidth` 在会话保持打开期间持续更新: | 名称 | 描述 | | ------------- | ------------------------------------ | | `listen_addr` | APISIX 接受该会话的地址。 | | `type` | 流量方向:`ingress` 或 `egress`。 | | `side` | 连接侧:`downstream` 或 `upstream`。 | ### `apisix_llm_latency` 的标签[​](#apisix_llm_latency-的标签 "apisix_llm_latency-的标签的直接链接") 以下标签用于区分 `apisix_llm_latency` 指标。 | 名称 | 描述 | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | LLM 延迟类型:`total` 表示完整响应延迟,`ttft` 表示流式请求的首 Token 时间。自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。此前将每个 `apisix_llm_latency` 样本都视为总延迟的 Dashboard、告警和记录规则必须添加 `type="total"`。 | | route | 当 `prefer_name` 为 `false`(默认值)时,为 HTTP 状态源自的路由 ID;当 `prefer_name` 为 `true` 时,为路由名称。如果请求不匹配任何路由,则默认为空字符串。 | | route\_id | 无论 `prefer_name` 设置如何,HTTP 状态源自的路由 ID。 | | service | 当 `prefer_name` 为 `false`(默认值)时,为 HTTP 状态源自的服务 ID;当 `prefer_name` 为 `true` 时,为服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 | | service\_id | 无论 `prefer_name` 设置如何,HTTP 状态源自的服务 ID。 | | consumer | 与请求关联的消费者名称。如果请求没有关联消费者,则默认为空字符串。 | | node | `ai-proxy` 或 `ai-proxy-multi` 选中的 LLM 实例名称,而不是上游 IP 地址。 | | gateway\_group\_id | HTTP 状态源自的网关组 ID。 | | instance\_id | HTTP 状态源自的网关实例 ID。 | | api\_product\_id | HTTP 状态源自的产品 ID。 | | request\_type | HTTP 状态源自的请求类型。 | | request\_llm\_model | 客户端请求中发送的模型名称。自 API7 企业版 3.9.7 和 APISIX 3.17.0 起引入。 | | llm\_model | 网关实际使用的目标模型。如果 AI 实例配置了模型,则使用该值;否则使用客户端请求的模型。 | ### 其他 LLM 指标的标签[​](#其他-llm-指标的标签 "其他 LLM 指标的标签的直接链接") 以下标签用于区分 `apisix_llm_prompt_tokens`、`apisix_llm_completion_tokens`、`apisix_llm_active_connections`、`apisix_llm_prompt_tokens_dist` 和 `apisix_llm_completion_tokens_dist` 指标。 | 名称 | 描述 | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | route | 当 `prefer_name` 为 `false`(默认值)时,为 HTTP 状态源自的路由 ID;当 `prefer_name` 为 `true` 时,为路由名称。如果请求不匹配任何路由,则默认为空字符串。 | | route\_id | 无论 `prefer_name` 设置如何,HTTP 状态源自的路由 ID。 | | matched\_uri | 匹配请求的路由 URI。如果请求不匹配任何路由,则默认为空字符串。 | | matched\_host | 匹配请求的路由主机。如果请求不匹配任何路由,或者路由上未配置主机,则默认为空字符串。 | | service | 当 `prefer_name` 为 `false`(默认值)时,为 HTTP 状态源自的服务 ID;当 `prefer_name` 为 `true` 时,为服务名称。如果匹配的路由不属于任何服务,则默认为路由上配置的主机值。 | | service\_id | 无论 `prefer_name` 设置如何,HTTP 状态源自的服务 ID。 | | consumer | 与请求关联的消费者名称。如果请求没有关联消费者,则默认为空字符串。 | | node | `ai-proxy` 或 `ai-proxy-multi` 选中的 LLM 实例名称,而不是上游 IP 地址。 | | gateway\_group\_id | HTTP 状态源自的网关组 ID。 | | instance\_id | HTTP 状态源自的网关实例 ID。 | | api\_product\_id | HTTP 状态源自的产品 ID。 | | request\_type | HTTP 状态源自的请求类型。 | | request\_llm\_model | 客户端请求中发送的模型名称。自 API7 企业版 3.9.7 和 APISIX 3.17.0 起引入。 | | llm\_model | 网关实际使用的目标模型。如果 AI 实例配置了模型,则使用该值;否则使用客户端请求的模型。 | 提示词与补全 Token 计数器和分布直方图在不同产品中使用不同的标签集。APISIX 导出 `route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model`。API7 企业版还导出 `route`、`matched_uri`、`matched_host` 和 `service`,以及网关实例和 API 产品标签。 `request_llm_model` 和 `llm_model` 的值来自客户端和服务提供方数据,最长为 128 字节。自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。如果不需要按模型拆分时序,请禁用这些标签。 ### AI Cache 指标的标签[​](#ai-cache-指标的标签 "AI Cache 指标的标签的直接链接") 四个 AI Cache 指标共享以下标签。只有 `apisix_ai_cache_hits_total` 包含 `layer`。 | 名称 | 描述 | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `layer` | 返回缓存命中的缓存层:`exact` 或 `semantic`。该结构性标签不能禁用。 | | `route` | 路由名称;如果路由没有名称,则为空字符串。 | | `route_id` | 路由 ID。 | | `service` | 服务名称;如果路由未引用服务,则为空字符串。 | | `service_id` | 服务 ID;如果路由未引用服务,则为空字符串。 | | `consumer` | Consumer 名称;如果请求未关联 Consumer,则为空字符串。 | | `node` | `ai-proxy` 或 `ai-proxy-multi` 选中的 LLM 实例名称,而不是上游 IP 地址。 | | `request_type` | 请求类型,例如 `ai_chat` 或 `ai_stream`。 | | `request_llm_model` | 客户端请求中发送的模型名称。 | | `llm_model` | 网关实际使用的目标模型。如果 AI 实例配置了模型,则使用该值;否则使用客户端请求的模型。缓存命中时不会访问 LLM,因此该值为空。 | API7 企业版还为这些指标导出 `matched_uri`、`matched_host`,以及网关实例和 API 产品标签。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了如何在不同场景下使用 `prometheus` 插件。 ### 获取 APISIX 指标[​](#获取-apisix-指标 "获取 APISIX 指标的直接链接") 以下示例展示了如何从 APISIX 获取指标。 默认的 Prometheus 指标端点和其他 Prometheus 相关配置可以在[静态配置](https://docs.apiseven.com/hub/prometheus/configuration.md#%E9%9D%99%E6%80%81%E9%85%8D%E7%BD%AE)中找到。如果你想自定义这些配置,请参阅[配置文件](https://docs.apiseven.com/apisix/reference/configuration-files.md#configyaml-and-configyamlexample)。 如果你在容器化环境中部署网关,并希望从外部访问 Prometheus 指标端点,请在网关静态配置中更新 Prometheus 导出地址: * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` plugin_attr: prometheus: export_addr: ip: 0.0.0.0 ``` 重新加载网关以使更改生效。 对于 APISIX Helm Chart,在 Chart values 中启用 Prometheus。该配置会将 `plugin_attr.prometheus.export_addr.ip` 渲染为 `0.0.0.0`: values.yaml ``` apisix: prometheus: enabled: true ``` 对于 API7 网关 Helm Chart,更新 Prometheus 插件属性: values.yaml ``` pluginAttrs: prometheus: export_addr: ip: 0.0.0.0 port: 9091 ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 向 APISIX Prometheus 指标端点发送请求: ``` curl "http://127.0.0.1:9091/apisix/prometheus/metrics" ``` 你应该看到类似于以下的输出: ``` # HELP apisix_bandwidth Total bandwidth in bytes consumed per service in Apisix # TYPE apisix_bandwidth counter apisix_bandwidth{type="egress",route="",service="",consumer="",node=""} 8417 apisix_bandwidth{type="egress",route="1",service="",consumer="",node="127.0.0.1"} 1420 apisix_bandwidth{type="egress",route="2",service="",consumer="",node="127.0.0.1"} 1420 apisix_bandwidth{type="ingress",route="",service="",consumer="",node=""} 189 apisix_bandwidth{type="ingress",route="1",service="",consumer="",node="127.0.0.1"} 332 apisix_bandwidth{type="ingress",route="2",service="",consumer="",node="127.0.0.1"} 332 # HELP apisix_etcd_modify_indexes Etcd modify index for APISIX keys # TYPE apisix_etcd_modify_indexes gauge apisix_etcd_modify_indexes{key="consumers"} 0 apisix_etcd_modify_indexes{key="global_rules"} 0 ... ``` ### 通过禁用标签降低指标基数[​](#通过禁用标签降低指标基数 "通过禁用标签降低指标基数的直接链接") 插件元数据可将选定标签的值折叠为空字符串,在保留指标标签模式的同时减少时序数量。APISIX 和 API7 企业版为 HTTP 状态和延迟指标使用不同的元数据键。 API7 企业版会导出额外维度,因此两种产品接受的标签也有所不同: | 指标元数据键 | APISIX 中可禁用的标签 | API7 企业版的差异 | | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | `http_status` | `route`、`matched_uri`、`matched_host`、`service`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model`、`response_source` | 使用键 `status`。额外支持 `route_id`、`service_id`、`mcp_request_type` 和 `mcp_tool_name`,但不允许禁用 `response_source`。 | | `http_latency` | `route`、`service`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` | 使用键 `latency`。额外支持 `route_id`、`service_id`、`mcp_request_type` 和 `mcp_tool_name`。 | | `bandwidth` | `route`、`service`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` | 额外支持 `route_id`、`service_id`、`mcp_request_type` 和 `mcp_tool_name`。 | | `llm_latency` | `route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` | 还支持 `route` 和 `service`。 | | `llm_prompt_tokens`、`llm_completion_tokens`、`llm_prompt_tokens_dist`、`llm_completion_tokens_dist` | `route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` | 还支持 `route`、`matched_uri`、`matched_host` 和 `service`。 | | `llm_active_connections` | `route`、`route_id`、`matched_uri`、`matched_host`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` | 标签相同。 | | `ai_cache_hits_total`、`ai_cache_misses_total`、`ai_cache_bypasses_total`、`ai_cache_embedding_latency` | `route`、`route_id`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` | 还支持 `matched_uri` 和 `matched_host`。 | 本表不包含结构性标签,因为这些标签不能禁用。 在 API7 企业版中,`stream_status` 元数据键可以禁用 `apisix_stream_status` 的 `node` 标签。`code` 和 `listen_addr` 是结构性标签。自 API7 企业版 3.9.19 和 3.10.6 起引入。 在 APISIX 中,使用以下配置禁用 HTTP 状态和延迟指标的 `node` 标签: ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/prometheus" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "disabled_labels": { "http_status": ["node"], "http_latency": ["node"] } }' ``` 对于 API7 企业版,请改用 `status` 和 `latency`: ``` { "disabled_labels": { "status": ["node"], "latency": ["node"] } } ``` 通过启用了该插件的路由发送请求,然后获取指标端点。受影响的时序应保留 `node` 标签,但其值为空: ``` apisix_http_status{code="200",route="1",matched_uri="/get",matched_host="",service="",consumer="",node="",request_type="traditional_http",request_llm_model="",llm_model="",response_source="upstream"} 1 ``` 模式会拒绝用于区分不同测量值的结构性标签,包括 HTTP 状态的 `code`,HTTP 延迟、带宽和 LLM 延迟的 `type`,以及 AI Cache 命中的 `layer`。APISIX 与 API7 企业版的可选标签集并不相同;请根据所配置的网关查阅[插件元数据参考](https://docs.apiseven.com/hub/prometheus/configuration.md#%E6%8F%92%E4%BB%B6%E5%85%83%E6%95%B0%E6%8D%AE)。 ### 在公共 API 端点上暴露 APISIX 指标[​](#在公共-api-端点上暴露-apisix-指标 "在公共 API 端点上暴露 APISIX 指标的直接链接") 以下示例展示了如何禁用默认在端口 `9091` 上暴露端点的 Prometheus 导出服务器,并在 APISIX 用于监听其他客户端请求的端口 `9080` 上的新公共 API 端点上暴露 APISIX Prometheus 指标。 警告 如果收集大量指标,插件可能会占用大量 CPU 资源进行指标计算,并对常规请求的处理产生负面影响。 为了解决这个问题,APISIX 使用 [特权代理(privileged agent)](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/process.md#enable_privileged_agent) 并将指标计算卸载到单独的进程。如果你使用配置文件中配置的指标端点(如 [上文](#%E8%8E%B7%E5%8F%96-apisix-%E6%8C%87%E6%A0%87) 所示),此优化将自动应用。如果你使用 `public-api` 插件暴露指标端点,你将无法从该优化中受益。 要通过 `public-api` 暴露指标,请先禁用默认的 Prometheus 导出服务器: * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` plugin_attr: prometheus: enable_export_server: false ``` 重新加载网关以使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.prometheus` 的 Chart values,并保留 values 文件中的其他配置。 对于 APISIX Helm Chart,设置以下 values: values.yaml ``` apisix: pluginAttrs: prometheus: enable_export_server: false ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` pluginAttrs: prometheus: enable_export_server: false ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 接下来,创建一个带有 [`public-api`](https://docs.apiseven.com/hub/public-api.md) 插件的路由,并为 APISIX 指标暴露一个公共 API 端点: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "prometheus-metrics", "uri": "/prometheus_metrics", "plugins": { "public-api": { "uri": "/apisix/prometheus/metrics" } } }' ``` adc.yaml ``` routes: - uri: /prometheus_metrics name: prometheus-metrics plugins: public-api: uri: /apisix/prometheus/metrics ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD prometheus-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: prometheus-public-api-config spec: plugins: - name: public-api config: uri: /apisix/prometheus/metrics --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: prometheus-metrics-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /prometheus_metrics filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: prometheus-public-api-config ``` prometheus-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: prometheus-metrics-route spec: ingressClassName: apisix http: - name: prometheus-metrics-route match: paths: - /prometheus_metrics plugins: - name: public-api enable: true config: uri: /apisix/prometheus/metrics ``` 将配置应用到集群: ``` kubectl apply -f prometheus-ic.yaml ``` 向新的指标端点发送请求以进行验证: ``` curl "http://127.0.0.1:9080/prometheus_metrics" ``` 你应该看到类似于以下的输出: ``` # HELP apisix_http_requests_total The total number of client requests since APISIX started # TYPE apisix_http_requests_total gauge apisix_http_requests_total 1 # HELP apisix_nginx_http_current_connections Number of HTTP connections # TYPE apisix_nginx_http_current_connections gauge apisix_nginx_http_current_connections{state="accepted"} 1 apisix_nginx_http_current_connections{state="active"} 1 apisix_nginx_http_current_connections{state="handled"} 1 apisix_nginx_http_current_connections{state="reading"} 0 apisix_nginx_http_current_connections{state="waiting"} 0 apisix_nginx_http_current_connections{state="writing"} 1 ... ``` ### 将 APISIX 与 Prometheus 和 Grafana 集成[​](#将-apisix-与-prometheus-和-grafana-集成 "将 APISIX 与 Prometheus 和 Grafana 集成的直接链接") 要了解如何使用 Prometheus 收集 APISIX 指标并在 Grafana 中将其可视化,请参阅 [操作指南](https://docs.apiseven.com/apisix/how-to-guide/observability/monitor-apisix-with-prometheus.md)。 ### 监控上游健康状态[​](#监控上游健康状态 "监控上游健康状态的直接链接") 以下示例展示了如何监控上游节点的健康状态。 创建一个带有 `prometheus` 插件的路由并配置上游主动健康检查: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "prometheus-route", "uri": "/get", "plugins": { "prometheus": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1, "127.0.0.1:20001": 1 }, "checks": { "active": { "timeout": 5, "http_path": "/status", "healthy": { "interval": 2, "successes": 1 }, "unhealthy": { "interval": 1, "http_failures": 2 } }, "passive": { "healthy": { "http_statuses": [200, 201], "successes": 3 }, "unhealthy": { "http_statuses": [500], "http_failures": 3, "tcp_failures": 3 } } } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: prometheus-route plugins: prometheus: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 - host: 127.0.0.1 port: 20001 weight: 1 checks: active: timeout: 5 http_path: /status healthy: interval: 2 successes: 1 unhealthy: interval: 1 http_failures: 2 passive: healthy: http_statuses: - 200 - 201 successes: 3 unhealthy: http_statuses: - 500 http_failures: 3 tcp_failures: 3 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD prometheus-health-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: healthy-httpbin spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: unhealthy-httpbin spec: type: ExternalName externalName: example.com --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: healthy-httpbin-health spec: targetRefs: - group: "" kind: Service name: healthy-httpbin healthCheck: active: type: http httpPath: /status/200 timeout: 5s healthy: interval: 2s successes: 1 unhealthy: interval: 1s httpFailures: 2 passive: type: http healthy: httpCodes: - 200 - 201 successes: 3 unhealthy: httpCodes: - 500 httpFailures: 3 tcpFailures: 3 --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: unhealthy-httpbin-health spec: targetRefs: - group: "" kind: Service name: unhealthy-httpbin healthCheck: active: type: http httpPath: /status/200 timeout: 5s healthy: interval: 2s successes: 1 unhealthy: interval: 1s httpFailures: 2 passive: type: http healthy: httpCodes: - 200 - 201 successes: 3 unhealthy: httpCodes: - 500 httpFailures: 3 tcpFailures: 3 --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: prometheus-plugin-config spec: plugins: - name: prometheus config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: prometheus-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /status/200 filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: prometheus-plugin-config backendRefs: - name: healthy-httpbin port: 80 weight: 1 - name: unhealthy-httpbin port: 80 weight: 1 ``` prometheus-health-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Service name: healthy-httpbin port: 80 - type: Service name: unhealthy-httpbin port: 80 healthCheck: active: type: http httpPath: /status timeout: 5 healthy: interval: 2s successes: 1 unhealthy: interval: 1s httpFailures: 2 passive: type: http healthy: httpCodes: - 200 - 201 successes: 3 unhealthy: httpCodes: - 500 httpFailures: 3 tcpFailures: 3 --- apiVersion: v1 kind: Service metadata: namespace: aic name: healthy-httpbin spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: unhealthy-httpbin spec: type: ExternalName externalName: example.com --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: prometheus-route spec: ingressClassName: apisix http: - name: prometheus-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: prometheus enable: true config: {} ``` 将配置应用到集群: ``` kubectl apply -f prometheus-health-ic.yaml ``` 向 APISIX Prometheus 指标端点发送请求: ``` curl "http://127.0.0.1:9091/apisix/prometheus/metrics" ``` 你应该看到类似于以下的输出: ``` # HELP apisix_upstream_status upstream status from health check # TYPE apisix_upstream_status gauge apisix_upstream_status{name="/upstreams/",ip="",port="80"} 1 apisix_upstream_status{name="/upstreams/",ip="",port="80"} 0 ``` 在该示例输出中,一个上游节点处于健康状态,另一个上游节点处于不健康状态。 要了解有关如何配置主动和被动健康检查的更多信息,请参阅 [健康检查](https://docs.apiseven.com/apisix/how-to-guide/traffic-management/health-check.md)。 ### 为指标添加额外标签[​](#为指标添加额外标签 "为指标添加额外标签的直接链接") 以下示例展示了如何向指标添加额外标签并在标签值中使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 目前,只有以下指标支持额外标签: * `apisix_http_status` * `apisix_http_latency` * `apisix_bandwidth` 请在 Prometheus 静态配置中添加额外标签: * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` plugin_attr: prometheus: # prometheus 插件 metrics: # 使用内置变量创建额外标签。 http_status: extra_labels: # 设置 http_status 指标的额外标签。 - upstream_addr: $upstream_addr # 添加 upstream_addr 标签,其值为 NGINX 变量 $upstream_addr。 - route_name: $route_name # 添加 route_name 标签,其值为 APISIX 变量 $route_name。 ``` 重新加载网关以使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.prometheus.metrics` 的 Chart values,并保留 values 文件中的其他配置。 对于 APISIX Helm Chart,设置以下 values: values.yaml ``` apisix: pluginAttrs: prometheus: metrics: http_status: extra_labels: - upstream_addr: $upstream_addr - route_name: $route_name ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` pluginAttrs: prometheus: metrics: http_status: extra_labels: - upstream_addr: $upstream_addr - route_name: $route_name ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 请注意,如果你在标签值中定义了一个变量,但它不对应任何现有的 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md),则标签值将默认为空字符串。 创建一个带有 `prometheus` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "prometheus-route", "uri": "/get", "name": "extra-label", "plugins": { "prometheus": {} }, "upstream": { "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: extra-label plugins: prometheus: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD prometheus-labels-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: prometheus-plugin-config spec: plugins: - name: prometheus config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: prometheus-route spec: parentRefs: - name: apisix hostnames: - "prometheus.example.com" rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: prometheus-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` prometheus-labels-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: prometheus-route spec: ingressClassName: apisix http: - name: prometheus-route match: hosts: - "prometheus.example.com" paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: prometheus enable: true config: {} ``` 将配置应用到集群: ``` kubectl apply -f prometheus-labels-ic.yaml ``` 发送请求到该路由以进行验证: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该看到 `HTTP/1.1 200 OK` 响应。 向 APISIX Prometheus 指标端点发送请求: ``` curl "http://127.0.0.1:9091/apisix/prometheus/metrics" ``` 你应该看到类似于以下的输出: ``` # HELP apisix_http_status HTTP status codes per service in APISIX # TYPE apisix_http_status counter apisix_http_status{code="200",route="1",matched_uri="/get",matched_host="",service="",consumer="",node="54.237.103.220",request_type="traditional_http",request_llm_model="",llm_model="",response_source="upstream",upstream_addr="54.237.103.220:80",route_name="extra-label"} 1 ``` ### 使用 Prometheus 监控 TCP/UDP 流量[​](#使用-prometheus-监控-tcpudp-流量 "使用 Prometheus 监控 TCP/UDP 流量的直接链接") 以下示例展示了如何在 APISIX 中收集 TCP/UDP 流量指标。 如需收集 TCP/UDP 指标,请启用 stream proxy,并将 `prometheus` 添加到现有 stream 插件列表中。请保留部署使用的其他 stream 插件;以下主机/Docker 示例展示了本教程所需的最小列表。 * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` apisix: proxy_mode: http&stream # 同时启用 L4 和 L7 代理 stream_proxy: # 配置 L4 代理 tcp: - 9100 # 设置 TCP 代理监听端口 udp: - 9200 # 设置 UDP 代理监听端口 stream_plugins: - prometheus # 为 stream proxy 启用 prometheus ``` 重新加载网关以使更改生效。 对于 APISIX Helm Chart,请配置 stream listener,并包含希望网关加载的完整 stream plugin 列表。以下示例保留默认 stream plugins 并加入 `prometheus`: values.yaml ``` service: stream: enabled: true tcp: - 9100 udp: - 9200 apisix: stream_plugins: - ip-restriction - limit-conn - mqtt-proxy - prometheus - syslog ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` gateway: stream: enabled: true tcp: - addr: 9100 udp: - addr: 9200 ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 在 API7 企业版中,stream 插件列表由控制面下发,因此上面的 values 已经足够,其它部署形态中展示的 `stream_plugins` 配置项在这里不需要。 创建一个启用了 `prometheus` 插件的[流路由](https://docs.apiseven.com/apisix/key-concepts/stream-routes.md): ``` curl "http://127.0.0.1:9180/apisix/admin/stream_routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "prometheus-route", "plugins": { "prometheus":{} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 发送请求到该流路由以进行验证: ``` curl -i "http://127.0.0.1:9100" ``` 你应该看到 `HTTP/1.1 200 OK` 响应。 向 APISIX Prometheus 指标端点发送请求: ``` curl "http://127.0.0.1:9091/apisix/prometheus/metrics" ``` 你应该看到类似于以下的输出: ``` # HELP apisix_stream_connection_total Total number of connections handled per stream route in APISIX # TYPE apisix_stream_connection_total counter apisix_stream_connection_total{route="prometheus-route"} 1 ``` APISIX 还会导出终止状态。如果 APISIX-Runtime 提供 stream-metrics 模块,抓取结果还会包含活动连接和带宽: ``` # HELP apisix_stream_active_connections Number of stream sessions currently being proxied per listening address # TYPE apisix_stream_active_connections gauge apisix_stream_active_connections{listen_addr="0.0.0.0:9100"} 0 # HELP apisix_stream_status Stream sessions per termination status in APISIX # TYPE apisix_stream_status counter apisix_stream_status{code="200",listen_addr="0.0.0.0:9100",node="54.237.103.220:80"} 1 # HELP apisix_stream_bandwidth Total bandwidth in bytes proxied by the stream subsystem in APISIX # TYPE apisix_stream_bandwidth counter apisix_stream_bandwidth{listen_addr="0.0.0.0:9100",type="ingress",side="downstream"} 78 apisix_stream_bandwidth{listen_addr="0.0.0.0:9100",type="egress",side="downstream"} 219 apisix_stream_bandwidth{listen_addr="0.0.0.0:9100",type="egress",side="upstream"} 78 apisix_stream_bandwidth{listen_addr="0.0.0.0:9100",type="ingress",side="upstream"} 219 ``` 具体上游地址和字节数取决于请求。上例中的活动连接 gauge 为 `0`,因为请求在抓取前已完成;请在连接保持打开时进行抓取,以观察正值。 活动连接和带宽指标使用默认大小为 `1m` 的共享内存区域。当网关暴露大量 stream 监听地址时,请增大该区域: config.yaml ``` nginx_config: stream: metrics_zone_size: 2m ``` 更改区域大小后,请重新加载 APISIX。在没有 stream-metrics 模块的运行时中,APISIX 会继续导出连接总数和状态指标,但不会发布活动连接或带宽指标。 --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 默认情况下,[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中已预先配置 `prometheus`。 提示词和补全 Token 直方图默认使用 `1`、`10`、`50`、`100`、`200`、`500`、`1000`、`2000`、`5000`、`10000`、`20000`、`50000`、`100000`、`200000`、`500000` 和 `1000000` 个 Token 作为桶边界。如果其他边界更适合实际工作负载,请配置 `llm_prompt_tokens_buckets` 和 `llm_completion_tokens_buckets`。 需要更新的文件取决于网关的部署方式: * Host or Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` plugin_attr: prometheus: # prometheus 插件属性 export_uri: /apisix/prometheus/metrics # 设置 Prometheus 指标端点的 URI。 metric_prefix: apisix_ # 设置 APISIX 生成的 Prometheus 指标前缀。 enable_export_server: true # 启用 Prometheus 导出服务器。 export_addr: # 设置 Prometheus 导出服务器的地址。 ip: 127.0.0.1 # 设置 IP 地址。 port: 9091 # 设置端口。 refresh_interval: 15 # 仅在 APISIX 中可用。 # 设置刷新缓存指标数据的时间间隔(秒)。 fetch_metric_timeout: 5 # 仅在 API7 企业版中可用。 # 获取指标的超时时间(秒)。超时后,API 仅返回基本指标, # 包括 nginx_http_current_connections、http_requests_total、 # etcd_reachable、prometheus_disable、node_info、etcd_modify_indexes、 # shared_dict_capacity_bytes 和 shared_dict_free_space_bytes。 allow_degradation: false # 仅在 API7 企业版中可用。 # 如果为 true,则允许在共享内存不足时降级。 degradation_pause_steps: [ 60 ] # 仅在 API7 企业版中可用。 # 插件处于降级状态并回收其占用的共享内存时, # 跳过插件执行的时间(秒)。 # metrics: # 为指标创建额外标签。 # http_status: # 这些指标将以 `apisix_` 为前缀。 # extra_labels: # 设置 http_status 指标的额外标签。 # - upstream_addr: $upstream_addr # - status: $upstream_status # expire: 0 # 指标的过期时间(秒)。 # 0 表示指标不会过期。 # http_latency: # extra_labels: # 设置 http_latency 指标的额外标签。 # - upstream_addr: $upstream_addr # expire: 0 # 指标的过期时间(秒)。 # 0 表示指标不会过期。 # bandwidth: # extra_labels: # 设置 bandwidth 指标的额外标签。 # - upstream_addr: $upstream_addr # expire: 0 # 指标的过期时间(秒)。 # 0 表示指标不会过期。 # default_buckets: # 省略此键时,内置 `http_latency` 直方图默认使用以下毫秒桶。 # 仅在需要覆盖默认值时取消下列列表的注释。 # - 1 # - 2 # - 5 # - 10 # - 20 # - 50 # - 100 # - 200 # - 500 # - 1000 # - 2000 # - 5000 # - 10000 # - 30000 # - 60000 # llm_latency_buckets: # 设置 `apisix_llm_latency` 的毫秒桶。 # # 自 API7 企业版 3.9.7 和 APISIX 3.17.0 起引入。 # # 同时适用于 `type=total` 和 `type=ttft`。 # # 自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。 # - 100 # - 500 # - 1000 # - 5000 # llm_prompt_tokens_buckets: # 自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。 # # 设置 `apisix_llm_prompt_tokens_dist` 直方图的桶,单位为 Token。 # - 100 # - 1000 # - 10000 # llm_completion_tokens_buckets: # 自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。 # # 设置 `apisix_llm_completion_tokens_dist` 直方图的桶,单位为 Token。 # - 100 # - 1000 # - 10000 ``` 然后重新加载网关,使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.prometheus` 的 Chart values,并保持 values 文件中的其他配置不变。 对于 APISIX Helm Chart,请设置以下 values: values.yaml ``` apisix: pluginAttrs: prometheus: export_uri: /apisix/prometheus/metrics metric_prefix: apisix_ enable_export_server: true export_addr: ip: 127.0.0.1 port: 9091 refresh_interval: 15 # 在此添加其余 prometheus plugin_attr 字段。 ``` 对于 API7 网关 Helm Chart,请设置以下 values: values.yaml ``` pluginAttrs: prometheus: export_uri: /apisix/prometheus/metrics metric_prefix: apisix_ enable_export_server: true export_addr: ip: 127.0.0.1 port: 9091 fetch_metric_timeout: 5 allow_degradation: false degradation_pause_steps: [ 60 ] # 在此添加其余 prometheus plugin_attr 字段。 ``` 然后使用当前网关版本对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 你可以使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)创建 `extra_labels`。有关更多信息,请参阅[为指标添加额外标签](https://docs.apiseven.com/hub/prometheus.md#%E4%B8%BA%E6%8C%87%E6%A0%87%E6%B7%BB%E5%8A%A0%E9%A2%9D%E5%A4%96%E6%A0%87%E7%AD%BE)。 ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * prefer\_name boolean 默认值:`false` *** 如果为 true,则在 Prometheus 指标中导出路由/服务名称而不是其 ID。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") APISIX 和 API7 企业版都支持插件元数据。下表说明了可用字段、元数据键和版本边界。 插件元数据通过 Admin API 或声明式配置进行设置。它与在 `config.yaml` 中渲染 `plugin_attr` 的 Helm values 相互独立。 * disabled\_labels object *** 要禁用的标签,用于减少指标数量并防止资源瓶颈。APISIX 使用 `http_status` 和 `http_latency` 作为对应指标的元数据键,而 API7 企业版使用 `status` 和 `latency`。定义指标身份的标签不能禁用,因为折叠这些标签会把不同的测量值合并到同一个时序中。这些标签包括 HTTP 状态指标的 `code`,HTTP 延迟、带宽和 LLM 延迟指标的 `type`,以及 `ai_cache_hits_total` 的 `layer`。结构标签校验自 API7 企业版 3.9.17、3.10.4 和 APISIX 3.18.0 起引入。有关各产品适用的键和标签集,请参阅[通过禁用标签降低指标基数](https://docs.apiseven.com/hub/prometheus.md#通过禁用标签降低指标基数)。 * http\_status array\[string] 有效值: `route`、`matched_uri`、`matched_host`、`service`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model` 和 `response_source` 的任意组合 *** 要为 `apisix_http_status` 禁用的标签。API7 企业版改用 `status`。自 APISIX 3.18.0 起引入。 * http\_latency array\[string] 有效值: `route`、`service`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合 *** 要为 `apisix_http_latency` 禁用的标签。API7 企业版改用 `latency`。自 APISIX 3.18.0 起引入。 * status array\[string] 有效值: `route`、`route_id`、`matched_uri`、`matched_host`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model`、`mcp_request_type` 和 `mcp_tool_name` 的任意组合 *** 要为 `apisix_http_status` 指标禁用的标签。仅在 API7 企业版中可用;APISIX 改用 `http_status`。`request_type`、`request_llm_model` 和 `llm_model` 标签自 API7 企业版 3.9.7 起引入。`mcp_request_type` 和 `mcp_tool_name` 标签自 API7 企业版 3.9.14 起引入。 * latency array\[string] 有效值: `route`、`route_id`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model`、`llm_model`、`mcp_request_type` 和 `mcp_tool_name` 的任意组合 *** 要为 `apisix_http_latency` 指标禁用的标签。仅在 API7 企业版中可用;APISIX 改用 `http_latency`。`request_type`、`request_llm_model` 和 `llm_model` 标签自 API7 企业版 3.9.7 起引入。`mcp_request_type` 和 `mcp_tool_name` 标签自 API7 企业版 3.9.14 起引入。 * bandwidth array\[string] 有效值: `APISIX`:`route`、`service`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `route_id`、`service_id`、`mcp_request_type` 和 `mcp_tool_name` *** 要为 `apisix_bandwidth` 指标禁用的标签。在 API7 企业版中可用,并自 APISIX 3.18.0 起引入。`request_type`、`request_llm_model` 和 `llm_model` 标签自 API7 企业版 3.9.7 起引入。`mcp_request_type` 和 `mcp_tool_name` 标签自 API7 企业版 3.9.14 起引入。 * stream\_status array\[string] 有效值: `node` *** 要为 `apisix_stream_status` 关闭的标签。`code` 与 `listen_addr` 决定该指标的身份,无法关闭。在 API7 企业版 3.9.x 系列中自 3.9.19 起可用,在 3.10.x 系列中自 3.10.6 起可用。 * llm\_latency array\[string] 有效值: `APISIX`:`route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `route` 和 `service` *** 要为 `apisix_llm_latency` 指标禁用的标签。自 API7 企业版 3.9.7 和 APISIX 3.18.0 起引入。 * llm\_prompt\_tokens array\[string] 有效值: `APISIX`:`route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `route`、`matched_uri`、`matched_host` 和 `service` *** 要为 `apisix_llm_prompt_tokens` 指标禁用的标签。自 API7 企业版 3.9.7 和 APISIX 3.18.0 起引入。 * llm\_completion\_tokens array\[string] 有效值: `APISIX`:`route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `route`、`matched_uri`、`matched_host` 和 `service` *** 要为 `apisix_llm_completion_tokens` 指标禁用的标签。自 API7 企业版 3.9.7 和 APISIX 3.18.0 起引入。 * llm\_active\_connections array\[string] 有效值: `route`、`route_id`、`matched_uri`、`matched_host`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合 *** 要为 `apisix_llm_active_connections` 指标禁用的标签。自 API7 企业版 3.9.7 和 APISIX 3.18.0 起引入。 * llm\_prompt\_tokens\_dist array\[string] 有效值: `APISIX`:`route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `route`、`matched_uri`、`matched_host` 和 `service` *** 要为 `apisix_llm_prompt_tokens_dist` 指标禁用的标签。自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。 * llm\_completion\_tokens\_dist array\[string] 有效值: `APISIX`:`route_id`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `route`、`matched_uri`、`matched_host` 和 `service` *** 要为 `apisix_llm_completion_tokens_dist` 指标禁用的标签。自 API7 企业版 3.9.14、3.10.1 和 APISIX 3.18.0 起引入。 * ai\_cache\_hits\_total array\[string] 有效值: `APISIX`:`route`、`route_id`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `matched_uri` 和 `matched_host` *** 要为 `apisix_ai_cache_hits_total` 指标禁用的标签。`layer` 是结构性标签,不能禁用,因为折叠它会把精确匹配缓存命中和语义缓存命中合并到同一个时序中。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起引入。 * ai\_cache\_misses\_total array\[string] 有效值: `APISIX`:`route`、`route_id`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `matched_uri` 和 `matched_host` *** 要为 `apisix_ai_cache_misses_total` 指标禁用的标签。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起引入。 * ai\_cache\_bypasses\_total array\[string] 有效值: `APISIX`:`route`、`route_id`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `matched_uri` 和 `matched_host` *** 要为 `apisix_ai_cache_bypasses_total` 指标禁用的标签。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起引入。 * ai\_cache\_embedding\_latency array\[string] 有效值: `APISIX`:`route`、`route_id`、`service`、`service_id`、`consumer`、`node`、`request_type`、`request_llm_model` 和 `llm_model` 的任意组合
`API7 企业版`:`APISIX` 的有效值外加 `matched_uri` 和 `matched_host` *** 要为 `apisix_ai_cache_embedding_latency` 指标禁用的标签。自 API7 企业版 3.9.16、3.10.3 和 APISIX 3.18.0 起引入。 --- # proxy-buffering `proxy-buffering` 插件动态禁用 NGINX [`proxy_buffering`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering) 指令。 对于 [Server-Sent Events(SSE)](https://en.wikipedia.org/wiki/Server-sent_events)上游服务,以及 etcd watch 事件等以增量或分块方式返回响应的服务,应禁用缓冲。 ## 示例[​](#示例 "示例的直接链接") ### 配置 SSE 上游[​](#配置-sse-上游 "配置 SSE 上游的直接链接") 以下示例演示了如何在具有 SSE 上游服务的路由上禁用 `proxy_buffering`。 为 SSE 启动一个[示例上游服务](https://hub.docker.com/r/jmalloc/echo-server): * Docker * Kubernetes ``` docker run -d -p 8080:8080 jmalloc/echo-server ``` 为 SSE 服务器部署创建 Kubernetes 清单文件: sse-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: sse-server spec: replicas: 1 selector: matchLabels: app: sse-server template: metadata: labels: app: sse-server spec: containers: - name: echo-server image: jmalloc/echo-server ports: - containerPort: 8080 ``` 为 SSE 服务再创建一个 Kubernetes 清单文件: sse-service.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: sse-service spec: selector: app: sse-server ports: - protocol: TCP port: 8080 targetPort: 8080 type: ClusterIP ``` 应用清单: ``` kubectl apply -f sse-deployment.yaml -f sse-service.yaml ``` 创建一个指向上游的路由并配置 `proxy-buffering`: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-buffering-route", "uri": "/.sse", "plugins": { "proxy-buffering": { "disable_proxy_buffering": true } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:8080": 1 } } }' ``` adc.yaml ``` services: - name: sse-service routes: - uris: - /.sse name: proxy-buffering-route plugins: proxy-buffering: disable_proxy_buffering: true upstream: type: roundrobin nodes: - host: 127.0.0.1 port: 8080 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-buffering-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-buffering-plugin-config spec: plugins: - name: proxy-buffering config: disable_proxy_buffering: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-buffering-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /.sse filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-buffering-plugin-config backendRefs: - name: sse-service port: 8080 ``` proxy-buffering-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-buffering-route spec: ingressClassName: apisix http: - name: proxy-buffering-route match: paths: - /.sse upstreams: - serviceName: sse-service servicePort: 8080 plugins: - name: proxy-buffering config: disable_proxy_buffering: true ``` 应用配置: ``` kubectl apply -f proxy-buffering-ic.yaml ``` 向路由发送请求: ``` curl "http://127.0.0.1:9080/.sse" -H "Accept: text/event-stream" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应,并看到类似于以下的连续事件流: ``` event: server data: 162291b28f55 id: 1 event: request data: GET /.sse HTTP/1.1 data: data: Host: 127.0.0.1:9080 data: Accept: text/event-stream data: User-Agent: curl/7.74.0 data: X-Forwarded-For: 172.19.0.1 data: X-Forwarded-Host: 127.0.0.1 data: X-Forwarded-Port: 9080 data: X-Forwarded-Proto: http data: X-Real-Ip: 172.19.0.1 data: id: 2 event: time data: 2023-10-19T02:13:53Z id: 3 event: time data: 2023-10-19T02:13:54Z id: 4 event: time data: 2023-10-19T02:13:55Z id: 5 ... ``` #### (可选) 查看缓冲效果[​](#可选-查看缓冲效果 "(可选) 查看缓冲效�果的直接链接") 在本节中,如果不关闭 `proxy_buffering`,你将看到代理缓冲对 SSE 的影响。为了演示,代理缓冲区大小将调整为较大的值。 将以下代码片段添加到网关静态配置中: * 主机或 Docker * Kubernetes (Helm) config.yaml ``` nginx_config: http_configuration_snippet: | server { listen 9080; location /sse { proxy_buffering on; proxy_buffers 4 2m; } } ``` 对于 APISIX Helm Chart,请设置以下值: values.yaml ``` apisix: nginx: configurationSnippet: httpStart: | server { listen 9080; location /sse { proxy_buffering on; proxy_buffers 4 2m; } } ``` 对于 API7 网关 Helm Chart,请设置以下值: values.yaml ``` configurationSnippet: httpStart: | server { listen 9080; location /sse { proxy_buffering on; proxy_buffers 4 2m; } } ``` 然后使用当前网关版本对应的 Chart 应用该 values 文件: ``` helm upgrade -n -f values.yaml ``` ❶ 虽然显式配置,但 `proxy_buffering` [默认](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering)为 `on`。 ❷ 配置 `proxy_buffers` 使用 4 个缓冲区,每个缓冲区大小为 2 MB。 重新加载网关以使更改生效。 重新创建不带 `proxy-buffering` 的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-buffering-route", "uri": "/.sse", "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:8080": 1 } } }' ``` adc.yaml ``` services: - name: sse-service routes: - uris: - /.sse name: proxy-buffering-route upstream: type: roundrobin nodes: - host: 127.0.0.1 port: 8080 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-buffering-ic.yaml ``` apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-buffering-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /.sse backendRefs: - name: sse-service port: 8080 ``` proxy-buffering-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-buffering-route spec: ingressClassName: apisix http: - name: proxy-buffering-route match: paths: - /.sse upstreams: - serviceName: sse-service servicePort: 8080 ``` 应用配置: ``` kubectl apply -f proxy-buffering-ic.yaml ``` 向路由发送请求: ``` curl "http://127.0.0.1:9080/.sse" -H "Accept: text/event-stream" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应并看到相同的事件流。但是,请注意,由于缓冲的影响,事件不会定期收到,这在处理 SSE 上游时是不希望出现的。 --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * disable\_proxy\_buffering boolean 默认值:`false` *** 如果为 true,则将 NGINX `proxy_buffering` 指令设置为 `off`。 --- # proxy-cache `proxy-cache` 插件提供了根据缓存键缓存响应的功能。该插件支持基于磁盘和基于内存的缓存选项,可缓存 [GET](https://anything.org/learn/serving-over-http/#get-request)、[POST](https://anything.org/learn/serving-over-http/#post-request) 和 [HEAD](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) 请求。 可以根据请求 HTTP 方法、响应状态码、请求头值等条件有选择地缓存响应。 默认情况下,已认证消费者使用相互隔离的有效缓存键。该隔离行为自 API7 企业版 3.9.13 和 APISIX 3.17.0 起提供。除非启用 `cache_set_cookie`,否则内存缓存策略不会缓存包含 `Set-Cookie` 的响应;对于上游标记为 `private`、`no-store` 或 `no-cache` 的响应则一律不缓存。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `proxy-cache`。 ### 在磁盘上缓存数据[​](#在磁盘上缓存数据 "在磁盘上缓存数据的直接链接") 与内存缓存相比,磁盘缓存策略具有系统重启时数据持久化和存储容量更大的优点。它适用于优先考虑持久性并且可以容忍稍大的缓存访问延迟的应用程序。 以下示例演示了如何在路由上使用 `proxy-cache` 插件将数据缓存在磁盘上。 使用磁盘缓存策略时,缓存 TTL 由 `Expires` 或 `Cache-Control` 响应头决定。如果两个响应头均不存在,或者 APISIX 因上游不可用而返回 `502 Bad Gateway` 或 `504 Gateway Timeout`,缓存 TTL 将使用[配置文件](https://docs.apiseven.com/hub/proxy-cache/configuration.md#%E9%9D%99%E6%80%81%E9%85%8D%E7%BD%AE)中配置的默认值。 创建一个使用 `proxy-cache` 插件的路由以在磁盘上缓存数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-cache-route", "uri": "/anything", "plugins": { "proxy-cache": { "cache_strategy": "disk" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: proxy-cache-service routes: - name: proxy-cache-route uris: - /anything plugins: proxy-cache: cache_strategy: disk upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-cache-plugin-config spec: plugins: - name: proxy-cache config: cache_strategy: disk --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-cache-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-cache-route spec: ingressClassName: apisix http: - name: proxy-cache-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: proxy-cache enable: true config: cache_strategy: disk ``` 将配置应用到集群: ``` kubectl apply -f proxy-cache-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明插件已成功启用: ``` Apisix-Cache-Status: MISS ``` 由于第一个响应之前没有可用缓存,因此显示 `Apisix-Cache-Status: MISS`。 在缓存 TTL 窗口内再次发送相同的请求。你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明缓存命中: ``` Apisix-Cache-Status: HIT ``` 等待缓存超过 TTL 后过期,然后再次发送相同的请求。你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明缓存已过期: ``` Apisix-Cache-Status: EXPIRED ``` ### 在内存中缓存数据[​](#在内存中缓存数据 "在内存中缓存数据的直接链接") 内存缓存策略具有访问缓存数据延迟低的优点,因为从 RAM 检索数据比从磁盘存储检索数据更快。它也适用于存储不需要长期持久化的临时数据,从而可以高效地缓存经常更改的数据。 内存缓存策略会根据上游 `Vary` 响应头列出的请求头计算不同变体,并分别缓存响应;带有 `Vary: *` 的响应不会被缓存。该行为自 API7 企业版 3.9.14、3.10.0 和 APISIX 3.17.0 起提供。 以下示例演示了如何在路由上使用 `proxy-cache` 插件将数据缓存在内存中。 创建一个使用 `proxy-cache` 的路由并将其配置为使用基于内存的缓存: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-cache-route", "uri": "/anything", "plugins": { "proxy-cache": { "cache_strategy": "memory", "cache_zone": "memory_cache", "cache_ttl": 10 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: proxy-cache-service routes: - name: proxy-cache-route uris: - /anything plugins: proxy-cache: cache_strategy: memory cache_zone: memory_cache cache_ttl: 10 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-cache-plugin-config spec: plugins: - name: proxy-cache config: cache_strategy: memory cache_zone: memory_cache cache_ttl: 10 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-cache-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-cache-route spec: ingressClassName: apisix http: - name: proxy-cache-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: proxy-cache enable: true config: cache_strategy: memory cache_zone: memory_cache cache_ttl: 10 ``` 将配置应用到集群: ``` kubectl apply -f proxy-cache-ic.yaml ``` ❶ `cache_strategy`: 设置为 `memory` 以进行内存设置。 ❷ `cache_zone`: 设置为内存缓存区域的名称。 ❸ `cache_ttl`: 将内存缓存的生存时间设置为 10 秒。 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明插件已成功启用: ``` Apisix-Cache-Status: MISS ``` 由于第一个响应之前没有可用缓存,因此显示 `Apisix-Cache-Status: MISS`。 在缓存 TTL 窗口内再次发送相同的请求。你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头,表明缓存命中: ``` Apisix-Cache-Status: HIT ``` ### 手动清除缓存[​](#手动清除缓存 "手动清除缓存的直接链接") 虽然缓存响应通常会根据 TTL 过期,但你可能需要在缓存过期前清除缓存数据。 以下示例演示了如何使用 `PURGE` 方法清除磁盘上的缓存数据。`PURGE` 也支持内存缓存;如需测试,请使用上一个示例中的内存缓存配置。 将 `PURGE` 请求发送到与缓存请求相同的路由 URI。插件为 `PURGE` 请求派生缓存键的方式与填充缓存的请求相同。请使用相同的主机、URI、查询参数以及 `cache_key` 引用的任何其他值。如果缓存键按消费者隔离,请以同一消费者身份发送请求。 `PURGE` 会删除同一有效基础缓存键下索引的所有内存 `Vary` 变体。该行为自 API7 企业版 3.9.14、3.10.0 和 APISIX 3.17.0 起提供。 创建一个将响应缓存到磁盘的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-cache-route", "uri": "/anything", "plugins": { "proxy-cache": { "cache_strategy": "disk" } }, "upstream": { "type": "roundrobin", "pass_host": "node", "scheme": "https", "nodes": { "httpbingo.org:443": 1 } } }' ``` adc.yaml ``` services: - name: proxy-cache-service routes: - name: proxy-cache-route uris: - /anything plugins: proxy-cache: cache_strategy: disk upstream: type: roundrobin pass_host: node scheme: https nodes: - host: httpbingo.org port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbingo-external-domain spec: type: ExternalName externalName: httpbingo.org --- apiVersion: apisix.apache.org/v1alpha1 kind: BackendTrafficPolicy metadata: namespace: aic name: httpbingo-https spec: targetRefs: - name: httpbingo-external-domain kind: Service group: "" passHost: node scheme: https --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-cache-plugin-config spec: plugins: - name: proxy-cache config: cache_strategy: disk --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-cache-plugin-config backendRefs: - name: httpbingo-external-domain port: 443 ``` proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbingo-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbingo.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-cache-route spec: ingressClassName: apisix http: - name: proxy-cache-route match: paths: - /anything upstreams: - name: httpbingo-external-domain plugins: - name: proxy-cache enable: true config: cache_strategy: disk ``` 将配置应用到集群: ``` kubectl apply -f proxy-cache-ic.yaml ``` 发送请求以填充缓存: ``` curl -i "http://127.0.0.1:9080/anything" ``` 再次发送相同的请求,并验证响应中包含 `Apisix-Cache-Status: HIT`。 向同一 URI 发送 `PURGE` 请求: ``` curl -i "http://127.0.0.1:9080/anything" -X PURGE ``` 你应该会看到 `HTTP/1.1 200 OK` 响应,表明缓存响应已清除。如果没有与缓存键匹配的缓存响应,插件将返回 `HTTP/1.1 404 Not Found`。 再次向路由发送 `GET` 请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会看到以下响应头,表明先前的缓存响应已不可用: ``` Apisix-Cache-Status: MISS ``` ### 有条件地缓存响应[​](#有条件地缓存响应 "有条件地缓存响应的直接链接") 以下示例演示了如何配置 `proxy-cache` 插件以有条件地缓存响应。 创建一个使用 `proxy-cache` 插件的路由并配置 `no_cache` 属性: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-cache-route", "uri": "/anything", "plugins": { "proxy-cache": { "no_cache": ["$arg_no_cache", "$http_no_cache"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: proxy-cache-service routes: - name: proxy-cache-route uris: - /anything plugins: proxy-cache: no_cache: - $arg_no_cache - $http_no_cache upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-cache-plugin-config spec: plugins: - name: proxy-cache config: no_cache: - $arg_no_cache - $http_no_cache --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-cache-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-cache-route spec: ingressClassName: apisix http: - name: proxy-cache-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: proxy-cache enable: true config: no_cache: - $arg_no_cache - $http_no_cache ``` 将配置应用到集群: ``` kubectl apply -f proxy-cache-ic.yaml ``` ❶ `no_cache`: 如果 URL 参数 `no_cache` 和响应头 `no_cache` 的值中至少有一个不为空且不等于 `0`,则不会缓存响应。 使用指示缓存绕过的 URL 参数 `no_cache` 值向路由发送几个请求: ``` curl -i "http://127.0.0.1:9080/anything?no_cache=1" ``` 你应该会收到所有请求的 `HTTP/1.1 200 OK` 响应,并且每次都能观察到以下响应头: ``` Apisix-Cache-Status: EXPIRED ``` 使用 URL 参数 `no_cache` 值为零向路由发送其他几个请求: ``` curl -i "http://127.0.0.1:9080/anything?no_cache=0" ``` 你应该会收到所有请求的 `HTTP/1.1 200 OK` 响应,并开始看到缓存命中: ``` Apisix-Cache-Status: HIT ``` 你还可以按如下方式指定 `no_cache` 响应头中的值: ``` curl -i "http://127.0.0.1:9080/anything" -H "no_cache: 1" ``` 不应缓存响应: ``` Apisix-Cache-Status: EXPIRED ``` ### 有条件地从缓存检索响应[​](#有条件地从缓存检索响应 "有条件地从缓存检索响应的直接链接") 以下示例演示了如何配置 `proxy-cache` 插件以有条件地从缓存中检索响应。 创建一个使用 `proxy-cache` 插件的路由并配置 `cache_bypass` 属性: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-cache-route", "uri": "/anything", "plugins": { "proxy-cache": { "cache_bypass": ["$arg_bypass", "$http_bypass"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: proxy-cache-service routes: - name: proxy-cache-route uris: - /anything plugins: proxy-cache: cache_bypass: - $arg_bypass - $http_bypass upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-cache-plugin-config spec: plugins: - name: proxy-cache config: cache_bypass: - $arg_bypass - $http_bypass --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-cache-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-cache-route spec: ingressClassName: apisix http: - name: proxy-cache-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: proxy-cache enable: true config: cache_bypass: - $arg_bypass - $http_bypass ``` 将配置应用到集群: ``` kubectl apply -f proxy-cache-ic.yaml ``` ❶ `cache_bypass`: 如果 URL 参数 `bypass` 和响应头 `bypass` 的值中至少有一个不为空且不等于 `0`,则不会从缓存中检索响应。 使用指示缓存绕过的 URL 参数 `bypass` 值向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything?bypass=1" ``` 你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头: ``` Apisix-Cache-Status: BYPASS ``` 使用 URL 参数 `bypass` 值为零向路由发送另一个请求: ``` curl -i "http://127.0.0.1:9080/anything?bypass=0" ``` 你应该会看到 `HTTP/1.1 200 OK` 响应,并带有以下响应头: ``` Apisix-Cache-Status: MISS ``` 你还可以按如下方式指定 `bypass` 响应头中的值: ``` curl -i "http://127.0.0.1:9080/anything" -H "bypass: 1" ``` 应绕过缓存: ``` Apisix-Cache-Status: BYPASS ``` ### 缓存 502 和 504 错误响应代码[​](#缓存-502-和-504-错误响应代码 "缓存 502 和 504 错误响应代码的直接链接") 当上游服务返回 500 范围内的服务器错误时,`proxy-cache` 插件仅在返回状态为 `502 Bad Gateway` 或 `504 Gateway Timeout` 时才会缓存响应。 以下示例演示了当上游服务返回 `504 Gateway Timeout` 时 `proxy-cache` 插件的行为。 创建一个使用 `proxy-cache` 插件的路由并配置一个虚拟上游服务: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-cache-route", "uri": "/timeout", "plugins": { "proxy-cache": { } }, "upstream": { "type": "roundrobin", "nodes": { "12.34.56.78": 1 } } }' ``` adc.yaml ``` services: - name: proxy-cache-service routes: - name: proxy-cache-route uris: - /timeout plugins: proxy-cache: {} upstream: type: roundrobin nodes: - host: 12.34.56.78 port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-cache-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: dummy-upstream spec: type: ExternalName externalName: dummy.example.com --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-cache-plugin-config spec: plugins: - name: proxy-cache config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-cache-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /timeout filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-cache-plugin-config backendRefs: - name: dummy-upstream port: 80 ``` proxy-cache-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: dummy-upstream spec: ingressClassName: apisix externalNodes: - type: Domain name: dummy.example.com --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-cache-route spec: ingressClassName: apisix http: - name: proxy-cache-route match: paths: - /timeout upstreams: - name: dummy-upstream plugins: - name: proxy-cache enable: true ``` 将配置应用到集群: ``` kubectl apply -f proxy-cache-ic.yaml ``` 向路由生成几个请求: ``` seq 4 | xargs -I{} curl -I "http://127.0.0.1:9080/timeout" ``` 你应该看到类似于以下的响应: ``` HTTP/1.1 504 Gateway Time-out ... Apisix-Cache-Status: MISS HTTP/1.1 504 Gateway Time-out ... Apisix-Cache-Status: HIT HTTP/1.1 504 Gateway Time-out ... Apisix-Cache-Status: HIT HTTP/1.1 504 Gateway Time-out ... Apisix-Cache-Status: HIT ``` 但是,如果上游服务返回 `503 Service Temporarily Unavailable`,则不会缓存响应。 --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 网关[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)包含磁盘缓存和缓存区域的代理缓存设置。需要更新的文件取决于网关的部署方式: * 主机或 Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` apisix: proxy_cache: cache_ttl: 10s # 磁盘缓存使用的默认缓存 TTL;仅当响应中不包含 `Expires` # 和 `Cache-Control` 响应头,或 APISIX 因上游不可用而返回 # `502 Bad Gateway` 或 `504 Gateway Timeout` 时生效 zones: - name: disk_cache_one memory_size: 50m disk_size: 1G disk_path: /tmp/disk_cache_one cache_levels: 1:2 # - name: disk_cache_two # memory_size: 50m # disk_size: 1G # disk_path: "/tmp/disk_cache_two" # cache_levels: "1:2" - name: memory_cache memory_size: 50m ``` 然后[重新加载 APISIX](https://docs.apiseven.com/apisix/reference/apisix-cli.md#apisix-reload),使更改生效。 在 APISIX Helm Chart 2.16.0 或更高版本和 API7 Gateway Helm Chart 3.10.3 或更高版本中,请设置 `apisix.proxyCache`。 两个 Chart 都会在网关配置中将此值渲染为 `apisix.proxy_cache`: values.yaml ``` apisix: proxyCache: cacheTtl: 10s zones: - name: disk_cache_one memory_size: 50m disk_size: 1G disk_path: /tmp/disk_cache_one cache_levels: 1:2 - name: memory_cache memory_size: 50m ``` 然后使用该网关发布版本对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * cache\_strategy string 默认值:`disk` 有效值: `disk` 或 `memory` *** 缓存策略。缓存在磁盘或内存中。 * cache\_zone string 默认值:`disk_cache_one` *** 与缓存策略一起使用的缓存区域。该值应与[配置文件](https://docs.apiseven.com/hub/proxy-cache/configuration.md#静态配置)中定义的缓存区域之一匹配,并应对应于缓存策略。例如,当使用内存缓存策略时,你应该使用内存缓存区域。 * cache\_key array\[string] 默认值:`["$host", "$request_uri"]` *** 用于缓存的键。 支持值中的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)和常量字符串。变量应以 `$` 符号为前缀。 * cache\_bypass array\[string] *** 解析值的一个或多个参数,如果任何值不为空且不等于 `0`,则不会从缓存中检索响应。 支持值中的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)和常量字符串。变量应以 `$` 符号为前缀。 * cache\_method array\[string] 默认值:`["GET", "HEAD"]` 有效值: "GET"、"POST" 和 "HEAD" 方法的任意组合 *** 响应应被缓存的请求方法。 * cache\_http\_status array\[integer] 默认值:`[200, 301, 404]` 有效值: 200 到 599 之间整数值的任意组合(含边界值) *** 响应应被缓存的响应 HTTP 状态码。 * hide\_cache\_headers boolean 默认值:`false` *** 如果为 true,则隐藏 `Expires` 和 `Cache-Control` 响应头。 * cache\_control boolean 默认值:`false` *** 为 `true` 时,内存缓存策略会遵循受支持的请求 `Cache-Control` 指令,并根据上游响应的 `s-maxage`、`max-age` 或 `Expires` 计算缓存 TTL。无论该配置为何值,包含 `Cache-Control: private`、`no-store` 或 `no-cache` 的响应都不会缓存在内存中。 * no\_cache array\[string] *** 解析值的一个或多个参数,如果任何值不为空且不等于 `0`,则不会缓存响应。 支持值中的[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)和常量字符串。变量应以 `$` 符号为前缀。 * cache\_ttl integer 默认值:`300` 有效值: 大于或等于 1 *** 使用内存缓存时的缓存生存时间(TTL),单位为秒。 要调整磁盘缓存的 TTL,请更新[配置文件](https://docs.apiseven.com/hub/proxy-cache/configuration.md#静态配置)中的 `cache_ttl`。TTL 值会与从上游服务收到的响应头 [`Cache-Control`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control) 和 [`Expires`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expires) 的值共同计算。 * consumer\_isolation boolean 默认值:`true` *** 如果为 true,当请求解析出 Consumer 或远程用户时,将已认证 Consumer 身份添加到实际缓存键前。若 `cache_key` 已包含 `$consumer_name`、`$consumer_group_id`、`$remote_user` 或 `$http_authorization` 等携带身份的变量,则不会重复添加。自 API7 企业版 3.9.13 和 APISIX 3.17.0 起可用。 * cache\_set\_cookie boolean 默认值:`false` *** 如果为 true,允许内存缓存策略缓存包含 `Set-Cookie` 响应头的响应。默认情况下,此类响应不会被缓存。自 API7 企业版 3.9.13 和 APISIX 3.17.0 起可用。 * max\_resp\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** memory 缓存策略缓冲的响应体最大字节数。达到或超过该大小的响应会直接流式传输给客户端,不会被缓存。跨越阈值的数据块会在执行限制前先进入缓冲,因此瞬时内存用量可能超过配置值。此字段不适用于磁盘缓存。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 --- # proxy-mirror `proxy-mirror` 插件复制 APISIX 的入口流量并将其转发到指定的上游,而不会中断常规服务。你可以配置插件镜像所有流量或仅镜像一部分流量。该机制有利于多种用例,包括故障排除、安全检查、分析等。 请注意,APISIX 会忽略接收镜像流量的上游主机的任何响应。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何为不同场景配置 `proxy-mirror`。 ### 镜像部分流量[​](#镜像部分流量 "镜像部分流量的直接链接") 以下示例演示了如何配置 `proxy-mirror` 以将 50% 的流量镜像到路由并将其转发到另一个上游服务。 启动一个示例 NGINX 服务器以接收镜像流量: * Docker * Kubernetes ``` docker run -p 8081:80 --name nginx nginx ``` 你应该在终端会话中看到 NGINX 访问日志和错误日志。 为 NGINX 部署创建 Kubernetes 清单文件: nginx-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: namespace: aic name: nginx spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: ClusterIP ``` 将该清单应用到集群: ``` kubectl apply -f nginx-deployment.yaml ``` 打开一个新的终端会话并创建一个带有 `proxy-mirror` 的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "traffic-mirror-route", "uri": "/get", "plugins": { "proxy-mirror": { "host": "http://127.0.0.1:8081", "sample_ratio": 0.5 } }, "upstream": { "nodes": { "httpbin.org": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: proxy-mirror-service routes: - name: traffic-mirror-route uris: - /get plugins: proxy-mirror: host: "http://127.0.0.1:8081" sample_ratio: 0.5 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-mirror-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-mirror-plugin-config spec: plugins: - name: proxy-mirror config: host: "http://nginx.aic.svc" sample_ratio: 0.5 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-mirror-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-mirror-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` proxy-mirror-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-mirror-route spec: ingressClassName: apisix http: - name: traffic-mirror-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: proxy-mirror enable: true config: host: "http://nginx.aic.svc" sample_ratio: 0.5 ``` 将配置应用到集群: ``` kubectl apply -f proxy-mirror-ic.yaml ``` ❶ `host`: 配置要转发镜像流量的方案和主机地址。 ❷ `sample_ratio`: 将采样率配置为 0.5 以镜像 50% 的流量。 向该路由发送若干请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该会收到所有请求的 `HTTP/1.1 200 OK` 响应。 回到 NGINX 终端会话,你应该会看到许多访问日志条目,大约是生成的请求数的一半: ``` 172.17.0.1 - - [29/Jan/2024:23:11:01 +0000] "GET /get HTTP/1.1" 404 153 "-" "curl/7.64.1" "-" ``` 这表明 APISIX 已将请求镜像到 NGINX 服务器。在这里,HTTP 响应状态为 `404`,因为示例 NGINX 服务器未实现该路由。 ### 配置镜像超时[​](#配置镜像超时 "配置镜像超时的直接链接") 以下示例演示如何更新插件默认的连接、读取和发送超时。当镜像流量发送到响应很慢的后端服务时,这一配置非常有用。 请求镜像通过子请求实现,因此子请求延迟过高可能会阻塞原始请求。默认情况下,连接、读取和发送超时均为 60 秒。若要更改这些默认值,请配置网关静态设置: * 主机或 Docker * Kubernetes (Helm) 在网关配置文件中添加或更新以下配置: config.yaml ``` plugin_attr: proxy-mirror: timeout: connect: 2000ms read: 2000ms send: 2000ms ``` 重新加载网关以使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.proxy-mirror` 的 Chart values,并保持 values 文件的其余部分不变。 对于 APISIX Helm Chart,请设置以下值: values.yaml ``` apisix: pluginAttrs: proxy-mirror: timeout: connect: 2000ms read: 2000ms send: 2000ms ``` 对于 API7 Gateway Helm Chart,请设置以下值: values.yaml ``` pluginAttrs: proxy-mirror: timeout: connect: 2000ms read: 2000ms send: 2000ms ``` 然后使用当前网关版本对应的 Chart 应用该 values 文件: ``` helm upgrade -n -f values.yaml ``` --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 默认情况下,插件的超时值已在[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中预先配置。 需要更新的文件取决于网关的部署方式: * 主机或 Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` plugin_attr: proxy-mirror: timeout: connect: 60s read: 60s send: 60s ``` 然后重新加载网关,使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.proxy-mirror` 的 Chart values,并保持 values 文件的其余部分不变。 对于 APISIX Helm Chart,请设置以下值: values.yaml ``` apisix: pluginAttrs: proxy-mirror: timeout: connect: 60s read: 60s send: 60s ``` 对于 API7 Gateway Helm Chart,请设置以下值: values.yaml ``` pluginAttrs: proxy-mirror: timeout: connect: 60s read: 60s send: 60s ``` 然后使用该网关发布版本对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * host string 必填 *** 转发镜像流量的主机地址。该地址应包含方案但不包含路径,例如 `http://127.0.0.1:8081`。 * path string *** 镜像 HTTP 流量使用的请求路径。如果未指定,则使用当前路由 URI 路径。对于原生 gRPC 和 grpc-web 流量,该字段会被忽略,网关会保留访问阶段重写后的有效 gRPC 方法路径。 * path\_concat\_mode string 默认值:`replace` 有效值: `replace` 或 `prefix` *** 指定 `path` 时的拼接模式。设置为 `replace` 时,配置的路径替换请求路径;设置为 `prefix` 时,请求路径会追加到配置的路径后。对于原生 gRPC 和 grpc-web 流量,该字段会被忽略,网关会保留有效的 gRPC 方法路径。 * sample\_ratio number 默认值:`1` 有效值: 介于 0.00001 和 1 之间(含边界值) *** 将被镜像的请求比例。默认情况下,所有流量都会被镜像。 --- # proxy-rewrite `proxy-rewrite` 插件提供了重写 APISIX 转发到上游服务请求的选项。使用该插件,你可以修改 HTTP 方法、请求目标上游地址、请求头等。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下的路由上配置 `proxy-rewrite`。 ### 重写 Host 请求头[​](#重写-host-请求头 "重写 Host 请求头的直接链接") 以下示例演示了如何修改请求中的 `Host` 头。请注意,你不应使用 `headers.set` 来设置 `Host` 头。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "methods": ["GET"], "uri": "/headers", "plugins": { "proxy-rewrite": { "host": "myapisix.demo" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: proxy-rewrite-route methods: - GET plugins: proxy-rewrite: host: myapisix.demo upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: host: myapisix.demo --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: host: myapisix.demo ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 向 `/headers` 发送请求以检查发送到上游的所有请求头: ``` curl "http://127.0.0.1:9080/headers" ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", "Host": "myapisix.demo", "User-Agent": "curl/8.2.1", "X-Amzn-Trace-Id": "Root=1-64fef198-29da0970383150175bd2d76d", "X-Forwarded-Host": "127.0.0.1" } } ``` ### 重写 URI 并设置请求头[​](#重写-uri-并设置请求头 "重写 URI 并设置请求头的直接链接") 以下示例演示了如何重写请求上游 URI 并设置其他请求头值。如果客户端请求中存在相同的请求头,则插件中设置的相应请求头值将覆盖客户端请求中的值。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "methods": ["GET"], "uri": "/", "plugins": { "proxy-rewrite": { "uri": "/anything", "headers": { "set": { "X-Api-Version": "v1", "X-Api-Engine": "apisix" } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - / name: proxy-rewrite-route methods: - GET plugins: proxy-rewrite: uri: /anything headers: set: X-Api-Version: v1 X-Api-Engine: apisix upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: uri: /anything headers: set: X-Api-Version: v1 X-Api-Engine: apisix --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - / upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: uri: /anything headers: set: X-Api-Version: v1 X-Api-Engine: apisix ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 发送请求进行验证: ``` curl "http://127.0.0.1:9080/" -H 'X-Api-Version: v2' ``` 你应该看到类似于以下的响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "httpbin.org", "User-Agent": "curl/8.2.1", "X-Amzn-Trace-Id": "Root=1-64fed73a-59cd3bd640d76ab16c97f1f1", "X-Api-Engine": "apisix", "X-Api-Version": "v1", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "GET", "origin": "::1, 103.248.35.179", "url": "http://localhost/anything" } ``` 请注意,现有的请求头和请求中传递的 `X-Api-Version` 请求头值都被插件中配置的值覆盖。 ### 重写 URI 并追加请求头[​](#重写-uri-并追加请求头 "重写 URI 并追加请求头的直接链接") 以下示例演示了如何重写请求上游 URI 并追加其他请求头值。如果客户端请求中存在相同的请求头,它们的值将追加到插件中配置的请求头值之后。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "methods": ["GET"], "uri": "/", "plugins": { "proxy-rewrite": { "uri": "/headers", "headers": { "add": { "X-Api-Version": "v1", "X-Api-Engine": "apisix" } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - / name: proxy-rewrite-route methods: - GET plugins: proxy-rewrite: uri: /headers headers: add: X-Api-Version: v1 X-Api-Engine: apisix upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: uri: /headers headers: add: X-Api-Version: v1 X-Api-Engine: apisix --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - / upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: uri: /headers headers: add: X-Api-Version: v1 X-Api-Engine: apisix ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 发送请求进行验证: ``` curl "http://127.0.0.1:9080/" -H 'X-Api-Version: v2' ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", "Host": "httpbin.org", "User-Agent": "curl/8.2.1", "X-Amzn-Trace-Id": "Root=1-64fed73a-59cd3bd640d76ab16c97f1f1", "X-Api-Engine": "apisix", "X-Api-Version": "v2,v1", "X-Forwarded-Host": "127.0.0.1" } } ``` 请注意,现有的请求头和请求中传递的 `X-Api-Version` 请求头值都追加在插件中配置的值之后。 ### 删除现有请求头[​](#删除现有请求头 "删除现有请求头的直接链接") 以下示例演示了如何删除现有的请求头 `User-Agent`。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "methods": ["GET"], "uri": "/headers", "plugins": { "proxy-rewrite": { "headers": { "remove":[ "User-Agent" ] } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: proxy-rewrite-route methods: - GET plugins: proxy-rewrite: headers: remove: - User-Agent upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: headers: remove: - User-Agent --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: headers: remove: - User-Agent ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 发送请求以验证指定的请求头是否已被删除: ``` curl "http://127.0.0.1:9080/headers" ``` 你应该看到类似于以下的响应,其中 `User-Agent` 请求头不存在: ``` { "headers": { "Accept": "*/*", "Host": "httpbin.org", "X-Amzn-Trace-Id": "Root=1-64fef302-07f2b13e0eb006ba776ad91d", "X-Forwarded-Host": "127.0.0.1" } } ``` ### 使用正则表达式重写 URI[​](#使用正则表达式重写-uri "使用正则表达式重写 URI的直接链接") 以下示例演示了如何从原始上游 URI 路径中解析文本,并使用它们来组成新的上游 URI 路径。在此示例中,APISIX 配置为将所有请求从 `/test/user/agent` 转发到 `/user-agent`。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "uri": "/test/*", "plugins": { "proxy-rewrite": { "regex_uri": ["^/test/(.*)/(.*)", "/$1-$2"] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /test/* name: proxy-rewrite-route plugins: proxy-rewrite: regex_uri: - ^/test/(.*)/(.*) - /$1-$2 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: regex_uri: - ^/test/(.*)/(.*) - /$1-$2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /test/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - /test/* upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: regex_uri: - ^/test/(.*)/(.*) - /$1-$2 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 向 `/test/user/agent` 发送请求以检查是否被重定向到 `/user-agent`: ``` curl "http://127.0.0.1:9080/test/user/agent" ``` 你应该看到类似于以下的响应: ``` { "user-agent": "curl/8.2.1" } ``` ### 添加 URL 参数[​](#添加-url-参数 "添加 URL 参数的直接链接") 以下示例演示了如何向请求添加 URL 参数。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "methods": ["GET"], "uri": "/get", "plugins": { "proxy-rewrite": { "uri": "/get?arg1=apisix&arg2=plugin" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: proxy-rewrite-route methods: - GET plugins: proxy-rewrite: uri: /get?arg1=apisix&arg2=plugin upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: uri: /get?arg1=apisix&arg2=plugin --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: uri: /get?arg1=apisix&arg2=plugin ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 发送请求以验证 URL 参数是否也转发到了上游: ``` curl "http://127.0.0.1:9080/get" ``` 你应该看到类似于以下的响应: ``` { "args": { "arg1": "apisix", "arg2": "plugin" }, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.2.1", "X-Amzn-Trace-Id": "Root=1-64fef6dc-2b0e09591db7353a275cdae4", "X-Forwarded-Host": "127.0.0.1" }, "origin": "127.0.0.1, 103.248.35.148", "url": "http://127.0.0.1/get?arg1=apisix&arg2=plugin" } ``` ### 重写 HTTP 方法[​](#重写-http-方法 "重写 HTTP 方法的直接链接") 以下示例演示了如何将 GET 请求重写为 POST 请求。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "proxy-rewrite-route", "methods": ["GET"], "uri": "/get", "plugins": { "proxy-rewrite": { "uri": "/anything", "method":"POST" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: proxy-rewrite-route methods: - GET plugins: proxy-rewrite: uri: /anything method: POST upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: uri: /anything method: POST --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: proxy-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: proxy-rewrite-route spec: ingressClassName: apisix http: - name: proxy-rewrite-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: uri: /anything method: POST ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` 向 `/get` 发送 GET 请求,以验证它是否被转换为对 `/anything` 的 POST 请求: ``` curl "http://127.0.0.1:9080/get" ``` 你应该看到类似于以下的响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.2.1", "X-Amzn-Trace-Id": "Root=1-64fef7de-0c63387645353998196317f2", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "POST", "origin": "::1, 103.248.35.179", "url": "http://localhost/anything" } ``` ### 将消费者名称转发到上游[​](#将消费者名称转发到上游 "将消费者名称转发到上游的直接链接") 以下示例演示了如何将成功通过身份认证的消费者名称转发到上游服务。作为示例,你将使用 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md) 作为身份认证方法。 * Admin API * ADC * Ingress Controller 创建一个消费者 `JohnDoe`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "JohnDoe" }' ``` 为消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/JohnDoe/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 接下来,创建一个启用了密钥身份认证的路由,并配置 `proxy-rewrite` 以将消费者名称添加到请求头: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "consumer-restricted-route", "uri": "/get", "plugins": { "key-auth": {}, "proxy-rewrite": { "headers": { "set": { "X-Apisix-Consumer": "$consumer_name" }, "remove": [ "Apikey" ] } } }, "upstream" : { "nodes": { "httpbin.org":1 } } }' ``` 创建一个配置了 `key-auth` 凭证的消费者,以及一个配置了 `key-auth` 和 `proxy-rewrite` 插件的路由: adc.yaml ``` consumers: - username: JohnDoe credentials: - name: cred-john-key-auth type: key-auth config: key: john-key services: - name: httpbin routes: - name: consumer-restricted-route uris: - /get plugins: key-auth: {} proxy-rewrite: headers: set: X-Apisix-Consumer: $consumer_name remove: - Apikey upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: key-auth name: cred-john-key-auth config: key: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: proxy-rewrite config: headers: set: X-Apisix-Consumer: $consumer_name remove: - Apikey --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: consumer-restricted-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: consumer-restricted-route spec: ingressClassName: apisix http: - name: consumer-restricted-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: key-auth enable: true - name: proxy-rewrite enable: true config: headers: set: X-Apisix-Consumer: $consumer_name remove: - Apikey ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` ❶ 使用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md#apisix-%E5%8F%98%E9%87%8F)将消费者名称添加到请求头 `X-Apisix-Consumer`。 ❷ 删除身份认证密钥,使其对上游服务不可见。 作为消费者 `JohnDoe` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key' ``` 你应该收到带有以下正文的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.4.0", "X-Amzn-Trace-Id": "Root=1-664b01a6-2163c0156ed4bff51d87d877", "X-Apisix-Consumer": "JohnDoe", "X-Forwarded-Host": "127.0.0.1" }, "origin": "172.19.0.1, 203.12.12.12", "url": "http://127.0.0.1/get" } ``` 信息 使用 Ingress Controller 时,消费者名称会带有命名空间前缀。例如,`aic` 命名空间中名为 `JohnDoe` 的消费者会在 `X-Apisix-Consumer` 请求头中显示为 `aic_johndoe`。 向路由发送另一个不带有效凭证的请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该收到 `HTTP/1.1 401 Unauthorized` 响应。 ### 在 `radixtree_uri_with_parameter` 路由模式下动态转发请求[​](#在-radixtree_uri_with_parameter-路由模式下动态转发请求 "在-radixtree_uri_with_parameter-路由模式下动态转发请求的直接链接") 以下示例演示了如何使用 `uri_param_*` 变量提取 URL 路径的一部分,并将该值作为新请求头转发到上游服务。此示例假设 APISIX 运行在 `radixtree_uri_with_parameter` [路由模式](https://docs.apiseven.com/apisix/reference/router-options.md)下。 创建如下路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "httpbin", "uri": "/anything/user/:user_id/profile", "plugins":{ "proxy-rewrite": { "headers": { "set": { "X-User-ID": "$uri_param_user_id" } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: httpbin uris: - /anything/user/:user_id/profile plugins: proxy-rewrite: headers: set: X-User-ID: $uri_param_user_id upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD proxy-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: proxy-rewrite-plugin-config spec: plugins: - name: proxy-rewrite config: headers: set: X-User-ID: $uri_param_user_id --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: httpbin spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything/user/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: proxy-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` proxy-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: httpbin spec: ingressClassName: apisix http: - name: httpbin match: paths: - /anything/user/*/profile upstreams: - name: httpbin-external-domain plugins: - name: proxy-rewrite enable: true config: headers: set: X-User-ID: $uri_param_user_id ``` 将配置应用到集群: ``` kubectl apply -f proxy-rewrite-ic.yaml ``` ❶ 匹配请求 `/anything/user/:user_id/profile`,其中 `user_id` 是一个参数。 ❷ 将 `user_id` 参数值分配给新请求头 `X-User-ID`。 向路由发送请求: ``` curl "http://127.0.0.1:9080/anything/user/123/profile" ``` 你应该看到以下响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-68873cf5-7248f64d19d607ea50aa9735", "X-Forwarded-Host": "127.0.0.1", "X-User-Id": "123" }, ... } ``` 路由参数也可以接受 URL 编码的字符串。例如,如果你发送如下请求: ``` curl -i "http://127.0.0.1:9080/anything/user/123%20456/profile" ``` 用户 ID 将被提取为 `123 456`: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-68873d37-7634825b20d05dee3a852cb9", "X-Forwarded-Host": "127.0.0.1", "X-User-Id": "123 456" }, ... } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)了解所有插件可用的配置选项。 * uri string *** 新的上游 URI 路径。值可以是[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * method string 有效值: `GET`、`POST`、`PUT`、`HEAD`、`DELETE`、`OPTIONS`、`MKCOL`、`COPY`、`MOVE`、`PROPFIND`、`LOCK`、`UNLOCK`、`PATCH` 或 `TRACE` *** 重写请求使用的 HTTP 方法。 * regex\_uri array\[string] *** 用于匹配客户端请求 URI 路径并组成新上游 URI 路径的正则表达式。当同时配置 `uri` 和 `regex_uri` 时,`uri` 具有更高优先级。 请在扁平数组中提供一对或多对值。奇数位置的元素是匹配模式,偶数位置的元素是替换值。插件会按顺序计算各组值,并应用第一个匹配项。 例如,使用 `["^/test/(.*)/(.*)", "/$1-$2", "^/other/(.*)", "/other"]` 时,对 `/test/user/agent` 的请求会重写为 `/user-agent`,对 `/other/hello` 的请求会重写为 `/other`。 * set\_ngx\_uri boolean 默认值:`false` *** 该参数目前仅在 API7 企业版中可用,并将很快更新到 APISIX。 如果为 false,`ngx.var.uri` 的值将保持不变,保留原始路由 `uri`。如果为 true,`ngx.var.uri` 将更新为 `proxy-rewrite` 中指定的 `uri` 值。 * host string *** 设置 [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host) 请求头。 * headers object *** 要执行的请求头动作。可以设置为动作动词 `add`、`remove` 和/或 `set` 的对象;或由要 `set` 的请求头组成的对象。 当配置多个动作动词时,动作按 `add`、`remove` 和 `set` 的顺序执行。 * add object *** 追加到请求的请求头。如果请求中已存在该请求头,则将追加该请求头值。请求头值可以设置为常量、一个或多个[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md),或使用 `$1-$2-$3` 等变量的 `regex_uri` 匹配结果。 请求头值也可以是数组。每个值都会独立解析,并按数组顺序追加为单独的请求头行。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 * set object *** 设置到请求的请求头。如果请求中已存在该请求头,则将覆盖该请求头值。请求头值可以设置为常量、一个或多个[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md),或使用 `$1-$2-$3` 等变量的 `regex_uri` 匹配结果。 请求头值也可以是数组。每个值都会独立解析,且该数组会按数组顺序生成单独的请求头行,并替换任何现有值。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 不应用于设置 `Host`。 * remove array\[string] *** 从请求中删除的请求头。 * use\_real\_request\_uri\_unsafe boolean 默认值:`false` *** 如果为 true,则绕过 URI 规范化并允许完整的原始请求 URI。启用此选项被认为是不安全的。 --- # public-api `public-api` 插件用于暴露内部 API 端点,使其可公开访问。该插件的主要用途之一是暴露由其他插件创建的内部端点。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `public-api`。 ### 在自定义端点暴露 Prometheus 指标[​](#在自定义端点暴露-prometheus-指标 "在自定义端点暴露 Prometheus 指标的直接链接") 以下示例演示了如何禁用默认在 `9091` 端口暴露端点的 Prometheus 导出服务器,并在 APISIX 用于监听其他客户端请求的 `9080` 端口上,通过新的公共 API 端点暴露 APISIX Prometheus 指标。 你还需要配置路由,使得内部端点 `/apisix/prometheus/metrics` 通过自定义端点暴露。 警告 如果收集的指标数量较大,该插件可能会占用大量 CPU 资源进行指标计算,并对常规请求的处理产生负面影响。 为解决此问题,APISIX 使用 [特权进程](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/process.md#enable_privileged_agent) 并将指标计算卸载到单独的进程。如果你使用配置文件中 `plugin_attr.prometheus.export_addr` 下配置的指标端点,此优化将自动应用。如果通过 `public-api` 插件暴露指标端点,则无法享受此优化。 要通过 `public-api` 暴露指标,请先禁用默认的 Prometheus 导出服务器: * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` plugin_attr: prometheus: enable_export_server: false ``` 重新加载网关以使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.prometheus` 的 Chart values,并保留 values 文件中的其他配置。 对于 APISIX Helm Chart,设置以下 values: values.yaml ``` apisix: pluginAttrs: prometheus: enable_export_server: false ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` pluginAttrs: prometheus: enable_export_server: false ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 接下来,创建一个使用 `public-api` 插件的路由,为 APISIX 指标暴露一个公共 API 端点: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "prometheus-metrics", "uri": "/prometheus_metrics", "plugins": { "public-api": { "uri": "/apisix/prometheus/metrics" } } }' ``` adc.yaml ``` services: - name: public-api-metrics-service routes: - name: prometheus-metrics uris: - /prometheus_metrics plugins: public-api: uri: /apisix/prometheus/metrics ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD public-api-ic.yaml ``` apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: prometheus-metrics spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /prometheus_metrics filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: public-api-metrics-plugin-config --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: public-api-metrics-plugin-config spec: plugins: - name: public-api config: uri: /apisix/prometheus/metrics ``` public-api-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: prometheus-metrics spec: ingressClassName: apisix http: - name: prometheus-metrics match: paths: - /prometheus_metrics plugins: - name: public-api enable: true config: uri: /apisix/prometheus/metrics ``` 应用配置: ``` kubectl apply -f public-api-ic.yaml ``` ❶ 将路由 `uri` 设置为自定义端点路径。 ❷ 将插件 `uri` 设置为要暴露的内部端点。 向自定义指标端点发送请求: ``` curl "http://127.0.0.1:9080/prometheus_metrics" ``` 你应该看到类似如下的输出: ``` # HELP apisix_http_requests_total The total number of client requests since APISIX started # TYPE apisix_http_requests_total gauge apisix_http_requests_total 1 # HELP apisix_nginx_http_current_connections Number of HTTP connections # TYPE apisix_nginx_http_current_connections gauge apisix_nginx_http_current_connections{state="accepted"} 1 apisix_nginx_http_current_connections{state="active"} 1 apisix_nginx_http_current_connections{state="handled"} 1 apisix_nginx_http_current_connections{state="reading"} 0 apisix_nginx_http_current_connections{state="waiting"} 0 apisix_nginx_http_current_connections{state="writing"} 1 ... ``` ### 暴露批量请求端点[​](#暴露批量请求端点 "暴露批量请求端点的直接链接") 以下示例演示了如何使用 `public-api` 插件为 `batch-requests` 插件暴露端点,该插件用于在向网关发送请求之前将多个请求组装成一个请求。 创建一个示例路由指向 httpbin 的 `/anything` 端点,用于验证目的: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "httpbin-anything", "uri": "/anything", "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: httpbin-anything uris: - /anything upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD public-api-httpbin-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: httpbin-anything spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything backendRefs: - name: httpbin-external-domain port: 80 ``` public-api-httpbin-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: httpbin-anything spec: ingressClassName: apisix http: - name: httpbin-anything match: paths: - /anything upstreams: - name: httpbin-external-domain ``` 应用配置: ``` kubectl apply -f public-api-httpbin-ic.yaml ``` 创建一个使用 `public-api` 插件的路由,并将路由 `uri` 设置为要暴露的内部端点: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "batch-requests", "uri": "/apisix/batch-requests", "plugins": { "public-api": {} } }' ``` adc.yaml ``` services: - name: public-api-batch-service routes: - name: batch-requests uris: - /apisix/batch-requests plugins: public-api: {} ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD public-api-batch-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: public-api-batch-plugin-config spec: plugins: - name: public-api config: {} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: batch-requests spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /apisix/batch-requests filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: public-api-batch-plugin-config ``` public-api-batch-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: batch-requests spec: ingressClassName: apisix http: - name: batch-requests match: paths: - /apisix/batch-requests plugins: - name: public-api enable: true ``` 应用配置: ``` kubectl apply -f public-api-batch-ic.yaml ``` 向暴露的批量请求端点发送一个由 GET 和 POST 请求组成的管道请求: ``` curl "http://127.0.0.1:9080/apisix/batch-requests" -X POST -d ' { "pipeline": [ { "method": "GET", "path": "/anything" }, { "method": "POST", "path": "/anything", "body": "a post request" } ] }' ``` 你应该会收到两个请求的响应,类似如下: ``` [ { "reason": "OK", "body": "{\n \"args\": {}, \n \"data\": \"\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-5a30174f5534287928c54ca9\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"GET\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n", "headers": { ... }, "status": 200 }, { "reason": "OK", "body": "{\n \"args\": {}, \n \"data\": \"a post request\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Content-Length\": \"14\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-0eddcec07f154dac0d77876f\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"POST\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n", "headers": { ... }, "status": 200 } ] ``` 如果你想在自定义端点暴露批量请求端点,可以如下创建带有 `public-api` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "batch-requests", "uri": "/batch-requests", "plugins": { "public-api": { "uri": "/apisix/batch-requests" } } }' ``` adc.yaml ``` services: - name: public-api-batch-service routes: - name: batch-requests uris: - /batch-requests plugins: public-api: uri: /apisix/batch-requests ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD public-api-batch-ic.yaml ``` apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: batch-requests spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /batch-requests filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: public-api-batch-plugin-config --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: public-api-batch-plugin-config spec: plugins: - name: public-api config: uri: /apisix/batch-requests ``` public-api-batch-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: batch-requests spec: ingressClassName: apisix http: - name: batch-requests match: paths: - /batch-requests plugins: - name: public-api enable: true config: uri: /apisix/batch-requests ``` 应用配置: ``` kubectl apply -f public-api-batch-ic.yaml ``` ❶ 将路由 `uri` 设置为自定义端点路径。 ❷ 将插件 `uri` 设置为要暴露的内部端点。 现在批量请求端点应该暴露为 `/batch-requests`,而不是 `/apisix/batch-requests`。 向暴露的批量请求端点发送一个由 GET 和 POST 请求组成的管道请求: ``` curl "http://127.0.0.1:9080/batch-requests" -X POST -d ' { "pipeline": [ { "method": "GET", "path": "/anything" }, { "method": "POST", "path": "/anything", "body": "a post request" } ] }' ``` 你应该会收到两个请求的响应,类似如下: ``` [ { "reason": "OK", "body": "{\n \"args\": {}, \n \"data\": \"\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-5a30174f5534287928c54ca9\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"GET\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n", "headers": { ... }, "status": 200 }, { "reason": "OK", "body": "{\n \"args\": {}, \n \"data\": \"a post request\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Content-Length\": \"14\", \n \"Host\": \"127.0.0.1\", \n \"User-Agent\": \"curl/8.6.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-67b6e33b-0eddcec07f154dac0d77876f\", \n \"X-Forwarded-Host\": \"127.0.0.1\"\n }, \n \"json\": null, \n \"method\": \"POST\", \n \"origin\": \"192.168.107.1, 43.252.208.84\", \n \"url\": \"http://127.0.0.1/anything\"\n}\n", "headers": { ... }, "status": 200 } ] ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * uri string *** 要暴露的内部端点。如果未配置,则暴露路由URI。 --- # real-ip `real-ip` 插件允许 APISIX 通过 HTTP 请求头或 HTTP 查询字符串中传递的 IP 地址来设置客户端的真实 IP。当 APISIX 位于反向代理之后时,这特别有用,因为否则代理可能会充当请求发起客户端。 该插件的功能类似于 NGINX 的 [ngx\_http\_realip\_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html),但提供了更大的灵活性。 ## 信任转发的客户端信息[​](#信任转发的客户端信息 "信任转发的客户端信息的直接链接") 以下两项信任设置分别作用于不同范围: * 全局配置 `apisix.trusted_addresses` 用于标识直接连接到网关的可信反向代理。网关可以保留这些代理提供的 `Forwarded` 和 `X-Forwarded-*` 请求头;OpenID Connect 重定向 URI 的自动构建等功能,也只会对来自这些地址的请求使用转发的协议、主机和端口。此设置本身不会重写网关识别的客户端 IP。 * 插件字段 `trusted_addresses` 用于限制哪些直接对等端可以在路由上提供 `source` 所指定的值。对等端受信任时,插件会使用该来源重写网关识别的客户端 IP。 只应配置你所管理的代理地址。信任任意地址会允许客户端伪造其表面上的 IP 地址、协议、主机或端口。当对等端未通过适用的信任检查时,网关会保留直接连接地址,并替换或清除不受信任的转发来源请求头。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了如何在不同场景下配置 `real-ip`。 ### 从 URI 参数获取真实客户端地址[​](#从-uri-参数获取真实客户端地址 "从 URI 参数获取真实客户端地址的直接链接") 以下示例展示了如何使用 URI 参数更新客户端 IP 地址。 创建一个路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "real-ip-route", "uri": "/get", "plugins": { "real-ip": { "source": "arg_realip", "trusted_addresses": ["127.0.0.0/24"] }, "response-rewrite": { "headers": { "remote_addr": "$remote_addr", "remote_port": "$remote_port" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: real-ip-route uris: - /get plugins: real-ip: source: arg_realip trusted_addresses: - 127.0.0.0/24 response-rewrite: headers: remote_addr: $remote_addr remote_port: $remote_port upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD real-ip-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: real-ip-plugin-config spec: plugins: - name: real-ip config: source: arg_realip trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: headers: remote_addr: $remote_addr remote_port: $remote_port --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: real-ip-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: real-ip-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` real-ip-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: real-ip-route spec: ingressClassName: apisix http: - name: real-ip-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: real-ip config: source: arg_realip trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: headers: remote_addr: $remote_addr remote_port: $remote_port ``` 应用配置: ``` kubectl apply -f real-ip-ic.yaml ``` ❶ 配置 `source` 以使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 从 URL 参数 `realip` 获取值。 ❷ 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 和端口是否实际已更新。 在 URL 参数中带上真实 IP 和端口发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/get?realip=1.2.3.4:9080" ``` 你应该看到响应包含以下请求头: ``` remote_addr: 1.2.3.4 remote_port: 9080 ``` ### 从请求头获取真实客户端地址[​](#从请求头获取真实客户端地址 "从请求头获取真实客户端地址的直接链接") 以下示例展示了当 APISIX 位于反向代理(如负载均衡器)之后时,如果代理在 [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) 请求头中暴露了真实客户端 IP,如何设置真实客户端 IP。 创建一个路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "real-ip-route", "uri": "/get", "plugins": { "real-ip": { "source": "http_x_forwarded_for", "trusted_addresses": ["127.0.0.0/24"] }, "response-rewrite": { "headers": { "remote_addr": "$remote_addr" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: real-ip-route uris: - /get plugins: real-ip: source: http_x_forwarded_for trusted_addresses: - 127.0.0.0/24 response-rewrite: headers: remote_addr: $remote_addr upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD real-ip-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: real-ip-plugin-config spec: plugins: - name: real-ip config: source: http_x_forwarded_for trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: headers: remote_addr: $remote_addr --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: real-ip-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: real-ip-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` real-ip-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: real-ip-route spec: ingressClassName: apisix http: - name: real-ip-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: real-ip config: source: http_x_forwarded_for trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: headers: remote_addr: $remote_addr ``` 应用配置: ``` kubectl apply -f real-ip-ic.yaml ``` ❶ 配置 `source` 以使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 从请求头 `X-Forwarded-For` 获取值。 ❷ 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际已更新。 发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/get" \ -H "X-Forwarded-For: 10.26.3.19" ``` 你应该看到包含以下请求头的响应: ``` remote_addr: 10.26.3.19 ``` IP 地址应对应于请求发起客户端的 IP 地址。 ### 从多层代理后获取真实客户端地址[​](#从多层代理后获取真实客户端地址 "从多层代理后获取真实客户端地址的直接链接") 以下示例展示了当 APISIX 位于多层代理之后时,如何获取真实客户端 IP,这会导致 [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) 请求头包含代理 IP 地址列表。 创建一个路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "real-ip-route", "uri": "/get", "plugins": { "real-ip": { "source": "http_x_forwarded_for", "recursive": true, "trusted_addresses": ["192.128.0.0/16", "127.0.0.1/32"] }, "response-rewrite": { "headers": { "remote_addr": "$remote_addr" } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: real-ip-route uris: - /get plugins: real-ip: source: http_x_forwarded_for recursive: true trusted_addresses: - 192.128.0.0/16 - 127.0.0.1/32 response-rewrite: headers: remote_addr: $remote_addr upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD real-ip-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: real-ip-plugin-config spec: plugins: - name: real-ip config: source: http_x_forwarded_for recursive: true trusted_addresses: - 192.128.0.0/16 - 127.0.0.1/32 - name: response-rewrite config: headers: remote_addr: $remote_addr --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: real-ip-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: real-ip-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` real-ip-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: real-ip-route spec: ingressClassName: apisix http: - name: real-ip-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: real-ip config: source: http_x_forwarded_for recursive: true trusted_addresses: - 192.128.0.0/16 - 127.0.0.1/32 - name: response-rewrite config: headers: remote_addr: $remote_addr ``` 应用配置: ``` kubectl apply -f real-ip-ic.yaml ``` ❶ 配置 `source` 以使用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 从请求头 `X-Forwarded-For` 获取值。 ❷ 将 `recursive` 设置为 `true`,以便将与受信任地址之一匹配的原始客户端地址替换为配置的 `source` 中发送的最后一个非受信任地址。 ❸ 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际已更新。 发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/get" \ -H "X-Forwarded-For: 127.0.0.2, 192.128.1.1, 127.0.0.1" ``` 你应该看到包含以下请求头的响应: ``` remote_addr: 127.0.0.2 ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * source string 必填 *** 一个 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md),例如 `http_x_forwarded_for` 或 `arg_realip`。变量值应为代表客户端真实 IP 地址的有效 IP 地址,可选择带有端口。 * trusted\_addresses array\[string] 有效值: IPv4 或 IPv6 地址数组(支持 CIDR 表示法) *** 已知会发送正确替换地址的受信任地址。此配置设置 [`set_real_ip_from`](https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from) 指令。 * recursive boolean 默认值:`false` *** 如果为 false,则将与受信任地址之一匹配的原始客户端地址替换为配置的 `source` 中发送的最后一个地址。 如果为 true,则将与受信任地址之一匹配的原始客户端地址替换为配置的 `source` 中发送的最后一个非受信任地址。 --- # request-id `request-id` 插件为通过网关代理的每个请求分配唯一 ID,可用于请求追踪和调试。如果请求中已通过 `header_name` 指定的请求头包含 ID,插件会使用该值,而不生成新 ID。 默认情况下,网关日志中会包含请求 ID。启用该插件后,请求 ID 还会添加到响应头中。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `request-id` 插件。 ### 了解网关日志中的请求 ID[​](#了解网关日志中的请求-id "了解网关日志中的请求 ID的直接链接") 从 Apache APISIX 3.15.0 和 API7 企业版 3.3.0 起,无论是否启用该插件,访问日志和错误日志中都会包含请求 ID。 * 禁用该插件时,请求 ID 默认为 Nginx 内置的 `$request_id`。 * 启用该插件时,请求 ID 设置为插件生成的唯一 ID。 这可确保请求追踪始终可用,并在启用插件后提供增强功能。 以下示例演示了禁用和启用插件时,请求 ID 在网关日志中的显示方式。 创建一条未配置 `request-id` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-id-service routes: - name: request-id-route uris: - /anything upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything backendRefs: - name: httpbin-external-domain port: 80 ``` request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain ``` 将配置应用到集群: ``` kubectl apply -f request-id-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。在网关日志中,你应该会看到类似以下的条目,其中最后一个值是 NGINX 内置 `$request_id` 生成的请求 ID: ``` 192.168.215.1 - - [30/Jan/2026:07:21:31 +0000] localhost:9080 "GET /anything HTTP/1.1" 200 391 1.657 "-" "curl/8.6.0" 3.210.41.225:80 200 1.608 "http://localhost:9080" "8a14012e5d0414aff4f15f04b0bd8cb9" ``` 更新路由并配置 `request-id` 插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "plugins": { "request-id": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-id-service routes: - name: request-id-route uris: - /anything plugins: request-id: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-id-plugin-config spec: plugins: - name: request-id config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-id-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: request-id enable: true ``` 将配置应用到集群: ``` kubectl apply -f request-id-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。在网关日志中,你应该会看到类似以下的条目,其中最后一个值是插件生成的请求 ID: ``` 192.168.215.1 - - [30/Jan/2026:07:36:24 +0000] localhost:9080 "GET /anything HTTP/1.1" 200 391 0.685 "-" "curl/8.6.0" 52.20.30.6:80 200 0.653 "http://localhost:9080" "8c0ac818-f9d6-4160-be60-8fc74e76be73" ``` ### 将请求 ID 附加到默认响应头[​](#将请求-id-附加到默认响应头 "将请求 ID 附加到默认响应头的直接链接") 以下示例展示了如何在路由上配置 `request-id`,如果请求中未传递请求 ID,则生成一个请求 ID 并将其附加到默认的 `X-Request-Id` 响应头中。当请求中已设置 `X-Request-Id` 请求头时,插件将使用请求头中的值作为请求 ID。 使用默认配置(显式定义)在路由上创建 `request-id` 插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "plugins": { "request-id": { "header_name": "X-Request-Id", "include_in_response": true, "algorithm": "uuid" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-id-service routes: - name: request-id-route uris: - /anything plugins: request-id: header_name: X-Request-Id include_in_response: true algorithm: uuid upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-id-plugin-config spec: plugins: - name: request-id config: header_name: X-Request-Id include_in_response: true algorithm: uuid --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-id-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: request-id enable: true config: header_name: X-Request-Id include_in_response: true algorithm: uuid ``` 将配置应用到集群: ``` kubectl apply -f request-id-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并看到响应头包含带有生成 ID 的 `X-Request-Id`: ``` X-Request-Id: b9b2c0d4-d058-46fa-bafc-dd91a0ccf441 ``` 向路由发送带有自定义请求 ID 的请求: ``` curl -i "http://127.0.0.1:9080/anything" -H 'X-Request-Id: some-custom-request-id' ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并看到响应包含带有自定义请求 ID 的 `X-Request-Id` 头: ``` X-Request-Id: some-custom-request-id ``` ### 将请求 ID 附加到自定义响应头[​](#将请求-id-附加到自定义响应头 "将请求 ID 附加到自定义响应头的直接链接") 以下示例展示了如何在路由上配置 `request-id`,将生成的请求 ID 附加到指定的响应头。 创建带有 `request-id` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "plugins": { "request-id": { "header_name": "X-Req-Identifier", "include_in_response": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-id-service routes: - name: request-id-route uris: - /anything plugins: request-id: header_name: X-Req-Identifier include_in_response: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-id-plugin-config spec: plugins: - name: request-id config: header_name: X-Req-Identifier include_in_response: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-id-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: request-id enable: true config: header_name: X-Req-Identifier include_in_response: true ``` 将配置应用到集群: ``` kubectl apply -f request-id-ic.yaml ``` ❶ 定义携带请求 ID 的自定义请求头。 ❷ 在响应头中包含请求 ID。 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并看到响应包含带有生成 ID 的 `X-Req-Identifier` 头: ``` X-Req-Identifier: 1c42ff59-ee4c-4103-a980-8359f4135b21 ``` ### 在响应头中隐藏请求 ID[​](#在响应头中隐藏请求-id "在响应头中隐藏请求 ID的直接链接") 以下示例展示了如何在路由上配置 `request-id`,将生成的请求 ID 附加到指定请求头。包含请求 ID 的请求头应转发到上游服务,但不返回在响应头中。 创建带有 `request-id` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "plugins": { "request-id": { "header_name": "X-Req-Identifier", "include_in_response": false } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-id-service routes: - name: request-id-route uris: - /anything plugins: request-id: header_name: X-Req-Identifier include_in_response: false upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-id-plugin-config spec: plugins: - name: request-id config: header_name: X-Req-Identifier include_in_response: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-id-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: request-id enable: true config: header_name: X-Req-Identifier include_in_response: false ``` 将配置应用到集群: ``` kubectl apply -f request-id-ic.yaml ``` ❶ 定义携带请求 ID 的自定义请求头。 ❷ 不在响应头中包含请求 ID。 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并且在响应头中**没有**看到 `X-Req-Identifier` 头。在响应体中,你应该看到: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-6752748c-7d364f48564508db1e8c9ea8", "X-Forwarded-Host": "127.0.0.1", "X-Req-Identifier": "268092bc-15e1-4461-b277-bf7775f2856f" }, ... } ``` 这表明请求 ID 已转发到上游服务,但未在响应头中返回。 ### 生成按时间排序的 UUID v7 ID[​](#生成按时间排序的-uuid-v7-id "生成按时间排序的 UUID v7 ID的直接链接") 以下示例配置 `request-id` 生成符合 RFC 9562 的 UUID v7。毫秒时间戳和 worker 本地序列使 ID 可按字典序排序,并在单个 worker 内单调递增,但不同 worker 或网关实例之间不保证顺序协调。UUID v7 自 API7 企业版 3.9.8 和 APISIX 3.17.0 起支持。若需要生成不按时间排序的紧凑 URL 安全 ID,请将 `algorithm` 设置为 `nanoid`。 创建带有 `request-id` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "plugins": { "request-id": { "algorithm": "uuidv7" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-id-service routes: - name: request-id-route uris: - /anything plugins: request-id: algorithm: uuidv7 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-id-plugin-config spec: plugins: - name: request-id config: algorithm: uuidv7 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-id-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: request-id enable: true config: algorithm: uuidv7 ``` 将配置应用到集群: ``` kubectl apply -f request-id-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应,并看到响应中包含值为 UUID v7 的 `X-Request-Id` 响应头: ``` X-Request-Id: 0194f4d8-e8d7-7d39-8a6b-6f18f5c95b46 ``` 若要改用 `nanoid`,请在同一路由配置中将 `algorithm` 改为 `nanoid`,应用更新后再次发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 响应中的 `X-Request-Id` 应包含类似以下的紧凑 URL 安全 ID: ``` X-Request-Id: kepgHWCH2ycQ6JknQKrX2 ``` ### 在全局和路由上附加请求 ID[​](#在全局和路由上附加请求-id "在全局和路由上附加请求 ID的直接链接") 以下示例展示了如何将 `request-id` 配置为全局插件,并在路由上配置它以附加两个 ID。 * Admin API * ADC * Ingress Controller 创建一个全局规则,使用 `request-id` 插件将请求 ID 添加到自定义请求头: ``` curl -i "http://127.0.0.1:9180/apisix/admin/global_rules" -X PUT -d '{ "id": "rule-for-request-id", "plugins": { "request-id": { "header_name": "Global-Request-ID" } } }' ``` 创建一个带有 `request-id` 插件的路由,将请求 ID 添加到另一个自定义请求头: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-id-route", "uri": "/anything", "plugins": { "request-id": { "header_name": "Route-Request-ID" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 将 `request-id` 插件配置为全局规则,并在路由上配置该插件: adc.yaml ``` global_rules: - id: rule-for-request-id plugins: request-id: header_name: Global-Request-ID services: - name: request-id-service routes: - name: request-id-route uris: - /anything plugins: request-id: header_name: Route-Request-ID upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `GatewayProxy` 清单,将 `request-id` 启用为全局插件: gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 你的控制面连接配置 plugins: - name: request-id enabled: true config: header_name: Global-Request-ID ``` 创建一个带有 `request-id` 插件的路由,将请求 ID 添加到另一个自定义请求头: request-id-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-id-plugin-config spec: plugins: - name: request-id config: header_name: Route-Request-ID --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-id-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-id-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f gatewayproxy.yaml -f request-id-ic.yaml ``` 为全局 `request-id` 插件创建 Kubernetes 清单文件: global-request-id.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixGlobalRule metadata: namespace: aic name: global-request-id spec: ingressClassName: apisix plugins: - name: request-id enable: true config: header_name: Global-Request-ID ``` 创建一个带有 `request-id` 插件的路由,将请求 ID 添加到另一个自定义请求头: request-id-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-id-route spec: ingressClassName: apisix http: - name: request-id-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: request-id enable: true config: header_name: Route-Request-ID ``` 将配置应用到集群: ``` kubectl apply -f global-request-id.yaml -f request-id-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并看到响应包含以下头: ``` Global-Request-ID: 2e9b99c1-08ed-4a74-b347-49c0891b07ad Route-Request-ID: d755666b-732c-4f0e-a30e-a7a71ace4e26 ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * header\_name string 默认值:`X-Request-Id` *** 指定携带请求唯一 ID 的请求头名称。注意,如果请求在 `header_name` 指定的请求头中已携带 ID,插件将使用该请求头的值作为唯一 ID,而不会用生成的 ID 覆盖它。 * include\_in\_response boolean 默认值:`true` *** 如果为 true,则在响应头中包含生成的请求 ID,请求头名称为 `header_name` 的值。 * algorithm string 默认值:`uuid` 有效值: `uuid`、`nanoid`、`range_id`、`ksuid` 或 `uuidv7` *** 指定用于生成唯一 ID 的算法。 设置为 `uuid` 时,插件生成通用唯一标识符;设置为 `nanoid` 时,生成紧凑且 URL 安全的 ID;设置为 `range_id` 时,使用特定参数生成顺序 ID;设置为 `ksuid` 时,生成可按时间排序的全局唯一 ID。KSUID 支持自 API7 企业版 3.9.0 和 APISIX 3.14.0 起提供。设置为 `uuidv7` 时,插件生成符合 RFC 9562 的 UUID v7,其中包含毫秒时间戳、worker 本地序列和随机位。UUID v7 在单个 worker 内单调递增,但不同 worker 或网关实例之间不保证顺序协调。UUID v7 支持自 API7 企业版 3.9.8 和 APISIX 3.17.0 起提供。 * range\_id object *** 定义使用 `range_id` 算法生成请求 ID 的配置。 * char\_set string 默认值:`abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789` 有效值: 最小长度为 6 *** 指定用于 `range_id` 算法的字符集。 * length integer 默认值:`16` 有效值: 大于或等于 6 *** 设置 `range_id` 算法生成 ID 的长度。 --- # request-validation `request-validation` 插件在将请求转发到上游服务之前对其进行验证。该插件使用 [JSON Schema](https://github.com/api7/jsonschema) 进行验证,并且可以验证请求的请求头(headers)和请求体(body)。 请参阅 [JSON schema 规范](https://json-schema.org/specification) 以了解有关语法的更多信息。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `request-validation`。 ### 验证请求头[​](#验证请求头 "验证请求头的直接链接") 以下示例展示了如何根据定义的 JSON schema 验证请求头。 如下所示创建带有 `request-validation` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-validation-route", "uri": "/get", "plugins": { "request-validation": { "header_schema": { "type": "object", "required": ["User-Agent", "Host"], "properties": { "User-Agent": { "type": "string", "pattern": "^curl\/" }, "Host": { "type": "string", "enum": ["httpbin.org", "httpbin"] } } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-validation-service routes: - name: request-validation-route uris: - /get plugins: request-validation: header_schema: type: object required: - User-Agent - Host properties: User-Agent: type: string pattern: "^curl/" Host: type: string enum: - httpbin.org - httpbin upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-validation-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-validation-plugin-config spec: plugins: - name: request-validation config: header_schema: type: object required: - User-Agent - Host properties: User-Agent: type: string pattern: "^curl/" Host: type: string enum: - httpbin.org - httpbin --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-validation-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-validation-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-validation-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-validation-route spec: ingressClassName: apisix http: - name: request-validation-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: request-validation enable: true config: header_schema: type: object required: - User-Agent - Host properties: User-Agent: type: string pattern: "^curl/" Host: type: string enum: - httpbin.org - httpbin ``` 将配置应用到集群: ``` kubectl apply -f request-validation-ic.yaml ``` ❶ `required`:要求请求必须包含指定的请求头。 ❷ `properties`:要求请求头必须符合指定的条件。 #### 验证符合 Schema 的请求[​](#验证符合-schema-的请求 "验证符合 Schema 的请求的直接链接") 发送一个带有符合 Schema 的 `Host: httpbin` 请求头的请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Host: httpbin" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin", "User-Agent": "curl/7.74.0", "X-Amzn-Trace-Id": "Root=1-6509ae35-63d1e0fd3934e3f221a95dd8", "X-Forwarded-Host": "httpbin" }, "origin": "127.0.0.1, 183.17.233.107", "url": "http://httpbin/get" } ``` #### 验证不符合 Schema 的请求[​](#验证不符合-schema-的请求 "验证不符合 Schema 的请求的直接链接") 发送一个不带任何请求头的请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你应该收到 `HTTP/1.1 400 Bad Request` 响应,表明请求验证失败: ``` property "Host" validation failed: matches none of the enum value ``` 发送一个包含必需请求头但不符合其值要求的请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Host: httpbin" -H "User-Agent: cli-mock" ``` 你应该收到 `HTTP/1.1 400 Bad Request` 响应,表明 `User-Agent` 请求头的值不匹配预期模式: ``` property "User-Agent" validation failed: failed to match pattern "^curl/" with "cli-mock" ``` ### 自定义拒绝消息和状态码[​](#自定义拒绝消息和状态码 "自定义拒绝消息和状态码的直接链接") 以下示例展示了当验证失败时如何自定义响应状态码和消息。 如下所示配置带有 `request-validation` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-validation-route", "uri": "/get", "plugins": { "request-validation": { "header_schema": { "type": "object", "required": ["Host"], "properties": { "Host": { "type": "string", "enum": ["httpbin.org", "httpbin"] } } }, "rejected_code": 403, "rejected_msg": "Request header validation failed." } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-validation-service routes: - name: request-validation-route uris: - /get plugins: request-validation: header_schema: type: object required: - Host properties: Host: type: string enum: - httpbin.org - httpbin rejected_code: 403 rejected_msg: "Request header validation failed." upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-validation-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-validation-plugin-config spec: plugins: - name: request-validation config: header_schema: type: object required: - Host properties: Host: type: string enum: - httpbin.org - httpbin rejected_code: 403 rejected_msg: "Request header validation failed." --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-validation-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-validation-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-validation-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-validation-route spec: ingressClassName: apisix http: - name: request-validation-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: request-validation enable: true config: header_schema: type: object required: - Host properties: Host: type: string enum: - httpbin.org - httpbin rejected_code: 403 rejected_msg: "Request header validation failed." ``` 将配置应用到集群: ``` kubectl apply -f request-validation-ic.yaml ``` ❶ `rejected_code`:自定义拒绝状态码。 ❷ `rejected_msg`:自定义拒绝消息。 发送一个带有配置错误的 `Host` 请求头的请求: ``` curl -i "http://127.0.0.1:9080/get" -H "Host: httpbin2" ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应和自定义消息: ``` Request header validation failed. ``` ### 验证请求体[​](#验证请求体 "验证请求体的直接链接") 以下示例展示了如何根据定义的 JSON schema 验证请求体。 `request-validation` 插件支持验证两种类型的媒体类型: * `application/json` * `application/x-www-form-urlencoded` #### 验证 JSON 请求体[​](#验证-json-请求体 "验证 JSON 请求体的直接链接") 如下所示创建带有 `request-validation` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-validation-route", "uri": "/post", "plugins": { "request-validation": { "header_schema": { "type": "object", "required": ["Content-Type"], "properties": { "Content-Type": { "type": "string", "pattern": "^application\/json$" } } }, "body_schema": { "type": "object", "required": ["required_payload"], "properties": { "required_payload": {"type": "string"}, "boolean_payload": {"type": "boolean"}, "array_payload": { "type": "array", "minItems": 1, "items": { "type": "integer", "minimum": 200, "maximum": 599 }, "uniqueItems": true, "default": [200] } } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-validation-service routes: - name: request-validation-route uris: - /post plugins: request-validation: header_schema: type: object required: - Content-Type properties: Content-Type: type: string pattern: "^application/json$" body_schema: type: object required: - required_payload properties: required_payload: type: string boolean_payload: type: boolean array_payload: type: array minItems: 1 items: type: integer minimum: 200 maximum: 599 uniqueItems: true default: - 200 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-validation-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-validation-plugin-config spec: plugins: - name: request-validation config: header_schema: type: object required: - Content-Type properties: Content-Type: type: string pattern: "^application/json$" body_schema: type: object required: - required_payload properties: required_payload: type: string boolean_payload: type: boolean array_payload: type: array minItems: 1 items: type: integer minimum: 200 maximum: 599 uniqueItems: true default: - 200 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-validation-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /post filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-validation-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-validation-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-validation-route spec: ingressClassName: apisix http: - name: request-validation-route match: paths: - /post upstreams: - name: httpbin-external-domain plugins: - name: request-validation enable: true config: header_schema: type: object required: - Content-Type properties: Content-Type: type: string pattern: "^application/json$" body_schema: type: object required: - required_payload properties: required_payload: type: string boolean_payload: type: boolean array_payload: type: array minItems: 1 items: type: integer minimum: 200 maximum: 599 uniqueItems: true default: - 200 ``` 将配置应用到集群: ``` kubectl apply -f request-validation-ic.yaml ``` 发送一个符合 Schema 的 JSON 请求体的请求进行验证: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H "Content-Type: application/json" \ -d '{"required_payload":"hello", "array_payload":[301]}' ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "{\"array_payload\":[301],\"required_payload\":\"hello\"}", "files": {}, "form": {}, "headers": { ... }, "json": { "array_payload": [ 301 ], "required_payload": "hello" }, "origin": "127.0.0.1, 183.17.233.107", "url": "http://127.0.0.1/post" } ``` 如果你发送一个未指定 `Content-Type: application/json` 的请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -d '{"required_payload":"hello,world"}' ``` 你应该收到类似于以下的 `HTTP/1.1 400 Bad Request` 响应: ``` property "Content-Type" validation failed: failed to match pattern "^application/json$" with "application/x-www-form-urlencoded" ``` 同样,如果你发送一个缺少必需 JSON 字段 `required_payload` 的请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H "Content-Type: application/json" \ -d '{}' ``` 你应该收到 `HTTP/1.1 400 Bad Request` 响应: ``` property "required_payload" is required ``` #### 验证 URL 编码表单请求体[​](#验证-url-编码表单请求体 "验证 URL 编码表单请求体的直接链接") 如下所示创建带有 `request-validation` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "request-validation-route", "uri": "/post", "plugins": { "request-validation": { "header_schema": { "type": "object", "required": ["Content-Type"], "properties": { "Content-Type": { "type": "string", "pattern": "^application\/x-www-form-urlencoded$" } } }, "body_schema": { "type": "object", "required": ["required_payload","enum_payload"], "properties": { "required_payload": {"type": "string"}, "enum_payload": { "type": "string", "enum": ["enum_string_1", "enum_string_2"], "default": "enum_string_1" } } } } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: request-validation-service routes: - name: request-validation-route uris: - /post plugins: request-validation: header_schema: type: object required: - Content-Type properties: Content-Type: type: string pattern: "^application/x-www-form-urlencoded$" body_schema: type: object required: - required_payload - enum_payload properties: required_payload: type: string enum_payload: type: string enum: - enum_string_1 - enum_string_2 default: enum_string_1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD request-validation-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: request-validation-plugin-config spec: plugins: - name: request-validation config: header_schema: type: object required: - Content-Type properties: Content-Type: type: string pattern: "^application/x-www-form-urlencoded$" body_schema: type: object required: - required_payload - enum_payload properties: required_payload: type: string enum_payload: type: string enum: - enum_string_1 - enum_string_2 default: enum_string_1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: request-validation-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /post filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: request-validation-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` request-validation-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: request-validation-route spec: ingressClassName: apisix http: - name: request-validation-route match: paths: - /post upstreams: - name: httpbin-external-domain plugins: - name: request-validation enable: true config: header_schema: type: object required: - Content-Type properties: Content-Type: type: string pattern: "^application/x-www-form-urlencoded$" body_schema: type: object required: - required_payload - enum_payload properties: required_payload: type: string enum_payload: type: string enum: - enum_string_1 - enum_string_2 default: enum_string_1 ``` 将配置应用到集群: ``` kubectl apply -f request-validation-ic.yaml ``` 发送一个带有 URL 编码表单数据的请求进行验证: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "required_payload=hello&enum_payload=enum_string_1" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "", "files": {}, "form": { "enum_payload": "enum_string_1", "required_payload": "hello" }, "headers": { ... }, "json": null, "origin": "127.0.0.1, 183.17.233.107", "url": "http://127.0.0.1/post" } ``` 发送一个缺少 URL 编码字段 `enum_payload` 的请求: ``` curl -i "http://127.0.0.1:9080/post" -X POST \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "required_payload=hello" ``` 你应该收到以下的 `HTTP/1.1 400 Bad Request` 响应: ``` property "enum_payload" is required ``` ## 附录:JSON Schema[​](#附录json-schema "附录:JSON Schema的直接链接") 以下部分提供了样板 JSON schema,你可以根据需要进行调整、组合并在此插件中使用。有关完整参考,请参阅 [JSON schema 规范](https://json-schema.org/specification)。 ### 枚举值[​](#枚举值 "枚举值的直接链接") ``` { "body_schema": { "type": "object", "required": ["enum_payload"], "properties": { "enum_payload": { "type": "string", "enum": ["enum_string_1", "enum_string_2"], "default": "enum_string_1" } } } } ``` ### 布尔值[​](#布尔值 "布尔值的直接链接") ``` { "body_schema": { "type": "object", "required": ["bool_payload"], "properties": { "bool_payload": { "type": "boolean", "default": true } } } } ``` ### 数值[​](#数值 "数值的直接链接") ``` { "body_schema": { "type": "object", "required": ["integer_payload"], "properties": { "integer_payload": { "type": "integer", "minimum": 1, "maximum": 65535 } } } } ``` ### 字符串[​](#字符串 "字符串的直接链接") ``` { "body_schema": { "type": "object", "required": ["string_payload"], "properties": { "string_payload": { "type": "string", "minLength": 1, "maxLength": 32 } } } } ``` ### 字符串正则表达式[​](#字符串正则表达式 "字符串正则表达式的直接链接") ``` { "body_schema": { "type": "object", "required": ["regex_payload"], "properties": { "regex_payload": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "[[^[a-zA-Z0-9_]+$]]" } } } } ``` ### 数组[​](#数组 "数组的直接链接") ``` { "body_schema": { "type": "object", "required": ["array_payload"], "properties": { "array_payload": { "type": "array", "minItems": 1, "items": { "type": "integer", "minimum": 200, "maximum": 599 }, "uniqueItems": true, "default": [200, 302] } } } } ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * header\_schema object *** 请求头的 Schema。 必须至少配置 `header_schema` 和 `body_schema` 中的一个。 * body\_schema object *** 请求体的 Schema。 必须至少配置 `header_schema` 和 `body_schema` 中的一个。 * rejected\_code integer 默认值:`400` 有效值: 介于 200 和 599 之间(含边界值) *** 拒绝请求时返回的状态码。 * rejected\_msg string *** 拒绝请求时返回的消息。 * max\_req\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** 配置 `body_schema` 时读取的请求体最大字节数。超过该大小的请求体会使用 `rejected_code` 拒绝,后者默认为 `400`。仅配置 `header_schema` 时,此字段无效。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 --- # response-rewrite `response-rewrite` 插件提供了重写 APISIX 及其上游服务返回给客户端的响应的选项。使用该插件,你可以修改 HTTP 状态码、响应头、响应体等。 例如,你可以使用此插件来: * 通过设置 `Access-Control-Allow-*` 头来支持 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。 * 通过设置 HTTP 状态码和 `Location` 头来指示重定向。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下的路由上配置 `response-rewrite`。 ### 重写响应头和响应体[​](#重写响应头和响应体 "重写响应头和响应体的直接链接") 以下示例演示了如何仅对具有 `200` HTTP 状态码的响应添加响应体和响应头。 创建一个带有 `response-rewrite` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "response-rewrite-route", "methods": ["GET"], "uri": "/headers", "plugins": { "response-rewrite": { "body": "{\"code\":\"ok\",\"message\":\"new json body\"}", "headers": { "set": { "X-Server-id": 3, "X-Server-status": "on", "X-Server-balancer-addr": "$balancer_ip:$balancer_port" } }, "vars": [ [ "status","==",200 ] ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: response-rewrite-route methods: - GET plugins: response-rewrite: body: '{"code":"ok","message":"new json body"}' headers: set: X-Server-id: 3 X-Server-status: "on" X-Server-balancer-addr: "$balancer_ip:$balancer_port" vars: - - status - "==" - 200 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD response-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: response-rewrite-plugin-config spec: plugins: - name: response-rewrite config: body: '{"code":"ok","message":"new json body"}' headers: set: X-Server-id: 3 X-Server-status: "on" X-Server-balancer-addr: "$balancer_ip:$balancer_port" vars: - - status - "==" - 200 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: response-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: response-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` response-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: response-rewrite-route spec: ingressClassName: apisix http: - name: response-rewrite-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: response-rewrite enable: true config: body: '{"code":"ok","message":"new json body"}' headers: set: X-Server-id: 3 X-Server-status: "on" X-Server-balancer-addr: "$balancer_ip:$balancer_port" vars: - - status - "==" - 200 ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` 发送请求以进行验证: ``` curl -i "http://127.0.0.1:9080/headers" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` ... X-Server-id: 3 X-Server-status: on X-Server-balancer-addr: 50.237.103.220:80 {"code":"ok","message":"new json body"} ``` ### 使用正则过滤器重写响应头[​](#使用正则过滤器重写响应头 "使用正则过滤器重写响应头的直接链接") 以下示例演示了如何使用正则过滤器匹配来替换响应的 `X-Amzn-Trace-Id`。 创建一个带有 `response-rewrite` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "response-rewrite-route", "methods": ["GET"], "uri": "/headers", "plugins":{ "response-rewrite":{ "filters":[ { "regex":"X-Amzn-Trace-Id", "scope":"global", "replace":"X-Amzn-Trace-Id-Replace" } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: response-rewrite-route methods: - GET plugins: response-rewrite: filters: - regex: X-Amzn-Trace-Id scope: global replace: X-Amzn-Trace-Id-Replace upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD response-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: response-rewrite-plugin-config spec: plugins: - name: response-rewrite config: filters: - regex: X-Amzn-Trace-Id scope: global replace: X-Amzn-Trace-Id-Replace --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: response-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: response-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` response-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: response-rewrite-route spec: ingressClassName: apisix http: - name: response-rewrite-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: response-rewrite enable: true config: filters: - regex: X-Amzn-Trace-Id scope: global replace: X-Amzn-Trace-Id-Replace ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` 发送请求以进行验证: ``` curl -i "http://127.0.0.1:9080/headers" ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.2.1", "X-Amzn-Trace-Id-Replace": "Root=1-6500095d-1041b05e2ba9c6b37232dbc7", "X-Forwarded-Host": "127.0.0.1" } } ``` ### 解码 Base64 格式的响应体[​](#解码-base64-格式的响应体 "解码 Base64 格式的响应体的直接链接") 以下示例演示了如何解码 Base64 格式的响应体。 创建一个带有 `response-rewrite` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "response-rewrite-route", "methods": ["GET"], "uri": "/get", "plugins":{ "response-rewrite": { "body": "SGVsbG8gV29ybGQ=", "body_base64": true } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /get name: response-rewrite-route methods: - GET plugins: response-rewrite: body: SGVsbG8gV29ybGQ= body_base64: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD response-rewrite-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: response-rewrite-plugin-config spec: plugins: - name: response-rewrite config: body: SGVsbG8gV29ybGQ= body_base64: true --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: response-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: response-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` response-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: response-rewrite-route spec: ingressClassName: apisix http: - name: response-rewrite-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: response-rewrite enable: true config: body: SGVsbG8gV29ybGQ= body_base64: true ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` 发送请求以进行验证: ``` curl "http://127.0.0.1:9080/get" ``` 你应该看到以下响应: ``` Hello World ``` ### 重写响应及其与执行阶段的联系[​](#重写响应及其与执行阶段的联系 "重写响应及其与执行阶段的联系的直接链接") 以下示例演示了 `response-rewrite` 插件与[执行阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)之间的联系,通过配置带有 `key-auth` 插件的 `response-rewrite` 插件,观察在未经身份认证的请求情况下,响应如何仍然被重写为 `200 OK`。 * Admin API * ADC * Ingress Controller 创建一个消费者 `jack`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jack" }' ``` 为消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jack-key-auth", "plugins": { "key-auth": { "key": "jack-key" } } }' ``` 创建一个带有 `key-auth` 的路由,并配置 `response-rewrite` 以重写响应状态码和响应体: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "response-rewrite-route", "uri": "/get", "plugins": { "key-auth": {}, "response-rewrite": { "status_code": 200, "body": "{\"code\": 200, \"msg\": \"success\"}" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建一个配置了 `key-auth` 凭证的消费者,以及一个配置了 `key-auth` 和 `response-rewrite` 插件的路由: adc.yaml ``` consumers: - username: jack credentials: - name: cred-jack-key-auth type: key-auth config: key: jack-key services: - name: httpbin routes: - name: response-rewrite-route uris: - /get plugins: key-auth: {} response-rewrite: status_code: 200 body: '{"code": 200, "msg": "success"}' upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD response-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jack spec: gatewayRef: name: apisix credentials: - type: key-auth name: cred-jack-key-auth config: key: jack-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: response-rewrite-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: response-rewrite config: status_code: 200 body: '{"code": 200, "msg": "success"}' --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: response-rewrite-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: response-rewrite-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` response-rewrite-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jack spec: ingressClassName: apisix authParameter: keyAuth: value: key: jack-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: response-rewrite-route spec: ingressClassName: apisix http: - name: response-rewrite-route match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: key-auth enable: true - name: response-rewrite enable: true config: status_code: 200 body: '{"code": 200, "msg": "success"}' ``` 将配置应用到集群: ``` kubectl apply -f response-rewrite-ic.yaml ``` 使用有效密钥向路由发送请求: ``` curl -i "http://127.0.0.1:9080/get" -H 'apikey: jack-key' ``` 你应该收到如下所示的 `HTTP/1.1 200 OK` 响应: ``` {"code": 200, "msg": "success"} ``` 向路由发送不带任何密钥的请求: ``` curl -i "http://127.0.0.1:9080/get" ``` 你仍然应该收到相同的 `HTTP/1.1 200 OK` 响应,而不是来自 `key-auth` 插件的 `HTTP/1.1 401 Unauthorized`。这表明 `response-rewrite` 插件仍然重写了响应。 这是因为 `response-rewrite` 插件的 **header\_filter** 和 **body\_filter** 阶段逻辑将在其他插件的 **access** 或 **rewrite** 阶段中的 [`ngx.exit`](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxexit) 之后继续运行。 下表总结了 `ngx.exit` 对执行阶段的影响。 | 阶段 | rewrite | access | header\_filter | body\_filter | | ------------------ | -------- | -------- | -------------- | ------------ | | **rewrite** | ngx.exit | | | | | **access** | × | ngx.exit | | | | **header\_filter** | ✓ | ✓ | ngx.exit | | | **body\_filter** | ✓ | ✓ | × | ngx.exit | 例如,如果 `ngx.exit` 发生在 **rewrite** 阶段,它将中断 **access** 阶段的执行,但不会干扰 **header\_filter** 和 **body\_filter** 阶段。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)了解所有插件可用的配置选项。 * status\_code integer 有效值: 介于 200 和 598 之间(含边界值) *** 响应中的新 HTTP 状态码。 * body string *** 新的响应体。`Content-Length` 头也将被重置。不应与 `filters` 一起配置。 * body\_base64 boolean 默认值:`false` *** 如果为 true,则在发送给客户端之前解码 `body` 中配置的响应体,这对于图像和 protobuf 解码很有用。请注意,此配置不能用于解码上游响应。 * headers object *** 按 `add`、`remove` 和 `set` 的顺序执行的动作。 * add array\[string] *** 追加到响应的响应头。如果响应中已存在该响应头,则将追加该响应头值。响应头值可以设置为常量,或一个或多个[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * set object *** 设置到响应的响应头。如果响应中已存在该响应头,则将覆盖该响应头值。响应头值可以设置为常量,或一个或多个[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 * remove array\[string] *** 从响应中删除的响应头。 * vars array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的匹配条件数组,用于按条件执行插件。 * filters array\[object] *** 通过将一个指定字符串替换为另一个字符串来修改响应体的过滤器列表。不应与 `body` 一起配置。 * regex string 必填 *** 在响应体上匹配的正则表达式模式。 * scope string 默认值:`once` 有效值: `once` 或 `global` *** 替换范围。`once` 替换第一个匹配的实例,`global` 进行全局替换。 * replace string 必填 *** 用于替换的内容。 * options string 默认值:`jo` *** 用于控制匹配操作执行方式的正则表达式选项。请参阅 [Lua NGINX 模块](https://github.com/openresty/lua-nginx-module#ngxrematch)以了解可用选项。 * max\_resp\_body\_size integer 默认值:`67108864` 有效值: 大于或等于 1 *** 配置 `filters` 时缓冲的响应体最大字节数。超过该大小的响应会在运行过滤器前截断到此大小。跨越阈值的数据块会在执行限制前先进入缓冲,因此瞬时内存用量可能超过配置值。未配置 `filters` 时,此字段无效。自 API7 企业版 3.9.17 和 3.10.4 以及 APISIX 3.18.0 起引入。 --- # rocketmq-logger `rocketmq-logger` 插件将请求和响应日志作为 JSON 对象以批处理的方式推送到 RocketMQ 集群,并支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `rocketmq-logger` 插件。 要按照示例操作,请使用以下 Docker compose 文件启动一个 RocketMQ 集群示例: * Docker * Kubernetes docker-compose.yml ``` version: "3" services: rocketmq_namesrv: image: apacherocketmq/rocketmq:4.6.0 container_name: rmqnamesrv restart: unless-stopped ports: - "9876:9876" command: sh mqnamesrv networks: rocketmq_net: rocketmq_broker: image: apacherocketmq/rocketmq:4.6.0 container_name: rmqbroker restart: unless-stopped ports: - "10909:10909" - "10911:10911" - "10912:10912" depends_on: - rocketmq_namesrv command: sh mqbroker -n rmqnamesrv:9876 -c ../conf/broker.conf networks: rocketmq_net: networks: rocketmq_net: ``` 启动容器: ``` docker compose up -d ``` 几秒钟后,名称服务器和代理应该会启动。 创建 `TopicTest` 主题: ``` docker exec -i rmqnamesrv rm /home/rocketmq/rocketmq-4.6.0/conf/tools.yml docker exec -i rmqnamesrv /home/rocketmq/rocketmq-4.6.0/bin/mqadmin updateTopic -n rmqnamesrv:9876 -t TopicTest -c DefaultCluster ``` 为 RocketMQ NameServer 和 Broker Deployment 创建 Kubernetes 清单文件: rocketmq-deployment.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: rocketmq-namesrv spec: replicas: 1 selector: matchLabels: app: rocketmq-namesrv template: metadata: labels: app: rocketmq-namesrv spec: containers: - name: rocketmq-namesrv image: apacherocketmq/rocketmq:4.6.0 command: ["sh", "mqnamesrv"] ports: - containerPort: 9876 --- apiVersion: v1 kind: Service metadata: namespace: aic name: rocketmq-namesrv spec: selector: app: rocketmq-namesrv ports: - port: 9876 targetPort: 9876 type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: rocketmq-broker spec: replicas: 1 selector: matchLabels: app: rocketmq-broker template: metadata: labels: app: rocketmq-broker spec: containers: - name: rocketmq-broker image: apacherocketmq/rocketmq:4.6.0 command: ["sh", "mqbroker", "-n", "rocketmq-namesrv:9876", "-c", "../conf/broker.conf"] ports: - containerPort: 10909 - containerPort: 10911 - containerPort: 10912 --- apiVersion: v1 kind: Service metadata: namespace: aic name: rocketmq-broker spec: selector: app: rocketmq-broker ports: - name: fastlisten port: 10909 targetPort: 10909 - name: listen port: 10911 targetPort: 10911 - name: haservice port: 10912 targetPort: 10912 type: ClusterIP ``` 在配置的 RocketMQ 主题中等待消息: ``` kubectl apply -f rocketmq-deployment.yaml ``` Pod 运行后,创建 `TopicTest` 主题: ``` kubectl exec -n aic deploy/rocketmq-namesrv -- sh -c \ "rm -f /home/rocketmq/rocketmq-4.6.0/conf/tools.yml && \ /home/rocketmq/rocketmq-4.6.0/bin/mqadmin updateTopic \ -n rocketmq-namesrv:9876 -t TopicTest -c DefaultCluster" ``` 等待已配置的 RocketMQ 主题接收消息: * Docker * Kubernetes ``` docker run -it --name rockemq_consumer -e NAMESRV_ADDR=localhost:9876 --net host apacherocketmq/rocketmq:4.6.0 sh tools.sh org.apache.rocketmq.example.quickstart.Consumer ``` 几秒钟后,消费者应该会启动并监听来自 APISIX 的消息: ``` 01:32:17.823 [main] DEBUG i.n.u.i.l.InternalLoggerFactory - Using SLF4J as the default logging framework Consumer Started. ``` 打开一个新的终端会话,用于以下与 APISIX 交互的步骤。 在以下示例中向 APISIX 发送请求后,运行以下命令以输出 `TopicTest` 主题中的消息: ``` kubectl exec -n aic deploy/rocketmq-namesrv -- sh -c \ "/home/rocketmq/rocketmq-4.6.0/bin/mqadmin printMsg \ -n rocketmq-namesrv:9876 -t TopicTest" ``` ### 使用不同的元日志格式记录日志[​](#使用不同的元日志格式记录日志 "使用不同的元日志格式记录日志的直接链接") 以下示例展示了如何在路由上启用 `rocketmq-logger` 插件,该插件记录对路由的客户端请求并将日志推送到 RocketMQ。你还将了解 `default` 和 `origin` 元日志格式之间的区别。 创建一个启用 `rocketmq-logger` 的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "rocketmq-logger-route", "uri": "/anything", "plugins": { "rocketmq-logger": { "nameserver_list": [ "127.0.0.1:9876" ], "topic": "TopicTest", "key": "key1", "timeout": 30, "meta_format": "default", "batch_max_size": 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: rocketmq-logger-route plugins: rocketmq-logger: nameserver_list: - "127.0.0.1:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD rocketmq-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: rocketmq-logger-plugin-config spec: plugins: - name: rocketmq-logger config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: rocketmq-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: rocketmq-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` rocketmq-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: rocketmq-logger-route spec: ingressClassName: apisix http: - name: rocketmq-logger-route match: paths: - /anything* upstreams: - name: httpbin-external-domain plugins: - name: rocketmq-logger enable: true config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 ``` 应用配置: ``` kubectl apply -f rocketmq-logger-ic.yaml ``` ❶ `meta_format`: 设置为 `default` 日志格式。 ❷ `batch_max_size`: 设置为 1 以立即发送日志条目。 向路由发送请求以生成日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该在运行消费者的另一个终端中看到一个日志条目: ``` { "client_ip": "127.0.0.1", "upstream": "34.197.122.172:80", "start_time": 1744727400000, "request": { "headers": { "host": "127.0.0.1:9080", "accept": "*/*", "user-agent": "curl/8.6.0" }, "querystring": {}, "size": 86, "uri": "/anything", "url": "http://127.0.0.1:9080/anything", "method": "GET" }, "route_id": "rocketmq-logger-route", "apisix_latency": 8.9998455047607, "upstream_latency": 503, "latency": 511.99984550476, "response": { "size": 617, "headers": { "content-length": "391", "connection": "close", "date": "Tue, 15 Apr 2025 14:30:00 GMT", "server": "APISIX/3.15.0", "content-type": "application/json" }, "status": 200 }, "server": { "hostname": "apisix", "version": "3.15.0" }, "service_id": "" } ``` 将 `rocketmq-logger` 的元日志格式更新为 `origin`: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/rocketmq-logger-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "rocketmq-logger": { "meta_format": "origin" } } }' ``` 更新 `adc.yaml`,将 `meta_format` 修改为 `origin`: adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: rocketmq-logger-route plugins: rocketmq-logger: nameserver_list: - "127.0.0.1:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "origin" batch_max_size: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `rocketmq-logger-ic.yaml`,将 `PluginConfig` 中的 `meta_format` 更改为 `origin`: rocketmq-logger-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: rocketmq-logger-plugin-config spec: plugins: - name: rocketmq-logger config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "origin" batch_max_size: 1 ``` 应用更新后的配置: ``` kubectl apply -f rocketmq-logger-ic.yaml ``` 更新 `rocketmq-logger-ic.yaml`,将 `ApisixRoute` 中的 `meta_format` 更改为 `origin`: rocketmq-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: rocketmq-logger-route spec: ingressClassName: apisix http: - name: rocketmq-logger-route match: paths: - /anything* upstreams: - name: httpbin-external-domain plugins: - name: rocketmq-logger enable: true config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "origin" batch_max_size: 1 ``` 应用更新后的配置: ``` kubectl apply -f rocketmq-logger-ic.yaml ``` 再次向路由发送请求以生成新的日志条目: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该在运行消费者的另一个终端中看到一个日志条目: ``` GET /anything HTTP/1.1 host: 127.0.0.1:9080 user-agent: curl/8.6.0 accept: */* ``` ### 使用插件元数据记录请求和响应头[​](#使用插件元数据记录请求和响应头 "使用插件元数据记录请求和响应头的直接链接") 以下示例展示了如何使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)和[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)自定义日志格式,以记录请求和响应中的特定请求头和响应头。 在 APISIX 中,[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)用于配置同一插件的所有插件实例的通用元数据字段。当插件在多个资源中启用并且需要对其元数据字段进行统一更新时,这非常有用。 首先,创建一个启用 `rocketmq-logger` 的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "rocketmq-logger-route", "uri": "/anything", "plugins": { "rocketmq-logger": { "nameserver_list": [ "127.0.0.1:9876" ], "topic": "TopicTest", "key": "key1", "timeout": 30, "meta_format": "default", "batch_max_size": 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: rocketmq-logger-route plugins: rocketmq-logger: nameserver_list: - "127.0.0.1:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD rocketmq-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: rocketmq-logger-plugin-config spec: plugins: - name: rocketmq-logger config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: rocketmq-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: rocketmq-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` rocketmq-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: rocketmq-logger-route spec: ingressClassName: apisix http: - name: rocketmq-logger-route match: paths: - /anything* upstreams: - name: httpbin-external-domain plugins: - name: rocketmq-logger enable: true config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 ``` 应用配置: ``` kubectl apply -f rocketmq-logger-ic.yaml ``` ❶ `meta_format`: 设置为 `default` 日志格式。需要注意的是,如果你想使用插件元数据自定义日志格式,这是强制性的。如果 `meta_format` 设置为 `origin`,日志条目将保持 `origin` 格式。 ❷ `batch_max_size`: 设置为 1 以立即发送日志条目。 接下来,配置 `rocketmq-logger` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/rocketmq-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr", "env": "$http_env", "resp_content_type": "$sent_http_Content_Type" } }' ``` adc.yaml ``` plugin_metadata: - name: rocketmq-logger log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: rocketmq-logger: log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` ❶ 记录自定义请求头 `env`。 ❷ 记录响应头 `Content-Type`。 向路由发送带有 `env` 头的请求: ``` curl -i "http://127.0.0.1:9080/anything" -H "env: dev" ``` 你应该在运行消费者的另一个终端中看到一个日志条目: ``` { "host": "127.0.0.1", "client_ip": "127.0.0.1", "resp_content_type": "application/json", "route_id": "rocketmq-logger-route", "env": "dev", "@timestamp": "2025-04-15T14:30:00+00:00" } ``` ### 有条件地记录请求体[​](#有条件地记录请求体 "有条件地记录请求体的直接链接") 以下示例展示了如何有条件地记录请求体。 创建一个启用 `rocketmq-logger` 的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "rocketmq-logger": { "nameserver_list": [ "127.0.0.1:9876" ], "topic": "TopicTest", "key": "key1", "timeout": 30, "meta_format": "default", "batch_max_size": 1, "include_req_body": true, "include_req_body_expr": [["arg_log_body", "==", "yes"]] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" }, "uri": "/anything", "id": "rocketmq-logger-route" }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: rocketmq-logger-route plugins: rocketmq-logger: nameserver_list: - "127.0.0.1:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD rocketmq-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: rocketmq-logger-plugin-config spec: plugins: - name: rocketmq-logger config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: rocketmq-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: rocketmq-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` rocketmq-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: rocketmq-logger-route spec: ingressClassName: apisix http: - name: rocketmq-logger-route match: paths: - /anything* upstreams: - name: httpbin-external-domain plugins: - name: rocketmq-logger enable: true config: nameserver_list: - "rocketmq-namesrv.aic.svc:9876" topic: "TopicTest" key: "key1" timeout: 30 meta_format: "default" batch_max_size: 1 include_req_body: true include_req_body_expr: - - "arg_log_body" - "==" - "yes" ``` 应用配置: ``` kubectl apply -f rocketmq-logger-ic.yaml ``` ❶ `include_req_body`: 设置为 true 以包含请求体。 ❷ `include_req_body_expr`: 仅当 URL 查询字符串 `log_body` 为 `yes` 时包含请求体。 向路由发送带有满足条件的 URL 查询字符串的请求: ``` curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}' ``` 结果将是: ``` { ..., "method": "POST", "body": "{\"env\": \"dev\"}", "size": 183 } } ``` 向路由发送不带任何 URL 查询字符串的请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}' ``` 你不应该在日志中观察到请求体。 信息 除了将 `include_req_body` 或 `include_resp_body` 设置为 `true` 之外,如果你自定义了 `log_format`,插件将不会在日志中包含 body。 作为一种解决方法,你也许能够在日志格式中使用 NGINX 变量 `$request_body`,例如: ``` { "rocketmq-logger": { ..., "log_format": {"body": "$request_body"} } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * nameserver\_list array\[string] 必填 *** RocketMQ 名称服务器列表。 * topic string 必填 *** 推送数据的目标主题。 * key string *** 消息的 Key。 * tag string *** 消息的 Tag。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 你也可以通过配置[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)来全局配置日志格式,这将对所有 `rocketmq-logger` 插件实例生效。如果单个插件实例配置的日志格式与插件元数据中配置的日志格式不同,则单个插件实例的配置优先级更高。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/rocketmq-logger.md#使用插件元数据记录请求和响应头)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * timeout integer 默认值:`3` *** 上游发送数据的超时时间。 * use\_tls boolean 默认值:`false` *** 如果设置为 true,验证 SSL。 * access\_key string *** ACL 的访问密钥。设置为空字符串将禁用 ACL。 * secret\_key string *** ACL 的密钥。该值在存储到 etcd 前会使用 AES 加密。 * name string 默认值:`rocketmq logger` *** 批处理器的唯一标识符。如果你使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称将导出在 `apisix_batch_process_entries` 中。 * meta\_format string 默认值:`default` 有效值: `default` 或 `origin` *** 收集请求信息的格式。设置为 `default` 将以 JSON 格式收集信息,`origin` 将以原始 HTTP 请求格式收集信息。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/rocketmq-logger.md#使用不同的元日志格式记录日志)。 * include\_req\_body boolean 默认值:`false` *** 如果设置为 true,在日志中包含请求体。注意:如果请求体过大导致无法保存在内存中,由于 NGINX 的限制,它可能无法被记录。 * include\_req\_body\_expr array\[array] *** 一个包含一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。当 `include_req_body` 为 true 时使用。只有当此处配置的表达式求值为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果设置为 true,在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 一个包含一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。当 `include_resp_body` 为 true 时使用。只有当此处配置的表达式求值为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每一批次允许的最大日志条目数。一旦达到该数值,批次将被发送到日志服务。将此参数设置为 1 意味着立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(以秒为单位)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 批次中最旧条目在发送到日志服务之前允许保留的最长时间(以秒为单位)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(以秒为单位)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 在丢弃日志条目之前允许的最大失败重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # saml-auth `saml-auth` 插件使 APISIX 或 API7 Gateway 可作为服务提供商(SP),通过 [SAML 2.0](https://en.wikipedia.org/wiki/SAML_2.0) 身份提供商(IdP)认证用户。 ## 示例[​](#示例 "示例的直接链接") ### 与 Keycloak 集成[​](#与-keycloak-集成 "与 Keycloak 集成的直接链接") 以下示例假设本地可访问网关,并演示如何使用 Keycloak 配置 SAML 单点登录(SSO)。 #### 启动 Keycloak 服务器[​](#启动-keycloak-服务器 "启动 Keycloak 服务器的直接链接") 启动一个 Keycloak 实例,管理员用户名为 `admin`,管理员密码为 `admin-pass`: * Docker * Kubernetes ``` docker run -d --name keycloak \ -e 'KEYCLOAK_ADMIN=admin' \ -e 'KEYCLOAK_ADMIN_PASSWORD=admin-pass' \ -p 8080:8080 \ quay.io/keycloak/keycloak:25.0.4 start-dev ``` 启动后,在浏览器中访问 [`http://localhost:8080`](http://localhost:8080) 以访问 Keycloak 管理控制台。使用管理员用户名和密码登录。 创建用于部署 Keycloak 及其服务的 Kubernetes 清单文件: keycloak.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: keycloak spec: replicas: 1 selector: matchLabels: app: keycloak template: metadata: labels: app: keycloak spec: containers: - name: keycloak image: quay.io/keycloak/keycloak:25.0.4 args: - start-dev env: - name: KEYCLOAK_ADMIN value: admin - name: KEYCLOAK_ADMIN_PASSWORD value: admin-pass - name: KC_HTTP_PORT value: "8080" ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: namespace: aic name: keycloak spec: selector: app: keycloak ports: - port: 8080 targetPort: 8080 type: ClusterIP ``` 应用该清单: ``` kubectl apply -f keycloak.yaml ``` 等待 Pod 就绪。就绪后,将 Keycloak 端口转发到本地,使你能够访问管理控制台,并确保浏览器在 SAML 流程中能够访问 IdP: ``` kubectl port-forward -n aic service/keycloak 8080:8080 & ``` 端口转发生效后,在浏览器中访问 [`http://localhost:8080`](http://localhost:8080) 以打开 Keycloak 管理控制台,并使用管理员用户名和密码登录。 #### 创建客户端[​](#创建客户端 "创建客户端的直接链接") 在 Keycloak 中创建一个新客户端并进行如下配置: * 配置 **Client type** 为 `SAML`。 * 输入服务提供商 (SP) 名称作为 **Client ID**,例如 `api7`。 * 注意,该值应与你稍后将在插件中配置的 `sp_issuer` 参数值一致。 * 将 `http://127.0.0.1:9080/anything/login_callback` 添加到 **Valid redirect URIs**。 * 将 `http://127.0.0.1:9080/anything/logout_callback` 添加到 **Valid post logout redirect URIs**。 * 将 **Force POST binding** 选项设置为 `Off`。 * 确保 **Sign documents** 选项为 `On`。否则,SAML 响应中将缺少 `SigAlg` 和 `Signature`。 #### 查找 Realm 的 SAML 元数据[​](#查找-realm-的-saml-元数据 "查找 Realm 的 SAML 元数据的直接链接") 在此步骤中,你将从 Realm 的 SAML 元数据文件中找到 `idp_cert` 和 `idp_uri`。 选择 **Realm Settings**,在 **General** 选项卡下的 **Endpoints** 中,你应该能找到 **SAML 2.0 Identity Provider Metadata**。元数据文件应类似于以下内容: ``` wDDsXcgLGAZwZgpSb_jlBRf5MF8FoTcOYs0DgZ30Xcc MIICmzCCAYMCBgGRl7njKjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjQwODI4MDY0MjA3WhcNMzQwODI4MDY0MzQ3WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdYPYSFoX2MADSIgfLYQ5oZcLNE+qB+qsO8sNpiebMQE3RmI5+MmZC/aozRzkzxcY+AoM50qfHrM1yM99A9ZxZt6fW/MuIv6IP5zWLDl0XWGVeOH0HIH4/xBxQetBxm1HdOYpCQg5Wm9hmYfebmN7NfW8HjnORjfUuUGgs5eCiHVqfiCfphLF5w+DcIcnjIwyF+xVH/7fRWgo5inBSeIavZh/LEv7LzBeRleGgoZ/+q7cVQiL2e0b8rsslqUOZJmwdPU3VSS0vW1bmXsZsfaZD0bgakFvSj0ARzwIbxc74eEQYKflHGS0zkrpm+TsO5KUn59SCPOhGNgGYpKKv6cY1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBABN21PoEiTaZ20qQUdKD03m+bySlF4jRX2AeZqCedBaW+nHrbefaJdEnE9AcXBENCWVr6ntdeREaL9dW6KpV1hT4BmnXO2aiFotZe4Vc2W6cv7nDpjil6Q5/isbT5sriYhcU9oXBAaLf9dlg7K/X1l1+zcy9Pd1uKUfrC+5ds/Zv+xHiiK4h55o8shcmBmQ7bsanzNmjIQNnyF+lNRciGRvgJp59TR7AWpiBQDTNW1KK3XjO9lmN8nCEPbpdNGi77TDX0OZVrbbPy3vL4n8Gi3oQptHhmV7xou4fTEn9TCrdW82OLOduBCMk9t0tFFNB8Hlxq5XsLVLYW7O9GGcjDmI= urn:oasis:names:tc:SAML:2.0:nameid-format:persistent urn:oasis:names:tc:SAML:2.0:nameid-format:transient urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress ``` 记下 `X509Certificate` 中的证书内容,用于插件配置中的 `idp_cert`。 `SingleSignOnService.Location` URL 也将在稍后的 `idp_uri` 插件配置中使用,其中 `localhost` 应替换为你的私有 IP 地址。例如,`idp_uri` 类似于 `http://192.168.2.101:8080/realms/master/protocol/saml`。 #### 创建服务提供商 (SP) 证书和密钥[​](#创建服务提供商-sp-证书和密钥 "创建服务提供商 (SP) 证书和密钥的直接链接") 有两种方法可以创建服务提供商的证书和密钥,并在 Keycloak 中配置证书: 1. 使用 openssl 在本地生成证书和私钥,并将证书导入 Keycloak 客户端;或者 2. 在 Keycloak 中生成证书和私钥,这会自动在 Keycloak 中配置证书。你需要保存证书和私钥,以便稍后在 API7 中进行插件配置。 对于第一种方法,使用 openssl 工具生成证书和私钥: ``` # 生成私钥 openssl genrsa -out sp_private_key.pem 2048 # 生成证书签名请求(CSR) openssl req -new -key sp_private_key.pem -out sp_csr.pem -subj "/CN=API7" # 生成自签名证书 openssl x509 -req -days 365 -in sp_csr.pem -signkey sp_private_key.pem -out sp_cert.pem ``` 在 Keycloak 中,转到客户端,在 **Keys** 选项卡下,如果你看到 **Client signature required** 选项设置为 **On**,你应该会看到 **Import Key** 按钮来导入 **Certificate**。选择 **Certificate PEM** 作为 **Archive format** 并导入 `sp_cert.pem`。 或者,如果你希望使用第二种方法在 Keycloak 中生成证书和密钥,你可以点击 **Certificate** 下的 **Regenerate**。这将更新客户端中配置的证书,并将私钥下载到你的主机。 #### 创建带有 `saml-auth` 插件的路由[​](#创建带有-saml-auth-插件的路由 "创建带有-saml-auth-插件的路由的直接链接") 提示 将 `idp_uri` 中的 IP 地址、`idp_cert`、`sp_cert` 和 `sp_private_key` 替换为你自己的值。使用 Admin API、ADC 或 Ingress Controller 创建路由时,还应配置随机生成的会话密钥 `secret`。 * Admin API * ADC * Ingress Controller 创建启用 `saml-auth` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "saml-auth-route", "uri": "/anything/*", "plugins": { "saml-auth": { "secret": "my_secret_key", "sp_issuer": "api7", "idp_uri": "http://192.168.2.101:8080/realms/master/protocol/saml", "login_callback_uri": "/anything/login_callback", "logout_callback_uri": "/anything/logout_callback", "logout_uri": "/anything/logout", "logout_redirect_uri": "/anything/logout_ok", "idp_cert": "-----BEGIN CERTIFICATE-----\nMIICmzCCAYMCBgGRl7njKjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0\nZXIwHhcNMjQwODI4MDY0MjA3WhcNMzQwODI4MDY0MzQ3WjARMQ8wDQYDVQQDDAZt\nYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdYPYSFoX2MADS\nIgfLYQ5oZcLNE+qB+qsO8sNpiebMQE3RmI5+MmZC/aozRzkzxcY+AoM50qfHrM1y\nM99A9ZxZt6fW/MuIv6IP5zWLDl0XWGVeOH0HIH4/xBxQetBxm1HdOYpCQg5Wm9hm\nYfebmN7NfW8HjnORjfUuUGgs5eCiHVqfiCfphLF5w+DcIcnjIwyF+xVH/7fRWgo5\ninBSeIavZh/LEv7LzBeRleGgoZ/+q7cVQiL2e0b8rsslqUOZJmwdPU3VSS0vW1bm\nXsZsfaZD0bgakFvSj0ARzwIbxc74eEQYKflHGS0zkrpm+TsO5KUn59SCPOhGNgGY\npKKv6cY1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBABN21PoEiTaZ20qQUdKD03m+\nbySlF4jRX2AeZqCedBaW+nHrbefaJdEnE9AcXBENCWVr6ntdeREaL9dW6KpV1hT4\nBmnXO2aiFotZe4Vc2W6cv7nDpjil6Q5/isbT5sriYhcU9oXBAaLf9dlg7K/X1l1+\nzcy9Pd1uKUfrC+5ds/Zv+xHiiK4h55o8shcmBmQ7bsanzNmjIQNnyF+lNRciGRvg\nJp59TR7AWpiBQDTNW1KK3XjO9lmN8nCEPbpdNGi77TDX0OZVrbbPy3vL4n8Gi3oQ\nptHhmV7xou4fTEn9TCrdW82OLOduBCMk9t0tFFNB8Hlxq5XsLVLYW7O9GGcjDmI=\n-----END CERTIFICATE-----", "sp_cert": "-----BEGIN CERTIFICATE-----\nMIIC0TCCAbmgAwIBAgIUAT7h3zLAul/3S1F9Ms9w7JjpoJ0wDQYJKoZIhvcNAQEL\nBQAwETEPMA0GA1UEAwwGQVBJU0lYMB4XDTI0MDgyNzA5MDk1NloXDTI1MDgyNzA5\nMDk1NlowETEPMA0GA1UEAwwGQVBJU0lYMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAvJBsuNfgvxe+xrBPr9+OCwD4dk3M9ua+14l9tlQHFgtqGXEq7nYc\n0ic9wqim+kdxpJWfiwG0mClklO0nELNsgBVrC06FqrcSe2CGEh91UBkGEOzvOgm7\nEBJOB/5Nc4tE/3NXM0ocfRgFXNEvGMkH9M+odGk7ZQraI/hfazwYgjOty1LrvSMp\nKhCfx0DpKlLuX0w2P9CfLuSgZ0ZTdN3Yr4icEuEs0i3ptCd/bip2fccKkRWEguIe\nywoDl/2fjubJFc5sFhl7Rtf+CeFKgqeByNPX2+UCix136L1r+VIlA+3ClInPWZUY\nWCbs/envBO6omUsnqPPCU2zVdYW0Qb+rrQIDAQABoyEwHzAdBgNVHQ4EFgQUvGIj\nuvPoHC74lhKSlOJAwrdq4WwwDQYJKoZIhvcNAQELBQADggEBAJU0+aKCUSYvN6oe\n7PHYD0ZvE13wItzKq/7DQQe1zA/kDoCvSyC8+gB+FZmdHmkGGNdNqXsQgHEnP7Y0\nx7gDqA3s0blXEkECfmmRcVxcS3rb8CVVFqiKdyRO91opdir5J9vbmiF7RK1ajFTy\nyemhK0xxFpPM+gTdetEj7AoVMrlRoOLC+L62GaSi/gpQmKPR91FLyj33vCfVrDCo\nQXYMPQmSbBCwlHrHWa/Px7F7aQ3fuwmY6jgObxewl3HUSCfV1TT4/uYV9GsrVx4p\np9LcyuVBuJroIlCJrk5Q/ozGhuiRoKApaTeUSjy5opziBRC2bF+TIxbO9Mkibtbh\nxvXZ4WE=\n-----END CERTIFICATE-----", "sp_private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8kGy41+C/F77G\nsE+v344LAPh2Tcz25r7XiX22VAcWC2oZcSrudhzSJz3CqKb6R3GklZ+LAbSYKWSU\n7ScQs2yAFWsLToWqtxJ7YIYSH3VQGQYQ7O86CbsQEk4H/k1zi0T/c1czShx9GAVc\n0S8YyQf0z6h0aTtlCtoj+F9rPBiCM63LUuu9IykqEJ/HQOkqUu5fTDY/0J8u5KBn\nRlN03diviJwS4SzSLem0J39uKnZ9xwqRFYSC4h7LCgOX/Z+O5skVzmwWGXtG1/4J\n4UqCp4HI09fb5QKLHXfovWv5UiUD7cKUic9ZlRhYJuz96e8E7qiZSyeo88JTbNV1\nhbRBv6utAgMBAAECggEAFPBeulnykZXD8BFVD/0dq1gkvxJdn884wvt4E76Z+Nc0\npXWdJFTGV4nXAF41CJbVZkbdLBT45mq2ShlZnK+n7UMzm1JRYocozL2Htcx7fPUC\naO++ku3QsXSu6JFTLXD6LPm0ZbQlnLiFo+xws+pi8Ur79E1ZNJuzZIooomJOgGqm\nz/0aTCw1JbMXAI7x0ygCYarfhqX4/M6qokV0Nt64hHxHxtrIWzVac+1QdR4WLaFL\nbdrb6QQeeCw5rWUrZfqmF6+NwCCeP5k/HMeVSwXsI+WrEVCjQBB2qpFqgiDNyfz2\n2i7UYXBP0PUmHEPsctWCYlWwqskBxLZnJdDKTmBCKwKBgQDpXpUpNgaI1LOrhxEQ\n5v1iXDSJweV8Kcdth+e6IGFLtxBgvhDNCijBhwKaFe90SFRldGQgZrz4tBKcxdEw\nslGbbNSSmVZ7nSMpZQoV74Uyrk2i7vxq6A9+ZCMWFpFIwoFBz4SUpnwEe+TEe/l3\nAMOz8BdFa3J0XzUhL7k5X+KaewKBgQDO2Yvi84JhwcmgRzlhv5o6gD40C5x1dv5w\nRqnXxnZGigVwtSBS6CoayBtL8MYNdTB5oM6qoF/FiVHYxbnwgD3d4net/BbUYz9H\nkONxwuEM0a35uSf2FHCaRn7BDPjmbdNmrkWr0bHyjlNAd1CQiwmeLxnaTwjf3C+M\nTdI+p08t9wKBgDms84Zk4MaOcv0we2pG/FaD3UQylInUNYJ/dSjN+d3hl32hW7uh\nCCOUP3NfenetrJYKZviPC6MXtgXi6el0GLEl+39jwDj6xAbl/tEfCjdVVsCu+dle\nEv40t2stFqj50UI3jFfEsZ/WEtrwnN3pZXSiIM46WOYj5ZiXF9rzNKjjAoGBAJcv\nwKPf8fM7rgA9Lr64SaTqqQxnVDMzByPPMkKpJzfFl9ZaPMb8NBIhInpuAIRDnGu5\n0nQ6BeYeyTjUxGP5h76O0YTUVWdlJxJK30L9+nnhI/T7lS6yn97TGcBGmAHsUfCh\n/gBoo1SzHDxpOPR8+0moCZBb5hOhHwvAsaPjq+bfAoGBALV/t+smBLogJOBXpfKU\n9LCXnnIqG804vyobSNCVoJm832gBTM7fVcTZa5I+0O+l1emEETIgKU+5ioP/qwou\nU3a/7jXX4hewCpmPVhvvlHgjs+UOBS6hXQMnq52h6mPhiikGOQ6YnqHtxyFORIlo\ntUlwMjanVlxRKyGJlBYQtADk\n-----END PRIVATE KEY-----" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` 创建启用 `saml-auth` 插件的路由: adc.yaml ``` services: - name: saml-auth-service routes: - name: saml-auth-route uris: - /anything/* plugins: saml-auth: secret: my_secret_key sp_issuer: api7 idp_uri: "http://192.168.2.101:8080/realms/master/protocol/saml" login_callback_uri: /anything/login_callback logout_callback_uri: /anything/logout_callback logout_uri: /anything/logout logout_redirect_uri: /anything/logout_ok idp_cert: "-----BEGIN CERTIFICATE-----\nMIICmzCCAYMCBgGRl7njKjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0\nZXIwHhcNMjQwODI4MDY0MjA3WhcNMzQwODI4MDY0MzQ3WjARMQ8wDQYDVQQDDAZt\nYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdYPYSFoX2MADS\nIgfLYQ5oZcLNE+qB+qsO8sNpiebMQE3RmI5+MmZC/aozRzkzxcY+AoM50qfHrM1y\nM99A9ZxZt6fW/MuIv6IP5zWLDl0XWGVeOH0HIH4/xBxQetBxm1HdOYpCQg5Wm9hm\nYfebmN7NfW8HjnORjfUuUGgs5eCiHVqfiCfphLF5w+DcIcnjIwyF+xVH/7fRWgo5\ninBSeIavZh/LEv7LzBeRleGgoZ/+q7cVQiL2e0b8rsslqUOZJmwdPU3VSS0vW1bm\nXsZsfaZD0bgakFvSj0ARzwIbxc74eEQYKflHGS0zkrpm+TsO5KUn59SCPOhGNgGY\npKKv6cY1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBABN21PoEiTaZ20qQUdKD03m+\nbySlF4jRX2AeZqCedBaW+nHrbefaJdEnE9AcXBENCWVr6ntdeREaL9dW6KpV1hT4\nBmnXO2aiFotZe4Vc2W6cv7nDpjil6Q5/isbT5sriYhcU9oXBAaLf9dlg7K/X1l1+\nzcy9Pd1uKUfrC+5ds/Zv+xHiiK4h55o8shcmBmQ7bsanzNmjIQNnyF+lNRciGRvg\nJp59TR7AWpiBQDTNW1KK3XjO9lmN8nCEPbpdNGi77TDX0OZVrbbPy3vL4n8Gi3oQ\nptHhmV7xou4fTEn9TCrdW82OLOduBCMk9t0tFFNB8Hlxq5XsLVLYW7O9GGcjDmI=\n-----END CERTIFICATE-----" sp_cert: "-----BEGIN CERTIFICATE-----\nMIIC0TCCAbmgAwIBAgIUAT7h3zLAul/3S1F9Ms9w7JjpoJ0wDQYJKoZIhvcNAQEL\nBQAwETEPMA0GA1UEAwwGQVBJU0lYMB4XDTI0MDgyNzA5MDk1NloXDTI1MDgyNzA5\nMDk1NlowETEPMA0GA1UEAwwGQVBJU0lYMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAvJBsuNfgvxe+xrBPr9+OCwD4dk3M9ua+14l9tlQHFgtqGXEq7nYc\n0ic9wqim+kdxpJWfiwG0mClklO0nELNsgBVrC06FqrcSe2CGEh91UBkGEOzvOgm7\nEBJOB/5Nc4tE/3NXM0ocfRgFXNEvGMkH9M+odGk7ZQraI/hfazwYgjOty1LrvSMp\nKhCfx0DpKlLuX0w2P9CfLuSgZ0ZTdN3Yr4icEuEs0i3ptCd/bip2fccKkRWEguIe\nywoDl/2fjubJFc5sFhl7Rtf+CeFKgqeByNPX2+UCix136L1r+VIlA+3ClInPWZUY\nWCbs/envBO6omUsnqPPCU2zVdYW0Qb+rrQIDAQABoyEwHzAdBgNVHQ4EFgQUvGIj\nuvPoHC74lhKSlOJAwrdq4WwwDQYJKoZIhvcNAQELBQADggEBAJU0+aKCUSYvN6oe\n7PHYD0ZvE13wItzKq/7DQQe1zA/kDoCvSyC8+gB+FZmdHmkGGNdNqXsQgHEnP7Y0\nx7gDqA3s0blXEkECfmmRcVxcS3rb8CVVFqiKdyRO91opdir5J9vbmiF7RK1ajFTy\nyemhK0xxFpPM+gTdetEj7AoVMrlRoOLC+L62GaSi/gpQmKPR91FLyj33vCfVrDCo\nQXYMPQmSbBCwlHrHWa/Px7F7aQ3fuwmY6jgObxewl3HUSCfV1TT4/uYV9GsrVx4p\np9LcyuVBuJroIlCJrk5Q/ozGhuiRoKApaTeUSjy5opziBRC2bF+TIxbO9Mkibtbh\nxvXZ4WE=\n-----END CERTIFICATE-----" sp_private_key: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8kGy41+C/F77G\nsE+v344LAPh2Tcz25r7XiX22VAcWC2oZcSrudhzSJz3CqKb6R3GklZ+LAbSYKWSU\n7ScQs2yAFWsLToWqtxJ7YIYSH3VQGQYQ7O86CbsQEk4H/k1zi0T/c1czShx9GAVc\n0S8YyQf0z6h0aTtlCtoj+F9rPBiCM63LUuu9IykqEJ/HQOkqUu5fTDY/0J8u5KBn\nRlN03diviJwS4SzSLem0J39uKnZ9xwqRFYSC4h7LCgOX/Z+O5skVzmwWGXtG1/4J\n4UqCp4HI09fb5QKLHXfovWv5UiUD7cKUic9ZlRhYJuz96e8E7qiZSyeo88JTbNV1\nhbRBv6utAgMBAAECggEAFPBeulnykZXD8BFVD/0dq1gkvxJdn884wvt4E76Z+Nc0\npXWdJFTGV4nXAF41CJbVZkbdLBT45mq2ShlZnK+n7UMzm1JRYocozL2Htcx7fPUC\naO++ku3QsXSu6JFTLXD6LPm0ZbQlnLiFo+xws+pi8Ur79E1ZNJuzZIooomJOgGqm\nz/0aTCw1JbMXAI7x0ygCYarfhqX4/M6qokV0Nt64hHxHxtrIWzVac+1QdR4WLaFL\nbdrb6QQeeCw5rWUrZfqmF6+NwCCeP5k/HMeVSwXsI+WrEVCjQBB2qpFqgiDNyfz2\n2i7UYXBP0PUmHEPsctWCYlWwqskBxLZnJdDKTmBCKwKBgQDpXpUpNgaI1LOrhxEQ\n5v1iXDSJweV8Kcdth+e6IGFLtxBgvhDNCijBhwKaFe90SFRldGQgZrz4tBKcxdEw\nslGbbNSSmVZ7nSMpZQoV74Uyrk2i7vxq6A9+ZCMWFpFIwoFBz4SUpnwEe+TEe/l3\nAMOz8BdFa3J0XzUhL7k5X+KaewKBgQDO2Yvi84JhwcmgRzlhv5o6gD40C5x1dv5w\nRqnXxnZGigVwtSBS6CoayBtL8MYNdTB5oM6qoF/FiVHYxbnwgD3d4net/BbUYz9H\nkONxwuEM0a35uSf2FHCaRn7BDPjmbdNmrkWr0bHyjlNAd1CQiwmeLxnaTwjf3C+M\nTdI+p08t9wKBgDms84Zk4MaOcv0we2pG/FaD3UQylInUNYJ/dSjN+d3hl32hW7uh\nCCOUP3NfenetrJYKZviPC6MXtgXi6el0GLEl+39jwDj6xAbl/tEfCjdVVsCu+dle\nEv40t2stFqj50UI3jFfEsZ/WEtrwnN3pZXSiIM46WOYj5ZiXF9rzNKjjAoGBAJcv\nwKPf8fM7rgA9Lr64SaTqqQxnVDMzByPPMkKpJzfFl9ZaPMb8NBIhInpuAIRDnGu5\n0nQ6BeYeyTjUxGP5h76O0YTUVWdlJxJK30L9+nnhI/T7lS6yn97TGcBGmAHsUfCh\n/gBoo1SzHDxpOPR8+0moCZBb5hOhHwvAsaPjq+bfAoGBALV/t+smBLogJOBXpfKU\n9LCXnnIqG804vyobSNCVoJm832gBTM7fVcTZa5I+0O+l1emEETIgKU+5ioP/qwou\nU3a/7jXX4hewCpmPVhvvlHgjs+UOBS6hXQMnq52h6mPhiikGOQ6YnqHtxyFORIlo\ntUlwMjanVlxRKyGJlBYQtADk\n-----END PRIVATE KEY-----" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD saml-auth-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: saml-auth-plugin-config spec: plugins: - name: saml-auth config: secret: my_secret_key sp_issuer: api7 idp_uri: "http://192.168.2.101:8080/realms/master/protocol/saml" login_callback_uri: /anything/login_callback logout_callback_uri: /anything/logout_callback logout_uri: /anything/logout logout_redirect_uri: /anything/logout_ok idp_cert: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" sp_cert: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" sp_private_key: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: saml-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: saml-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f saml-auth-ic.yaml ``` saml-auth-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: saml-auth-route spec: ingressClassName: apisix http: - name: saml-auth-route match: paths: - /anything/* upstreams: - name: httpbin-external-domain plugins: - name: saml-auth enable: true config: secret: my_secret_key sp_issuer: api7 idp_uri: "http://192.168.2.101:8080/realms/master/protocol/saml" login_callback_uri: /anything/login_callback logout_callback_uri: /anything/logout_callback logout_uri: /anything/logout logout_redirect_uri: /anything/logout_ok idp_cert: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" sp_cert: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" sp_private_key: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" ``` 将配置应用到集群: ``` kubectl apply -f saml-auth-ic.yaml ``` #### 验证[​](#验证 "验证的直接链接") 在浏览器中访问 [`http://127.0.0.1:9080/anything/saml-test`](http://127.0.0.1:9080/anything/saml-test) 并使用你的 Keycloak 凭证登录。 如果成功,你应该会被重定向并在浏览器中看到类似于以下的响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-CA,en-US;q=0.9,en;q=0.8", "Cookie": "saml_session=90f84a61-cb03-4f8c-8202-5e7b5267bda6", "Host": "127.0.0.1", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15", "X-Amzn-Trace-Id": "Root=1-66cf4d36-18bbacc80af8987b77b1f5c4", "X-Forwarded-Host": "127.0.0.1" }, "json": null, "method": "GET", "origin": "192.168.65.1, 203.91.85.123", "url": "http://127.0.0.1/anything/saml-test" } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅 [插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md) 了解所有插件可用的配置选项。 * sp\_issuer string 必填 *** 服务提供商 (SP) 在 SAML 认证过程中与身份提供商 (IdP) 通信时使用的唯一标识符。 * idp\_uri string 必填 *** 服务提供商 (SP) 发送认证请求以启动 SAML 认证过程的身份提供商 (IdP) 的 URL。 * idp\_cert string 必填 *** 身份提供商 (IdP) 提供的 X.509 证书,服务提供商 (SP) 使用它来验证 SAML 断言和响应的真实性和完整性。 * login\_callback\_uri string 必填 *** 服务提供商 (SP) 上的端点,身份提供商 (IdP) 将在用户成功认证后向其发送 SAML 响应。 登录回调 URI 应该是路由 URI 的子路径。例如,如果路由 `uri` 是 `/anything/*`,则登录回调 URI 可以是 `/anything/login_callback`。 * logout\_uri string 必填 *** 触发 SAML 注销过程的 URI 路径。 注销 URI 应该是路由 URI 的子路径。例如,如果路由 `uri` 是 `/anything/*`,则注销 URI 可以是 `/anything/logout`。 * logout\_callback\_uri string 必填 *** 服务提供商 (SP) 上接收身份提供商 (IdP) 在注销过程完成后发送的 SAML 注销响应的端点。 注销回调 URI 应该是路由 URI 的子路径。例如,如果路由 `uri` 是 `/anything/*`,则注销回调 URI 可以是 `/anything/logout_callback`。 * logout\_redirect\_uri string 必填 *** 注销过程完成后用户被重定向到的 URI,通常是回到服务提供商 (SP) 的应用程序或指定的着陆页。 注销重定向 URI 应该是路由 URI 的子路径。例如,如果路由 `uri` 是 `/anything/*`,则注销重定向 URI 可以是 `/anything/logout_ok`。 * sp\_cert string 必填 *** 服务提供商 (SP) 用于签署 SAML 请求和断言的 X.509 证书,确保与身份提供商 (IdP) 的安全通信。 * sp\_private\_key string 必填 *** 对应于服务提供商 (SP) 证书 `sp_cert` 的私钥,用于签署 SAML 请求和解密 SAML 断言。 该值在存储到数据库前会使用 AES 加密。 * secret string 必填 有效值: 8 到 32 个字符 *** 用于派生加密密钥以保护 SAML 会话数据和令牌的加密密钥。该密钥应为安全的强随机字符串,确保敏感的认证信息被加密且防篡改。 该值在存储到数据库前会使用 AES 加密。 自 API7 企业版 3.9.3 和 APISIX 3.17.0 起可用。 * auth\_protocol\_binding\_method string 默认值:`HTTP-Redirect` 有效值: `HTTP-Redirect` 或 `HTTP-POST` *** 认证协议绑定方式。自 API7 企业版 3.9.3 和 APISIX 3.17.0 起可用。 当绑定方式为 `HTTP-Redirect` 时,插件通过浏览器 GET 请求重定向发送 SAML 消息。插件不会显式配置该绑定的 cookie 属性;cookie 遵循浏览器或底层 HTTP 协议栈的默认设置(例如 `SameSite` 通常默认为 `Lax`,`Secure` 属性可能根据环境而省略)。 当绑定方式为 `HTTP-POST` 时,插件通过 POST 请求发送 SAML 消息。Cookie 会显式配置 `SameSite=None` 并启用 `Secure` 属性,以支持 HTTPS 上的跨域认证。 * secret\_fallbacks array\[string] *** 密钥轮换期间使用的备用密钥数组。 该值在存储到数据库前会使用 AES 加密。 自 API7 企业版 3.9.3 和 APISIX 3.17.0 起可用。 --- # Serverless Functions Serverless functions 由两个插件组成:`serverless-pre-function` 和 `serverless-post-function`。这些插件允许在函数挂钩的[执行阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E7%9A%84%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)的开始和结束时执行用户定义的逻辑。 ## 编写函数提示[​](#编写函数提示 "编写函数提示的直接链接") Serverless 插件中只允许使用 Lua 函数,不允许使用其他 Lua 代码。 例如,匿名函数是合法的: ``` return function() ngx.log(ngx.ERR, 'one') end ``` 闭包也是合法的: ``` local count = 1 return function() count = count + 1 ngx.say(count) end ``` 但除函数以外的代码是非法的: ``` local count = 1 ngx.say(count) ``` ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下配置 `serverless-pre-function` 和 `serverless-post-function` 插件。 ### 在阶段前后记录信息[​](#在阶段前后记录信息 "在阶段前后记录信息的直接链接") 以下示例演示了如何配置 serverless 插件以执行自定义逻辑,在 `rewrite` [阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E7%9A%84%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)前后将信息记录到错误日志中。 创建一个路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "id": "serverless-pre-route", "uri": "/anything", "plugins": { "serverless-pre-function": { "phase": "rewrite", "functions" : [ "return function() ngx.log(ngx.ERR, \"serverless pre function\"); end" ] }, "serverless-post-function": { "phase": "rewrite", "functions" : [ "return function(conf, ctx) ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); end" ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: serverless-pre-route uris: - /anything plugins: serverless-pre-function: phase: rewrite functions: - | return function() ngx.log(ngx.ERR, "serverless pre function") end serverless-post-function: phase: rewrite functions: - | return function(conf, ctx) ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) end upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD serverless-functions-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: serverless-functions-plugin-config spec: plugins: - name: serverless-pre-function config: phase: rewrite functions: - | return function() ngx.log(ngx.ERR, "serverless pre function") end - name: serverless-post-function config: phase: rewrite functions: - | return function(conf, ctx) ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) end --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: serverless-pre-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: serverless-functions-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` serverless-functions-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: serverless-pre-route spec: ingressClassName: apisix http: - name: serverless-pre-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: serverless-pre-function config: phase: rewrite functions: - | return function() ngx.log(ngx.ERR, "serverless pre function") end - name: serverless-post-function config: phase: rewrite functions: - | return function(conf, ctx) ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) end ``` 应用配置: ``` kubectl apply -f serverless-functions-ic.yaml ``` ❶ 将 serverless pre-function 逻辑挂钩到 `rewrite` [阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E7%9A%84%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)。 ❷ 定义一个 Lua 函数,在错误日志中记录一条 `serverless pre function` 消息。 ❸ 将 serverless post-function 逻辑挂钩到 `rewrite` [阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E7%9A%84%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)。 ❹ 定义一个 Lua 函数,在错误日志中记录匹配的 URI。`conf` 和 `ctx` 可以像其他插件一样作为前两个参数传递,其中 `conf` 是插件配置,`ctx` 是请求上下文。 发送请求到路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应,并在错误日志中看到以下条目: ``` 2024/05/09 15:07:09 [error] 51#51: *3963 [lua] [string "return function() ngx.log(ngx.ERR, "serverles..."]:1: func(): serverless pre function, client: 172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080" 2024/05/09 15:16:58 [error] 50#50: *9343 [lua] [string "return function(conf, ctx) ngx.log(ngx.ERR, "..."]:1: func(): match uri /anything, client: 172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080" ``` 第一个条目由 pre-function 添加,第二个条目由 post-function 添加。 ### 注册自定义变量[​](#注册自定义变量 "注册自定义变量的直接链接") 以下示例演示了如何使用 serverless 插件注册[自定义内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md),并在日志中使用新创建的变量。 信息 由于 Ingress Controller 不支持配置路由标签,因此无法使用它完成此示例。 启动一个示例 rsyslog 服务器: ``` docker run -d -p 514:514 --name example-rsyslog-server rsyslog/syslog_appliance_alpine ``` 创建一个带有 serverless 函数的[服务](https://docs.apiseven.com/apisix/key-concepts/services.md)以注册自定义变量 `a6_route_labels`,启用日志插件以稍后记录自定义变量,并配置上游: * Admin API * ADC ``` curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "id":"srv_custom_var", "plugins": { "serverless-pre-function": { "phase": "rewrite", "functions": [ "return function() local core = require \"apisix.core\" core.ctx.register_var(\"a6_route_labels\", function(ctx) local route = ctx.matched_route and ctx.matched_route.value if route and route.labels then return route.labels end return nil end); end" ] }, "syslog": { "host" : "172.0.0.1", "port" : 514, "flush_limit" : 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: srv-custom-var plugins: serverless-pre-function: phase: rewrite functions: - | return function() local core = require("apisix.core") core.ctx.register_var("a6_route_labels", function(ctx) local route = ctx.matched_route and ctx.matched_route.value if route and route.labels then return route.labels end return nil end) end syslog: host: 172.0.0.1 port: 514 flush_limit: 1 upstream: nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ `functions`: 注册一个自定义变量 `a6_route_labels` 并从匹配路由的 `labels` 属性中获取变量值。 ❷ `host` 和 `port`: 替换为你的 syslog 服务器的地址。 ❸ `flush_limit`: 设置为 1 以立即将日志推送到 syslog 服务器。 接下来,通过配置[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md),使用新变量更新所有 `syslog` 实例的日志格式: * Admin API * ADC ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/syslog" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "log_format": { "host": "$host", "client_ip": "$remote_addr", "labels": "$a6_route_labels" } }' ``` adc.yaml ``` plugin_metadata: syslog: log_format: host: "$host" client_ip: "$remote_addr" labels: "$a6_route_labels" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ `$host` 和 `$remote_addr`:NGINX 变量。 ❷ `$a6_route_labels`: 自定义变量。 最后,在服务中创建一个路由: * Admin API * ADC ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "id":"route_custom_var", "uri":"/get", "service_id": "srv_custom_var", "labels": { "key": "test_a6_route_labels" } }' ``` adc.yaml ``` # 其他配置 services: - name: srv-custom-var routes: - name: route-custom-var uris: - /get labels: key: test_a6_route_labels ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` ❶ `service_id`: 对应之前创建的服务。 ❷ `labels`: 要与自定义变量一起记录的路由信息。 要验证变量注册,请发送请求到路由: ``` curl "http://127.0.0.1:9080/get" ``` 你应该在 syslog 服务器中看到类似于以下的日志条目: ``` { "host":"127.0.0.1", "route_id":"route_custom_var", "client_ip":"172.19.0.1", "labels":{ "key":"test_a6_route_labels" }, "service_id":"srv_custom_var" } ``` 这验证了自定义变量已注册,并且它成功记录了路由中的 `labels` 信息。 ### 修改响应体中的特定字段[​](#修改响应体中的特定字段 "修改响�应体中的特定字段的直接链接") 以下示例演示了如何使用 serverless 插件从 JSON 响应体中删除特定字段。 在进行删除之前,首先配置如下路由以查看未修改的响应: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "id":"serverless-remove-body-info", "uri": "/get", "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: serverless-remove-body-info uris: - /get upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD serverless-remove-body-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: serverless-remove-body-info spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get backendRefs: - name: httpbin-external-domain port: 80 ``` serverless-remove-body-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: serverless-remove-body-info spec: ingressClassName: apisix http: - name: serverless-remove-body-info match: paths: - /get upstreams: - name: httpbin-external-domain ``` 应用配置: ``` kubectl apply -f serverless-remove-body-ic.yaml ``` 发送请求到路由: ``` curl "http://127.0.0.1:9080/get" ``` 你应该看到类似于以下的响应,其中包含你的主机和代理的 IP 信息: ``` { "args": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/8.4.0", "X-Amzn-Trace-Id": "Root=1-663db30f-51448a1b635f2f4338a4fcfc", "X-Forwarded-Host": "127.0.0.1" }, "origin": "172.19.0.1, 43.252.208.84", "url": "http://127.0.0.1/get" } ``` 要从响应中删除 `origin` 字段,请使用 serverless 插件更新路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/serverless-remove-body-info" -X PATCH \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "plugins": { "serverless-pre-function": { "phase": "header_filter", "functions" : [ "return function(conf, ctx) local core = require(\"apisix.core\") core.response.clear_header_as_body_modified() end" ] }, "serverless-post-function": { "phase": "body_filter", "functions" : [ "return function(conf, ctx) local cjson = require(\"cjson\") local core = require(\"apisix.core\") local body = core.response.hold_body_chunk(ctx) if not body then return end body = cjson.decode(body) body.origin = nil body = cjson.encode(body) ngx.arg[1] = body end" ] } } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: serverless-remove-body-info uris: - /get plugins: serverless-pre-function: phase: header_filter functions: - | return function(conf, ctx) local core = require("apisix.core") core.response.clear_header_as_body_modified() end serverless-post-function: phase: body_filter functions: - | return function(conf, ctx) local cjson = require("cjson") local core = require("apisix.core") local body = core.response.hold_body_chunk(ctx) if not body then return end body = cjson.decode(body) body.origin = nil body = cjson.encode(body) ngx.arg[1] = body end upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD serverless-remove-body-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: serverless-remove-body-plugin-config spec: plugins: - name: serverless-pre-function config: phase: header_filter functions: - | return function(conf, ctx) local core = require("apisix.core") core.response.clear_header_as_body_modified() end - name: serverless-post-function config: phase: body_filter functions: - | return function(conf, ctx) local cjson = require("cjson") local core = require("apisix.core") local body = core.response.hold_body_chunk(ctx) if not body then return end body = cjson.decode(body) body.origin = nil body = cjson.encode(body) ngx.arg[1] = body end --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: serverless-remove-body-info spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /get filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: serverless-remove-body-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` serverless-remove-body-ic.yaml ``` # 其他配置 # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: serverless-remove-body-info spec: ingressClassName: apisix http: - name: serverless-remove-body-info match: paths: - /get upstreams: - name: httpbin-external-domain plugins: - name: serverless-pre-function config: phase: header_filter functions: - | return function(conf, ctx) local core = require("apisix.core") core.response.clear_header_as_body_modified() end - name: serverless-post-function config: phase: body_filter functions: - | return function(conf, ctx) local cjson = require("cjson") local core = require("apisix.core") local body = core.response.hold_body_chunk(ctx) if not body then return end body = cjson.decode(body) body.origin = nil body = cjson.encode(body) ngx.arg[1] = body end ``` 应用配置: ``` kubectl apply -f serverless-remove-body-ic.yaml ``` ❶ 在 `header_filter` [阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E7%9A%84%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)执行 pre-function。 ❷ 在 `body_filter` [阶段](https://docs.apiseven.com/apisix/key-concepts/plugins.md#%E6%8F%92%E4%BB%B6%E7%9A%84%E6%89%A7%E8%A1%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)执行后置函数。 前置函数调用 `clear_header_as_body_modified`,以清除 `Content-Length` 等与响应体相关的响应头。后置函数使用 `hold_body_chunk` 收集响应体,解码 JSON 数据,移除 `origin` 字段,并将更新后的响应体写回响应。 再次发送请求到路由: ``` curl "http://127.0.0.1:9080/get" ``` 你应该看到没有 `origin` 信息的响应: ``` { "url":"http://127.0.0.1/get", "args":{}, "headers":{ "X-Forwarded-Host":"127.0.0.1", "Host":"127.0.0.1", "Accept":"*/*", "User-Agent":"curl/8.4.0", "X-Amzn-Trace-Id":"Root=1-663db276-1c15276864294d963c6e1755" } } ``` 对于更简单的响应修改,例如修改 HTTP 状态码、请求头或整个响应体,请使用 [`response-rewrite`](https://docs.apiseven.com/hub/response-rewrite.md) 插件。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * phase string 默认值:`access` 有效值: `rewrite`、`access`、`header_filter`、`body_filter`、`log` 和 `before_proxy` *** Serverless 函数执行之前的阶段。 * functions array\[string] 必填 *** 按顺序执行的函数列表。 仅允许 Lua 函数,不允许其他 Lua 代码。例如,匿名函数和闭包是合法的,而未包含在函数中的其他代码则不被允许。有关详细信息,请参阅[编写函数提示](https://docs.apiseven.com/hub/serverless-functions.md#编写函数提示)。 --- # SkyWalking `skywalking` 插件支持与 [Apache SkyWalking](https://skywalking.apache.org) 集成,用于请求追踪。 SkyWalking 使用其原生的 NGINX Lua 追踪器来提供服务和 URI 视角的追踪、拓扑分析和指标。APISIX 支持使用 HTTP 协议与 SkyWalking 服务器进行交互。 ## 示例[​](#示例 "示例的直接链接") 要按照示例操作,请启动 SkyWalking 存储、OAP 服务器和 Booster UI: * Docker * Kubernetes 要按照示例操作,请按照 [SkyWalking 文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-docker/) 使用 Docker Compose 启动存储、OAP 和 Booster UI。设置完成后,OAP 服务器应监听 `12800`,你应该可以通过 访问 UI。 参考 [SkyWalking 文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-k8s/),将 SkyWalking OAP 服务器和 UI 部署到 Kubernetes 集群中。你可以使用 [SkyWalking Helm Chart](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-k8s/#use-helm-to-install) 快速开始。 部署后,通常可以在集群内通过 `skywalking-oap.skywalking.svc.cluster.local:12800` 访问 OAP 服务器。 SkyWalking OAP 服务器可访问后,请根据网关部署方式完成配置。在 API7 网关中,`skywalking` 默认可通过 Dashboard 和 Admin API 使用。对于 APISIX 部署,在设置 SkyWalking OAP 服务器端点地址前,请先将 `skywalking` 加载到网关插件列表中。 * Host or Docker * Kubernetes (Helm) 对于 APISIX 宿主机或 Docker 部署,请保留 `config.yaml` 中现有插件列表,加入 `skywalking`,并更新 `plugin_attr.skywalking`: config.yaml ``` plugins: # 保留当前网关使用的完整插件列表。 - skywalking plugin_attr: skywalking: report_interval: 3 service_name: APISIX service_instance_name: APISIX Instance endpoint_addr: http://192.168.2.103:12800 ``` 重新加载网关以使配置更改生效。 对于 Helm 部署,请更新用于渲染 SkyWalking 插件属性的 values。对于 APISIX,还需要更新用于渲染网关插件列表的 value。请保留 values 文件中的其他配置。 对于 APISIX Helm Chart,`apisix.plugins` 会替换已加载插件列表。请从当前网关使用的完整插件列表开始,加入 `skywalking`,并在 `apisix.pluginAttrs` 下配置插件属性: values.yaml ``` apisix: plugins: # 保留当前网关使用的完整插件列表。 - skywalking pluginAttrs: skywalking: report_interval: 3 service_name: APISIX service_instance_name: APISIX Instance endpoint_addr: http://192.168.2.103:12800 ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` pluginAttrs: skywalking: report_interval: 3 service_name: APISIX service_instance_name: APISIX Instance endpoint_addr: http://192.168.2.103:12800 ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ### 追踪所有请求[​](#追踪所有请求 "追踪所有请求的直接链接") 以下示例展示了如何追踪通过路由的所有请求。 创建一个启用 `skywalking` 的路由,并将采样率配置为 1 以追踪所有请求: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "skywalking-route", "uri": "/anything", "plugins": { "skywalking": { "sample_ratio": 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: skywalking-route plugins: skywalking: sample_ratio: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD skywalking-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: skywalking-plugin-config spec: plugins: - name: skywalking config: sample_ratio: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: skywalking-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: skywalking-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` skywalking-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: skywalking-route spec: ingressClassName: apisix http: - name: skywalking-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: skywalking enable: true config: sample_ratio: 1 ``` 将配置应用到集群: ``` kubectl apply -f skywalking-ic.yaml ``` 向路由发送一些请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。 在 [SkyWalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该会看到一个名为 `APISIX` 的服务,其中包含与你的请求对应的追踪: ![SkyWalking 中的 APISIX 追踪](https://static.api7.ai/uploads/2025/01/15/UdwiO8NJ_skywalking-traces.png) ### 将追踪与日志关联[​](#将追踪与日志关联 "将追踪与日志关联的直接链接") 以下示例展示了如何在路由上配置 `skywalking-logger` 插件,以记录命中路由的请求信息。 创建一个启用 `skywalking-logger` 插件的路由,并使用你的 OAP 服务器 URI 配置插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "skywalking-logger-route", "uri": "/anything", "plugins": { "skywalking": { "sample_ratio": 1 }, "skywalking-logger": { "endpoint_addr": "http://192.168.2.103:12800" } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: skywalking-logger-route plugins: skywalking: sample_ratio: 1 skywalking-logger: endpoint_addr: "http://192.168.2.103:12800" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD skywalking-logs-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: skywalking-logs-config spec: plugins: - name: skywalking config: sample_ratio: 1 - name: skywalking-logger config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: skywalking-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: skywalking-logs-config backendRefs: - name: httpbin-external-domain port: 80 ``` skywalking-logs-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: skywalking-route spec: ingressClassName: apisix http: - name: skywalking-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: skywalking enable: true config: sample_ratio: 1 - name: skywalking-logger enable: true config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" ``` 将配置应用到集群: ``` kubectl apply -f skywalking-logs-ic.yaml ``` 向路由生成一些请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。 在 [SkyWalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该会看到一个名为 `APISIX` 的服务,其中包含与你的请求对应的追踪,你可以在其中查看关联的日志: ![SkyWalking UI 显示追踪时间线,并突出显示 View Logs 按钮](https://static.api7.ai/uploads/2025/01/16/soUpXm6b_trace-view-logs.png) ![SkyWalking UI 显示与所选追踪关联的日志条目](https://static.api7.ai/uploads/2025/01/16/XD934LvU_associated-logs.png) --- # skywalking-logger `skywalking-logger` 插件将请求和响应日志作为 JSON 对象以批处理的方式推送到 SkyWalking OAP 服务器,并支持自定义日志格式。 如果存在现有的追踪上下文,它会自动设置追踪日志关联,并依赖于 [SkyWalking 跨进程传播头协议](https://skywalking.apache.org/docs/main/next/en/api/x-process-propagation-headers-v3/)。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `skywalking-logger` 插件。 * Docker * Kubernetes 要按照示例操作,请按照 [SkyWalking 文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-docker/) 使用 Docker Compose 启动存储、OAP 和 Booster UI。设置完成后,OAP 服务器应监听 `12800`,你应该可以通过 访问 UI。 要按照示例操作,请参考 [SkyWalking 文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-k8s/),将 SkyWalking OAP 服务器和 UI 部署到 Kubernetes 集群中。你可以使用 [SkyWalking Helm Chart](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-k8s/#use-helm-to-install) 快速开始。 部署后,通常可以在集群内通过 `skywalking-oap.skywalking.svc.cluster.local:12800` 访问 OAP 服务器。 ### 使用默认日志格式记录请求[​](#使用默认日志格式记录请求 "使用默认日志格式记录请求的直接链接") 以下示例展示了如何在路由上配置 `skywalking-logger` 插件,以记录命中路由的请求信息。 创建一个启用 `skywalking-logger` 插件的路由,并使用你的 OAP 服务器 URI 配置插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "skywalking-logger-route", "uri": "/anything", "plugins": { "skywalking-logger": { "endpoint_addr": "http://192.168.2.103:12800" } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: skywalking-logger-route plugins: skywalking-logger: endpoint_addr: "http://192.168.2.103:12800" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD skywalking-logger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: skywalking-logger-plugin-config spec: plugins: - name: skywalking-logger config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: skywalking-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: skywalking-logger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` skywalking-logger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: skywalking-logger-route spec: ingressClassName: apisix http: - name: skywalking-logger-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: skywalking-logger enable: true config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" ``` 将配置应用到集群: ``` kubectl apply -f skywalking-logger-ic.yaml ``` 向路由发送请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。 在 [SkyWalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该会看到一个名为 `APISIX` 的服务,其中包含与你的请求对应的日志条目: ``` { "upstream_latency": 674, "request": { "method": "GET", "headers": { "user-agent": "curl/8.6.0", "host": "127.0.0.1:9080", "accept": "*/*" }, "url": "http://127.0.0.1:9080/anything", "size": 85, "querystring": {}, "uri": "/anything" }, "client_ip": "192.168.65.1", "route_id": "skywalking-logger-route", "start_time": 1736945107345, "upstream": "3.210.94.60:80", "server": { "version": "3.13.0", "hostname": "7edbcebe8eb3" }, "service_id": "", "response": { "size": 619, "status": 200, "headers": { "content-type": "application/json", "date": "Thu, 16 Jan 2025 12:45:08 GMT", "server": "APISIX/3.13.0", "access-control-allow-origin": "*", "connection": "close", "access-control-allow-credentials": "true", "content-length": "391" } }, "latency": 764.9998664856, "apisix_latency": 90.999866485596 } ``` ### 使用插件元数据记录请求和响应头[​](#使用插件元数据记录请求和响应头 "使用插件元数据记录请求和响应头的直接链接") 以下示例展示了如何使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)和[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)自定义日志格式,以记录请求和响应中的特定请求头和响应头。 在 APISIX 中,[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)用于配置同一插件的所有插件实例的通用元数据字段。当插件在多个资源中启用并且需要对其元数据字段进行统一更新时,这非常有用。 首先,创建一个启用 `skywalking-logger` 插件的路由,并使用你的 OAP 服务器 URI 配置插件(与[使用默认日志格式记录请求](#%E4%BD%BF%E7%94%A8%E9%BB%98%E8%AE%A4%E6%97%A5%E5%BF%97%E6%A0%BC%E5%BC%8F%E8%AE%B0%E5%BD%95%E8%AF%B7%E6%B1%82)相同)。 接下来,配置 `skywalking-logger` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/skywalking-logger" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr", "env": "$http_env", "resp_content_type": "$sent_http_Content_Type" } }' ``` adc.yaml ``` plugin_metadata: - name: skywalking-logger log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 更新现有 `GatewayProxy` 资源中的 `pluginMetadata` 字段: gateway-proxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # 控制面连接配置 # .... pluginMetadata: skywalking-logger: log_format: host: "$host" "@timestamp": "$time_iso8601" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 将配置应用到集群: ``` kubectl apply -f gateway-proxy.yaml ``` ❶ 记录自定义请求头 `env`。 ❷ 记录响应头 `Content-Type`。 向路由发送带有 `env` 头的请求: ``` curl -i "http://127.0.0.1:9080/anything" -H "env: dev" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。在 [SkyWalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该会看到一个名为 `APISIX` 的服务,其中包含与你的请求对应的日志条目: ``` [ { "route_id": "skywalking-logger-route", "client_ip": "192.168.65.1", "@timestamp": "2025-01-16T12:51:53+00:00", "host": "127.0.0.1", "env": "dev", "resp_content_type": "application/json" } ] ``` ### 有条件地记录请求体[​](#有条件地记录请求体 "有条件地记录请求体的直接链接") 以下示例展示了如何有条件地记录请求体。 创建一个启用 `skywalking-logger` 插件的路由,如下所示: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "skywalking-logger-route", "uri": "/anything", "plugins": { "skywalking-logger": { "endpoint_addr": "http://192.168.2.103:12800", "include_req_body": true, "include_req_body_expr": [["arg_log_body", "==", "yes"]] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: skywalking-logger-route plugins: skywalking-logger: endpoint_addr: "http://192.168.2.103:12800" include_req_body: true include_req_body_expr: - ["arg_log_body", "==", "yes"] upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD skywalking-logger-body-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: skywalking-logger-body-config spec: plugins: - name: skywalking-logger config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" include_req_body: true include_req_body_expr: - ["arg_log_body", "==", "yes"] --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: skywalking-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: skywalking-logger-body-config backendRefs: - name: httpbin-external-domain port: 80 ``` skywalking-logger-body-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: skywalking-logger-route spec: ingressClassName: apisix http: - name: skywalking-logger-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: skywalking-logger enable: true config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" include_req_body: true include_req_body_expr: - ["arg_log_body", "==", "yes"] ``` 将配置应用到集群: ``` kubectl apply -f skywalking-logger-body-ic.yaml ``` ❶ `include_req_body`: 设置为 true 以包含请求体。 ❷ `include_req_body_expr`: 仅当 URL 查询字符串 `log_body` 为 `yes` 时包含请求体。 向路由发送带有满足条件的 URL 查询字符串的请求: ``` curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}' ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应。在 [SkyWalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该会看到一个名为 `APISIX` 的服务,其中包含与你的请求对应的日志条目,并且记录了请求体: ``` [ { "request": { "url": "http://127.0.0.1:9080/anything?log_body=yes", "querystring": { "log_body": "yes" }, "uri": "/anything?log_body=yes", ..., "body": "{\"env\": \"dev\"}", }, ... } ] ``` 向路由发送不带任何 URL 查询字符串的请求: ``` curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}' ``` 你不应该观察到没有请求体的日志条目。 信息 除了将 `include_req_body` 或 `include_resp_body` 设置为 `true` 之外,如果你自定义了 `log_format`,插件将不会在日志中包含 body。 作为一种解决方法,你也许能够在日志格式中使用 NGINX 变量 `$request_body`,例如: ``` { "skywalking-logger": { ..., "log_format": {"body": "$request_body"} } } ``` ### 将追踪与日志关联[​](#将追踪与日志关联 "将追踪与日志关联的直接链接") 以下示例展示了如何在路由上配置 `skywalking-logger` 插件,以记录命中路由的请求信息。 SkyWalking setup 此示例还要求全局启用 `skywalking` 插件,并为其配置可访问的 OAP 端点地址。对于 Helm 部署,请参阅 [SkyWalking 插件设置](https://docs.apiseven.com/hub/skywalking.md#%E7%A4%BA%E4%BE%8B)。 创建一个启用 `skywalking-logger` 插件的路由,并使用你的 OAP 服务器 URI 配置插件: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "skywalking-logger-route", "uri": "/anything", "plugins": { "skywalking": { "sample_ratio": 1 }, "skywalking-logger": { "endpoint_addr": "http://192.168.2.103:12800" } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: skywalking-logger-route plugins: skywalking: sample_ratio: 1 skywalking-logger: endpoint_addr: "http://192.168.2.103:12800" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD skywalking-logger-trace-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: skywalking-logger-trace-config spec: plugins: - name: skywalking config: sample_ratio: 1 - name: skywalking-logger config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: skywalking-logger-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: skywalking-logger-trace-config backendRefs: - name: httpbin-external-domain port: 80 ``` skywalking-logger-trace-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: skywalking-logger-route spec: ingressClassName: apisix http: - name: skywalking-logger-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: skywalking enable: true config: sample_ratio: 1 - name: skywalking-logger enable: true config: endpoint_addr: "http://skywalking-oap.skywalking.svc.cluster.local:12800" ``` 将配置应用到集群: ``` kubectl apply -f skywalking-logger-trace-ic.yaml ``` 向路由生成一些请求: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。 在 [SkyWalking UI](http://localhost:8080) 中,导航到 **General Service** > **Services**。你应该会看到一个名为 `APISIX` 的服务,其中包含与你的请求对应的追踪,你可以在其中查看关联的日志: ![SkyWalking UI 显示追踪时间线,并突出显示 View Logs 按钮](https://static.api7.ai/uploads/2025/01/16/soUpXm6b_trace-view-logs.png) ![SkyWalking UI 显示与所选追踪关联的日志条目](https://static.api7.ai/uploads/2025/01/16/XD934LvU_associated-logs.png) --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * endpoint\_addr string 必填 *** SkyWalking OAP 服务器的 URI。 * service\_name string 默认值:`APISIX` *** SkyWalking 报告器的服务名称。 * service\_instance\_name string 默认值:`APISIX Instance Name` *** SkyWalking 报告器的服务实例名称。设置为 `$hostname` 以获取本地主机名。 * timeout integer 默认值:`3` 有效值: 大于 0 *** 发送请求后的连接保持时间。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 你也可以通过配置[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)来全局配置日志格式,这将对所有 `skywalking-logger` 插件实例生效。如果单个插件实例配置的日志格式与插件元数据中配置的日志格式不同,则单个插件实例的配置优先级更高。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/skywalking-logger.md#使用插件元数据记录请求和响应头)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * include\_req\_body boolean 默认值:`false` *** 如果设置为 true,在日志中包含请求体。注意:如果请求体过大导致无法保存在内存中,由于 NGINX 的限制,它可能无法被记录。 * include\_req\_body\_expr array\[array] *** 一个包含一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。当 `include_req_body` 为 true 时使用。只有当此处配置的表达式求值为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果设置为 true,在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 一个包含一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。当 `include_resp_body` 为 true 时使用。只有当此处配置的表达式求值为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * name string 默认值:`skywalking logger` *** 批处理器的唯一标识符。如果你使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称将导出在 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每一批次允许的最大日志条目数。一旦达到该数值,批次将被发送到日志服务。将此参数设置为 1 意味着立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(以秒为单位)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 批次中最旧条目在发送到日志服务之前允许保留的最长时间(以秒为单位)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(以秒为单位)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 在丢弃日志条目之前允许的最大失败重试次数。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,日志格式支持最多 5 层深度的嵌套结构。在 API7 企业版中,仅支持扁平的键值对结构,暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 默认情况下,[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中已预先配置插件的服务名称和端点地址。 需要更新的文件取决于网关的部署方式: * Host or Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` plugin_attr: skywalking: report_interval: 3 # 上报间隔(秒)。 service_name: APISIX # SkyWalking 上报器的服务名称。 service_instance_name: "APISIX Instance Name" # SkyWalking 上报器的服务实例名称。 # 设置为 $hostname 可获取本地主机名。 endpoint_addr: http://127.0.0.1:12800 # SkyWalking HTTP 端点。 ``` 然后重新加载网关,使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.skywalking` 的 Chart values。对于 APISIX,还需在应用这些 values 前确认网关插件列表中已加载该插件。请保持 values 文件中的其他配置不变。 对于 APISIX Helm Chart,请设置以下 values: values.yaml ``` apisix: pluginAttrs: skywalking: report_interval: 3 service_name: APISIX service_instance_name: "APISIX Instance Name" endpoint_addr: http://127.0.0.1:12800 ``` 对于 API7 网关 Helm Chart,请设置以下 values: values.yaml ``` pluginAttrs: skywalking: report_interval: 3 service_name: APISIX service_instance_name: "APISIX Instance Name" endpoint_addr: http://127.0.0.1:12800 ``` 然后使用当前网关版本对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * sample\_ratio number 默认值:`1` 有效值: 介于 0.00001 和 1 之间(含边界值) *** 请求采样的频率。将采样率设置为 `1` 意味着对所有请求进行采样。 --- # soap [企业版](https://api7.ai/enterprise) `soap` 插件提供了一种便捷的方法,用于在 RESTful HTTP 请求和 SOAP 请求以及它们对应的响应之间进行转换。 只需一个指向 [WSDL](https://en.wikipedia.org/wiki/Web_Services_Description_Language) 文件的 URL,API7 就会自动解析文件内容并生成转换逻辑,以允许协议转码。 ## 示例[​](#示例 "示例的直接链接") ### 前置条件[​](#前置条件 "前置条件的直接链接") `soap` 插件依赖独立的 `soap-proxy` 服务,该服务负责解析 WSDL 以及在 JSON 与 SOAP 之间进行转码。对于 Docker 部署,请在使用插件前启动 `soap-proxy`;对于 Helm 部署,请在配置网关 values 时启用由 Chart 管理的 `soap-proxy` 边车。 #### 启动 SOAP Proxy[​](#启动-soap-proxy "启动 SOAP Proxy的直接链接") * Docker * Kubernetes (Helm) 在与 APISIX 实例相同的网络中启动 `soap-proxy` 容器(请根据实际环境调整): ``` docker run -d \ --name soap-proxy \ --network=apisix-quickstart-net \ -p 5000:5000 \ api7/soap-proxy:1.0.0 ``` 对于 Helm 部署,请在网关 values 中启用由 Chart 管理的 `soap-proxy` 边车,并保持 values 文件中的其余内容不变。 values.yaml ``` soapProxy: enabled: true ``` 然后,将 values 文件应用到现有网关 Release: ``` helm upgrade api7/gateway -n -f values.yaml ``` #### 配置网关[​](#配置网关 "配置网关的直接链接") 默认情况下,`soap` 插件预期可通过 `http://127.0.0.1:5000` 访问 `soap-proxy`。请更新网关静态配置,使插件指向当前部署使用的代理服务地址: * Docker * Kubernetes (Helm) 将以下配置添加到 `config.yaml`: config.yaml ``` plugin_attr: soap: endpoint: http://soap-proxy:5000 timeout: 3000 ``` 重新加载网关,使更改生效: ``` apisix reload ``` 对于 API7 网关 Helm 部署,请启用由 Chart 管理的 SOAP Proxy 边车,并更新 Chart values 中的 `pluginAttrs.soap`。Chart 会将此值渲染到生成的网关配置 `plugin_attr.soap` 中。请保持 values 文件中的其余内容不变。 values.yaml ``` soapProxy: enabled: true pluginAttrs: soap: endpoint: http://127.0.0.1:5000 timeout: 3000 ``` 然后,将 values 文件应用到现有网关 Release: ``` helm upgrade api7/gateway -n -f values.yaml ``` ### 调用操作[​](#调用操作 "调用操作的直接链接") 以下示例演示了如何在路由上配置插件,并调用 WSDL 文件中指定的上游服务器上可用的操作。 创建一个带有 `soap` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H 'X-API-KEY: ${ADMIN_API_KEY}' \ -d '{ "id": "soap-hello", "uri": "/SayHello", "methods": ["POST"], "plugins": { "soap": { "wsdl_url": "https://apps.learnwebservices.com/services/hello?wsdl" } } }' ``` adc.yaml ``` services: - name: soap-service routes: - name: soap-hello uris: - /SayHello methods: - POST plugins: soap: wsdl_url: "https://apps.learnwebservices.com/services/hello?wsdl" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD soap-ic.yaml ``` apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: soap-hello spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /SayHello method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: soap-plugin-config --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: soap-plugin-config spec: plugins: - name: soap config: wsdl_url: "https://apps.learnwebservices.com/services/hello?wsdl" ``` soap-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: soap-hello spec: ingressClassName: apisix http: - name: soap-hello match: paths: - /SayHello methods: - POST plugins: - name: soap enable: true config: wsdl_url: "https://apps.learnwebservices.com/services/hello?wsdl" ``` 应用配置: ``` kubectl apply -f soap-ic.yaml ``` ❶ 将 URI 设置为 WSDL 文件中的操作名称。 ❷ 仅允许 POST 请求方法。 ❸ 设置 WSDL 文件的 URL 路径。 向路由发送请求以进行验证: ``` curl "http://127.0.0.1:9080/SayHello" -X POST -d '{"Name": "John Doe"}' ``` 你应该看到带有以下内容的 `HTTP/1.1 200 OK` 响应: ``` "Hello John Doe!" ``` --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 默认情况下,SOAP 代理 `endpoint` 和 `timeout` 等值已在默认配置文件 `config-default.yaml` 中预先配置。 需要更新的文件取决于网关部署方式: * 宿主机或 Docker * Kubernetes (Helm) 对于宿主机或 Docker 部署,配置以下设置: config.yaml ``` plugin_attr: soap: endpoint: http://127.0.0.1:5000 timeout: 3000 # 单位为毫秒 ``` 然后[重新加载网关](https://docs.apiseven.com/apisix/reference/apisix-cli.md#apisix-reload)以使更改生效。 对于 Helm 部署,请在 API7 网关 Helm Chart 中设置以下 values,并保留 values 文件中的其他配置。 values.yaml ``` soapProxy: enabled: true pluginAttrs: soap: endpoint: http://127.0.0.1:5000 timeout: 3000 ``` 然后将 values 文件应用到现有网关 release: ``` helm upgrade api7/gateway -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 请参阅[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)了解所有插件可用的配置选项。 * wsdl\_url string 必填 *** WSDL 文件的 URL。 * max\_req\_body\_size integer 默认值:`67108864` *** 缓冲到内存中的请求体最大字节数。超过该上限的请求体会被拒绝。自 API7 企业版 3.9.x 系列的 3.9.17 版本起可用,3.10.x 系列自 3.10.4 版本起可用。 --- # splunk-hec-logging `splunk-hec-logging` 插件将请求和响应上下文信息序列化为 [Splunk 事件数据格式](https://docs.splunk.com/Documentation/Splunk/latest/Data/FormateventsforHTTPEventCollector#Event_metadata) 并分批推送到 [Splunk HTTP 事件收集器 (HEC)](https://docs.splunk.com/Documentation/Splunk/latest/Data/UsetheHTTPEventCollector)。该插件还支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `splunk-hec-logging` 插件。 要跟随示例操作,请完成以下步骤以设置 Splunk: * Local Splunk * Kubernetes 完成以下步骤以设置 Splunk: 1. 安装 [Splunk](https://www.splunk.com/en_us/download.html)。默认情况下,Splunk Web 应在 `localhost:8000` 上运行。 2. 参阅[在 Splunk Web 中设置和使用 HTTP Event Collector](https://docs.splunk.com/Documentation/Splunk/latest/Data/UsetheHTTPEventCollector),创建 HTTP Event Collector。 3. 导航到 **Settings > Data Inputs**,并记下 Token 值。 4. 在 **HTTP Event Collector > Global Settings** 中启用所有 Token,并记下收集器端口;默认端口为 `8088`。 要验证设置,请使用你的令牌执行以下命令: ``` curl "http://localhost:8088/services/collector/event" \ -H "Authorization: Splunk " \ -d '{"event": "hello world"}' ``` 你应该看到 `success` 响应。 创建 Kubernetes 清单以部署启用了 HEC 的 Splunk: splunk-hec-server.yaml ``` apiVersion: v1 kind: ConfigMap metadata: namespace: aic name: splunk-defaults data: default.yml: | splunk: hec: enable: True ssl: False token: apisix-hec-token --- apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: splunk spec: replicas: 1 selector: matchLabels: app: splunk template: metadata: labels: app: splunk spec: enableServiceLinks: false containers: - name: splunk image: splunk/splunk:9.4 env: - name: SPLUNK_START_ARGS value: "--accept-license" # 接受 Splunk 通用条款:https://www.splunk.com/en_us/legal/splunk-general-terms.html - name: SPLUNK_GENERAL_TERMS value: "--accept-sgt-current-at-splunk-com" - name: SPLUNK_PASSWORD value: "Splunk@1234" ports: - containerPort: 8088 - containerPort: 8000 volumeMounts: - name: defaults mountPath: /tmp/defaults readinessProbe: httpGet: path: /services/collector/health port: 8088 initialDelaySeconds: 60 periodSeconds: 10 failureThreshold: 10 volumes: - name: defaults configMap: name: splunk-defaults --- apiVersion: v1 kind: Service metadata: namespace: aic name: splunk-hec spec: selector: app: splunk ports: - name: hec port: 8088 targetPort: 8088 - name: web port: 8000 targetPort: 8000 type: ClusterIP ``` 应用清单: ``` kubectl apply -f splunk-hec-server.yaml ``` 将 Splunk Web 端口转发到本机: ``` kubectl port-forward -n aic svc/splunk-hec 8000:8000 ``` 然后打开 `http://localhost:8000`,使用用户名 `admin` 和密码 `Splunk@1234` 登录。 ### 推送日志到 Splunk[​](#推送日志到-splunk "推送日志到 Splunk的直接链接") 以下示例展示了如何在路由上启用 `splunk-hec-logging` 插件,该插件记录客户端请求并将日志推送到 Splunk。 创建一个路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "splunk-route", "uri": "/anything", "plugins": { "splunk-hec-logging": { "endpoint": { "uri": "http://127.0.0.1:8088/services/collector/event", "token": "example-splunk-hec-token" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: splunk-route uris: - /anything plugins: splunk-hec-logging: endpoint: uri: http://127.0.0.1:8088/services/collector/event token: example-splunk-hec-token upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD splunk-hec-logging-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: splunk-hec-logging-plugin-config spec: plugins: - name: splunk-hec-logging config: endpoint: uri: http://splunk-hec.aic.svc.cluster.local:8088/services/collector/event token: apisix-hec-token --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: splunk-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: splunk-hec-logging-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` splunk-hec-logging-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: splunk-route spec: ingressClassName: apisix http: - name: splunk-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: splunk-hec-logging enable: true config: endpoint: uri: http://splunk-hec.aic.svc.cluster.local:8088/services/collector/event token: apisix-hec-token ``` 应用配置: ``` kubectl apply -f splunk-hec-logging-ic.yaml ``` ❶ 配置 Splunk HTTP 收集器端点。对于 Kubernetes,请使用集群内 `Service` 地址,例如 `http://splunk-hec.aic.svc.cluster.local:8088/services/collector/event`。 ❷ 替换为你的收集器令牌。 发送一些请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 Splunk Web 并在左侧菜单中选择 **Search & Reporting**。在搜索框中输入 `source="apache-apisix-splunk-hec-logging"` 并搜索来自 APISIX 的事件。你应该看到与你的请求对应的事件,如下所示: ### 使用插件元数据记录请求和响应头[​](#使用插件元数据记录请求和响应头 "使用插件元数据记录请求和响应头的直接链接") 以下示例展示了如何使用 [插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md) 和 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md) 自定义日志格式,以记录请头和响应头中的特定信息。 在 APISIX 中,[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md) 用于配置同一插件的所有插件实例的通用元数据字段。当一个插件在多个资源中启用并需要统一更新其元数据字段时,这非常有用。 创建一个路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "splunk-route", "uri": "/anything", "plugins": { "splunk-hec-logging": { "endpoint": { "uri": "http://127.0.0.1:8088/services/collector/event", "token": "example-splunk-hec-token" } } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: splunk-route uris: - /anything plugins: splunk-hec-logging: endpoint: uri: http://127.0.0.1:8088/services/collector/event token: example-splunk-hec-token upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD splunk-hec-logging-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: splunk-hec-logging-plugin-config spec: plugins: - name: splunk-hec-logging config: endpoint: uri: http://splunk-hec.aic.svc.cluster.local:8088/services/collector/event token: apisix-hec-token --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: splunk-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: splunk-hec-logging-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` splunk-hec-logging-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: splunk-route spec: ingressClassName: apisix http: - name: splunk-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: splunk-hec-logging enable: true config: endpoint: uri: http://splunk-hec.aic.svc.cluster.local:8088/services/collector/event token: apisix-hec-token ``` 应用配置: ``` kubectl apply -f splunk-hec-logging-ic.yaml ``` 配置 `splunk-hec-logging` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/splunk-hec-logging" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "route_id": "$route_id", "client_ip": "$remote_addr", "env": "$http_env", "resp_content_type": "$sent_http_Content_Type" } }' ``` adc.yaml ``` plugin_metadata: - name: splunk-hec-logging log_format: host: "$host" "@timestamp": "$time_iso8601" route_id: "$route_id" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: splunk-hec-logging: log_format: host: "$host" "@timestamp": "$time_iso8601" route_id: "$route_id" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: splunk-hec-logging: log_format: host: "$host" "@timestamp": "$time_iso8601" route_id: "$route_id" client_ip: "$remote_addr" env: "$http_env" resp_content_type: "$sent_http_Content_Type" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` ❶ 记录自定义请求头 `env`。 ❷ 记录响应头 `Content-Type`。 发送带有 `env` 头的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -H "env: dev" ``` 导航到 Splunk Web 并在左侧菜单中选择 **Search & Reporting**。在搜索框中输入 `source="apache-apisix-splunk-hec-logging"` 并搜索事件。你应该看到最新的事件对应你的请求,类似于以下内容: --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * endpoint object\[object] 必填 *** Splunk HEC 端点配置。 * uri string 必填 *** Splunk HEC 事件收集器 API 端点。 * token string 必填 *** Splunk HEC 认证令牌。API7 网关使用 AES 对该值进行静态加密;当启用 `apisix.data_encryption.enable_encrypt_fields` 时,APISIX 会在写入 etcd 前对其加密。 * channel string *** Splunk HEC 发送数据通道标识符。有关更多信息,请参阅 [关于 HTTP 事件收集器索引器确认](https://docs.splunk.com/Documentation/Splunk/latest/Data/AboutHECIDXAck)。 * timeout integer 默认值:`10` *** Splunk HEC 发送数据超时时间(秒)。 * keepalive\_timeout integer 默认值:`60000` 有效值: 大于或等于 1000 *** Keepalive 超时时间(毫秒)。 * ssl\_verify boolean 默认值:`true` *** 启用 SSL 验证。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,支持最多 5 层深度的嵌套日志格式结构。在 API7 企业版中,仅支持扁平键值结构;暂不支持嵌套结构。 你还可以使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)全局配置日志格式,这将为所有 `splunk-hec-logging` 插件实例配置日志格式。如果单个插件实例上配置的日志格式与插件元数据上配置的日志格式不同,则以单个插件实例上配置的日志格式为准。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/splunk-hec-logging.md#使用插件元数据记录请求和响应头)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * name string 默认值:`splunk-hec-logging` *** 批处理器的插件唯一标识符。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每个批次允许的最大日志条目数。一旦达到该数量,批次将被发送到 Splunk HEC/日志服务端点。将此参数设置为 1 表示立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(秒)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 在将批次发送到日志服务之前,允许的最早条目的最大存在时间(秒)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(秒)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 允许的最大重试次数,超过此次数将丢弃日志条目。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,支持最多 5 层深度的嵌套日志格式结构。在 API7 企业版中,仅支持扁平键值结构;暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:``在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192`;API7 企业版 3.9.18 与 3.10.5 中无默认值`` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.8.17 和 APISIX 3.15.0 中引入。 在 APISIX 3.18.0、API7 企业版 3.9 分支的 3.9.19 以及 3.10 分支的 3.10.6 中,默认值变更为 `8192`。在 API7 企业版 3.9.18、3.10.5 及更早的 APISIX 版本中,省略该参数会使积压队列不设上限。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # syslog `syslog` 插件将请求和响应日志作为 JSON 对象分批推送到 syslog 服务器,并支持自定义日志格式。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了如何在不同场景下配置 `syslog` 插件。 要跟随示例操作,你应该有一个运行中的 syslog 服务器,或者在 Docker 中启动一个示例 rsyslog 服务器: * Docker * Kubernetes ``` docker run -d -p 514:514/tcp --name example-rsyslog-server rsyslog/syslog_appliance_alpine ``` 查看服务器收到的日志: ``` docker logs -f example-rsyslog-server ``` 为示例 TCP syslog 接收器创建 Kubernetes 清单: syslog-server.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: example-rsyslog-server spec: replicas: 1 selector: matchLabels: app: example-rsyslog-server template: metadata: labels: app: example-rsyslog-server spec: containers: - name: tcp-syslog image: alpine/socat args: - -v - TCP-LISTEN:514,reuseaddr,fork - STDOUT ports: - containerPort: 514 protocol: TCP --- apiVersion: v1 kind: Service metadata: namespace: aic name: example-rsyslog-server spec: selector: app: example-rsyslog-server ports: - name: tcp-syslog port: 514 targetPort: 514 protocol: TCP type: ClusterIP ``` 应用清单: ``` kubectl apply -f syslog-server.yaml ``` 查看服务器收到的日志: ``` kubectl logs -n aic deploy/example-rsyslog-server -f ``` ### 推送日志到 Syslog 服务器[​](#推送日志到-syslog-服务器 "推送日志到 Syslog 服务器的直接链接") 以下示例展示了如何在路由上启用 `syslog` 插件,该插件记录客户端对路由的请求并将日志推送到 syslog 服务器。 创建一个路由并在其上启用 `syslog`: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "syslog-route", "uri": "/anything", "plugins": { "syslog": { "host": "127.0.0.1", "port": 514, "flush_limit": 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: syslog-route uris: - /anything plugins: syslog: host: 127.0.0.1 port: 514 flush_limit: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD syslog-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: syslog-plugin-config spec: plugins: - name: syslog config: host: example-rsyslog-server.aic.svc.cluster.local port: 514 flush_limit: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: syslog-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: syslog-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` syslog-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: syslog-route spec: ingressClassName: apisix http: - name: syslog-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: syslog enable: true config: host: example-rsyslog-server.aic.svc.cluster.local port: 514 flush_limit: 1 ``` 应用配置: ``` kubectl apply -f syslog-ic.yaml ``` ❶ `host`:替换为 syslog 服务器的地址。对于 Kubernetes,请使用集群内 `Service` 地址,例如 `example-rsyslog-server.aic.svc.cluster.local`。 ❷ `port`: 替换为你的 syslog 服务器端口。 ❸ `flush_limit`:设置为 `1`,以便立即将日志推送到 syslog 服务器。 发送一个请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 在 syslog 服务器中,你应该看到类似以下的日志条目: ``` { "response": { "status": 200, "headers": { "access-control-allow-credentials": "true", "connection": "close", "date": "Fri, 17 Apr 2026 05:39:46 GMT", "access-control-allow-origin": "*", "server": "APISIX/3.16.0", "content-type": "application/json", "content-length": "387" }, "size": 614 }, "service_id": "", "client_ip": "172.19.0.1", "server": { "hostname": "eff61bf7be4d", "version": "3.16.0" }, "upstream": "35.171.123.176:80", "apisix_latency": 13.999900817871, "request": { "method": "GET", "url": "http://127.0.0.1:9080/anything", "querystring": {}, "size": 86, "uri": "/anything", "headers": { "host": "127.0.0.1:9080", "accept": "*/*", "user-agent": "curl/7.29.0" } }, "route_id": "syslog-route", "upstream_latency": 165, "latency": 178.99990081787, "start_time": 1709334859598 } ``` ### 使用插件元数据自定义日志格式[​](#使用插件元数据自定义日志格式 "使用插件元数据自定义日志格式的直接链接") 以下示例展示了如何使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)自定义日志格式。在插件元数据中配置的日志格式将应用于所有 `syslog` 插件实例。 创建一个启用 `syslog` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "syslog-route", "uri": "/anything", "plugins": { "syslog": { "host": "127.0.0.1", "port": 514, "flush_limit": 1 } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: syslog-route uris: - /anything plugins: syslog: host: 127.0.0.1 port: 514 flush_limit: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD syslog-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: syslog-plugin-config spec: plugins: - name: syslog config: host: example-rsyslog-server.aic.svc.cluster.local port: 514 flush_limit: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: syslog-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: syslog-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` syslog-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: syslog-route spec: ingressClassName: apisix http: - name: syslog-route match: paths: - /anything methods: - GET upstreams: - name: httpbin-external-domain plugins: - name: syslog enable: true config: host: example-rsyslog-server.aic.svc.cluster.local port: 514 flush_limit: 1 ``` 应用配置: ``` kubectl apply -f syslog-ic.yaml ``` 配置 `syslog` 的插件元数据: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/syslog" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "route_id": "$route_id", "client_ip": "$remote_addr", "resp_content_type": "$sent_http_Content_Type" } }' ``` adc.yaml ``` plugin_metadata: - name: syslog log_format: host: "$host" "@timestamp": "$time_iso8601" route_id: "$route_id" client_ip: "$remote_addr" resp_content_type: "$sent_http_Content_Type" ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: syslog: log_format: host: "$host" "@timestamp": "$time_iso8601" route_id: "$route_id" client_ip: "$remote_addr" resp_content_type: "$sent_http_Content_Type" ``` gatewayproxy.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: namespace: aic name: apisix-config spec: provider: type: ControlPlane controlPlane: # ... # 控制面连接配置 pluginMetadata: syslog: log_format: host: "$host" "@timestamp": "$time_iso8601" route_id: "$route_id" client_ip: "$remote_addr" resp_content_type: "$sent_http_Content_Type" ``` 应用配置: ``` kubectl apply -f gatewayproxy.yaml ``` 发送一个请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 在 syslog 服务器中,你应该看到类似以下的日志条目: ``` { "@timestamp": "2026-04-17T05:39:46+00:00", "resp_content_type": "application/json", "host": "127.0.0.1", "route_id": "syslog-route", "client_ip": "172.19.0.1" } ``` ### 有条件地记录请求体[​](#有条件地记录请求体 "有条件地记录请求体的直接链接") 以下示例展示了如何有条件地记录请求体。 创建一个启用 `syslog` 插件的路由如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "syslog-route", "uri": "/anything", "plugins": { "syslog": { "host": "127.0.0.1", "port": 514, "flush_limit": 1, "include_req_body": true, "include_req_body_expr": [["arg_log_body", "==", "yes"]] } }, "upstream": { "nodes": { "httpbin.org:80": 1 }, "type": "roundrobin" } }' ``` adc.yaml ``` services: - name: httpbin routes: - name: syslog-route uris: - /anything plugins: syslog: host: 127.0.0.1 port: 514 flush_limit: 1 include_req_body: true include_req_body_expr: - - arg_log_body - == - "yes" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD syslog-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: syslog-plugin-config spec: plugins: - name: syslog config: host: example-rsyslog-server.aic.svc.cluster.local port: 514 flush_limit: 1 include_req_body: true include_req_body_expr: - - arg_log_body - == - "yes" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: syslog-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: syslog-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` syslog-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: syslog-route spec: ingressClassName: apisix http: - name: syslog-route match: paths: - /anything methods: - POST upstreams: - name: httpbin-external-domain plugins: - name: syslog enable: true config: host: example-rsyslog-server.aic.svc.cluster.local port: 514 flush_limit: 1 include_req_body: true include_req_body_expr: - - arg_log_body - == - "yes" ``` 应用配置: ``` kubectl apply -f syslog-ic.yaml ``` ❶ `include_req_body`:设置为 `true` 以包含请求体。 ❷ `include_req_body_expr`:仅当 URL 查询字符串 `log_body` 为 `yes` 时包含请求体。在基于 YAML 的配置中,请用引号括起 `"yes"`,以避免 YAML 将其转换为布尔值。 发送一个满足条件的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST \ -H "Content-Type: application/json" \ -d '{"env":"dev"}' ``` 你应该看到请求体被记录: ``` { "response": { "status": 200, "headers": { "connection": "close", "server": "APISIX/3.16.0", "date": "Fri, 17 Apr 2026 05:55:06 GMT", "access-control-allow-origin": "*", "access-control-allow-credentials": "true", "content-type": "application/json", "content-length": "531" }, "size": 759 }, "service_id": "", "client_ip": "172.19.0.1", "server": { "hostname": "eff61bf7be4d", "version": "3.16.0" }, "upstream": "35.171.123.176:80", "apisix_latency": 0, "request": { "method": "POST", "url": "http://127.0.0.1:9080/anything?log_body=yes", "querystring": { "log_body": "yes" }, "size": 164, "body": "{\"env\":\"dev\"}", "uri": "/anything?log_body=yes", "headers": { "accept": "*/*", "user-agent": "curl/7.29.0", "host": "127.0.0.1:9080", "content-type": "application/json", "content-length": "13" } }, "route_id": "syslog-route", "upstream_latency": 892, "latency": 1011.0001564026, "start_time": 1709340364390 } ``` 发送一个不带 URL 查询字符串的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -X POST \ -H "Content-Type: application/json" \ -d '{"env":"dev"}' ``` 你不应该在日志中看到请求体。 信息 如果你在设置 `include_req_body` 或 `include_resp_body` 为 `true` 的同时自定义了 `log_format`,插件将不会在日志中包含这些内容。 作为变通方法,你可以在日志格式中使用 NGINX 变量 `$request_body`,例如: ``` { "syslog": { ..., "log_format": {"body": "$request_body"} } } ``` --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * host string 必填 *** syslog 服务器的 IP 地址或主机名。 * port integer 必填 *** syslog 服务器的目标端口。 * timeout integer 默认值:`3000` 有效值: 大于 0 *** 上游发送数据的超时时间(毫秒)。 * tls boolean 默认值:`false` *** 如果为 true,则验证 TLS。 * flush\_limit integer 默认值:`4096` 有效值: 大于 0 *** 在将日志推送到 syslog 服务器之前,缓冲区和当前消息允许的最大大小(KB)。 * drop\_limit integer 默认值:`1048576` 有效值: 大于 0 *** 在丢弃日志之前,缓冲区和当前消息允许的最大大小(KB)。 * sock\_type string 默认值:`tcp` 有效值: `tcp` 或 `udp` *** 使用的传输层协议。 * pool\_size integer 默认值:`5` 有效值: 大于或等于 5 *** `sock:keepalive` 使用的保活连接池大小。 * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,支持最多 5 层深度的嵌套日志格式结构。在 API7 企业版中,仅支持扁平键值结构;暂不支持嵌套结构。 你还可以使用[插件元数据](https://docs.apiseven.com/apisix/key-concepts/plugin-metadata.md)全局配置日志格式,这将为所有 `syslog` 插件实例配置日志格式。如果单个插件实例上配置的日志格式与插件元数据上配置的日志格式不同,则以单个插件实例上配置的日志格式为准。有关更多详细信息,请参阅[示例](https://docs.apiseven.com/hub/syslog.md#使用插件元数据自定义日志格式)。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * include\_req\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含请求体。注意,如果请求体太大无法保存在内存中,由于 NGINX 的限制,它可能无法被记录。 * include\_req\_body\_expr array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。仅当 `include_req_body` 为 true 时使用。只有当此处配置的表达式计算结果为 true 时,才会记录请求体。 * include\_resp\_body boolean 默认值:`false` *** 如果为 true,则在日志中包含响应体。 * include\_resp\_body\_expr array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 条件的数组。仅当 `include_resp_body` 为 true 时使用。只有当此处配置的表达式计算结果为 true 时,才会记录响应体。 * max\_req\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的请求体大小上限(字节)。如果请求体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * max\_resp\_body\_bytes integer 默认值:`524288` 有效值: 大于或等于 1 *** 日志中包含的响应体大小上限(字节)。如果响应体超过此值,将被截断。自 APISIX 3.16.0 起可用。 * name string 默认值:`sys logger` *** 批处理器的插件唯一标识符。如果你使用 [Prometheus](https://docs.apiseven.com/hub/prometheus.md) 监控 APISIX 指标,该名称将导出到 `apisix_batch_process_entries` 中。 * batch\_max\_size integer 默认值:`1000` 有效值: 大于 0 *** 每个批次允许的最大日志条目数。一旦达到该数量,批次将被发送到日志服务。将此参数设置为 1 表示立即处理。 * inactive\_timeout integer 默认值:`5` 有效值: 大于 0 *** 在将批次发送到日志服务之前,等待新日志的最长时间(秒)。该值应小于 `buffer_duration`。 * buffer\_duration integer 默认值:`60` 有效值: 大于 0 *** 在将批次发送到日志服务之前,允许的最早条目的最大存在时间(秒)。 * retry\_delay integer 默认值:`1` 有效值: 大于或等于 0 *** 如果批次发送失败,重试发送到日志服务的时间间隔(秒)。 * max\_retry\_count integer 默认值:`0` 有效值: 大于或等于 0 *** 允许的最大重试次数,超过此次数将丢弃日志条目。 ## 插件元数据[​](#插件元数据 "插件元数据的直接链接") * log\_format object *** 使用 JSON 格式的键值对自定义日志格式。值可以引用 [内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 从 APISIX 3.15.0 开始,支持最多 5 层深度的嵌套日志格式结构。在 API7 企业版中,仅支持扁平键值结构;暂不支持嵌套结构。 * log\_format\_extra object *** 用于向默认日志条目添加额外字段,使用 JSON 格式的键值对。值可引用[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。已配置的字段不会覆盖现有默认字段。插件实例优先于插件元数据;在实例上设置空对象会禁用元数据值。配置 `log_format` 时,`log_format_extra` 会被忽略。自 API7 企业版 3.9.15、3.10.2 和 APISIX 3.18.0 起引入。 * max\_pending\_entries integer 默认值:`` 在 APISIX 3.18.0 与 API7 企业版 3.9.19、3.10.6 中为 `8192` `` 有效值: 大于或等于 1 *** 批处理器中等待处理的最大条目数。当积压达到此限制时,新条目会被丢弃。 此参数在 API7 企业版 3.9.x 系列中自 3.9.19 起可用,在 3.10.x 系列中自 3.10.6 起可用,并且在 APISIX 中自 3.18.0 起可用。 有关容量规划和验证指南,请参见[批处理器](https://docs.apiseven.com/apisix/reference/batch-processor.md#configure-the-pending-entry-limit)。 --- # traffic-label `traffic-label` 插件对请求表达式求值,并从首个能产生动作的匹配规则中按权重选择动作。当前版本支持在请求转发到上游前添加或替换请求头。 ## 示例[​](#示例 "示例的直�接链接") 以下示例展示了如何在不同场景下的路由上配置 `traffic-label`。 ### 定义单个匹配条件[​](#定义单个匹配条件 "定义单个匹配条件的直接链接") 以下示例展示了一个包含一个匹配条件和一个关联动作的简单规则。如果请求的 URI 为 `/headers`,插件将向请求添加头 `"X-Server-Id": "100"`。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "traffic-label-route", "uri":"/headers", "plugins":{ "traffic-label": { "rules": [ { "match": [ ["uri", "==", "/headers"] ], "actions": [ { "set_headers": { "X-Server-Id": 100 } } ] } ] } }, "upstream":{ "type":"roundrobin", "nodes":{ "httpbin.org:80":1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: traffic-label-route plugins: traffic-label: rules: - match: - - uri - "==" - /headers actions: - set_headers: X-Server-Id: 100 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-label-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-label-plugin-config spec: plugins: - name: traffic-label config: rules: - match: - - uri - "==" - /headers actions: - set_headers: X-Server-Id: 100 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-label-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-label-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` traffic-label-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-label-route spec: ingressClassName: apisix http: - name: traffic-label-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: traffic-label config: rules: - match: - - uri - "==" - /headers actions: - set_headers: X-Server-Id: 100 ``` 应用配置: ``` kubectl apply -f traffic-label-ic.yaml ``` 发送请求进行验证: ``` curl "http://127.0.0.1:9080/headers" ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", ... "X-Server-Id": "100" } } ``` ### 定义带有逻辑运算符的多个匹配条件[​](#定义带有逻辑运算符的多个匹配条件 "定义带有逻辑运算符的多个匹配条件的直接链接") 你可以使用[逻辑运算符](https://docs.apiseven.com/apisix/reference/apisix-expressions.md#logical-operators)构建更复杂的匹配条件。 以下示例展示了一个规则,包含两个通过 `OR` 逻辑分组的匹配条件和一个关联动作。如果满足其中任何一个条件,插件将向请求添加头 `"X-Server-Id": "100"`。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "traffic-label-route", "uri":"/headers", "plugins":{ "traffic-label": { "rules": [ { "match": [ "OR", ["arg_version", "==", "v1"], ["arg_env", "==", "dev"] ], "actions": [ { "set_headers": { "X-Server-Id": 100 } } ] } ] } }, "upstream":{ "type":"roundrobin", "nodes":{ "httpbin.org:80":1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: traffic-label-route plugins: traffic-label: rules: - match: - OR - - arg_version - "==" - v1 - - arg_env - "==" - dev actions: - set_headers: X-Server-Id: 100 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-label-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-label-plugin-config spec: plugins: - name: traffic-label config: rules: - match: - OR - - arg_version - "==" - v1 - - arg_env - "==" - dev actions: - set_headers: X-Server-Id: 100 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-label-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-label-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` traffic-label-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-label-route spec: ingressClassName: apisix http: - name: traffic-label-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: traffic-label config: rules: - match: - OR - - arg_version - "==" - v1 - - arg_env - "==" - dev actions: - set_headers: X-Server-Id: 100 ``` 应用配置: ``` kubectl apply -f traffic-label-ic.yaml ``` 发送请求进行验证: ``` curl "http://127.0.0.1:9080/headers?env=dev" ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", ... "X-Server-Id": "100" } } ``` 如果你发送一个不匹配任何条件的请求,你将不会看到 `"X-Server-Id": "100"` 被添加到请求头中。 ### 创建加权动作[​](#创建加权动作 "创建加权动作的直接链接") 以下示例展示了一个包含一个匹配条件和多个加权动作的规则,进入的请求将根据权重比例进行分配。 如果某个 `weight` 没有关联任何动作,则这部分请求将不会执行任何动作。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "traffic-label-route", "uri":"/headers", "plugins":{ "traffic-label": { "rules": [ { "match": [ ["uri", "==", "/headers"] ], "actions": [ { "set_headers": { "X-Server-Id": 100 }, "weight": 3 }, { "set_headers": { "X-API-Version": "v2" }, "weight": 2 }, { "weight": 5 } ] } ] } }, "upstream":{ "type":"roundrobin", "nodes":{ "httpbin.org:80":1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: traffic-label-route plugins: traffic-label: rules: - match: - - uri - "==" - /headers actions: - set_headers: X-Server-Id: 100 weight: 3 - set_headers: X-API-Version: v2 weight: 2 - weight: 5 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-label-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-label-plugin-config spec: plugins: - name: traffic-label config: rules: - match: - - uri - "==" - /headers actions: - set_headers: X-Server-Id: 100 weight: 3 - set_headers: X-API-Version: v2 weight: 2 - weight: 5 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-label-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-label-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` traffic-label-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-label-route spec: ingressClassName: apisix http: - name: traffic-label-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: traffic-label config: rules: - match: - - uri - "==" - /headers actions: - set_headers: X-Server-Id: 100 weight: 3 - set_headers: X-API-Version: v2 weight: 2 - weight: 5 ``` 应用配置: ``` kubectl apply -f traffic-label-ic.yaml ``` 每个动作执行的比例取决于该动作的权重相对于 `actions` 字段下列出的所有动作总权重的比例。这里,总权重计算为所有动作权重的总和:3 + 2 + 5 = 10。 因此: ❶ 30% 的请求应具有 `X-Server-Id: 100` 请求头。 ❷ 20% 的请求应具有 `X-API-Version: v2` 请求头。 ❸ 50% 的请求将不会执行任何动作。 生成 50 个连续请求来验证加权动作: ``` resp=$(seq 50 | xargs -I{} curl "http://127.0.0.1:9080/headers" -sL) && \ count_w3=$(echo "$resp" | grep -i "X-Server-Id" | wc -l) && \ count_w2=$(echo "$resp" | grep -i "X-API-Version" | wc -l) && \ echo X-Server-Id: $count_w3, X-API-Version: $count_w2 ``` 响应显示请求头是以加权方式添加到请求中的: ``` X-Server-Id: 15, X-API-Version: 10 ``` ### 定义多个匹配规则[​](#定义多个匹配规则 "定义多个匹配规则的直接链接") 以下示例展示了使用多个规则,每个规则都有自己的匹配条件和动作。 * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "traffic-label-route", "uri":"/headers", "plugins":{ "traffic-label": { "rules": [ { "match": [ ["arg_version", "==", "v1"] ], "actions": [ { "set_headers": { "X-Server-Id": 100 } } ] }, { "match": [ ["arg_version", "==", "v2"] ], "actions": [ { "set_headers": { "X-Server-Id": 200 } } ] } ] } }, "upstream":{ "type":"roundrobin", "nodes":{ "httpbin.org:80":1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /headers name: traffic-label-route plugins: traffic-label: rules: - match: - - arg_version - "==" - v1 actions: - set_headers: X-Server-Id: 100 - match: - - arg_version - "==" - v2 actions: - set_headers: X-Server-Id: 200 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-label-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-label-plugin-config spec: plugins: - name: traffic-label config: rules: - match: - - arg_version - "==" - v1 actions: - set_headers: X-Server-Id: 100 - match: - - arg_version - "==" - v2 actions: - set_headers: X-Server-Id: 200 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-label-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-label-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` traffic-label-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-label-route spec: ingressClassName: apisix http: - name: traffic-label-route match: paths: - /headers upstreams: - name: httpbin-external-domain plugins: - name: traffic-label config: rules: - match: - - arg_version - "==" - v1 actions: - set_headers: X-Server-Id: 100 - match: - - arg_version - "==" - v2 actions: - set_headers: X-Server-Id: 200 ``` 应用配置: ``` kubectl apply -f traffic-label-ic.yaml ``` 发送请求到 `/headers?version=v1` 进行验证: ``` curl "http://127.0.0.1:9080/headers?version=v1" ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", ... "X-Server-Id": "100" } } ``` 发送请求到 `/headers?version=v2` 进行验证: ``` curl "http://127.0.0.1:9080/headers?version=v2" ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", ... "X-Server-Id": "200" } } ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * rules array\[object] 必填 *** 一个或多个匹配条件与待执行动作的组合数组。 规则按顺序求值。规则匹配后,插件按权重选择一个动作;若所选动作包含 `set_headers`,则应用该动作并停止求值。若所选对象仅包含 `weight`,则继续求值下一条规则。 * match array\[array] 必填 *** 一个或多个匹配条件的数组,格式为 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)。 * actions array\[object] 必填 *** 当条件成功匹配时要执行的一个或多个动作的数组。 * set\_headers object *** 一个或多个应用到请求的请求头,格式为 `{"name": "value", ...}`,其中 `value` 可以是[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。如果同名请求头已存在,它将被覆盖。 * weight integer 默认值:`1` *** 动作分布的权重。 --- # traffic-split `traffic-split` 插件根据条件和/或权重将流量引导至各种上游服务。它提供了一种动态且灵活的方法来实现发布策略和管理流量。 ## 示例[​](#示例 "示例的直接链接") 以下示例展示了使用 `traffic-split` 插件的不同用例。 ### 实现灰度发布[​](#实现灰度发布 "实现灰度发布的直接链接") 以下示例演示了如何使用此插件实现灰度发布。 灰度发布是一种渐进式部署方式,其中逐步增加的流量比例会被引导至新版本,从而实现受控、可观测的发布过程。此方法可确保在完全重定向所有流量之前,尽早识别并解决新版本中的潜在问题。 创建一个路由并配置 `traffic-split` 插件,规则如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/headers", "id": "traffic-split-route", "plugins": { "traffic-split": { "rules": [ { "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "httpbin.org:443":1 } }, "weight": 3 }, { "weight": 2 } ] } ] } }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "mock.api7.ai:443":1 } } }' ``` adc.yaml ``` services: - name: traffic-split-service routes: - uris: - /headers name: traffic-split-route plugins: traffic-split: rules: - weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-split-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: mockapi7-external-domain spec: type: ExternalName externalName: mock.api7.ai --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-split-plugin-config spec: plugins: - name: traffic-split config: rules: - weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-split-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-split-plugin-config backendRefs: - name: mockapi7-external-domain port: 443 ``` traffic-split-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbin.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mockapi7-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: mock.api7.ai port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-split-route spec: ingressClassName: apisix http: - name: traffic-split-route match: paths: - /headers upstreams: - name: mockapi7-external-domain plugins: - name: traffic-split enable: true config: rules: - weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 ``` 将配置应用到集群: ``` kubectl apply -f traffic-split-ic.yaml ``` 每个上游的流量比例由该上游的权重相对于所有上游的总权重决定。这里,总权重计算为:3 + 2 = 5。 因此: ❶ 预计 60% 的流量将转发到 `httpbin.org`。 ❷ 预计 40% 的流量将转发到 `mock.api7.ai`。 向路由发送 10 个连续请求以进行验证: ``` resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers" -sL) && \ count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \ count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \ echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7 ``` 你应该看到类似于以下的响应: ``` httpbin.org: 6, mock.api7.ai: 4 ``` 相应地调整上游权重以完成灰度发布。 ### 实现蓝绿部署[​](#实现蓝绿部署 "实现蓝绿部署的直接链接") 以下示例演示了如何使用此插件实现蓝绿部署。 蓝绿部署是一种部署策略,涉及维护两个相同的环境:*蓝色* 和 *绿色*。蓝色环境指的是当前的生产部署,绿色环境指的是新部署。一旦绿色环境经过测试准备好进行生产,流量将被路由到绿色环境,使其成为新的生产部署。 创建一个路由并配置 `traffic-split` 插件,规则如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/headers", "id": "traffic-split-route", "plugins": { "traffic-split": { "rules": [ { "match": [ { "vars": [ ["http_release","==","new_release"] ] } ], "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "httpbin.org:443":1 } } } ] } ] } }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "mock.api7.ai:443":1 } } }' ``` adc.yaml ``` services: - name: traffic-split-service routes: - uris: - /headers name: traffic-split-route plugins: traffic-split: rules: - match: - vars: - ["http_release", "==", "new_release"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-split-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: mockapi7-external-domain spec: type: ExternalName externalName: mock.api7.ai --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-split-plugin-config spec: plugins: - name: traffic-split config: rules: - match: - vars: - ["http_release", "==", "new_release"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-split-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-split-plugin-config backendRefs: - name: mockapi7-external-domain port: 443 ``` traffic-split-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbin.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mockapi7-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: mock.api7.ai port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-split-route spec: ingressClassName: apisix http: - name: traffic-split-route match: paths: - /headers upstreams: - name: mockapi7-external-domain plugins: - name: traffic-split enable: true config: rules: - match: - vars: - ["http_release", "==", "new_release"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 ``` 将配置应用到集群: ``` kubectl apply -f traffic-split-ic.yaml ``` ❶ 仅当请求包含请求头 `release: new_release` 时才执行插件以重定向流量。 向带有 `release` 请求头的路由发送请求: ``` curl "http://127.0.0.1:9080/headers" -H 'release: new_release' ``` 你应该看到类似于以下的响应: ``` { "headers": { "Accept": "*/*", "Host": "httpbin.org", ... } } ``` 向不带任何附加请求头的路由发送请求: ``` curl "http://127.0.0.1:9080/headers" ``` 你应该看到类似于以下的响应: ``` { "headers": { "accept": "*/*", "host": "mock.api7.ai", ... } } ``` ### 使用 APISIX 表达式定义 POST 请求的匹配条件[​](#使用-apisix-表达式定义-post-请求的匹配条件 "使用 APISIX 表达式定义 POST 请求的匹配条件的直接链接") 以下示例演示了如何使用 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 在规则中定义匹配条件,以便在满足 POST 请求的特定条件时有条件地执行插件。 创建一个路由并配置 `traffic-split` 插件,规则如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/post", "methods": ["POST"], "id": "traffic-split-route", "plugins": { "traffic-split": { "rules": [ { "match": [ { "vars": [ ["post_arg_id", "==", "1"] ] } ], "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "httpbin.org:443":1 } } } ] } ] } }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "mock.api7.ai:443":1 } } }' ``` adc.yaml ``` services: - name: traffic-split-service routes: - uris: - /post methods: - POST name: traffic-split-route plugins: traffic-split: rules: - match: - vars: - ["post_arg_id", "==", "1"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-split-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: mockapi7-external-domain spec: type: ExternalName externalName: mock.api7.ai --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-split-plugin-config spec: plugins: - name: traffic-split config: rules: - match: - vars: - ["post_arg_id", "==", "1"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-split-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /post method: POST filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-split-plugin-config backendRefs: - name: mockapi7-external-domain port: 443 ``` traffic-split-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbin.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mockapi7-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: mock.api7.ai port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-split-route spec: ingressClassName: apisix http: - name: traffic-split-route match: paths: - /post methods: - POST upstreams: - name: mockapi7-external-domain plugins: - name: traffic-split enable: true config: rules: - match: - vars: - ["post_arg_id", "==", "1"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 ``` 将配置应用到集群: ``` kubectl apply -f traffic-split-ic.yaml ``` 发送正文中带有 `id=1` 的 POST 请求: ``` curl "http://127.0.0.1:9080/post" -X POST \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'id=1' ``` ❶ 你也可以在 `Content-Type` 中指定字符集,例如 `Content-Type: application/x-www-form-urlencoded;charset=UTF-8`。 你应该看到类似于以下的响应: ``` { "args": {}, "data": "", "files": {}, "form": { "id": "1" }, "headers": { "Accept": "*/*", "Content-Length": "4", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", ... }, ... } ``` 发送正文中不带 `id=1` 的 POST 请求: ``` curl "http://127.0.0.1:9080/post" -X POST \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'random=string' ``` 你应该看到请求被转发到了 `mock.api7.ai`。 ### 使用 APISIX 表达式定义 AND 匹配条件[​](#使用-apisix-表达式定义-and-匹配条件 "使用 APISIX 表达式定义 AND 匹配条件的直接链接") 以下示例演示了如何使用 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 在规则中定义匹配条件,以便在满足多个条件时有条件地执行插件。 创建一个路由并配置 `traffic-split` 插件,匹配规则如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/headers", "id": "traffic-split-route", "plugins": { "traffic-split": { "rules": [ { "match": [ { "vars": [ ["arg_name","==","jack"], ["http_user-id",">","23"], ["http_apisix-key","~~","[a-z]+"] ] } ], "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "httpbin.org:443":1 } }, "weight": 3 }, { "weight": 2 } ] } ] } }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "mock.api7.ai:443":1 } } }' ``` adc.yaml ``` services: - name: traffic-split-service routes: - uris: - /headers name: traffic-split-route plugins: traffic-split: rules: - match: - vars: - ["arg_name", "==", "jack"] - ["http_user-id", ">", "23"] - ["http_apisix-key", "~~", "[a-z]+"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-split-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: mockapi7-external-domain spec: type: ExternalName externalName: mock.api7.ai --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-split-plugin-config spec: plugins: - name: traffic-split config: rules: - match: - vars: - ["arg_name", "==", "jack"] - ["http_user-id", ">", "23"] - ["http_apisix-key", "~~", "[a-z]+"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-split-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-split-plugin-config backendRefs: - name: mockapi7-external-domain port: 443 ``` traffic-split-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbin.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mockapi7-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: mock.api7.ai port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-split-route spec: ingressClassName: apisix http: - name: traffic-split-route match: paths: - /headers upstreams: - name: mockapi7-external-domain plugins: - name: traffic-split enable: true config: rules: - match: - vars: - ["arg_name", "==", "jack"] - ["http_user-id", ">", "23"] - ["http_apisix-key", "~~", "[a-z]+"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 ``` 将配置应用到集群: ``` kubectl apply -f traffic-split-ic.yaml ``` ❶ 仅当满足所有三个条件时才执行插件以重定向流量。 如果满足条件,60% 的流量应被引导至 `httpbin.org`,另外 40% 应被引导至 `mock.api7.ai`。如果不满足条件,所有流量应被引导至 `mock.api7.ai`。 发送 10 个满足所有条件的连续请求以进行验证: ``` resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name=jack" -H 'user-id: 30' -H 'apisix-key: helloapisix' -sL) && \ count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \ count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \ echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7 ``` 你应该看到类似于以下的响应: ``` httpbin.org: 6, mock.api7.ai: 4 ``` 发送 10 个不满足条件的连续请求以进行验证: ``` resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name=random" -sL) && \ count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \ count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \ echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7 ``` 你应该看到类似于以下的响应: ``` httpbin.org: 0, mock.api7.ai: 10 ``` ### 使用 APISIX 表达式定义 OR 匹配条件[​](#使用-apisix-表达式定义-or-匹配条件 "使用 APISIX 表达式定义 OR 匹配条件的直接链接") 以下示例演示了如何使用 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 在规则中定义匹配条件,以便在满足任一组条件时有条件地执行插件。 创建一个路由并配置 `traffic-split` 插件,匹配规则如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/headers", "id": "traffic-split-route", "plugins": { "traffic-split": { "rules": [ { "match": [ { "vars": [ ["arg_name","==","jack"], ["http_user-id",">","23"], ["http_apisix-key","~~","[a-z]+"] ] }, { "vars": [ ["arg_name2","==","rose"], ["http_user-id2","!",">","33"], ["http_apisix-key2","~~","[a-z]+"] ] } ], "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "httpbin.org:443":1 } }, "weight": 3 }, { "weight": 2 } ] } ] } }, "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "mock.api7.ai:443":1 } } }' ``` adc.yaml ``` services: - name: traffic-split-service routes: - uris: - /headers name: traffic-split-route plugins: traffic-split: rules: - match: - vars: - ["arg_name", "==", "jack"] - ["http_user-id", ">", "23"] - ["http_apisix-key", "~~", "[a-z]+"] - vars: - ["arg_name2", "==", "rose"] - ["http_user-id2", "!", ">", "33"] - ["http_apisix-key2", "~~", "[a-z]+"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-split-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: mockapi7-external-domain spec: type: ExternalName externalName: mock.api7.ai --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-split-plugin-config spec: plugins: - name: traffic-split config: rules: - match: - vars: - ["arg_name", "==", "jack"] - ["http_user-id", ">", "23"] - ["http_apisix-key", "~~", "[a-z]+"] - vars: - ["arg_name2", "==", "rose"] - ["http_user-id2", "!", ">", "33"] - ["http_apisix-key2", "~~", "[a-z]+"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-split-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-split-plugin-config backendRefs: - name: mockapi7-external-domain port: 443 ``` traffic-split-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbin.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mockapi7-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: mock.api7.ai port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-split-route spec: ingressClassName: apisix http: - name: traffic-split-route match: paths: - /headers upstreams: - name: mockapi7-external-domain plugins: - name: traffic-split enable: true config: rules: - match: - vars: - ["arg_name", "==", "jack"] - ["http_user-id", ">", "23"] - ["http_apisix-key", "~~", "[a-z]+"] - vars: - ["arg_name2", "==", "rose"] - ["http_user-id2", "!", ">", "33"] - ["http_apisix-key2", "~~", "[a-z]+"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 3 - weight: 2 ``` 将配置应用到集群: ``` kubectl apply -f traffic-split-ic.yaml ``` ❶ 和 ❷:当满足任一组条件时执行插件以重定向流量。 或者,你也可以在这些条件的 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md#logical-operators) 中使用 OR 运算符。 如果满足条件,60% 的流量应被引导至 `httpbin.org`,另外 40% 应被引导至 `mock.api7.ai`。如果不满足条件,所有流量应被引导至 `mock.api7.ai`。 发送 10 个满足第二组条件的连续请求以进行验证: ``` resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name2=rose" -H 'user-id:30' -H 'apisix-key2: helloapisix' -sL) && \ count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \ count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \ echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7 ``` 你应该看到类似于以下的响应: ``` httpbin.org: 6, mock.api7.ai: 4 ``` 发送 10 个不满足任一组条件的连续请求以进行验证: ``` resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/headers?name=random" -sL) && \ count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \ count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \ echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7 ``` 你应该看到类似于以下的响应: ``` httpbin.org: 0, mock.api7.ai: 10 ``` ### 为不同的上游配置不同的规则[​](#为不同的上游配置不同的规则 "为不��同的上游配置不同的规则的直接链接") 以下示例演示了如何在规则集和上游之间设置一对一的映射。 创建一个路由并配置 `traffic-split` 插件,匹配规则如下: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "uri": "/headers", "id": "traffic-split-route", "plugins": { "traffic-split": { "rules": [ { "match": [ { "vars": [ ["http_x-api-id","==","1"] ] } ], "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "httpbin.org:443":1 } }, "weight": 1 } ] }, { "match": [ { "vars": [ ["http_x-api-id","==","2"] ] } ], "weighted_upstreams": [ { "upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "mock.api7.ai:443":1 } }, "weight": 1 } ] } ] } }, "upstream": { "type": "roundrobin", "nodes": { "postman-echo.com:443": 1 }, "scheme": "https", "pass_host": "node" } }' ``` adc.yaml ``` services: - name: traffic-split-service routes: - uris: - /headers name: traffic-split-route plugins: traffic-split: rules: - match: - vars: - ["http_x-api-id", "==", "1"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 1 - match: - vars: - ["http_x-api-id", "==", "2"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 weight: 1 upstream: type: roundrobin scheme: https pass_host: node nodes: - host: postman-echo.com port: 443 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD traffic-split-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: v1 kind: Service metadata: namespace: aic name: mockapi7-external-domain spec: type: ExternalName externalName: mock.api7.ai --- apiVersion: v1 kind: Service metadata: namespace: aic name: postman-echo-external-domain spec: type: ExternalName externalName: postman-echo.com --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: traffic-split-plugin-config spec: plugins: - name: traffic-split config: rules: - match: - vars: - ["http_x-api-id", "==", "1"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 1 - match: - vars: - ["http_x-api-id", "==", "2"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 weight: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: traffic-split-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /headers filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: traffic-split-plugin-config backendRefs: - name: postman-echo-external-domain port: 443 ``` traffic-split-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: httpbin.org port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: mockapi7-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: mock.api7.ai port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: postman-echo-external-domain spec: ingressClassName: apisix scheme: https passHost: node externalNodes: - type: Domain name: postman-echo.com port: 443 --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: traffic-split-route spec: ingressClassName: apisix http: - name: traffic-split-route match: paths: - /headers upstreams: - name: postman-echo-external-domain plugins: - name: traffic-split enable: true config: rules: - match: - vars: - ["http_x-api-id", "==", "1"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: httpbin.org port: 443 weight: 1 weight: 1 - match: - vars: - ["http_x-api-id", "==", "2"] weighted_upstreams: - upstream: type: roundrobin scheme: https pass_host: node nodes: - host: mock.api7.ai port: 443 weight: 1 weight: 1 ``` 将配置应用到集群: ``` kubectl apply -f traffic-split-ic.yaml ``` ❶ 仅当请求包含请求头 `x-api-id: 1` 时才执行插件以重定向流量。 ❷ 仅当请求包含请求头 `x-api-id: 2` 时才执行插件以重定向流量。 发送带有请求头 `x-api-id: 1` 的请求: ``` curl "http://127.0.0.1:9080/headers" -H 'x-api-id: 1' ``` 你应该看到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "headers": { "Accept": "*/*", "Host": "httpbin.org", ... } } ``` 发送带有请求头 `x-api-id: 2` 的请求: ``` curl "http://127.0.0.1:9080/headers" -H 'x-api-id: 2' ``` 你应该看到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "headers": { "accept": "*/*", "host": "mock.api7.ai", ... } } ``` 发送不带任何附加请求头的请求: ``` curl "http://127.0.0.1:9080/headers" ``` 你应该看到类似于以下的响应: ``` { "headers": { "accept": "*/*", "host": "postman-echo.com", ... } } ``` --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * rules array\[object] *** 要执行的一组或多组匹配条件和动作。 * match array\[object] *** 用于条件流量拆分的匹配规则。 * vars array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的匹配条件数组,用于按条件执行插件。 * weighted\_upstreams array\[object] *** 上游配置列表。 * upstream\_id string or integer *** 配置的上游对象的 ID。 * weight integer 默认值:`1` *** 每个上游的权重。 * upstream object *** 上游的配置。 此处不支持 [upstream](https://docs.apiseven.com/apisix/reference/admin-api#tag/Upstream/paths/~1apisix~1admin~1upstreams/post) 的某些配置选项。这些字段包括 `service_name`、`discovery_type`、`checks`、`retries`、`retry_timeout`、`desc` 和 `labels`。作为解决方法,您可以创建一个上游对象并在 `upstream_id` 中配置它。 * type string 默认值:`roundrobin` 有效值: `roundrobin`、`chash`、`ewma` 或 `least_conn` *** 流量拆分算法。`roundrobin` 表示加权轮询,`chash` 表示一致性哈希,`ewma` 表示指数加权移动平均,`least_conn` 表示最少连接。 * hash\_on string 默认值:`vars` 有效值: `vars`、`header`、`cookie`、`consumer` 或 `vars_combinations` *** 当 `type` 为 `chash` 时使用。支持对[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)、请求头、Cookie、消费者或[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)的组合进行哈希。 * key string *** 当 `type` 为 `chash` 时使用。当 `hash_on` 设置为 `header` 或 `cookie` 时,`key` 为必填项。当 `hash_on` 设置为 `consumer` 时,无需配置 `key`,因为 Consumer 名称会自动用作键。 * nodes object *** 上游节点的地址。 * timeout object *** 连接、发送和接收消息的超时时间(以秒为单位)。 * pass\_host string 默认值:`pass` 有效值: `pass`、`node` 或 `rewrite` *** 决定如何传递主机名的模式。`pass` 将客户端的主机名传递给上游。`node` 传递上游节点中配置的主机。`rewrite` 传递 `upstream_host` 中配置的值。 * upstream\_host string *** 当 `pass_host` 为 `rewrite` 时使用。上游的主机名。 * name string *** 上游的标识符,用于指定服务名称、使用场景等。 --- # ua-restriction `ua-restriction` 插件支持通过配置 User-Agent 的白名单或黑名单来限制对上游资源的访问。常见的用例是防止网络爬虫过载上游资源并导致服务降级。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了如何在不同场景下配置 `ua-restriction` 插件。 ### 拒绝网络爬虫并自定义错误消息[​](#拒绝网络爬虫并自定义错误消息 "拒绝网络爬虫并自定义错误消息的直接链接") 以下示例展示了如何配置插件来抵御不需要的网络爬虫并自定义拒绝消息。 * Admin API * ADC * Ingress Controller 创建一个路由如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ua-restriction-route", "uri": "/anything", "plugins": { "ua-restriction": { "bypass_missing": false, "denylist": [ "(Baiduspider)/(\\d+)\\.(\\d+)", "bad-bot-1" ], "message": "Access denied" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: ua-restriction-service routes: - name: ua-restriction-route uris: - /anything plugins: ua-restriction: bypass_missing: false denylist: - "(Baiduspider)/(\\d+)\\.(\\d+)" - "bad-bot-1" message: "Access denied" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD ua-restriction-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ua-restriction-plugin-config spec: plugins: - name: ua-restriction config: bypass_missing: false denylist: - "(Baiduspider)/(\\d+)\\.(\\d+)" - "bad-bot-1" message: "Access denied" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ua-restriction-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ua-restriction-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f ua-restriction-ic.yaml ``` ua-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ua-restriction-route spec: ingressClassName: apisix http: - name: ua-restriction-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: ua-restriction enable: true config: bypass_missing: false denylist: - "(Baiduspider)/(\\d+)\\.(\\d+)" - "bad-bot-1" message: "Access denied" ``` 将配置应用到集群: ``` kubectl apply -f ua-restriction-ic.yaml ``` ❶ 不允许绕过 UA 限制规则。 ❷ 配置不应访问上游资源的 User-Agent。 ❸ 自定义拒绝访问时的错误消息。 发送请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 使用被禁止的 User-Agent 发送另一个请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -H 'User-Agent: Baiduspider/5.0' ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应以及以下消息: ``` {"message":"Access denied"} ``` ### 绕过 UA 限制检查[​](#绕过-ua-限制检查 "绕过 UA 限制检查的直接链接") 以下示例展示了如何配置插件以允许特定 User-Agent 的请求绕过 UA 限制。 * Admin API * ADC * Ingress Controller 创建一个路由如下: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "ua-restriction-route", "uri": "/anything", "plugins": { "ua-restriction": { "bypass_missing": true, "allowlist": [ "good-bot-1" ], "message": "Access denied" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }' ``` adc.yaml ``` services: - name: ua-restriction-service routes: - name: ua-restriction-route uris: - /anything plugins: ua-restriction: bypass_missing: true allowlist: - "good-bot-1" message: "Access denied" upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD ua-restriction-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: ua-restriction-allowlist-plugin-config spec: plugins: - name: ua-restriction config: bypass_missing: true allowlist: - "good-bot-1" message: "Access denied" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: ua-restriction-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: ua-restriction-allowlist-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 将配置应用到集群: ``` kubectl apply -f ua-restriction-ic.yaml ``` ua-restriction-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: ua-restriction-route spec: ingressClassName: apisix http: - name: ua-restriction-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: ua-restriction enable: true config: bypass_missing: true allowlist: - "good-bot-1" message: "Access denied" ``` 将配置应用到集群: ``` kubectl apply -f ua-restriction-ic.yaml ``` ❶ 允许绕过 UA 限制规则。 ❷ 配置应允许访问上游资源的 User-Agent。 发送未修改 User-Agent 的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" ``` 你应该收到 `HTTP/1.1 403 Forbidden` 响应以及以下消息: ``` {"message":"Access denied"} ``` 发送另一个使用空 User-Agent 的请求到该路由: ``` curl -i "http://127.0.0.1:9080/anything" -H 'User-Agent: ' ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 --- ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * bypass\_missing boolean 默认值:`false` *** 如果为 true,则在缺少 `User-Agent` 请求头时绕过 User-Agent 限制检查。 * allowlist array\[string] *** 允许的 User-Agent 列表。支持正则表达式。 `allowlist` 和 `denylist` 必须至少配置其中之一,但不能同时配置。 * denylist array\[string] *** 拒绝的 User-Agent 列表。支持正则表达式。 `allowlist` 和 `denylist` 必须至少配置其中之一,但不能同时配置。 * message string 默认值:`Not allowed` *** 当 User-Agent 被拒绝访问时返回的消息。 --- # workflow `workflow` 插件支持根据使用 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md)定义的规则集,对客户端流量有条件地执行用户自定义操作,从而实现细粒度流量管理。 如果你希望应用更复杂的匹配条件和操作,请参阅 [`traffic-label`](https://docs.apiseven.com/hub/traffic-label.md) 插件。 ## 示例[​](#示例 "示例的直接链接") 以下示例演示了如何在不同场景下使用 `workflow` 插件。 ### 按条件返回 HTTP 状态码[​](#按条件返回-http-状态码 "按条件返回 HTTP 状态码的直接链接") 以下示例演示了一个具有单个匹配条件和单个关联操作的简单规则,用于按条件返回 HTTP 状态码。 创建一个启用 `workflow` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "workflow-route", "uri": "/anything/*", "plugins": { "workflow":{ "rules":[ { "case":[ ["uri", "==", "/anything/rejected"] ], "actions":[ [ "return", {"code": 403} ] ] } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything/* name: workflow-route plugins: workflow: rules: - case: - ["uri", "==", "/anything/rejected"] actions: - - return - code: 403 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD workflow-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: workflow-plugin-config spec: plugins: - name: workflow config: rules: - case: - ["uri", "==", "/anything/rejected"] actions: - - return - code: 403 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: workflow-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: workflow-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` workflow-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: workflow-route spec: ingressClassName: apisix http: - name: workflow-route match: paths: - /anything/* upstreams: - name: httpbin-external-domain plugins: - name: workflow enable: true config: rules: - case: - ["uri", "==", "/anything/rejected"] actions: - - return - code: 403 ``` 将配置应用到集群: ``` kubectl apply -f workflow-ic.yaml ``` ❶ 仅当请求的 URI 路径为 `/anything/rejected` 时触发动作。 ❷ 当规则匹配时,返回 HTTP 状态码 403。 发送一个不匹配任何规则的请求: ``` curl -i "http://127.0.0.1:9080/anything/anything" ``` 你应该会收到 `HTTP/1.1 200 OK` 响应。 发送一个匹配已配置规则的请求: ``` curl -i "http://127.0.0.1:9080/anything/rejected" ``` 你应该会收到如下内容的 `HTTP/1.1 403 Forbidden` 响应: ``` {"error_msg":"rejected by workflow"} ``` ### 根据 URI 和查询参数条件式应用限流[​](#根据-uri-和查询参数条件式应用限流 "根据 URI 和查询参数条件式应用限流的直接链接") 以下示例演示了一个具有两个匹配条件和一个关联操作的规则,用于按条件对请求进行限流。 创建一个启用 `workflow` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "workflow-route", "uri": "/anything/*", "plugins":{ "workflow":{ "rules":[ { "case":[ ["uri", "==", "/anything/rate-limit"], ["arg_env", "==", "v1"] ], "actions":[ [ "limit-count", { "count":1, "time_window":60, "rejected_code":429 } ] ] } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything/* name: workflow-route plugins: workflow: rules: - case: - ["uri", "==", "/anything/rate-limit"] - ["arg_env", "==", "v1"] actions: - - limit-count - count: 1 time_window: 60 rejected_code: 429 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD workflow-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: workflow-plugin-config spec: plugins: - name: workflow config: rules: - case: - ["uri", "==", "/anything/rate-limit"] - ["arg_env", "==", "v1"] actions: - - limit-count - count: 1 time_window: 60 rejected_code: 429 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: workflow-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: workflow-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` workflow-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: workflow-route spec: ingressClassName: apisix http: - name: workflow-route match: paths: - /anything/* upstreams: - name: httpbin-external-domain plugins: - name: workflow enable: true config: rules: - case: - ["uri", "==", "/anything/rate-limit"] - ["arg_env", "==", "v1"] actions: - - limit-count - count: 1 time_window: 60 rejected_code: 429 ``` 将配置应用到集群: ``` kubectl apply -f workflow-ic.yaml ``` ❶ 匹配 URI 路径 `/anything/rate-limit`。 ❷ 匹配值为 `v1` 的查询参数 `env`。有关可用于构建条件的更多变量,请参阅[内置变量](https://docs.apiseven.com/apisix/reference/built-in-variables.md)。 ❸ 当两个条件都匹配时应用限流。 连续发送两个匹配第二条规则的请求: ``` curl -i "http://127.0.0.1:9080/anything/rate-limit?env=v1" ``` 你应该会收到一个 `HTTP/1.1 200 OK` 响应和一个 `HTTP 429 Too Many Requests` 响应。 发送不匹配该条件的请求: ``` curl -i "http://127.0.0.1:9080/anything/anything?env=v1" ``` 由于这些请求未被限流,你应该会收到所有请求的 `HTTP/1.1 200 OK` 响应。 ### 根据消费者条件式应用限流[​](#根据消费者条件式应用限流 "根据消费者条件式应用限流的直接链接") 以下示例演示如何配置插件以根据以下规格执行限流: * 消费者 `john` 应在 30 秒时间窗口内拥有 5 个请求的配额。 * 消费者 `jane` 应在 30 秒时间窗口内拥有 3 个请求的配额。 * 所有其他消费者应在 30 秒时间窗口内拥有 2 个请求的配额。 虽然此示例将使用 [`key-auth`](https://docs.apiseven.com/hub/key-auth.md),但你可以轻松地将其替换为其他身份验证插件。 * Admin API * ADC * Ingress Controller 创建消费者 `john`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "john" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-john-key-auth", "plugins": { "key-auth": { "key": "john-key" } } }' ``` 创建第二个消费者 `jane`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jane" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jane-key-auth", "plugins": { "key-auth": { "key": "jane-key" } } }' ``` 创建第三个消费者 `jimmy`: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "username": "jimmy" }' ``` 为该消费者创建 `key-auth` 凭证: ``` curl "http://127.0.0.1:9180/apisix/admin/consumers/jimmy/credentials" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "cred-jimmy-key-auth", "plugins": { "key-auth": { "key": "jimmy-key" } } }' ``` 创建一个启用 `workflow` 插件的路由: ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "workflow-route", "uri": "/anything", "plugins":{ "key-auth": {}, "workflow":{ "rules":[ { "actions": [ [ "limit-count", { "count": 5, "key": "consumer_john", "key_type": "constant", "rejected_code": 429, "time_window": 30, "policy": "local" } ] ], "case": [ [ "consumer_name", "==", "john" ] ] }, { "actions": [ [ "limit-count", { "count": 3, "key": "consumer_jane", "key_type": "constant", "rejected_code": 429, "time_window": 30, "policy": "local" } ] ], "case": [ [ "consumer_name", "==", "jane" ] ] }, { "actions": [ [ "limit-count", { "count": 2, "key": "$consumer_name", "key_type": "var", "rejected_code": 429, "time_window": 30, "policy": "local" } ] ] } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` 创建三个消费者和一个按消费者启用限速的路由: adc.yaml ``` consumers: - username: john credentials: - name: key-auth type: key-auth config: key: john-key - username: jane credentials: - name: key-auth type: key-auth config: key: jane-key - username: jimmy credentials: - name: key-auth type: key-auth config: key: jimmy-key services: - name: httpbin routes: - uris: - /anything name: workflow-route plugins: key-auth: {} workflow: rules: - case: - ["consumer_name", "==", "john"] actions: - - limit-count - count: 5 key: consumer_john key_type: constant rejected_code: 429 time_window: 30 policy: local - case: - ["consumer_name", "==", "jane"] actions: - - limit-count - count: 3 key: consumer_jane key_type: constant rejected_code: 429 time_window: 30 policy: local - actions: - - limit-count - count: 2 key: "$consumer_name" key_type: var rejected_code: 429 time_window: 30 policy: local upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` 创建三个消费者和一个按消费者启用限速的路由: 关于消费者名称 使用 Ingress Controller 配置消费者时,消费者名称会按 `namespace_consumername` 格式生成。因此,`workflow` 插件中的 `consumer_name` 逻辑应匹配此格式的消费者名称。 * Gateway API * APISIX CRD workflow-ic.yaml ``` apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: john spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: john-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jane spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: jane-key --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: jimmy spec: gatewayRef: name: apisix credentials: - type: key-auth name: primary-key config: key: jimmy-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: workflow-plugin-config spec: plugins: - name: key-auth config: _meta: disable: false - name: workflow config: rules: - case: - ["consumer_name", "==", "aic_john"] actions: - - limit-count - count: 5 key: consumer_john key_type: constant rejected_code: 429 time_window: 30 policy: local - case: - ["consumer_name", "==", "aic_jane"] actions: - - limit-count - count: 3 key: consumer_jane key_type: constant rejected_code: 429 time_window: 30 policy: local - actions: - - limit-count - count: 2 key: "$consumer_name" key_type: var rejected_code: 429 time_window: 30 policy: local --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: workflow-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: workflow-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` workflow-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: john spec: ingressClassName: apisix authParameter: keyAuth: value: key: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jane spec: ingressClassName: apisix authParameter: keyAuth: value: key: jane-key --- apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: jimmy spec: ingressClassName: apisix authParameter: keyAuth: value: key: jimmy-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: workflow-route spec: ingressClassName: apisix http: - name: workflow-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: key-auth enable: true - name: workflow enable: true config: rules: - case: - ["consumer_name", "==", "aic_john"] actions: - - limit-count - count: 5 key: consumer_john key_type: constant rejected_code: 429 time_window: 30 policy: local - case: - ["consumer_name", "==", "aic_jane"] actions: - - limit-count - count: 3 key: consumer_jane key_type: constant rejected_code: 429 time_window: 30 policy: local - actions: - - limit-count - count: 2 key: "$consumer_name" key_type: var rejected_code: 429 time_window: 30 policy: local ``` 将配置应用到集群: ``` kubectl apply -f workflow-ic.yaml ``` ❶ 在路由上启用 `key-auth`。 ❷ 匹配消费者 `john` 并应用 30 秒时间窗口内 5 个请求的限流配额。 ❸ 匹配消费者 `jane` 并应用 30 秒时间窗口内 3 个请求的限流配额。 ❹ 匹配所有其他消费者,并为每个消费者应用 30 秒时间窗口内 2 个请求的限流配额。 要验证,请使用 `john` 的密钥连续发送 6 个请求: ``` resp=$(seq 6 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: john-key' -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示在 6 个请求中,5 个请求成功(状态码 200),而其余请求被拒绝(状态码 429)。 ``` 200: 5, 429: 1 ``` 使用 `jane` 的密钥连续发送 6 个请求: ``` resp=$(seq 6 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jane-key' -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示在 6 个请求中,3 个请求成功(状态码 200),而其余请求被拒绝(状态码 429)。 ``` 200: 3, 429: 3 ``` 使用 `jimmy` 的密钥连续发送 3 个请求: ``` resp=$(seq 3 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jimmy-key' -o /dev/null -s -w "%{http_code}\n") && \ count_200=$(echo "$resp" | grep "200" | wc -l) && \ count_429=$(echo "$resp" | grep "429" | wc -l) && \ echo "200": $count_200, "429": $count_429 ``` 你应该看到以下响应,显示在 3 个请求中,2 个请求成功(状态码 200),而其余请求被拒绝(状态码 429)。 ``` 200: 2, 429: 1 ``` ### 使用滑动窗口应用高级限流[​](#使用滑动窗口应用高级限流 "使用滑动窗口应用高级限流的直接链接") 以下示例演示如何配置 `workflow` 与企业版 `limit-count-advanced` 插件,以使用滑动窗口算法按条件执行限流。 创建一个启用 `workflow` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "workflow-route", "uri": "/anything/*", "plugins":{ "workflow":{ "rules":[ { "case": [ ["uri", "==", "/anything/rate-limit-advanced"] ], "actions": [ [ "limit-count-advanced", { "count": 5, "time_window": 10, "rejected_code": 429, "policy": "local", "key_type": "var", "key": "remote_addr", "window_type": "sliding" } ] ] } ] } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything/* name: workflow-route plugins: workflow: rules: - case: - ["uri", "==", "/anything/rate-limit-advanced"] actions: - - limit-count-advanced - count: 5 time_window: 10 rejected_code: 429 policy: local key_type: var key: remote_addr window_type: sliding upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD workflow-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: workflow-plugin-config spec: plugins: - name: workflow config: rules: - case: - ["uri", "==", "/anything/rate-limit-advanced"] actions: - - limit-count-advanced - count: 5 time_window: 10 rejected_code: 429 policy: local key_type: var key: remote_addr window_type: sliding --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: workflow-route spec: parentRefs: - name: apisix rules: - matches: - path: type: PathPrefix value: /anything/ filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: workflow-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` workflow-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: workflow-route spec: ingressClassName: apisix http: - name: workflow-route match: paths: - /anything/* upstreams: - name: httpbin-external-domain plugins: - name: workflow enable: true config: rules: - case: - ["uri", "==", "/anything/rate-limit-advanced"] actions: - - limit-count-advanced - count: 5 time_window: 10 rejected_code: 429 policy: local key_type: var key: remote_addr window_type: sliding ``` 将配置应用到集群: ``` kubectl apply -f workflow-ic.yaml ``` ❶ 匹配 URI 路径 `/anything/rate-limit-advanced`。 ❷ 条件匹配时应用限流。 ❸ 将限流算法设置为滑动窗口。 每隔一秒向匹配该条件的路由生成 7 个请求: ``` for i in $(seq 7); do (curl -I "http://127.0.0.1:9080/anything/rate-limit-advanced" &) sleep 1 done ``` 你应该会收到大多数请求的 `HTTP/1.1 200 OK` 响应,其余请求为 `HTTP 429 Too Many Requests` 响应。 如果你向具有其他路径的路由发送请求,例如: ``` curl -i "http://127.0.0.1:9080/anything/else" ``` 由于条件不匹配,你将不会观察到任何生效的限流。 --- ## 参数[​](#参数 "参数的直接链接") 有关所有插件均可使用的配置项,请参阅[插件通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md)。 * rules array\[object] 必填 *** 要执行的一组或多组匹配条件和动作。 * case array\[array] *** 一个或多个 [APISIX 表达式](https://docs.apiseven.com/apisix/reference/apisix-expressions.md) 形式的匹配条件数组。 * actions array\[array] 必填 *** 条件匹配成功时要执行的动作数组。目前,该数组仅支持一个动作,且应为 `return` 或 `limit-count`。如果你使用的是 API7 企业版,还可以使用 `limit-count-advanced` 或 `limit-conn` 作为动作。 当动作设置为 `return` 时,你可以配置在匹配条件时返回给客户端的 HTTP 状态码。 当动作设置为 `limit-count` 时,你可以配置 [`limit-count`](https://docs.apiseven.com/hub/limit-count/configuration.md) 插件的所有选项,但 `group` 除外。 当动作设置为 `limit-count-advanced` 时,你可以配置 [`limit-count-advanced`](https://docs.apiseven.com/hub/limit-count-advanced/configuration.md) 插件的所有选项,但 `group` 除外。 当动作设置为 `limit-conn` 时,你可以配置 [`limit-conn`](https://docs.apiseven.com/hub/limit-conn/configuration.md) 插件的所有选项。 --- # zipkin [Zipkin](https://github.com/openzipkin/zipkin) 是一个开源的分布式追踪系统。`zipkin` 插件对 APISIX 进行插桩,并根据 [Zipkin API 规范](https://zipkin.io/pages/instrumenting.html) 将追踪信息发送到 Zipkin。 该插件还可以将追踪信息发送到其他兼容的收集器,例如 [Jaeger](https://www.jaegertracing.io/docs/1.51/getting-started/#migrating-from-zipkin) 和 [Apache SkyWalking](https://skywalking.apache.org/docs/main/latest/en/setup/backend/zipkin-trace/#zipkin-receiver),它们都支持 Zipkin [v1](https://zipkin.io/zipkin-api/zipkin-api.yaml) 和 [v2](https://zipkin.io/zipkin-api/zipkin2-api.yaml) API。 ## 示例[​](#示例 "示例的直接链接") 下面的示例展示了使用 `zipkin` 插件的不同用例。 ### 发送追踪到 Zipkin[​](#发送追踪到-zipkin "发送追踪到 Zipkin的直接链接") 以下示例展示了如何使用 [Zipkin API v2](https://zipkin.io/zipkin-api/zipkin2-api.yaml) 追踪路由请求并将追踪信息发送到 Zipkin。你还将了解跨度版本 2 与跨度版本 1 之间的区别。 在 Docker 中启动一个 Zipkin 实例: * Docker * Kubernetes ``` docker run -d --name zipkin -p 9411:9411 openzipkin/zipkin ``` zipkin-server.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: zipkin spec: replicas: 1 selector: matchLabels: app: zipkin template: metadata: labels: app: zipkin spec: containers: - name: zipkin image: openzipkin/zipkin ports: - containerPort: 9411 --- apiVersion: v1 kind: Service metadata: namespace: aic name: zipkin spec: selector: app: zipkin ports: - port: 9411 targetPort: 9411 type: ClusterIP ``` 应用清单: ``` kubectl apply -f zipkin-server.yaml ``` 创建一个启用了 `zipkin` 的路由,并使用默认的跨度版本 2: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "zipkin-tracing-route", "uri": "/anything", "plugins": { "zipkin": { "endpoint": "http://127.0.0.1:9411/api/v2/spans", "sample_ratio": 1, "span_version": 2 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: zipkin-tracing-route plugins: zipkin: endpoint: "http://127.0.0.1:9411/api/v2/spans" sample_ratio: 1 span_version: 2 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD zipkin-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: zipkin-plugin-config spec: plugins: - name: zipkin config: endpoint: "http://zipkin.aic.svc.cluster.local:9411/api/v2/spans" sample_ratio: 1 span_version: 2 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: zipkin-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: zipkin-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` zipkin-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: zipkin-route spec: ingressClassName: apisix http: - name: zipkin-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: zipkin enable: true config: endpoint: "http://zipkin.aic.svc.cluster.local:9411/api/v2/spans" sample_ratio: 1 span_version: 2 ``` 将配置应用到集群: ``` kubectl apply -f zipkin-ic.yaml ``` ❶ 根据需要调整 Zipkin HTTP 端点的 IP 地址。 ❷ 将采样率配置为 1 以追踪每个请求。 ❸ 将跨度版本设置为 2。 发送请求到该路由: ``` curl "http://127.0.0.1:9080/anything" ``` 你应该收到类似于以下的 `HTTP/1.1 200 OK` 响应: ``` { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Host": "127.0.0.1", "User-Agent": "curl/7.64.1", "X-Amzn-Trace-Id": "Root=1-65af2926-497590027bcdb09e34752b78", "X-B3-Parentspanid": "347dddedf73ec176", "X-B3-Sampled": "1", "X-B3-Spanid": "429afa01d0b0067c", "X-B3-Traceid": "aea58f4b490766eccb08275acd52a13a", "X-Forwarded-Host": "127.0.0.1" }, ... } ``` 导航到 的 Zipkin web UI 并点击 **Run Query**,你应该看到与请求对应的追踪: ![Zipkin UI 显示与搜索查询匹配的追踪列表](https://static.api7.ai/uploads/2024/01/23/MaXhacYO_zipkin-run-query.png) 点击 **Show** 查看更多追踪详情: ![Zipkin 追踪详情视图显示单个请求的跨度](https://static.api7.ai/uploads/2024/01/23/3SmfFq9f_trace-details.png) 请注意,使用跨度版本 2 时,每个被追踪的请求都会创建以下跨度: ``` request ├── proxy └── response ``` 其中 `proxy` 代表从请求开始到 `header_filter` 开始的时间,`response` 代表从 `header_filter` 开始到 `log` 开始的时间。 自 API7 企业版 3.9.10 和 APISIX 3.17.0 起,请求跨度包含 `apisix.response_source` 标签,用于分类响应来源:`apisix`(由 APISIX 生成,如插件拒绝)、`nginx`(NGINX 代理错误)或 `upstream`(来自上游服务的真实响应)。 现在,更新路由上的插件以使用跨度版本 1: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes/zipkin-tracing-route" -X PATCH \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "plugins": { "zipkin": { "span_version": 1 } } }' ``` 更新 `adc.yaml`,将 `span_version` 设置为 1: adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: zipkin-tracing-route plugins: zipkin: endpoint: "http://127.0.0.1:9411/api/v2/spans" sample_ratio: 1 span_version: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD 更新 `zipkin-ic.yaml`,将 `span_version` 设置为 1: zipkin-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: zipkin-plugin-config spec: plugins: - name: zipkin config: endpoint: "http://zipkin.aic.svc.cluster.local:9411/api/v2/spans" sample_ratio: 1 span_version: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: zipkin-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: zipkin-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` 更新 `zipkin-ic.yaml`,将 `span_version` 设置为 1: zipkin-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: zipkin-route spec: ingressClassName: apisix http: - name: zipkin-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: zipkin enable: true config: endpoint: "http://zipkin.aic.svc.cluster.local:9411/api/v2/spans" sample_ratio: 1 span_version: 1 ``` 重新应用配置: ``` kubectl apply -f zipkin-ic.yaml ``` 发送另一个请求到该路由: ``` curl "http://127.0.0.1:9080/anything" ``` 在 Zipkin web UI 中,你应该看到一个新的追踪,其详情类似于以下内容: ![Zipkin v1 追踪详情视图显示单个请求的跨度](https://static.api7.ai/uploads/2024/01/23/OPw2sTPa_v1-trace-spans.png) 请注意,使用较旧的跨度版本 1 时,每个被追踪的请求都会创建以下跨度: ``` request ├── rewrite ├── access └── proxy └── body_filter ``` ### 发送追踪到 Jaeger[​](#发送追踪到-jaeger "发送追踪到 Jaeger的直接链接") 以下示例展示了如何追踪对路由的请求并将追踪信息发送到 Jaeger。 在 Docker 中启动一个 Jaeger 实例: * Docker * Kubernetes ``` docker run -d --name jaeger \ -e COLLECTOR_ZIPKIN_HOST_PORT=9411 \ -p 16686:16686 \ -p 9411:9411 \ jaegertracing/all-in-one ``` jaeger-server.yaml ``` apiVersion: apps/v1 kind: Deployment metadata: namespace: aic name: jaeger spec: replicas: 1 selector: matchLabels: app: jaeger template: metadata: labels: app: jaeger spec: containers: - name: jaeger image: jaegertracing/all-in-one env: - name: COLLECTOR_ZIPKIN_HOST_PORT value: "9411" ports: - containerPort: 16686 - containerPort: 9411 --- apiVersion: v1 kind: Service metadata: namespace: aic name: jaeger spec: selector: app: jaeger ports: - name: ui port: 16686 targetPort: 16686 - name: zipkin port: 9411 targetPort: 9411 type: ClusterIP ``` 应用清单: ``` kubectl apply -f jaeger-server.yaml ``` 创建一个带有 `zipkin` 插件的路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${ADMIN_API_KEY}" \ -d '{ "id": "zipkin-tracing-route", "uri": "/anything", "plugins": { "zipkin": { "endpoint": "http://127.0.0.1:9411/api/v2/spans", "sample_ratio": 1 } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org": 1 } } }' ``` adc.yaml ``` services: - name: httpbin routes: - uris: - /anything name: zipkin-tracing-route plugins: zipkin: endpoint: "http://127.0.0.1:9411/api/v2/spans" sample_ratio: 1 upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1 ``` 将配置同步到网关: ``` adc sync -f adc.yaml ``` * Gateway API * APISIX CRD zipkin-jaeger-ic.yaml ``` apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: zipkin-jaeger-plugin-config spec: plugins: - name: zipkin config: endpoint: "http://jaeger.aic.svc.cluster.local:9411/api/v2/spans" sample_ratio: 1 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: zipkin-jaeger-route spec: parentRefs: - name: apisix hostnames: - "jaeger.example.com" rules: - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: zipkin-jaeger-plugin-config backendRefs: - name: httpbin-external-domain port: 80 ``` zipkin-jaeger-ic.yaml ``` apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: zipkin-jaeger-route spec: ingressClassName: apisix http: - name: zipkin-jaeger-route match: hosts: - "jaeger.example.com" paths: - /* upstreams: - name: httpbin-external-domain plugins: - name: zipkin enable: true config: endpoint: "http://jaeger.aic.svc.cluster.local:9411/api/v2/spans" sample_ratio: 1 ``` 将配置应用到集群: ``` kubectl apply -f zipkin-jaeger-ic.yaml ``` ❶ 根据需要调整 Zipkin HTTP 端点的 IP 地址。 ❷ 将采样率配置为 1 以追踪每个请求。 发送请求到该路由: * Admin API * ADC * Ingress Controller ``` curl "http://127.0.0.1:9080/anything" ``` ``` curl "http://127.0.0.1:9080/anything" ``` ``` curl "http://127.0.0.1:9080/anything" -H "Host: jaeger.example.com" ``` 你应该收到 `HTTP/1.1 200 OK` 响应。 导航到 的 Jaeger web UI,选择 APISIX 作为服务,然后点击 **Find Traces**,你应该看到与请求对应的追踪: ![Jaeger UI 显示由 Zipkin 转发的追踪](https://static.api7.ai/uploads/2024/01/23/X6QdLN3l_jaeger.png) 同样,点击进入追踪后,你应该会发现更多跨度详情: ![Jaeger 追踪详情视图显示从 Zipkin 转发的请求](https://static.api7.ai/uploads/2024/01/23/iP9fXI2A_jaeger-details.png) ### 在日志记录中使用追踪变量[​](#在日志记录中使用追踪变量 "在日志记录中使用追踪变量的直接链接") 以下示例展示了如何配置 `zipkin` 插件以设置以下内置变量,这些变量可用于日志插件或访问日志: * `zipkin_context_traceparent`:[父级链路](https://www.w3.org/TR/trace-context/#trace-context-http-headers-format) ID * `zipkin_trace_id`:当前跨度的链路 ID * `zipkin_span_id`:当前跨度的跨度 ID 启用这些变量的访问日志输出,并允许插件设置 NGINX 变量: * Host or Docker * Kubernetes (Helm) 在网关配置文件中新增或更新以下配置: config.yaml ``` nginx_config: http: enable_access_log: true access_log_format: '{"time": "$time_iso8601","zipkin_context_traceparent": "$zipkin_context_traceparent","zipkin_trace_id": "$zipkin_trace_id","zipkin_span_id": "$zipkin_span_id","remote_addr": "$remote_addr"}' access_log_format_escape: json plugin_attr: zipkin: set_ngx_var: true ``` ❶ `access_log_format`: 自定义访问日志格式以使用 `zipkin` 插件变量。 ❷ `set_ngx_var`: 设置 `zipkin` 变量。 重新加载网关以使配置更改生效。 对于 Helm 部署,请更新用于渲染访问日志格式和 `plugin_attr.zipkin` 的 values,并保留 values 文件中的其他配置。 对于 APISIX Helm Chart,设置以下 values: values.yaml ``` apisix: nginx: logs: enableAccessLog: true accessLogFormat: '{"time": "$time_iso8601","zipkin_context_traceparent": "$zipkin_context_traceparent","zipkin_trace_id": "$zipkin_trace_id","zipkin_span_id": "$zipkin_span_id","remote_addr": "$remote_addr"}' accessLogFormatEscape: json pluginAttrs: zipkin: set_ngx_var: true ``` 对于 API7 网关 Helm Chart,设置以下 values: values.yaml ``` logs: enableAccessLog: true accessLogFormat: '{"time": "$time_iso8601","zipkin_context_traceparent": "$zipkin_context_traceparent","zipkin_trace_id": "$zipkin_trace_id","zipkin_span_id": "$zipkin_span_id","remote_addr": "$remote_addr"}' accessLogFormatEscape: json pluginAttrs: zipkin: set_ngx_var: true ``` 然后使用当前网关 release 对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` 生成请求时,你应该看到类似于以下的访问日志条目: ``` {"time": "23/Jan/2024:06:28:00 +0000","zipkin_context_traceparent": "00-61bce33055c56f5b9bec75227befd142-13ff3c7370b29925-01","zipkin_trace_id": "61bce33055c56f5b9bec75227befd142","zipkin_span_id": "13ff3c7370b29925","remote_addr": "172.28.0.1"} ``` --- ## 静态配置[​](#静态配置 "静态配置的直接链接") 默认情况下,[默认配置](https://github.com/apache/apisix/blob/master/apisix/cli/config.lua)中 `zipkin` 插件的 NGINX 变量配置设置为 false。 需要更新的文件取决于网关的部署方式: * Host or Docker * Kubernetes (Helm) 对于主机或 Docker 部署,请配置以下设置: config.yaml ``` plugin_attr: zipkin: set_ngx_var: true ``` 然后重新加载网关,使更改生效。 对于 Helm 部署,请更新用于渲染 `plugin_attr.zipkin` 的 Chart values,并保持 values 文件中的其他配置不变。 对于 APISIX Helm Chart,请设置以下 values: values.yaml ``` apisix: pluginAttrs: zipkin: set_ngx_var: true ``` 对于 API7 网关 Helm Chart,请设置以下 values: values.yaml ``` pluginAttrs: zipkin: set_ngx_var: true ``` 然后使用当前网关版本对应的 Chart 应用 values 文件: ``` helm upgrade -n -f values.yaml ``` ## 参数[​](#参数 "参数的直接链接") 请参阅插件[通用配置](https://docs.apiseven.com/apisix/reference/plugin-common-configurations.md),了解所有插件通用的配置选项。 * endpoint string 必填 *** 用于接收跨度的 Zipkin 端点,例如 `http://127.0.0.1:9411/api/v2/spans`。 * sample\_ratio number 必填 有效值: 介于 0.00001 和 1 之间(含边界值) *** 采样请求的频率。设置为 1 表示采样每个请求。 * service\_name string 默认值:`APISIX` *** Zipkin 中显示的 Zipkin 报告器的服务名称。 * server\_addr string 默认值:`the value of $server_addr` 有效值: IPv4 地址 *** Zipkin 报告器的 IPv4 地址。例如,你可以将其设置为你的外部 IP 地址。 * span\_version integer 默认值:`2` 有效值: 1 或 2 *** 跨度类型的版本。 --- AI 流量网关 # AISIX AI 网关 在 AI 服务提供方前建立稳定的 API 契约 AISIX AI 网关是面向 LLM 与 AI Agent 流量的 Rust 原生网关。[开源网关](https://github.com/api7/aisix)以单个静态二进制运行,可以独立使用,也可以搭配 AISIX Cloud 实现集中管理。无论采用哪种方式,应用都调用稳定的模型别名,而 AI 平台团队负责管理模型服务提供方凭证、路由、故障转移、限流、缓存、安全护栏和可观测性。AISIX Cloud 还提供集中的用量和预算管理。 [开始使用](https://docs.apiseven.com/ai-gateway/getting-started/products-and-deployment-options.md)[查看支持的端点](https://docs.apiseven.com/ai-gateway/endpoints/overview.md) 启动 On-Premises AISIX Cloud 部署localhost:8080 ``` curl -fsSL https://run.api7.ai/aisix-self-hosted/quickstart | bash # 启动控制面和控制台 # Dashboard: http://localhost:8080 ``` ## 请求如何流转 应用先调用 AISIX。AISIX 会完成调用方认证、模型别名解析、策略执行,并将请求转发到选定的服务提供方。 应用**应用、智能体与后端服务**使用网关签发的调用方 API Key,发送兼容 OpenAI 的请求。 -> AISIX 网关边界**稳定契约,可治理的服务提供方访问** AISIX 让客户端流量保持同一套 API 形态,同时在每次请求中解析真实的服务提供方目标。 认证调用方解析模型别名执行限流、缓存和安全护栏选择服务提供方路由 -> 服务提供方**OpenAI、Anthropic、Bedrock、Vertex、Azure**接收由网关携带服务提供方凭证发起的请求。 服务提供方响应会通过 AISIX 返回,并继续保持同一套面向客户端的契约。 ## 当 AI 流量经过 AISIX,会发生什么变化 应用团队继续调用熟悉的 API,AI 平台团队则把模型服务提供方凭证、模型别名、路由和策略统一沉淀到可运维的网关层。AISIX Cloud 还提供共享的用量和预算控制。 *访问控制***调用方 API Key 与模型访问白名单**认证应用身份,并决定每个 API Key 可以访问哪些模型别名。 *服务提供方***集中管理上游凭证**将服务提供方密钥、base URL 和适配器细节从应用代码中解耦出来。 *路由***稳定别名与故障转移**对外暴露一个模型别名,由 AISIX 在背后选择真实目标模型。 *策略***限流、缓存、安全护栏和遥测**在请求离开网关边界前,执行面向 AI 场景的控制并提供用量可见性。 ## 已经使用 APISIX 或 API7 Gateway,为什么还需要 AISIX? APISIX 和 API7 Gateway 可以通过 AI 插件为常规网关路由添加 AI 能力。这适合以 API 流量为主、AI 调用只是现有 API 网关部署中的一部分的团队。 AISIX 面向以 AI 流量为核心负载的团队。它将模型服务提供方密钥、模型别名、调用方 API Key、路由、策略和 AI 用量遥测作为一等资源管理,而不是普通路由上的插件配置。AISIX Cloud 还提供集中的用量视图和预算。 *APISIX* **为现有 API 路由增加 AI 能力。**当现有 API 网关路由就是调用或转换 AI 服务的自然入口时,可以使用 AI 插件。 *AISIX* **让 AI 流量进入专门的网关域。**当应用需要调用稳定模型名称,而 AI 平台团队需要统一管理模型服务提供方密钥、路由、策略和用量可见性时,请使用 AISIX。 继续阅读 ## 选择下一条路径 首先选择 AISIX 的运行方式,然后了解 AISIX Cloud、连接应用,或为生产环境准备网关。 [*开始使用*](https://docs.apiseven.com/ai-gateway/getting-started/products-and-deployment-options.md) [**选择产品和部署选项**独立运行开源网关,或使用 AISIX Cloud 并选择控制面的托管方。](https://docs.apiseven.com/ai-gateway/getting-started/products-and-deployment-options.md) [*AISIX Cloud*](https://docs.apiseven.com/ai-gateway/cloud/overview.md) [**通过控制面管理 AISIX 网关**了解控制面工作流、集中式用量上报和预算控制。](https://docs.apiseven.com/ai-gateway/cloud/overview.md) [*集成*](https://docs.apiseven.com/ai-gateway/integrations.md) [**连接应用和 AI 工具**将客户端 SDK、编程 Agent 和应用框架指向 AISIX 网关。](https://docs.apiseven.com/ai-gateway/integrations.md) [*生产运行*](https://docs.apiseven.com/ai-gateway/deployment/production.md) [**为生产运行准备网关**查看生产网关所需的部署、安全、健康状态、指标和故障排查指南。](https://docs.apiseven.com/ai-gateway/deployment/production.md) --- # 控制 Agent 访问权限 对于 Agent-to-Agent(A2A)流量,每个调用方 API Key 都定义了该调用方可以访问哪些已注册 Agent。除非 API Key 的 `allowed_agents` 授权涵盖 Agent 的注册名称,否则 AISIX 会拒绝 Agent 调用和 Agent Card 发现请求。 当共享同一网关的不同客户端需要访问不同上游 Agent 时,请分别配置授权。本指南介绍 AISIX 如何匹配 Agent 名称和模式、如何通过 AISIX Cloud 或 `resources.yaml` 更新授权,以及请求超出授权范围时的行为。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 请完成 AISIX Cloud 或开源 AISIX 网关的[配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)。如需验证修改后的授权,请保持 Shell、网关和测试 Agent 运行。 ## Agent 访问权限的工作原理[​](#agent-访问权限的工作原理 "Agent 访问权限的工作原理的直接链接") `allowed_agents` 是调用方 API Key 上的 Agent 名称模式列表。如果省略该字段,或将其设置为 `null` 或空列表,则该 API Key 没有 A2A Agent 访问权限。 每个模式都与 Agent 注册的 `name` 进行匹配: | 条目 | 授予的权限 | 示例 | | -------- | ----------------------------------- | ----------------------------------------------------------------- | | 精确名称 | 一个 Agent。 | `invoice-processor` 仅授予对该 Agent 的访问权限。 | | 名称模式 | 名称与一个 `*` 通配符匹配的 Agent。 | `invoice-*` 授予对名称以 `invoice-` 开头的所有 Agent 的访问权限。 | | `*` | 所有已注册 Agent。 | `*` 授予对当前和未来 Agent 的访问权限。 | 如需最小访问权限,请使用精确名称。只有当调用方可以访问当前和未来的所有 Agent 时,才使用 `*`。 匹配器与 [MCP 工具模式](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md)使用的单 `*` Glob 匹配器相同。一个条目最多只能包含一个 `*`。 ## 配置 Agent 访问权限[​](#配置-agent-访问权限 "配置 Agent 访问权限的直接链接") 设置调用方应保留的完整 Agent 列表。AISIX Cloud 将授权存储在 API Key 资源中;开源 AISIX 网关从 `resources.yaml` 中读取授权。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 更新配置指南中创建的调用方 API Key: ``` curl -fsS -X PATCH \ "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "allowed_agents": ["echo-agent", "invoice-*"] }' | jq ``` 该部分更新会替换原有 Agent 授权,同时保留 API Key 的模型、MCP 和其他设置。控制面会自动将更改下发到已连接的网关。 如需撤销所有 A2A Agent 访问权限,请发送 `"allowed_agents": []` 或 `"allowed_agents": null`。 ### 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 将现有的 `quickstart-caller` 条目替换为以下更新后的条目,以设置 `allowed_agents`。保留 `api_keys` 中的所有其他条目及所有无关集合,不要创建第二个顶层 `api_keys` 键: resources.yaml(Agent 访问权限) ``` api_keys: - display_name: quickstart-caller key_env: CALLER_API_KEY allowed_models: - gpt-4o-mini allowed_agents: - echo-agent - invoice-* ``` 验证完整文件并重新加载: ``` docker exec aisix-quickstart \ aisix validate --resources /etc/aisix/resources.yaml docker kill --signal HUP aisix-quickstart ``` 删除 `allowed_agents` 或将其设置为空列表,即可撤销此调用方的所有 A2A Agent 访问权限。 ## 执行访问控制的方式[​](#执行访问控制的方式 "执行访问控制的方式的直接链接") 网关会先确认 Agent 存在且已启用,再检查授权。对于 A2A 调用和 Agent Card 发现,网关都会在联系上游 Agent 之前执行此检查: * 对 `/a2a/` 的 JSON-RPC 调用。 * 对 `/a2a//.well-known/agent-card.json` 的 Agent Card 请求。 调用方看到的结果取决于 Agent 和 API Key 的状态: * 未知或已禁用的 Agent 返回 `404`。 * 已知但不在 API Key 授权范围内的 Agent 返回 `403`,且 AISIX 不会联系上游 Agent。 * 已知且在 API Key 授权范围内的 Agent 会被转发到上游。 由于系统先检查 Agent 是否存在,经过身份认证的调用方可以区分无权访问的 Agent 与不存在的 Agent。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已限定调用方 API Key 可以访问的 Agent。可以继续阅读以下指南,完善调用方和上游控制路径: * [上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md):配置 AISIX 如何向每个上游 Agent 进行身份认证。 * [限流和预算](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md):应用请求和并发限制,并使用 AISIX Cloud 预算。 * [调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md):查看模型、MCP 和 A2A 流量共用的 API Key 设置。 --- # 可观测性 A2A 流量与模型流量使用相同的遥测管道。用量事件字段会标识调用方、Agent、方法和结果;Prometheus 标签则用于区分 Agent 流量与模型流量。 可以使用这些信号统计 Agent 调用量并监控失败。限流和上游错误会出现在与模型流量相同的可观测性工具中;在 AISIX Cloud 中,预算拒绝也会显示在这些工具中。 ## 用量事件[​](#用量事件 "用量事件的直接链接") 当网关能够把请求归因到已启用的 Agent 和调用方时,AISIX 会发出一条 A2A 用量事件。因不支持的上游认证、限流、上游失败,或 AISIX Cloud 中配置的预算而被拒绝的调用也包括在内;格式错误的请求体则可能在产生事件之前就被拒绝。 事件会进入与模型用量相同的接收端,并标识调用方、Agent、方法、结果和时间: | 字段 | 值 | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `inbound_protocol` | `a2a` | | `a2a_agent_name` | 被调用的已注册 Agent。 | | `a2a_method` | 调用方原样写入的 JSON-RPC 方法,例如 `message/send` 或其 1.0 拼写 `SendMessage`;仅当 AISIX 能从请求体读取该方法时才有值。 | | `a2a_operation` | `a2a_method` 所对应的规范化操作。做聚合时请按此字段分组而不是原始方法:A2A 0.3 和 1.0 会把同一个操作拼成两种写法,无法识别的方法归为 `unknown`。 | | `a2a_protocol_version` | AISIX 向该 Agent 声明的协议版本,`0.3` 或 `1.0`。 | | `a2a_task_id` | 本次调用创建或操作的任务。用它可以把 `message/send`、`tasks/get`、`tasks/resubscribe` 中所有涉及同一任务的请求汇集起来。调用未涉及任务时为空。 | | `a2a_context_id` | 该任务所属的上下文(会话),用于把一次多轮交互中的多个任务串联起来。 | | `a2a_task_state` | Agent 最后上报的任务状态,已归一为 `submitted`、`working`、`input-required`、`auth-required`、`completed`、`canceled`、`failed`、`rejected` 或 `unknown`。没有任何响应携带状态时为空。 | | `a2a_stream_event_count` | 流式调用中转发给调用方的事件数。非流式调用为 0。 | | `upstream_ttft_ms` | Agent 发出第一个流式事件的耗时。结合 `upstream_latency_ms`,可以区分长时间没有任何输出的流与很快开始输出的流。 | | `prompt_tokens`、`completion_tokens` | 消息文本的 Token 数,由网关统计。参见 [Token 统计](#token-counts)。 | | `api_key_id` | 发起调用的调用方 API Key。 | | `status_code` | 调用结果状态。 | | `upstream_latency_ms` | 上游 Agent 调用耗时。 | | `downstream_latency_ms` | 调用方等待 Agent 调用的总时间。 | | `request_id`、`occurred_at` | 关联 ID 和时间戳。 | ### Token 统计[​](#token-counts "Token 统计的直接链接") A2A Agent 不会上报自身用量——协议中根本没有 usage 字段——因此 AISIX 自行统计消息文本:用网关自带的分词器统计调用方消息和 Agent 回复中的文本部分。统计结果写入 `prompt_tokens` 和 `completion_tokens`,同时事件带上 `usage_estimated: true`,表示这些数字由网关得出而非上游上报。需要「供应商实际计费」口径时,请按该标志过滤。 只有 `message/send` 和 `message/stream` 会被统计。`tasks/get` 这类读取操作返回的是 Agent 生成时已经统计过的答案,重复统计会让一个答案按轮询次数被反复上报。 `cost_usd` 保持为零:Agent 如何收费不是网关能观测到的。这些统计**只上报、不计费**:它们不会计入调用方 Key 的 `tpm` / `tpd` Token 窗口。预算是另一套机制——它限制的是美元花费,而零成本不会产生任何花费。参见[流量控制](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md)。 文件和数据部分不参与统计。它们的字节不是自然语言,把 base64 内容算进去会让估算失真。 Agent 网关目前只会执行一次贯穿整个请求的上游尝试,因此 `upstream_latency_ms` 和 `downstream_latency_ms` 会报告相同的持续时间。保留两个独立字段可使 A2A 记录与其他网关流量保持一致;在其他流量中,重试和网关处理可能使二者不同。 事件**不会**包含请求或响应消息内容。只有当某个[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md)配置了完整内容采集时,消息文本才会到达该导出器,并且永远不会进入 AISIX Cloud 控制面。 A2A 用量事件通过与模型用量事件相同的路径投递。所有已配置的可观测性导出器都会接收这些事件,因此 A2A 流量会与网关的其余流量一起显示。在 AISIX Cloud 中,它们还会流向控制面的用量接收端。 ## 指标[​](#指标 "指标的直接链接") A2A 请求会出现在网关的 Prometheus 指标中。使用下表中的标签筛选相关指标序列: | 目标 | 指标 | 过滤条件 | | --------------------------- | ----------------------------------- | --------------------------------------------- | | 按结果统计 A2A 请求。 | `aisix_requests_total` | `provider="a2a"` 和 `model="a2a"` | | 跟踪正在处理的 A2A 请求。 | `aisix_proxy_in_flight_requests` | `endpoint="/a2a"` 和 `inbound_protocol="a2a"` | | 测量 Agent 调用的完整时长。 | `aisix_request_e2e_latency_seconds` | `endpoint="/a2a"` | | 检查 A2A 用量事件发送情况。 | `aisix_usage_events_emitted_total` | `handler="a2a"` | `aisix_a2a_*` 系列承载了共享指标族无法表达的维度:调用到了哪个 Agent、调用的是哪个操作。 | 指标 | 标签 | 回答什么问题 | | ------------------------------- | ------------------------------ | -------------------------------------------------------- | | `aisix_a2a_requests_total` | `agent`、`operation`、`status` | 某个 Agent 某个操作的调用量和失败率。 | | `aisix_a2a_ttfb_seconds` | `agent`、`operation` | Agent 发出第一个流式事件需要多久。 | | `aisix_a2a_stream_events_total` | `agent`、`operation` | 转发的事件数。除以流式操作的请求数即为每次调用的事件数。 | | `aisix_a2a_task_state_total` | `agent`、`state` | 各个结束状态的发生速率,例如 `failed` 占比是否在上升。 | `aisix_a2a_requests_total` 与 `aisix_proxy_requests_total{endpoint="/a2a"}` 的数字并不一致,这有两处是有意为之。在 Agent 解析出来之前就被拒绝的调用——Key 无效、Agent 未授权、Agent 不存在——没有可归属的 Agent,因此只计入 proxy 系列。被调用方中途放弃的流在这里是 `4xx`,在那里是 `2xx`,因为响应确实是以 200 开始的。看 Agent 健康度用这个系列,看路由流量用 proxy 系列。 端到端直方图同样从请求的前置校验之后才开始。在进入 A2A 统计之前就被拒绝的调用不会出现在其中;已进入统计、但在下发之前被拒绝的调用记录为零时长。对于已下发的调用,该直方图覆盖从 Agent 调用开始到流结束的完整时长。 任务 ID、上下文 ID 和 JSON-RPC 请求 ID 永远不会作为指标标签。正是它们让单次调用可追踪,也正因如此它们不能做标签值;请到用量事件和链路追踪中查找。 筛选用量事件发送情况时应使用 handler 标签。该计数器会限制协议标签的基数,并把 A2A 事件归入 `other`。 这种标签行为只影响 Prometheus 发送计数器。实际投递的用量事件仍会将流量标识为 A2A,并包含 Agent 名称和方法。 指标通过专用指标监听器的 `GET /metrics` 暴露。完整指标目录和标签语义请参见[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 ## 验证指标[​](#验证指标 "验证指标的直接链接") 要验证 A2A 指标是否发出,请先通过网关发送一次 A2A 调用,再抓取专用指标监听器。下例使用默认监听地址和路径;如果启动配置设置了不同的 `observability.metrics.prometheus.addr`,请相应调整地址。 指标族会在首次观测后注册,因此只有记录调用之后才会出现 A2A 序列: ``` curl -sS "http://127.0.0.1:9090/metrics" \ | grep -E 'aisix_a2a_|aisix_request_e2e_latency_seconds.*endpoint="/a2a"|handler="a2a"|provider="a2a"' ``` 输出应包含共享指标和 A2A 专属指标的样本: | 指标 | 标签 | | ----------------------------------- | ----------------------------------------- | | `aisix_usage_events_emitted_total` | `handler="a2a"` | | `aisix_requests_total` | `provider="a2a"` | | `aisix_a2a_requests_total` | `agent` 和 `operation` 标识解析出的调用。 | | `aisix_request_e2e_latency_seconds` | `endpoint="/a2a"` | ## 下一步[​](#下一步 "下一步的直接链接") 你现在已了解 A2A 调用在用量事件和指标中的位置。使用以下指南查看完整指标目录,或调整产生这些信号的流量: * [指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md):查看完整指标目录、标签和 A2A 相关说明。 * [限流与预算](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md):对 A2A 调用应用请求限制、并发限制和预算。 * [控制 Agent 访问](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md):将调用方 API Key 的权限限定为特定 Agent 或全部 Agent。 --- # Agent 网关概述 AISIX 在 `/a2a/` 上公开已注册的 Agent-to-Agent(A2A)Agent,为 A2A 客户端和其他 Agent 提供一条需要身份认证的统一访问路径。调用方提供 AISIX 调用方 API Key;网关会检查该 API Key 是否可以访问目标,并在不暴露上游凭证的情况下转发 A2A JSON-RPC 请求。 因此,Agent 流量与模型和 MCP 流量使用相同的身份认证、访问控制、流量控制和遥测边界。同一个调用方 API Key 可以管理调用方能够使用的模型、MCP 工具和 A2A Agent。 每个 A2A Agent 资源代表一个通过 HTTP 使用 JSON-RPC 2.0 [A2A 协议](https://a2a-protocol.org/)的上游 Agent。 ## Agent 网关的工作原理[​](#agent-网关的工作原理 "Agent 网关的工作原理的直接链接") 每个上游 Agent 都有一个 `name`。AISIX 会在代理监听器的 `/a2a/` 上公开该 Agent。在 AISIX Cloud 中,Agent 在组织级注册,并公开给所选环境。在开源 AISIX 网关中,Agent 通常在 `resources.yaml` 中声明。 AISIX 会原样转发请求正文。每个 Agent 资源固定使用 A2A `1.0` 或 `0.3`,调用方必须采用为该 Agent 配置的格式。AISIX 不会在协议版本之间转换。 当 Agent 调用通过身份认证和访问检查后,网关会应用请求和并发限制、使用已配置的上游凭证联系 Agent,并记录 A2A 用量遥测。AISIX Cloud 还可以应用涵盖调用方 API Key 的预算。 ## 开始使用[​](#开始使用 "开始使用的直接链接") 按照[配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)运行 A2A Echo Agent,通过 AISIX Cloud 或 `resources.yaml` 注册该 Agent,并授予调用方访问权限。随后使用官方 A2A Go SDK 客户端,通过网关发送 A2A 1.0 消息。继续阅读 [A2A 流式传输与 Agent Card 发现](https://docs.apiseven.com/ai-gateway/agent-gateway/streaming-and-discovery.md),接收流式任务事件。网关具备公共源地址后,还可以按照同一指南验证面向客户端的 Agent Card 解析。两种管理方式配置的是相同的网关运行时和 A2A 端点。 ## 客户端连接[​](#客户端连接 "客户端连接的直接链接") A2A 客户端通过 AISIX 代理监听器调用已注册的 Agent: | 设置 | 值 | | -------------- | --------------------------------------------------------------- | | Agent URL | `/a2a/` | | Agent Card URL | `/a2a//.well-known/agent-card.json` | | 协议 | 通过 HTTP 使用 JSON-RPC 2.0 的 A2A 1.0 或 0.3 | | 请求头 | `Authorization: Bearer ` | 调用方 API Key 控制客户端可以访问哪些 Agent。客户端只连接 AISIX,不会收到上游凭证。 该端点接受 Agent 所配置 A2A 版本定义的 JSON-RPC 方法,包括消息、任务、流式传输和推送通知配置方法。流式方法返回 `text/event-stream`,AISIX 会在上游 Agent 发出事件时逐个中继。 ## Agent Card[​](#agent-card "Agent Card的直接链接") 客户端可以通过 AISIX 请求已注册 Agent 的发现文档: ``` GET /a2a//.well-known/agent-card.json ``` 该请求使用与 A2A 调用相同的调用方身份认证和 Agent 访问检查。AISIX 使用 Agent 已配置的上游凭证获取上游 Card,然后将其中公布的所有服务 URL 重写为网关路径。其他 Card 字段保持不变。 AISIX 从 `X-Forwarded-Proto` 获取公布的协议,从 `Host` 获取主机与端口。请配置信任的反向代理,将这些请求头设置为网关的公共地址。如果没有 `X-Forwarded-Proto`,AISIX 使用 `https`。 上游 Card 当前必须包含 A2A 0.3 使用的顶级 `url` 字段。对于 A2A 1.0 Agent,请发布同时包含 `url` 和 `supportedInterfaces` 的兼容 Card。AISIX 会重写 Card 中的每个服务 URL。 AISIX 首先检查注册路径下的 `agent-card.json`,然后检查其源地址下的同名文件。如果两个位置均未返回可用 Card,AISIX 会对较早的 `agent.json` 文件名重复上述检查。 ## 治理 A2A 调用[​](#治理-a2a-调用 "治理 A2A 调用的直接链接") A2A 调用与模型请求使用相同的调用方 API Key 边界,无需为 Agent 流量配置单独的策略栈。 可以使用以下指南优化 A2A 路径: * [上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md):配置 AISIX 如何向上游 Agent 进行身份认证。 * [控制 Agent 访问权限](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md):将每个调用方 API Key 的权限范围限定为精确的 Agent 名称、名称模式或所有 Agent。 * [限流和预算](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md):应用调用方请求和并发限制,并使用 AISIX Cloud 预算。 * [安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md):在输入检查位置扫描 A2A 消息文本。环境、调用方 API Key 和团队挂载可以覆盖 A2A 调用;模型和 MCP 服务器挂载不能覆盖。 * [可观测性](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md):查看 A2A 调用生成的用量事件和指标。 ## 当前限制[​](#当前限制 "当前限制的直接链接") 以下限制会影响 AISIX 公开的 Agent 接口和控制能力: * AISIX 通过 `/a2a/` 提供 A2A JSON-RPC 调用,不公开基于 A2A REST 路径的端点,例如 `POST .../v1/message:send` 或 `GET .../v1/tasks/{id}`。 * 不支持 OAuth 2.0 上游身份认证。请按照[上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md)中的说明使用 `none`、`bearer` 或 `api_key`。 * 输入安全护栏会在转发前扫描 A2A 请求中的消息文本,适用环境、调用方 API Key 和团队作用域;挂载到模型或 MCP 服务器作用域的安全护栏不适用于 A2A。目前尚未接入针对 Agent 响应的输出安全护栏检查。访问控制、请求和并发限制、AISIX Cloud 预算以及用量遥测仍然适用。 * 请使用 A2A HTTP URL 注册 Agent。目前不支持直接注册 Amazon Bedrock AgentCore、Azure AI Foundry 或 Vertex AI Agent Engine 等云 Agent 运行时资源。 ## 排查 Agent 调用问题[​](#排查-agent-调用问题 "排查 Agent 调用问题的直接链接") 如果调用方无法访问 Agent,请检查以下项目: * A2A Agent 资源已启用,并且网关可以访问该资源。 * 在 AISIX Cloud 中,`allowed_environments` 包含调用方 API Key 所属环境。 * 调用方 API Key 的 `allowed_agents` 授权涵盖已注册的 Agent 名称。 * 请求正文和方法使用该 Agent 配置的 A2A 协议版本。 * 已配置的上游身份认证与 Agent 的要求相符。 缺少调用方 API Key 或 API Key 无效时返回 `401`。已知但不在 API Key 授权范围内的 Agent 返回 `403`,未知或已禁用的 Agent 返回 `404`。对于 JSON-RPC 调用,上游不可访问或上游 HTTP 状态不成功时,会返回 `502` 及 JSON-RPC 错误信封;AISIX 不会公开上游响应正文。Agent Card 获取失败时也会返回 `502`,但使用普通 HTTP 错误,而不是 JSON-RPC 信封。 有关端点级行为,请参阅[代理 API 参考](https://docs.apiseven.com/ai-gateway/reference/proxy-api.md#a2a-gateway)。有关错误响应详情,请参阅[请求头和错误代码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md#a2a-errors)。 --- # 配置 Agent 网关 AISIX 通过 `/a2a/` 上需要调用方身份认证的网关端点公开已注册的 Agent-to-Agent(A2A)Agent。本指南将官方 A2A Echo Agent 连接到现有 AISIX 网关,并为快速入门中的调用方授予访问权限。随后,官方 A2A Go SDK 客户端通过网关发送 A2A 1.0 消息。 你可以选择 AISIX Cloud 或开源配置流程。两种流程的注册步骤不同,但配置的网关行为相同。完成任一流程后,均使用相同的 Agent Card 就绪检查和 SDK 客户端调用验证结果。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下环境: * 如使用 AISIX Cloud,请完成 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md),并保持其中的 Shell 和 `aisix-dp` 网关运行。 * 如使用开源 AISIX 网关,请完成[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md),并停留在其中的 Shell 和工作目录,同时保持 `aisix-quickstart` 网关运行。 * [Docker](https://docs.docker.com/get-docker/)、[cURL](https://curl.se/) 和 [jq](https://jqlang.github.io/jq/)。 ## 启动 A2A 测试 Agent[​](#启动-a2a-测试-agent "启动 A2A 测试 Agent的直接链接") 本示例在 Docker 中运行官方 A2A Go SDK 提供的 [Echo 服务器](https://github.com/a2aproject/a2a-go/blob/v2.5.0/cmd/README.md#--echo---echo-mode)。Agent 与现有网关会加入一个临时 Docker 网络,因此网关无需重启即可访问 Agent。Echo 服务器仅用于本地测试:它不进行身份认证,并会返回调用方发送的消息文本。该服务器会发布同时兼容 A2A 0.3 和 1.0 的 Agent Card,因此还可通过 AISIX 验证面向客户端的发现流程。Echo 服务器启动时不带上游凭证;后续客户端检查会将快速入门中的一次性调用方密钥传入该测试容器。完成本指南后,请停止并删除该容器。 根据所选配置流程设置网关容器名称。 如使用 AISIX Cloud: ``` export AISIX_GATEWAY_CONTAINER="aisix-dp" ``` 如使用开源 AISIX 网关: ``` export AISIX_GATEWAY_CONTAINER="aisix-quickstart" ``` 创建临时网络,并将正在运行的网关连接到该网络: ``` docker network create aisix-a2a docker network connect aisix-a2a "$AISIX_GATEWAY_CONTAINER" ``` 在同一网络中启动 Echo Agent。固定版本的 Go SDK 会在容器中下载并编译,因此首次启动可能需要约一分钟: ``` docker run -d --name aisix-a2a-echo \ --network aisix-a2a \ golang:1.25-alpine \ sh -c 'go run github.com/a2aproject/a2a-go/v2/cmd/a2a@v2.5.0 \ serve --echo --card-compat --host 0.0.0.0 --port 8080 \ --transport jsonrpc --protocol latest --name "AISIX A2A Echo"' ``` 等待 Agent 就绪: ``` for attempt in $(seq 1 120); do docker logs aisix-a2a-echo 2>&1 | grep -q "Listening on" && break sleep 1 done docker logs aisix-a2a-echo 2>&1 | grep "Listening on" ``` 最后一条命令会输出监听地址。在网关容器内,可以通过 `http://aisix-a2a-echo:8080` 访问该 Agent。 ## 注册 Agent 并授予访问权限[​](#注册-agent-并授予访问权限 "注册 Agent 并授予访问权限的直接链接") 通过部署对应的管理方式注册 Agent。两种方式都会将 Agent 命名为 `echo-agent`、固定为 A2A 1.0,并将其授权给现有的快速入门调用方。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 注册测试 Agent,并将其公开给快速入门环境: ``` A2A_AGENT_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/a2a_agents" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- </dev/null 2>&1 && break sleep 2 done curl -fsS \ "$AISIX_PROXY/a2a/echo-agent/.well-known/agent-card.json" \ -H "Authorization: Bearer $AISIX_A2A_KEY" \ >/dev/null ``` 设置客户端容器可访问的 Agent URL。两个 AISIX 快速入门指南均使用网关容器内的 `3000` 端口: ``` export AISIX_A2A_URL="http://${AISIX_GATEWAY_CONTAINER}:3000/a2a/echo-agent" ``` 在 echo-agent 容器内运行官方 A2A Go SDK 的命令行客户端。`--transport jsonrpc` 会直接连接已注册的 AISIX 端点,而非先解析 Agent Card: ``` docker exec aisix-a2a-echo \ go run github.com/a2aproject/a2a-go/v2/cmd/a2a@v2.5.0 \ send "$AISIX_A2A_URL" "Hello through AISIX" \ --transport jsonrpc \ --auth "Bearer $AISIX_A2A_KEY" \ --output json | jq -e \ '.artifacts[].parts[] | select(.text == "Hello through AISIX")' ``` 该命令会输出匹配的产物部分。AISIX 已对调用方进行身份认证、检查其 Agent 授权,并将 SDK 客户端的 A2A 1.0 请求转发到 Echo Agent。 ## 为实际 Agent 调整配置[​](#为实际-agent-调整配置 "为实际 Agent 调整配置的直接链接") 将测试 URL 替换为网关可访问的 A2A JSON-RPC 端点。将 `protocol_version` 设置为 Agent 支持的传输格式,并使用该格式发送请求。AISIX 支持 `"1.0"` 和 `"0.3"`,但不会在两者之间转换。 通过 `auth_type` 和 `secret` 配置所需的上游凭证。请参阅[上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md)。 对于开源 AISIX 网关,请验证完整的资源文件。如果运行中的网关已经具有所有被引用的环境变量,请发送 `SIGHUP`。如果新增或修改了环境变量,请使用新值重新创建容器。请参阅[重新加载资源文件](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md#reload-a-resources-file)。 ## 清理[​](#清理 "清理的直接链接") 如果要继续学习其他 Agent 网关指南,可以保留 Agent 和调用方授权。否则,请按照所用管理方式删除本指南添加的资源。 如使用 AISIX Cloud,请清除调用方的 Agent 授权并删除 Agent: ``` curl -fsS -X PATCH \ "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"allowed_agents":[]}' | jq curl -fsS -X DELETE "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 如使用开源 AISIX 网关,请从 `resources.yaml` 中删除新增的 `allowed_agents` 和 `a2a_agents`,验证文件并再次发送 `SIGHUP`。 删除测试 Agent 和临时网络: ``` docker rm -f aisix-a2a-echo docker network disconnect aisix-a2a "$AISIX_GATEWAY_CONTAINER" docker network rm aisix-a2a ``` ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已注册 A2A Agent、授予调用方访问权限,并使用官方 SDK 客户端通过 AISIX 发送 A2A 1.0 消息。可以继续阅读以下指南: * [A2A 流式传输与 Agent Card 发现](https://docs.apiseven.com/ai-gateway/agent-gateway/streaming-and-discovery.md):接收流式任务,并通过公共网关源地址验证面向客户端的 Agent Card。 * [配置上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md):为上游 Agent 使用 Bearer Token 或 API Key。 * [控制 Agent 访问权限](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md):授权精确的 Agent 名称、名称模式或所有已注册 Agent。 * [应用限流和预算](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md):使用调用方限流和 AISIX Cloud 预算治理 A2A 调用。 * [可观测性](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md):查看 A2A 调用生成的用量事件和指标。 --- # A2A 流式传输与 Agent Card 发现 [Agent 网关设置指南](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)使用官方 A2A Go SDK 客户端,通过 AISIX 发送非流式消息。本指南在已验证的路径上继续接收流式任务,并解析 AISIX 为客户端重写的 Agent Card。 这两项测试验证直接 JSON-RPC 请求之外的客户端行为。SDK 解释每个流式任务事件,并在发现过程中从返回的卡片中选择网关服务 URL,无需获知上游 Agent 的 URL 或凭证。 流式传输测试可在本地快速入门网络中运行。端到端的 Agent Card 解析需要客户端可访问的网关源地址;本指南使用公共 HTTPS 源地址。如果尚未配置该地址,请先完成流式传输测试,待部署后再返回发现部分。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始之前,请完成[设置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md),并保留以下资源: * AISIX 网关、`aisix-a2a-echo` 容器和 `aisix-a2a` Docker 网络。 * `AISIX_GATEWAY_CONTAINER`、`AISIX_A2A_URL` 和 `AISIX_A2A_KEY` 环境变量。 * `echo-agent` 注册信息和调用方授权。 设置过程会在 echo-agent 容器中下载并编译固定的 SDK 版本。客户端命令复用同一个版本及容器构建缓存。 ## 验证流式传输[​](#验证流式传输 "验证流式传输的直接链接") 设置指南保留了 `AISIX_A2A_URL`,客户端容器通过该地址访问网关。通过此端点发送流式消息: ``` docker exec aisix-a2a-echo \ go run github.com/a2aproject/a2a-go/v2/cmd/a2a@v2.5.0 \ send "$AISIX_A2A_URL" "Stream through AISIX" \ --transport jsonrpc \ --stream \ --auth "Bearer $AISIX_A2A_KEY" \ --output json ``` 客户端在事件到达时逐个输出。echo Agent 依次生成以下事件: 1. 已提交的任务。 2. 正在处理的状态更新。 3. 包含 `Stream through AISIX` 的产物更新。 4. 已完成的状态更新。 这验证了 AISIX 会中继 A2A 事件流,而非将其缓冲为一个响应。 ## 验证 Agent Card 发现[​](#验证-agent-card-发现 "验证 Agent Card 发现的直接链接") 设置指南启动的 echo 服务器会发布同时兼容 A2A 0.3 和 1.0 的卡片。AISIX 在以下路径提供面向客户端的版本: ``` /a2a/echo-agent/.well-known/agent-card.json ``` AISIX 从 `Host` 获取公布的主机信息,从 `X-Forwarded-Proto` 获取协议;未提供转发协议时,默认使用 `https`。如果由可信反向代理终止 TLS,请配置该代理,使其提供网关的公共值。返回的顶层 `url` 和 `supportedInterfaces` 中的每个条目都应指回客户端可访问的 AISIX `/a2a/echo-agent` 端点。 网关具备客户端可访问的公共源地址后,使用完整的卡片 URL 运行发现: ``` export AISIX_A2A_CARD_URL="https://gateway.example.com/a2a/echo-agent/.well-known/agent-card.json" docker exec aisix-a2a-echo \ go run github.com/a2aproject/a2a-go/v2/cmd/a2a@v2.5.0 \ discover "$AISIX_A2A_CARD_URL" \ --auth "Bearer $AISIX_A2A_KEY" \ --output json ``` 请提供完整的嵌套卡片 URL。A2A Go SDK 会将带有非根路径的 URL 视为完整卡片 URL,因此仅传入 Agent 服务 URL 会将发现请求发送到 `/a2a/echo-agent`,并返回 `405`。仅传入网关源地址会让 SDK 请求 `/.well-known/agent-card.json`,由于 AISIX 在已注册 Agent 的路径下提供卡片,此请求会返回 `404`。 要一起验证卡片解析及由此得到的服务 URL,请将相同卡片 URL 传给 `send`,并省略 `--transport`: ``` docker exec aisix-a2a-echo \ go run github.com/a2aproject/a2a-go/v2/cmd/a2a@v2.5.0 \ send "$AISIX_A2A_CARD_URL" "Discover and call through AISIX" \ --auth "Bearer $AISIX_A2A_KEY" \ --output json ``` 客户端通过 AISIX 获取卡片,选择其 JSON-RPC 1.0 接口,并将消息发送到重写后的网关 URL。客户端不会收到上游 Agent 的 URL 或凭证。 ## 流式传输与发现故障排查[​](#流式传输与发现故障排查 "流式传输与发现故障排查的直接链接") | 现象 | 检查项 | | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 直接调用的客户端返回 `401` | 确认 `--auth` 包含 `Bearer`,其后为 AISIX 调用方 API Key。 | | 直接调用的客户端返回 `403` | 确认调用方密钥的 `allowed_agents` 授权包含 `echo-agent`。 | | 发现请求返回 `404` 或 `405` | 传入完整的 `/a2a/echo-agent/.well-known/agent-card.json` URL。仅包含源地址的 URL 会解析到不存在的源地址级卡片路径并返回 `404`;Agent 服务 URL 则会被当作卡片获取,并返回 `405`。 | | 卡片公布了错误的 URL,或客户端绕过 AISIX、无法连接 | 检查顶层 `url` 和 `supportedInterfaces[].url`;它们均应使用客户端可访问的 AISIX 源地址及 `/a2a/echo-agent` 路径。如果由可信反向代理终止 TLS,请配置公共 `Host` 和 `X-Forwarded-Proto` 值。未提供转发协议时,AISIX 默认使用 `https`。 | | 非流式消息成功,但流式传输失败 | 确认上游卡片声明支持流式传输,并在网关和上游 Agent 日志中检查 `SendStreamingMessage` 请求。 | ## 下一步[​](#下一步 "下一步的直接链接") * [控制 Agent 访问](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md):授权具体 Agent 名称、名称模式或所有已注册 Agent。 * [上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md):在 AISIX 中保存上游 Bearer Token 和 API Key。 * [可观测性](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md):检查 A2A 请求、任务结果和流式传输故障。 --- # 限流和预算 对于 Agent-to-Agent(A2A)流量,调用方级限制配置在调用方 API Key 上。A2A 调用与模型流量共享 API Key 的请求和并发限制。涵盖该 API Key 的 AISIX Cloud 预算同样适用,但 A2A 调用报告的成本为零,不会增加已跟踪的支出。 A2A 没有单独的流量控制资源。请在调用方 API Key 上配置限流,并在 AISIX Cloud 中为涵盖该 API Key 的范围配置预算,然后在 `/a2a/` 上验证行为。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 请完成 AISIX Cloud 或开源 AISIX 网关的[配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)。保持 Shell、网关和测试 Agent 运行,以便验证限制。 ## 控制生效的位置[​](#控制生效的位置 "控制生效的位置的直接链接") 网关会对 `/a2a/` 上的每个 JSON-RPC 调用应用流量控制。Agent Card 发现请求不受限流影响。被限流的调用方仍可以获取其 API Key 有权访问的 Agent Card,但在窗口重置前无法再次调用该 Agent。 当限流或预算拒绝调用时,AISIX 会在联系上游 Agent 前返回,并将被拒绝的调用记录为[用量事件](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md)。 由于 A2A 调用不会解析模型,因此模型范围的限流策略不适用。调用方 API Key 上的请求级控制仍然适用。 ## 适用的限流[​](#适用的限流 "适用的限流的直接链接") 调用方 API Key 的 `rate_limit` 对象支持请求速率、Token 速率和并发限制。只有请求速率和并发限制会直接计量 A2A 调用: | 限制 | 是否适用于 A2A 调用 | 行为 | | -------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `rps`、`rpm`、`rph`、`rpd` | 是 | 每次 `/a2a/` 调用在对应窗口中计为一个请求。 | | `concurrency` | 是 | 每个正在处理的调用会占用一个许可,直到调用返回。 | | `tpm`、`tpd` | 否 | 系统会报告估算的 A2A Token 数量,但不会将其加入 Token 窗口。如果 API Key 的模型流量已耗尽共享 Token 窗口,A2A 调用仍可能被拒绝。 | 使用请求速率限制或 `concurrency` 控制 A2A 调用量。仅配置 Token 限制无法限制 A2A 调用。 有关完整字段参考和计数器存储选项,请参阅 [API Key 和模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md)。 ## 设置调用方限流[​](#设置调用方限流 "设置调用方限流的直接链接") 以下示例将配置指南中的调用方 API Key 限制为每分钟一个请求。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 更新现有的调用方 API Key: ``` curl -fsS -X PATCH \ "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "rate_limit": { "rpm": 1 } }' | jq ``` 该部分更新会保留 API Key 的模型、MCP 和 Agent 授权。控制面会自动将更改下发到已连接的网关。发送 `"rate_limit": null` 可清除内联限制。 ### 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 在 `resources.yaml` 的调用方条目中添加 `rate_limit`: resources.yaml(调用方限流) ``` api_keys: - display_name: quickstart-caller key_env: CALLER_API_KEY allowed_models: - gpt-4o-mini allowed_agents: - echo-agent rate_limit: rpm: 1 ``` 验证完整文件并重新加载: ``` docker exec aisix-quickstart \ aisix validate --resources /etc/aisix/resources.yaml docker kill --signal HUP aisix-quickstart ``` 删除 `rate_limit` 可清除内联限制。 ## 验证限流[​](#验证限流 "验证限流的直接链接") 配置生效后,在一分钟内调用 Agent 两次: ``` for call in 1 2; do curl -sS -o "/tmp/a2a-rate-limit-${call}.json" \ -w "call ${call}: HTTP %{http_code}\n" \ -X POST "$AISIX_PROXY/a2a/echo-agent" \ -H "Authorization: Bearer $AISIX_A2A_KEY" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "req-rate-limit", "method": "SendMessage", "params": { "message": { "messageId": "msg-rate-limit", "role": "ROLE_USER", "parts": [{"text": "Test the caller rate limit"}] } } }' done ``` 命令会为第一次调用输出 HTTP `200`,为第二次调用输出 HTTP `429`。被拒绝的调用不会到达上游 Agent。 ## 应用 AISIX Cloud 预算[​](#应用-aisix-cloud-预算 "应用 AISIX Cloud 预算的直接链接") 预算在 AISIX Cloud 中配置,并由其连接的网关执行。当涵盖调用方 API Key 的预算已耗尽时,AISIX 会在联系上游 Agent 前拒绝该 API Key 的 A2A 调用,并返回 `budget_exceeded` 错误。 A2A 协议没有模型服务提供方用量块,因此 AISIX 会估算文本 Token 以用于遥测,并将 `cost_usd` 记录为零。所以 A2A 调用不会增加预算支出。如果调用方的模型流量已耗尽预算,该调用方的 A2A 调用仍会被阻止,因为两者使用同一个调用方 API Key。 开源 AISIX 网关不提供预算管理服务。请使用调用方 API Key 的请求和并发限制控制 A2A 调用量。有关 AISIX Cloud 预算目标、拒绝行为和缓存,请参阅[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将调用方 API Key 控制应用到 A2A 流量。可以继续阅读以下指南,观察或优化结果: * [可观测性](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md):查看 A2A 调用生成的用量事件和指标。 * [控制 Agent 访问权限](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md):将调用方 API Key 的权限范围限定为特定 Agent 或模式。 * [API Key 和模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):查看所有限流字段。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):配置 AISIX Cloud 预算目标和拒绝行为。 --- # 上游身份认证 每个已注册的 Agent-to-Agent(A2A)Agent 都定义了 AISIX 是否以及如何向其上游进行身份认证。在获取 Agent Card 或转发 JSON-RPC 调用时,AISIX 会提供已配置的凭证(如有)。客户端使用调用方 API Key 向 AISIX 进行身份认证,默认情况下没有任何调用方请求头会到达该 Agent。需要看到某个请求头的 Agent(包括调用方自己的凭证),通过 [`forward_client_headers`](#forward-caller-headers-to-an-upstream-agent) 显式开启。 这种分离方式让每个上游可以采用所需的身份认证方案,而调用方只需保留一个 AISIX 凭证。AISIX Cloud 和开源 AISIX 网关通过不同管理方式支持相同的模式。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 请完成 AISIX Cloud 或开源 AISIX 网关的[配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)。如需执行可选的端到端验证,请保持同一个 Shell、网关、测试 Agent 和临时 Docker 网络运行。 ## 身份认证模式[​](#身份认证模式 "身份认证模式的直接链接") 请选择与上游 Agent 要求相符的模式: | `auth_type` | 必填字段 | 上游请求头 | | ----------- | -------- | -------------------------------- | | `none` | 无 | 不发送凭证。 | | `bearer` | `secret` | `Authorization: Bearer ` | | `api_key` | `secret` | `x-api-key: ` | `auth_type` 默认为 `none`。在此模式下,不要设置 `secret`。`bearer` 和 `api_key` 模式要求提供非空 `secret`。 使用凭证的上游应采用 HTTPS。如果为 `http://` URL 配置了 Bearer Token 或 API Key,网关会记录警告,因为凭证将以明文通过网络传输。 ## 配置上游身份认证[​](#配置上游身份认证 "配置上游身份认证的直接链接") 以下示例为配置指南中已注册的 `echo-agent` 添加 Bearer 身份认证。将该条目改为指向需要凭证的上游时,还应替换它的 URL。如果上游要求 `x-api-key`,请改用 `api_key`。echo Agent 本身不验证凭证。如需在本地测试凭证转发,请跳过这些示例,继续阅读[可选:使用本地测试代理验证](#optional-verify-with-a-local-test-proxy);该部分会提供专用 Token 和最终资源更新。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 导出凭证,然后更新已注册 Agent: ``` export A2A_AGENT_TOKEN="YOUR_UPSTREAM_TOKEN" curl -fsS -X PATCH "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- </.well-known/agent-card.json` 上的 Agent Card 拉取,以及 `/a2a/` 上的每个 JSON-RPC 方法都生效,因此 `message/send`、`message/stream` 和各类 task 操作都会收到这些请求头。 通过 AISIX Cloud Admin API,可以在创建 Agent 时设置,也可以之后 PATCH。PATCH 是整体替换已存储的列表;传空数组即清空: ``` curl -fsS -X PATCH "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "forward_client_headers": ["authorization", "x-trace-*"] }' ``` 在控制台中,同一设置是 Agent 表单里 **Advanced** 下的 **Forward client headers** 输入框,每行填一个请求头名称或通配符。 在开源 AISIX 网关加载的资源文件中: resources.yaml(把调用方凭证转发给内网 Agent) ``` a2a_agents: - name: invoice-processor url: https://agents.internal.example.com/a2a auth_type: none forward_client_headers: - authorization - x-trace-* ``` 每个条目可以是精确的请求头名称,也可以是包含一个 `*` 通配符的名称,匹配不区分大小写。被转发的请求头会到达该 Agent,无论 AISIX 本来打算怎么处理它。 点名一个凭证槽位,会把调用方的凭证**取代**网关的凭证交给该 Agent,绝不会两个都发。`bearer` 填的槽位是 `authorization`,`api_key` 填的槽位是 `x-api-key`。这正是让本就按最终用户 `Authorization` 授权的内网 Agent,在 AISIX 接入之后继续原样工作的方式。校验 `aud` 声明的 Agent 会拒绝签发给网关的 Token,因此只在你愿意把调用方取值托付给它的 Agent 上点名槽位。 凭证槽位以及链路上下文请求头 `traceparent` 和 `tracestate`,只有在模式精确点名时才会转发。`*` 或 `x-*` 这类通配符永远匹配不到它们,因为转发凭证或链路上下文是一个明确的动作,而不该被宽泛模式顺带扫进来。完整清单见[必须精确点名的请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#headers-that-must-be-named-exactly),各个面上这个集合是一样的。 `a2a-version` 绝不会被转发。它是 AISIX 自己就该 Agent 在 `protocol_version` 中所固定的线格式版本做出的声明,调用方的副本会覆盖这个固定值。其余任何模式都触及不到的名称——`host`、逐跳请求头、`x-aisix-*` 命名空间,以及描述 AISIX 会重新序列化的请求体的那些请求头——列在 [AISIX 绝不转发的调用方请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#caller-headers-aisix-never-forwards)中。 转发功能要求数据面运行 1.1.0 或更高版本。在更旧的网关上保存该字段时,AISIX Cloud 会给出提示;该网关仍会继续提供这个 Agent,只是不会额外中继任何请求头。 ## 可选:使用本地测试代理验证[​](#optional-verify-with-a-local-test-proxy "可选:使用本地测试代理验证的直接链接") 以上配置定义了 AISIX 应发送的凭证,但配置指南中的 echo Agent 不进行身份认证也会接受请求,因此无法证明网关提供了预期的 Token。如需进行本地端到端检查,请在 Agent 前放置一个使用 Bearer 身份认证的小型反向代理,并分别验证请求被接受和拒绝的情况。 该代理仅用于本地测试:它使用明文 HTTP,并会在转发已接受的请求到 echo Agent 前移除 Bearer Token。 以下辅助函数包含本地代理配置。请原样复制;后续步骤会配置和测试 AISIX。 启动本地 Bearer Token 验证代理 导出独立的上游 Token,然后在现有 Docker 网络上定义并启动测试代理: ``` export A2A_AGENT_TOKEN="a2a-upstream-test-token" start_a2a_auth_proxy() { docker rm -f aisix-a2a-auth >/dev/null 2>&1 || true docker run -d --name aisix-a2a-auth \ --network aisix-a2a \ -e UPSTREAM_TOKEN="$1" \ caddy:2.11.4-alpine \ sh -c 'caddy run --config /dev/stdin --adapter caddyfile <&1 | grep -q "serving initial configuration" && return sleep 1 done docker logs aisix-a2a-auth >&2 return 1 } start_a2a_auth_proxy "$A2A_AGENT_TOKEN" ``` ### 配置 AISIX 使用代理[​](#configure-aisix-to-use-the-proxy "配置 AISIX 使用代理的直接链接") 更新现有 `echo-agent`,使其使用 `http://aisix-a2a-auth:8082`、Bearer 身份认证,并将 `A2A_AGENT_TOKEN` 作为密钥。 对于 AISIX Cloud,请更新配置指南中创建的 Agent: ``` curl -fsS -X PATCH "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- <&2 exit 1 fi ``` 该请求会打印 HTTP `502`,`jq` 命令会打印 `true`,凭证检查不会产生输出。AISIX 会在 JSON-RPC 错误中包含上游状态,但不会代理上游响应正文。 恢复预期 Token,并移除临时响应文件: ``` start_a2a_auth_proxy "$A2A_AGENT_TOKEN" rm /tmp/aisix-a2a-auth-failure.json ``` 使用该本地身份认证配置时,请保持 `aisix-a2a-auth` 运行。在执行配置指南中的清理命令前移除它: ``` docker rm -f aisix-a2a-auth ``` ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已配置 AISIX 如何向上游 Agent 进行身份认证。可以继续阅读以下指南,控制调用方和流量: * [控制 Agent 访问权限](https://docs.apiseven.com/ai-gateway/agent-gateway/agent-access-control.md):将调用方 API Key 的权限范围限定为特定 Agent 或模式。 * [限流和预算](https://docs.apiseven.com/ai-gateway/agent-gateway/traffic-controls.md):应用请求和并发限制,并使用 AISIX Cloud 预算。 * [可观测性](https://docs.apiseven.com/ai-gateway/agent-gateway/observability.md):查看 A2A 调用生成的用量事件和指标。 * [上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md):同一个 `forward_client_headers` 字段在 AISIX 其他代理面上的用法,以及任何模式都无法触及的完整请求头清单。 --- # Admin Token Admin Token 允许自动化任务在没有浏览器会话的情况下调用 AISIX Cloud 控制面 API。 它适用于组织级工作流,例如 CI 流水线、基础设施自动化,或管理控制面资源的内部工具。它不是用于网关流量的调用方 API Key,也不是用于模型访问的上游服务提供方密钥。 一个 Admin Token 属于一个组织。控制面在认证请求时会使用这个组织绑定,因此 API 调用不需要额外的组织请求头。 ## 创建 Admin Token[​](#创建-admin-token "创建 Admin Token的直接链接") 只有组织 Owner 可以创建或吊销 Admin Token。 1. 打开 **Admin tokens**。 2. 选择 **New token**。 3. 输入唯一名称。 4. 选择过期时间,或选择 **Never**。 5. 选择一个或多个权限范围。 6. 创建 Token,并在离开一次性展示页面前复制明文值。 生成的 Admin Token 使用 `aisix_pat_` 前缀。明文值仅展示一次,之后控制面只保存其 SHA-256 摘要。如果丢失明文值,请吊销该 Token 并创建替代 Token。 ## 选择权限范围[​](#选择权限范围 "选择权限范围的直接链接") Admin Token 支持以下权限范围: | 权限范围 | 访问权限 | | -------- | ------------------------------------------------------------------------------------------------------------------- | | `read` | 对 AISIX Cloud Admin API 路由的只读访问权限。 | | `write` | 对 AISIX Cloud Admin API 路由的读写访问权限。 | | `scim` | 仅允许访问 `/scim/v2` 下的 [SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)端点。 | 盘点或报表任务可以使用 `read`。只有自动化确实需要创建、更新或删除控制面资源时,才使用 `write`。 SCIM Token 使用独立的创建流程:在 **Settings** 下的 **Directory sync (SCIM)** 中生成。`scim` 权限范围不能与其他权限范围组合使用,并且这些 Token 会在非 SCIM 路由上被拒绝,从而将身份提供方凭证限制为仅用于目录预配。 ## 使用 Admin Token[​](#使用-admin-token "使用 Admin Token的直接链接") 设置 AISIX Cloud Admin API 基础 URL,并在 `Authorization` 请求头中将 Token 作为 Bearer Token 发送: ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" curl -sS "${AISIX_CP}/environments" \ -H "Authorization: Bearer ${AISIX_TOKEN}" ``` 对于公共 OpenAPI 规范覆盖的路由,请参阅 [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)。工作流指南也可能提供特定任务的示例。例如,[成员](https://docs.apiseven.com/ai-gateway/cloud/members.md#%E4%BD%BF%E7%94%A8-api)展示了如何创建用于 API Key 归属的成员。 ## 轮换或吊销 Token[​](#轮换或吊销-token "轮换或吊销 Token的直接链接") 轮换 Admin Token 时,请创建替代 Token,更新使用它的自动化任务,确认自动化运行成功后,再吊销旧 Token。 吊销会立即生效。使用已吊销 Token 的请求会收到身份认证错误。 ## 下一步[​](#下一步 "下一步的直接链接") 创建具有 `write` 权限范围的 Admin Token 后,请继续阅读[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md),将接收环境资源并处理 AI 流量的运行时接入控制面。 如需配置组织访问权限,请继续阅读[成员](https://docs.apiseven.com/ai-gateway/cloud/members.md)。如需通过身份提供方进行预配,请参阅 [SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)。 --- # 连接 AISIX 网关 在 AISIX Cloud 部署中,AISIX 网关作为数据面运行在你的基础设施中。将网关添加到环境后,它可以接收配置、上报心跳和遥测数据,并请求预算决策。实时 AI 请求会直接发送到网关,不经过控制面。 网关使用为某个 AISIX Cloud 环境签发的证书包进行身份认证,并主动发起出站管理连接。 ## 连接的工作原理[​](#连接的工作原理 "连接的工作原理的直接链接") 证书包包含客户端证书、私钥和 CA 证书。客户端证书用于标识网关及其服务的环境。 AISIX 使用同一证书身份监听配置并调用网关管理 API。配置的管理端点也是心跳、遥测数据和预算检查请求的基础地址。除非部署提供了单独的端点,否则网关会从该 URL 推导配置存储端点。 ## 前提条件[​](#前提条件 "前提条件的直接链接") 连接网关前,请准备: * 网关所要接入的 AISIX Cloud 环境。 * 网关主机或集群到网关管理端点的出站网络访问。 * 用于保存客户端证书和私钥的 Secret 存储。 * 用于保存网关身份、生成的 mTLS 文件和配置快照缓存的可写本地存储。AISIX 默认将这些内容保存在 `/var/lib/aisix` 下。 对于容器或 Kubernetes 部署,如果重新创建的网关必须在首次重新连接控制面之前复用其身份和最近接受的配置,请将 `/var/lib/aisix` 挂载为持久化存储。每个网关实例应使用独立的可写卷。 ## 签发网关证书[​](#签发网关证书 "签发网关证书的直接链接") 1. 在 AISIX Cloud 控制台中,选择网关所要服务的环境。 2. 打开 **Data planes**。 3. 选择证书有效期,并可选择输入主机名。 4. 选择 **Issue certificate**。 5. 复制为目标部署生成的安装片段。 警告 私钥只会在签发证书的响应中显示一次。请立即复制证书包,将其保存在部署 Secret 系统中,不要提交或共享生成的片段。 控制台提供 Docker、Docker Compose、Kubernetes (Helm) 和 systemd 安装标签页。systemd 标签页会生成服务和凭证配置,但不会安装可执行文件。 ## 在 Kubernetes 上部署[​](#在-kubernetes-上部署 "在 Kubernetes 上部署的直接链接") 使用 **Kubernetes (Helm)** 标签页安装 `api7/aisix` Chart。控制台只生成这一种 Kubernetes 部署方式,因为 Chart 携带了网关停止时不丢流量所需的配置——`preStop` 暂停,以及足以覆盖排空过程的终止宽限期——而手写的清单只会沿用 Kubernetes 默认值。 对于由 Chart 管理、需要自动扩缩容、中断预算和 Prometheus 集成的生产部署,请参阅[在 Kubernetes 上部署 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md)。 ## 启动网关[​](#启动网关 "启动网关的直接链接") 在目标运行时环境中执行生成的指令。使用 systemd 指令前,请确认兼容的 `aisix-dp` 可执行文件已按生成的 unit 预期安装到 `/usr/local/bin/aisix-dp`。 生成的配置默认将代理监听端口绑定到 `3000`,将指标和状态监听端口绑定到 `9090`。有关监听器暴露方式和到控制面的出站连接,请参阅[端口参考](https://docs.apiseven.com/ai-gateway/reference/ports.md)。 请确保运行网关的同一用户可以写入 `/var/lib/aisix`。仅挂载 `/var/lib/aisix/mtls` 无法保留网关身份文件和快照缓存。 ## 验证连接[​](#验证连接 "验证连接的直接链接") 配置流量前,请先验证初始连接: 1. 确认进程启动时没有证书、信任链或配置存储连接错误。 2. 在环境的 **Data planes** 视图中,确认网关已显示且心跳时间较新。 3. 确认上报的主机名和证书 ID 对应预期的部署和环境。 配置模型服务提供方、模型别名和调用方 API Key 后,请验证端到端数据路径:确认投射资源已到达网关、实时请求能够成功执行,并且其用量或遥测数据已出现在控制面中。 如果网关没有显示,请检查管理端点、证书包、信任根、文件权限、状态目录和出站网络访问。健康的心跳可以确认管理 API 路径正常,但无法证明资源变更已经到达每个网关实例。保存第一个模型服务提供方密钥、模型和调用方 API Key 后,请使用[资源投射](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md)进行检查。 ## AISIX Cloud 连接配置[​](#aisix-cloud-连接配置 "AISIX Cloud 连接配置的直接链接") 请同时提供证书、私钥和 CA。证书包以文件挂载时使用文件路径变量;部署系统注入 PEM 内容时使用内联变量。同一证书角色不要同时配置两种形式。 | 配置项 | 使用变量 | | ------------------ | ------------------------------------ | | 网关管理基础 URL | `AISIX_MANAGED__CP_BASE_URL` | | 单独的配置存储端点 | `AISIX_MANAGED__CP_ETCD_ENDPOINT` | | 证书文件 | `AISIX_MANAGED__CP_CERT_FILE` | | 私钥文件 | `AISIX_MANAGED__CP_KEY_FILE` | | CA 证书文件 | `AISIX_MANAGED__CP_CA_FILE` | | 内联证书 | `AISIX_MANAGED__CP_CERT_PEM` | | 内联私钥 | `AISIX_MANAGED__CP_KEY_PEM` | | 内联 CA 证书 | `AISIX_MANAGED__CP_CA_PEM` | | 生成的 mTLS 目录 | `AISIX_MANAGED__MTLS_DIR` | | 网关身份文件 | `AISIX_MANAGED__DP_ID_FILE` | | 快照缓存文件 | `AISIX_MANAGED__SNAPSHOT_CACHE_PATH` | 仅当控制面提供的配置存储端点与网关管理基础 URL 不同时,才设置 `AISIX_MANAGED__CP_ETCD_ENDPOINT`。该端点应指定为不带 URL scheme 的 `host:port`。 默认状态路径分别为 `/var/lib/aisix/mtls`、`/var/lib/aisix/dp_id` 和 `/var/lib/aisix/config_cache.json`。为每个实例在 `/var/lib/aisix` 挂载一个卷即可覆盖这三个路径。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[选择模型服务提供方上游](https://docs.apiseven.com/ai-gateway/providers/overview.md)。每个提供方指南都会创建模型服务提供方密钥、模型别名和调用方 API Key,然后通过已连接的网关发送实时请求来验证配置。 如果保存的资源未按预期影响实时流量,请使用[资源投射](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md)追踪环境配置如何到达网关。 --- # 角色与自定义角色 每个组织成员都有一个角色,用于控制其可在 AISIX Cloud 控制台和 AISIX Cloud Admin API 中执行的操作。AISIX Cloud 为常见访问模式提供三个内置角色。需要更精细控制的组织可以定义自定义角色,即基于 API 执行权限检查时所使用的同一套资源定义创建的命名权限集合。 组织角色为成员在所有环境中设定基础权限。如果成员需要在某个环境中获得额外访问权限,owner 可以添加环境访问授权,而无需改变其在其他环境中的基础权限。 角色控制谁可以通过控制面配置网关。API Key 设置则单独决定 API Key 可以使用哪些模型和工具,以及其流量适用哪些预算。 ## 内置角色[​](#内置角色 "内置角色的直接链接") | 角色 | 访问权限 | | -------- | ------------------------------------------------------------------------------------ | | `owner` | 完全控制,包括账单、成员角色变更、移除成员和管理 Admin Token。 | | `admin` | 对所有资源具有读写权限。成员角色变更、移除成员和创建 Admin Token 仍仅限 owner 执行。 | | `member` | 对组织资源具有只读权限,不能读取审计事件。 | **Roles** 页面列出每个角色及其实际执行的权限。该页面使用与 API 检查每个请求时相同的权限目录。 ## 自定义角色[​](#自定义角色 "自定义角色的直接链接") 自定义角色是针对环境、模型、API Key、安全护栏、预算和审计事件等资源定义的一组命名 `read` 和 `write` 权限。它会替换成员的内置基础权限,而不是在其上扩展。例如,只对 `environments` 授予 `read` 权限的角色不能列出团队或查看用量。 常见用途包括: * 读取审计记录和用量、但不配置任何内容的 `auditor` 角色。 * 管理模型、服务提供方密钥和安全护栏、但不能变更成员或账单的 `gateway-operator` 角色。 * 以只读为主、仅对一种资源类型(例如预算)授予写权限的角色。 ### 创建和分配[​](#创建和分配 "创建和分配的直接链接") 1. 以组织 admin 或 owner 身份打开 **Roles**,然后选择 **New role**。 2. 输入永久的小写名称,例如 `auditor`。成员通过名称引用角色,因此需要不同名称时请创建新角色。 3. 选择角色授予的权限并保存。 4. 以组织 owner 身份在 **Members** 页面分配该角色。 对于由目录管理的访问权限,自定义角色可以用作默认角色或 SCIM 组到角色映射的目标。请参阅[目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)。 如需修改自定义角色的描述或权限,请打开 **Roles** 并选择 **Edit**。如需删除角色,请先清除[规则和限制](#rules-and-limits)中所述的引用,再选择 **Delete**。内置角色无法编辑或删除。 ## 环境范围访问[​](#环境范围访问 "环境范围访问的直接链接") 成员的组织角色适用于整个组织。环境访问授权会在一个环境内添加另一个角色。它可以扩展成员的组织角色,但不能缩小其权限。 例如,成员可以保留组织范围的只读访问权限,同时获得生产环境的 `admin` 授权。该授权会增加对生产环境内资源的写权限,但不会移除成员在其他位置的组织级访问权限。如需降低适用于整个组织的基础权限,请使用自定义组织角色。 * 成员对环境内资源的有效访问权限由组织角色与该环境的所有授权权限共同组成。 * 授权在其所属环境之外不生效。其他所有环境中的资源,以及成员、团队、设置、账单和自定义角色等组织级资源,仅由组织角色控制。 * 授权只覆盖环境内部的资源,不包含环境对象本身。环境范围的 admin 不能重命名或删除环境。 * 授权可以指向 `admin`、`member` 或任意自定义角色,但不能指向 `owner`。 * owner 已拥有全部访问权限,因此不能获得授权。只有 owner 可以编辑成员的授权。 * 删除环境时,指向该环境的授权也会被删除。 在 **Members** 页面管理授权:展开成员行中的 **Environment access**,添加、更改或移除环境与角色的配对,然后保存。 ## 使用 API[​](#使用-api "使用 API的直接链接") 使用具有 `read` 范围的 [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md) 列出角色和环境访问授权。具有 `write` 范围的 Token 可以创建、更新或删除角色。只有组织 owner 可以分配角色或替换环境访问授权。 运行示例前,请设置 AISIX Cloud Admin API 基础 URL 和 Token: ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" ``` ### 创建并分配自定义角色[​](#创建并分配自定义角色 "创建并分配自定义角色的直接链接") 创建组织范围的角色,并指定该角色应授予的权限: ``` curl -sS -X POST "${AISIX_CP}/roles" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "auditor", "description": "Read-only audit access", "permissions": [ { "action": "read", "resource": "audit" }, { "action": "read", "resource": "usage" } ] }' ``` owner 可以将该角色分配给成员。使用 `GET /members` 返回的成员 `user_id`: ``` export USER_ID="2c7d6e5f-4a3b-4c2d-8e1f-9a0b1c2d3e4f" curl -sS -X PATCH "${AISIX_CP}/members/${USER_ID}" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role": "auditor"}' ``` ### 更新或删除自定义角色[​](#更新或删除自定义角色 "更新或删除自定义角色的直接链接") 提供 `permissions` 会替换角色的完整权限集合: ``` curl -sS -X PATCH "${AISIX_CP}/roles/auditor" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "permissions": [ { "action": "read", "resource": "audit" } ] }' ``` 清除[规则和限制](#rules-and-limits)中所述的所有引用后,删除该角色: ``` curl -sS -X DELETE "${AISIX_CP}/roles/auditor" \ -H "Authorization: Bearer ${AISIX_TOKEN}" ``` 删除仍被引用的角色会返回 `409 ROLE_IN_USE`。成员分配和环境授权可以通过 AISIX Cloud Admin API 清除。待处理邀请和目录同步引用目前必须在控制台中清除。 ### 管理环境访问授权[​](#管理环境访问授权 "管理环境访问授权的直接链接") 环境访问路由使用 `GET /members` 返回的成员关系 `id`,而不是成员的 `user_id`。替换授权前,请先列出成员的当前授权: ``` export MEMBER_ID="8f3b2a1c-9d4e-4f6a-b7c8-1e2d3f4a5b6c" curl -sS "${AISIX_CP}/members/${MEMBER_ID}/role_bindings" \ -H "Authorization: Bearer ${AISIX_TOKEN}" ``` owner 可以替换完整的授权集合。每个环境最多出现一次: ``` curl -sS -X PUT "${AISIX_CP}/members/${MEMBER_ID}/role_bindings" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "bindings": [ { "env_id": "6b1c2c1e-0000-4000-8000-000000000002", "role": "admin" } ] }' ``` 发送空的 `bindings` 数组可移除所有环境访问授权。变更最多可能需要 30 秒才能在控制面副本间传播。 有关响应 Schema 和错误详情,请参阅 [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)。 ## 规则和限制[​](#rules-and-limits "规则和限制的直接链接") * admin 和 owner 可以创建、编辑和删除自定义角色。向成员分配任何角色仍仅限 owner 执行。 * 自定义角色不能授予超过内置 `admin` 角色的权限:仅限 owner 的操作不能授予,目录同步也不能分配 `owner`。 * 如果自定义角色已分配给成员或待处理邀请、用作目录同步默认角色或组到角色映射的目标,或者用于环境访问授权,则无法删除该角色。 * 删除自定义角色前,请重新分配成员、撤销待处理邀请、清除 **Directory sync (SCIM)** 中 **Default role** 和 **Group → role mappings** 下的所有引用,并从 **Environment access** 授权中移除该角色。 * 权限变更对持有该角色的所有成员生效,但最多可能需要 30 秒才能在控制面副本间传播。 ## 下一步[​](#下一步 "下一步的直接链接") 如需由身份提供方管理成员和角色分配,请继续阅读 [SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)。如需连接为环境资源提供服务的网关,请参阅[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 --- # 高可用 在 AISIX Cloud 中,应用通过运行时环境中的 AISIX 网关发送请求,独立的控制面则负责管理这些网关。在 On-Premises 中由你运行控制面;在 Hybrid Cloud 中由 API7 运行控制面。 这种分离使流量层和管理层可以采用彼此独立的可用性策略。高可用部署必须同时考虑应用流量路径、AISIX 网关、上游服务,以及每个网关与 AISIX Cloud 控制面的连接。 ## 高可用架构[​](#高可用架构 "高可用架构的直接链接") 下图展示了一种主动-主动参考模式,使实时流量不依赖于 AISIX Cloud 控制面路径。AISIX Cloud 控制面不是应用与上游服务之间的网络跳点。请根据可用性要求选择部署数量、网关实例数量和流量分配层级。 在此模式中,AISIX 网关跨独立故障域运行在两个主动部署中。全局负载均衡器在两个部署之间调度流量,每个部署的负载均衡器再将流量分配到多个网关实例。两个部署从同一 AISIX Cloud 环境接收配置。每个部署使用独立的网关证书;共享同一证书的实例仍会向控制面报告为不同的运行时实例。 ![包含两个主动 AISIX 网关部署、由网关发起的管理连接和共享 AISIX Cloud 控制面的 AISIX 高可用参考架构](https://static.apiseven.com/uploads/2026/07/29/G8trObIF_aisix-high-availability.svg) 控制面分别提供运维人员端点和网关管理端点。在此参考模式中,控制面 API、控制台和数据面管理器均以冗余服务副本运行。共享状态由稳定端点后的 PostgreSQL 复制部署提供。 这些组件描述的是一种高可用部署模式,并不代表 API7 托管的 AISIX Cloud 控制面的实际拓扑。图中也未规定具体的复制或故障转移实现。 ## AISIX Cloud 控制面组件[​](#aisix-cloud-控制面组件 "AISIX Cloud 控制面组件的直接链接") AISIX Cloud 控制面将用户管理、网关管理和共享状态分开。 | 组件 | 在架构中的作用 | | ---------------------- | --------------------------------------------------------------------------------------------------------------- | | AISIX Cloud 控制面端点 | 提供稳定的公共入口,并将请求路由到控制面 API。 | | 控制面 API | 处理 AISIX Cloud Admin API 操作,并将浏览器请求反向代理到控制台。它负责管理组织、环境、资源、证书、用量和预算。 | | 控制台 | 在控制面 API 后提供浏览器界面和身份认证工作流。 | | 网关管理端点 | 接受由网关发起的 mTLS 连接,无需开放到网关主机的入站访问。 | | 数据面管理器 | 下发已投射的配置,并从网关接收心跳、用量遥测和 AISIX Cloud 预算检查。 | | PostgreSQL 高可用集群 | 存储共享控制面状态。在此参考拓扑中,复制和故障转移位于稳定服务端点之后。 | 责任边界取决于控制面部署选项。对于 On-Premises 高可用控制面,请使用 Helm。跨故障域运行控制面 API、数据面管理器和控制台的冗余副本,并将它们连接到外部高可用 PostgreSQL 端点。 随附的 PostgreSQL Chart 默认不提供此参考模式中所示的复制数据库。Docker Compose 部署包为单主机部署,不支持此拓扑。在 Hybrid Cloud 中,控制面由 API7 运行。请参阅 [On-Premises 配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md)。 ## 请求路径上的可用性[​](#请求路径上的可用性 "请求路径上的可用性的直接链接") 高可用覆盖运行时环境、AISIX Cloud 控制面和上游服务。 | 区域 | 可用性要求 | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 应用流量 | 提供稳定的网关端点,并由全局流量层对每个部署执行健康检查。使用代理监听器的 [`/readyz` 端点](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#traffic-readiness)判断流量资格:它会移出正在排空的实例;只要运行中的实例仍能使用其持有的配置提供服务,就会保持该实例具备流量资格。尚未应用任何配置的实例同样会被排除在外,只是机制不同——它还没有绑定该监听器,探针得到的是被拒绝的连接而不是响应,参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 | | AISIX 网关 | 跨独立故障域运行冗余实例。当实例必须在重启后从缓存配置恢复时,请持久化每个实例的状态目录。 | | AISIX Cloud 控制面 | 对于 On-Premises,请跨故障域运行冗余控制面服务,并使用外部高可用 PostgreSQL 数据库。在 Hybrid Cloud 中,管理服务由 API7 运行。 | | 上游服务 | 如果请求必须在模型或模型服务提供方故障时继续,请为模型路由配置重试和多个目标。请将每个 MCP 服务器和 A2A Agent 部署在高韧性的服务端点之后,因为 AISIX 不会自动选择其他已注册的服务。 | ## 故障行为[​](#故障行为 "故障行为的直接链接") 实时流量路径与管理路径会彼此独立地发生故障。 | 故障 | 预期行为 | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 一个网关实例故障 | 负载均衡层将新请求转发到该部署中的健康实例。 | | 一个网关部署故障 | 全局负载均衡器将新请求转发到另一个健康部署。 | | 网关与控制面的连接中断 | 如果流量仍能到达正在运行的网关,该网关可继续使用内存中最近一次接受的配置。在中断期间重启的网关可以从有效的持久化快照恢复;如果没有快照,则必须等到获取配置后才能接收流量。新的资源投射会停止,连接恢复后继续上报心跳。请通过 `/status/config` 或 `aisix_config_*` 指标监控配置新鲜度。监听中断会同时影响所有实例,因此这是运维信号,而非负载均衡器信号。AISIX Cloud 预算检查遵循其配置的故障行为;发送到控制面的失败遥测批次可能会被丢弃。 | | 模型服务故障 | 只有已配置路由或故障转移时,AISIX 才能重试或改用其他模型目标。 | | MCP 服务器或 A2A Agent 故障 | 在其配置的端点恢复前,对该服务的请求都会失败。AISIX 不会自动选择其他已注册的 MCP 服务器或 A2A Agent。 | | 外部安全护栏服务故障 | AISIX 遵循配置的输入和输出故障行为。故障放行策略允许未经扫描的流量继续;故障关闭策略会将其阻断。 | ## 部署建议[​](#部署建议 "部署建议的直接链接") 对于上图所示的主动-主动模式,请在客户运行的流量层采用以下实践: * 在启用主动健康检查的全局负载均衡器后运行至少两个主动网关部署。 * 将每个部署放置在不同的故障域中,并使用冗余的部署负载均衡器将流量分配到多个网关实例。使用 `/readyz` 作为流量资格探针:它会让流量避开尚无可用配置的网关——首次应用配置之前,承载它的监听器根本没有绑定,探针会被拒绝——并允许从有效缓存快照恢复的实例在重新连接控制面期间继续提供服务。配置监听停滞会同时影响所有实例,因此应将配置新鲜度作为运维信号,而不是负载均衡器信号。请配置探针间隔、故障与恢复阈值以及连接排空,以避免流量抖动和进行中的请求中断。 * 为每个部署签发独立网关证书,使各部署拥有独立的凭证生命周期。同一部署中的实例可共享该部署的证书包。请通过部署使用的 Secret 系统保护每个私钥。 * 当实例必须在重启后恢复证书包、部署身份和最近一次接受的配置时,为每个实例提供独立的持久化状态目录。请勿在实例之间共享可写状态目录。[`api7/aisix` Helm Chart](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md) 默认使用每个 Pod 独立的临时状态,因此由 Chart 管理的 Pod 重启后,必须重新连接并下载配置,才能接收流量。 * 确保每个网关实例都能主动发起到 AISIX Cloud 控制面端点的 mTLS 连接。 * 对必须在实例间共享的限流计数器和缓存条目使用 Redis。内存中的计数器和缓存条目仅属于单个网关进程。如果 Redis 是可用性依赖,请使用 Redis Cluster、Redis Sentinel 或通过兼容端点提供的托管 Redis 服务。 * 单独配置模型路由和故障转移。网关冗余并不能使单一模型或模型服务提供方具备高可用性。请将 MCP 服务器和 A2A Agent 部署在高韧性端点之后,因为 AISIX 不会在已注册服务之间执行故障转移。 * 监控 `/readyz`、网关心跳新鲜度、已应用配置状态、被拒绝资源和导出器健康状况。实时请求成功只能证明流量路径正常,不能证明管理路径或遥测路径正常。 ## 网络和安全边界[​](#网络和安全边界 "网络和安全边界的直接链接") 请明确区分流量路径和管理路径: * 通过 HTTPS 向应用公开网关负载均衡器。 * 根据每个模型服务提供方或服务的配置,保持网关到上游服务的 TLS。 * 允许每个网关实例主动发起到 AISIX Cloud 控制面的 mTLS 连接。网关主机无需开放来自控制面的入站访问。 * 将指标和健康检查端点限制在负载均衡器及平台运维人员使用的监控网络内。 实时 AI 请求通过运行时环境中的 AISIX 网关,不会经过 AISIX Cloud 控制面。发送到 AISIX Cloud 控制面的用量遥测不包含提示词和响应正文,但包含请求、调用方、路由、用量和错误元数据。启用内容捕获时,外部可观测性导出器可能包含请求和响应内容,因此应采用与其他日志和追踪系统相同的数据处理控制。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 继续阅读[离线韧性](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md),了解控制面连接暂时中断期间的行为。如需了解上游连续性,请参阅[路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md)。 --- # 在 Kubernetes 上部署 AISIX 网关 使用 `api7/aisix` Helm Chart 在 Kubernetes 集群中部署、暴露和扩缩 AISIX 网关。网关在你的环境中承载实时 AI 流量,并连接现有 AISIX Cloud 控制面以接收配置。 该 Chart 需要数据面管理器端点,以及为目标环境签发的网关证书包。连接后,网关会从控制面接收模型、调用方 API Key 和策略。 ## 前提条件[​](#前提条件 "前提条件的直接链接") * 一个 Kubernetes 集群,已配置 `kubectl` 访问权限并安装 Helm 3。 * 可以访问一个能够签发网关证书的 AISIX Cloud 环境。 * 集群可以通过网络访问 AISIX Cloud 数据面管理器端点。如果使用 On-Premises,请先完成 [On-Premises 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md)。 ## 安装 Chart[​](#安装-chart "安装 Chart的直接链接") 在控制台中打开目标环境的 **Data planes** 视图并签发网关证书。**Kubernetes (Helm)** 标签页会提供下文使用的数据面管理器端点和证书包。本示例还将初始部署固定为一个副本。私钥只显示一次。 将证书包存储在 Secret 中,避免私钥出现在 values 文件中: ``` kubectl create namespace aisix kubectl -n aisix create secret generic aisix-gateway-certificate \ --from-file=cert.pem=./cert.pem \ --from-file=key.pem=./key.pem \ --from-file=ca.pem=./ca.pem ``` 使用同一视图中的数据面管理器端点安装 Chart: ``` helm repo add api7 https://charts.api7.ai helm repo update helm install aisix api7/aisix --namespace aisix --version 1.2.0 \ --set controlPlane.baseURL=https://dp-manager.example.com:7944 \ --set controlPlane.certificate.existingSecret=aisix-gateway-certificate \ --set replicaCount=1 ``` 网关首次上报心跳后,会出现在环境的 **Data planes** 视图中。Chart 默认为两个副本,但此初始命令只启动一个副本,因为在配置共享 Redis 之前,限流计数器使用每个副本各自的内存。控制台 Helm 代码片段省略了 `replicaCount`,因此原样安装会启动两个副本。如上所示,请在配置 Redis 前添加 `--set replicaCount=1`。增加副本数或启用自动扩缩容器前,请先[在副本间共享限流计数器](#share-rate-limit-counters-across-replicas)。 每个副本会注册为独立实例,并共享同一个证书。 查看 Chart 接受的所有值: ``` helm show values api7/aisix --version 1.2.0 ``` Chart 源码和软件包发布在 [`aisix-1.2.0` Helm Chart Release](https://github.com/api7/api7-helm-chart/releases/tag/aisix-1.2.0) 中。 ## 暴露网关[​](#暴露网关 "暴露网关的直接链接") Chart 默认为代理创建 `ClusterIP` 类型的 Service。如需通过云负载均衡器发布: ``` service: type: LoadBalancer port: 80 # 保留客户端源 IP,按模型配置的 IP 允许列表会使用该地址进行匹配。 externalTrafficPolicy: Local ``` 网关默认在容器内绑定端口 3000。Service 可以暴露端口 `80` 或 `443`,无需让进程绑定特权容器端口。 只有当网关必须直接监听某个低于 `1024` 的端口时,才在容器内绑定该端口。发布的镜像以非 root 用户 UID `10001` 运行,网关二进制文件具有生效的 `CAP_NET_BIND_SERVICE` 文件能力: ``` containerPorts: proxy: 80 ``` 如果你自定义渲染后的 Pod 并丢弃所有 capability,请为 AISIX 容器重新添加 `NET_BIND_SERVICE`: ``` spec: containers: - name: aisix securityContext: capabilities: drop: ["ALL"] add: ["NET_BIND_SERVICE"] ``` Kubernetes Restricted Pod Security Standard 允许此 capability。由于二进制文件的文件 capability 已设置 effective bit,如果运行时阻止授予该 capability,容器可能会因 `exec: Operation not permitted` 而失败。 只有当网关必须直接绑定节点且集群策略允许时,才使用 `hostNetwork` 或 `hostPort`。这些选项会引入节点端口冲突并降低网络隔离;Baseline 和 Restricted Pod Security Standard 也不允许使用它们。 完整的网络暴露和凭证模型请参阅[网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md)。 ## 在副本间共享限流计数器[​](#share-rate-limit-counters-across-replicas "在副本间共享限流计数器的直接链接") 限流计数器默认存储在每个网关自己的内存中,因此 *N* 个副本实际会执行每项已配置请求、Token 和并发限制的 *N* 倍。在运行多个副本前——包括自动扩缩容器新增的任何副本——请让所有副本指向同一个 Redis: ``` rateLimit: backend: redis redis: url: redis://redis.default.svc:6379 ``` 当连接 URL 包含密码时,请改用 `rateLimit.redis.existingSecret`。 所有副本都指向同一个 Redis 部署后,再提高 `replicaCount` 或启用下面的一种自动扩缩容方式。如果部署不使用请求、Token 或并发限制,也可以有意识地接受每个副本独立的内存后端。 ## 基于 CPU 或内存扩缩容[​](#基于-cpu-或内存扩缩容 "基于 CPU 或内存扩缩容的直接链接") `autoscaling` 会为网关 Deployment 创建 `HorizontalPodAutoscaler`: ``` autoscaling: enabled: true minReplicas: 2 maxReplicas: 20 targetCPUUtilizationPercentage: 70 ``` 目标值是 Pod 资源 *requests* 的百分比,因此 Chart 默认设置 CPU request。它特意不设置 CPU limit:限流会增加代理的长尾延迟,并抑制自动扩缩容器读取的信号。基于 CPU 扩缩容要求集群中安装 `metrics-server`。 在 Linux 上,`proxy.workers` 默认使用网关进程可用的 CPU 并行度。Kubernetes CPU request 不会限制该值,但 CPU limit 会限制。如果每个副本需要稳定的 Worker 数量,由于 Chart 不设置 CPU limit,请显式设置 `AISIX_PROXY__WORKERS`,并确保该值不超过为副本规划的 CPU 容量。有关 Worker 配置和容量规划注意事项,请参阅[每核一线程 Worker](https://docs.apiseven.com/ai-gateway/deployment/thread-per-core-workers.md)。 启用自动扩缩容后,Deployment 会省略 `spec.replicas`,避免后续 `helm upgrade` 重置自动扩缩容器选择的副本数。此后会忽略 `replicaCount` 值。 所有 `behavior` 策略都会原样传递,例如让缩容比 Kubernetes 默认行为更平缓: ``` autoscaling: behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Pods value: 1 periodSeconds: 60 ``` 对于 Pods、Object 或 External 指标(例如通过 Prometheus adapter 暴露的序列),请使用 `autoscaling.extraMetrics`。 ## 使用 KEDA 基于请求负载扩缩容[​](#使用-keda-基于请求负载扩缩容 "使用 KEDA 基于请求负载扩缩容的直接链接") CPU 是负载的间接指标。如需改为根据网关自身流量扩缩容,请使用 [KEDA](https://keda.sh),并针对[网关指标](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md)执行 Prometheus 查询。 启用示例前,请准备以下集群组件: * 安装 KEDA,包括 `ScaledObject` CRD 和控制器。 * 提供可查询网关指标的 Prometheus 服务器。 * 如果需要由 Chart 创建下文所示的抓取配置,请安装 Prometheus Operator 或其他能够消费 `ServiceMonitor` 对象的控制器。仅安装 CRD 会让 Helm 能够创建对象,但不会有组件将其转换为抓取配置。当 Prometheus 实例按标签选择 ServiceMonitor 时,请设置 `metrics.serviceMonitor.labels`。如果 Prometheus 通过其他方式发现指标 Service,请将 `metrics.serviceMonitor.enabled` 保持为 `false`,并省略该配置块。 确认所启用值依赖的 CRD 已经存在: ``` kubectl get crd scaledobjects.keda.sh # 仅当 metrics.serviceMonitor.enabled 为 true 时需要。 kubectl get crd servicemonitors.monitoring.coreos.com ``` 这些前提条件就绪后再配置 Chart: ``` metrics: serviceMonitor: enabled: true keda: enabled: true minReplicas: 2 maxReplicas: 20 pollingInterval: 15 cooldownPeriod: 300 triggers: - type: prometheus metadata: serverAddress: http://prometheus.monitoring.svc:9090 query: sum(rate(aisix_llm_requests_total[2m])) threshold: "100" ``` `aisix_llm_requests_total` 统计模型推理请求,例如 `/v1/chat/completions`,但不包括 MCP 或 A2A 调用。如果这类流量才是扩缩容依据,请使用 [`aisix_proxy_requests_total`](https://docs.apiseven.com/ai-gateway/reference/metrics.md#request-metrics)。 `autoscaling` 和 `keda` 互斥。同时启用两者会使 Helm 渲染失败,避免两个控制器同时写入 `spec.replicas`。 ## 扩缩容事件期间的行为[​](#扩缩容事件期间的行为 "扩缩容事件期间的行为的直接链接") 自动扩缩容器新增的副本在能够提供服务前不会接收流量。网关应用控制面配置之前根本不会绑定代理监听器,因此 Chart 指向该监听器的所有探针得到的都是被拒绝的连接,而不是响应。 覆盖这段等待的是 Chart 的 `startupProbe`。在启动探针成功之前,Kubernetes 会挡住就绪和存活探针,因此等待期间就绪探针根本不会执行,Pod 只是一直不进入就绪状态——Kubernetes 会让它保持在 Service 端点之外,存活探针也不会重启仍在连接控制面的 Pod。启动探针的预算是 `periodSeconds x failureThreshold`,需要覆盖连接控制面并应用其中内容的时间。控制面连接持续不可达、超过该预算的 Pod,其容器会被杀掉并重启,反复重启会表现为 `CrashLoopBackOff`——对于从来没有可提供服务内容的实例,这是预期结果。就绪契约以及如何设置该预算,请参阅[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 副本缩容时,Kubernetes 会同时开始将其从 Service 端点移除并终止 Pod。以下两个 Chart 配置会在此过程中保护进行中的请求。 `preStopSleepSeconds` 在容器收到 `SIGTERM` 前先暂停一段时间,让端点移除在网关开始关闭之前传播到每个节点。它覆盖的是监听 Kubernetes API 的负载均衡器;通过轮询健康检查感知的负载均衡器在整个暂停期间看到的仍是就绪的 Pod,由网关自身的排空窗口 `shutdown.min_drain_secs` 覆盖。 `terminationGracePeriodSeconds` 为整个终止流程设置上限——暂停、排空窗口、随后的在途请求排空,以及再之后最多 5 秒的快照缓存排空——因为网关排空本身没有截止时间。Kubernetes 对该值的默认是 30 秒,会中断流式响应,因此 Chart 采用了更长的取值。 两者都带有与该流程匹配的默认值,`helm show values api7/aisix --version 1.2.0` 会显示此版本的默认值。如果工作负载的流式传输时间超过暂停和排空窗口结束后剩余的预算,请提高 `terminationGracePeriodSeconds`。 观察扩缩容决策及其依据的指标: ``` kubectl -n aisix get hpa aisix --watch kubectl -n aisix describe hpa aisix ``` ## 应对节点中断[​](#应对节点中断 "应对节点中断的直接链接") `PodDisruptionBudget` 可防止节点排空、集群升级等主动中断一次性停止所有网关。分布约束可以避免副本集中在单个故障域: ``` podDisruptionBudget: enabled: true minAvailable: 50% topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/name: aisix ``` Chart 使用 `emptyDir` 卷挂载 `/var/lib/aisix`,因此其中的状态是临时的,且只属于单个 Pod。Pod 重启后会重新注册,并在接收流量前从控制面下载配置。请跨故障域保留多个副本,使现有副本可以在其他副本重启期间继续提供服务。如果网关必须在控制面不可用时使用缓存配置重启,请自定义工作负载,为每个副本提供独立的持久化状态目录。 更完整的部署模式请参阅[高可用](https://docs.apiseven.com/ai-gateway/cloud/high-availability.md)。 ## 设置其他网关配置[​](#set-any-other-gateway-configuration "设置其他网关配置的直接链接") 控制面负责动态资源,Chart 负责 Pod。对于 Chart 没有作为 value 暴露的[启动配置](https://docs.apiseven.com/ai-gateway/deployment/startup-configuration.md),请直接设置环境变量;每个配置字段都可以通过 `AISIX_
__` 访问: ``` extraEnvVars: - name: AISIX_OBSERVABILITY__LOG_LEVEL value: "debug" - name: AISIX_UPSTREAM__POOL_MAX_IDLE_PER_HOST value: "32" ``` 命名规则请参阅[环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 --- # 日志与审计 AISIX Cloud 控制面为运维人员提供两类证据链:用于 AISIX 网关流量的请求日志,以及用于控制面状态变更的审计日志。两者结合起来,可以帮助团队了解一次请求发生了什么,以及是谁修改了影响流量的资源。 使用请求日志排查具体的 AISIX 网关请求;使用审计日志排查配置、访问权限和其他控制面变更。 ## 请求日志[​](#request-logs "请求日志的直接链接") 请求日志基于 AISIX 网关遥测数据生成。它展示单个请求的结果,包括请求时间、状态、请求模型、调用方 API Key、延迟、Token 数量,以及可用时的尝试详情。延迟会从两个角度报告:调用方等待了多久,以及上游处理花费了多久。这样无需猜测即可判断慢请求的延迟来源。 展开一行会看到 AISIX 分配的**请求 ID**;如果这次调用到达了会返回 ID 的服务提供方,旁边还会有一个**服务提供方请求 ID**。二者含义不同:前者由 AISIX 通过 `x-aisix-request-id` 响应头返回给调用方,也是报障的调用方通常手上唯一有的 ID;后者是上游服务提供方在自己的响应中返回的 ID,例如 OpenAI 的 `chat.completion.id` 或 Anthropic 的消息 `id`,服务提供方的控制台和技术支持渠道正是按它检索这次调用的。先用前者查到该请求,再从中读取后者,然后拿它去找服务提供方。 如果本次调用没有产生服务提供方请求 ID,该字段不会显示:包括响应由缓存命中返回、请求在 AISIX 到达服务提供方之前就被拒绝,以及服务提供方响应本身就不带 ID 的端点(如 Embedding、音频和图像生成)。重试或故障转移的请求会按拿到响应的尝试各记录一个,因此请展开实际向调用方返回响应的那次尝试。 带有 `estimated` 标记的行包含一个或多个本地计算的 Token 数量,因为上游响应省略了这些值或将其报告为零。这种情况可能出现在 OpenAI 兼容中继、客户端在流式传输中途断开,以及上游返回部分响应后出错时。估算的 Token 数量会与服务提供方报告的数量一起计入支出和预算计算。排查用量或支出时,可以通过该标记区分估算值。有关支持的端点和估算行为,请参阅[用量上报](https://docs.apiseven.com/ai-gateway/cloud/usage-reporting.md#how-usage-is-reported)。 ![AISIX Cloud 控制面的请求日志页面,展示筛选条件、请求状态、Token 用量、延迟和展开后的请求详情](https://static.api7.ai/uploads/2026/06/25/vZnxzxum_log.png) 数据面会批量刷新遥测数据,因此刚完成的请求可能需要几秒才会出现。 每行都会显示本地日期和时间,因此跨越多天的时间范围仍易于阅读。将鼠标悬停在时间戳上可查看包含时区的完整日期和时间。 当需要验证实时请求、检查上游错误、确认策略拒绝,或查看路由与故障转移如何解析请求时,请先查看请求日志。 ### 解读延迟数据[​](#解读延迟数据 "解读延迟数据的直接链接") 请求日志行会显示调用方等待的时间。展开该行可以查看拆分后的测量值,因为单个数字无法判断慢请求是由服务提供方还是网关造成的: | 字段 | 测量内容 | 范围 | | -------------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | **调用方延迟** | 从网关收到请求,到完成非流式响应或开始发送流式响应。 | 整个请求,包括每次重试和故障转移尝试。 | | **上游延迟** | 实际处理该请求的尝试与服务提供方通信所花费的时间。 | 一次尝试。 | | **上游 TTFT** | 该尝试等待服务提供方首个流式帧的时间,无论帧内容为何——包括 `response.created`、`message_start` 等元数据起始帧。仅适用于流式请求。 | 一次尝试。 | 讨论 SLO 时应引用调用方延迟;**Overview** 页面中的 **Latency p50 / p99** 卡片也使用该指标。 上游 TTFT 在流的首个帧到达时停止计时,而不是首个可见 Token。这与部署在 AISIX 前面的代理和网关的统计口径一致,因此该值可以与它们记录的数据直接对比。如果推理模型在思考期间不输出任何可见内容——例如 `/v1/responses` 上游会立即打开流、但不输出推理摘要——那么即使回答文本很晚才开始,TTFT 也会很小;这段思考等待计入上游延迟,而不是 TTFT。 对于流式响应,调用方延迟会在流开始时停止计时,而不是等到流结束。流的总持续时间会随模型生成的 Token 数量增加,无法有效反映用户体验;用户真正感知的是输出开始出现前的等待时间。 比较这些字段可以定位延迟。如果请求未重试,而调用方延迟远高于上游 TTFT,说明时间花在网关侧处理上。常见原因是执行脱敏的输出安全护栏:它必须缓冲完整响应流后才能释放内容。如果两者接近,则主要耗时来自服务提供方。对于发生重试或故障转移的请求,差值还包含先前的尝试,因此应先查看尝试记录。 **Latency p50 / p99** 卡片只统计成功请求。被拒绝的请求通常很快,正是因为系统没有执行多少处理;如果将其计入,会拉低百分位数并掩盖实际的慢请求。 备注 0.7 之前的数据面只记录单一延迟值,没有面向调用方的延迟,因此这些记录不会计入延迟百分位数。升级后记录的流量才会使用拆分后的延迟字段。 ### 语义护栏测到了什么[​](#see-what-a-semantic-guardrail-measured "语义护栏测到了什么的直接链接") 如果某个基于向量相似度的安全护栏筛查过这个请求,展开该请求还会看到 **Semantic guardrail scores**。每条记录会给出安全护栏名称和运行的钩子、它比对的是哪个示例列表、实测相似度与其比较的阈值、产生该分数的 embedding 模型,以及最接近的那条示例在该列表中的行号。 放行的请求和被拒绝的请求都会记录,`monitor` 模式和 `block` 模式下也都会记录。这正是它对调优有价值的地方:监控命中只在安全护栏本应阻断时才出现,因此一个刚好差一点触发的行——拒绝阈值略高,或允许阈值略低——完全不会产生**监控命中**,看上去与安全护栏根本没在运行毫无区别。而相似度分数两种情况下都会记录。 A2A 和 Rerank 请求都可以报告这些分数,但两者都只运行输入钩子。A2A 不会解析模型或 MCP 服务器,因此只有环境、调用方 API Key 或团队作用域的绑定能够覆盖它。即使上游没有返回可读取的用量块,只要受到安全护栏归因,已筛查的 Rerank 请求就会发出用量事件并生成日志记录。 展开后看不到分数有以下几种原因:没有语义安全护栏筛查过它、它是旧版网关记录的、有别的安全护栏先拒绝了这个请求(链在第一次阻断处停止,因此优先级更高的安全护栏一旦命中,它后面的语义安全护栏就不会执行)、这一行是重试、故障转移或 Ensemble 请求中被取代的那次尝试(只有该请求的终态行带有分数,它并不总是列在最后)、作用在输出钩子上的行,其流式回复超出了 `max_buffer_bytes`、在安全护栏运行前就被拒绝、该行属于仅支持输入的端点但安全护栏仅配置了输出钩子、没有可筛查的文本(在默认的 `text_source: user_messages` 下,只带图片的请求不会发起向量嵌入调用),或者向量嵌入调用失败。最后一种最需要排除:筛查会在失败处中止,此时尚未产生分数,因此正在故障的向量嵌入模型看起来与一个没有命中的安全护栏完全一样。 embedding 调用失败会在同一行的别处留下信号,具体在哪个字段取决于该行的模式。`block` 且失败关闭(默认)会拒绝该请求,并在 `guardrail_enforced_hits` 中记录动作 `blocked_unavailable`,在 **Enforced hits** 中显示为 **check unavailable**。`monitor` 且失败关闭会照常放行,并在 `guardrail_monitor_hits` 中记录动作 `would_block`,在 **Monitor hits** 中显示为 **would block**——此时另外两个字段都不会写,因此这是最容易误读的一种。两种模式在失败放行时,都会让请求未经该安全护栏筛查就通过——链上其余安全护栏仍然执行了——并记录一条 **Bypass reason**(`guardrail_bypassed_reason`)。在把空白区域理解为「无事发生」之前,请先查这三处。 不同向量嵌入模型的分数不可互相比较,因此每个分数旁边都会显示对应的模型。被筛查的文本和示例文本都不会被记录——示例只通过 `top_example_index` 来标识,它是该方向列表中从 0 开始的序号,而控制台会把它渲染成从 1 开始的行号。如何使用这些数值选择阈值,参见[校准语义筛查安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/semantic-screening-calibration.md)。 ### 按请求类型筛选[​](#filter-by-request-kind "按请求类型筛选的直接链接") 每一行都会携带该请求要求网关做的事情——对话补全、图片生成、视频提交、工具调用——**Operation** 筛选器可以把日志收窄到其中一类。行上没有别的字段能回答这个问题:所有 OpenAI 兼容端点上报的入站协议相同,因此文本对话和图片生成看起来一样;模型名称也不是替代品,同一个模型可以服务多个端点,而调用方是通过别名和模型组来寻址模型的。 除四个对话类取值(`chat`、`messages`、`responses`、`completions`,常见情况)外,每一行都会标出操作类型;展开行即可看到取值本身。网关升级之前记录的请求不携带操作类型:它们既不会被标出,也不会被该筛选器选中。该筛选器在所有标签页上都生效——MCP、A2A 和透传流量本身也是操作类型——并且切换标签页后依然保持。它是在标签页之内收窄而不是覆盖标签页,因此一个本就为空的组合(比如在 LLM 标签页上选 `mcp`)会返回空列表,而不是列出 MCP 流量。 取值清单及各自的含义参见[区分请求类型](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#tell-request-kinds-apart),那里同时说明了同一个字段如何到达外部导出器。 在读计数之前有两点需要了解。操作类型描述的是**请求**,因此失败或被策略拒绝的行携带的取值与成功请求相同——这正是你能看出拒绝发生在哪个端点的原因。另外,发生重试或故障转移的请求每次尝试产生一行,因此按行计数得到的是尝试数而不是请求数。 ### 搜索请求[​](#搜索请求 "搜索请求的直接链接") 筛选器上方的搜索框会在请求的所有文本字段中查找输入内容,且不区分大小写。搜索范围包括错误消息和错误类别、请求模型和解析后的模型名称、服务提供方及服务提供方密钥标签,以及客户端 User-Agent、源 IP、完成原因、请求 ID 和服务提供方请求 ID——因此服务提供方技术支持渠道提供的 ID 也能在这里找到对应的请求。当你只掌握客户端报告的部分错误内容,却不知道它位于哪个字段时,可以使用搜索功能。 搜索会与筛选器组合,而不是替代筛选器。例如,搜索 `rate limit` 并同时选择 **5xx** 状态筛选器,只会返回文本中提到限流的服务端错误。已知请求 ID、模型、服务提供方密钥或调用方 API Key 时,专用筛选器仍是更精确的方式。 在 **Requested model / group** 筛选器中,直接输入会对别名进行不区分大小写的模糊(子串)匹配;从候选项选择模型或模型组时,则会对完整别名进行区分大小写的精确匹配。导出会沿用请求列表当前生效的输入或选择匹配方式。 ### 导出请求[​](#导出请求 "导出请求的直接链接") **Export** 会下载符合当前筛选条件和搜索内容的所有请求,而不仅是屏幕上的当前页。选择 **CSV** 可在电子表格中审查,选择 **JSON** 可供下游流水线使用;JSON 会返回与控制面 API 相同的字段,并包装在包含 `data` 数组和 `total` 总数的对象中。 两种格式都包含请求时间、请求 ID、尝试详情、状态和错误文本,还包括操作类型、请求模型和解析后的模型名称、调用方 API Key 名称、Token 数量、延迟及成本。调用方延迟和上游延迟会分别写入独立的列。CSV 文件采用带字节顺序标记的 UTF-8 编码,因此电子表格应用可以正确读取非 ASCII 错误消息。安全护栏相关的证据也会随行导出:`guardrail_scores` 记录各语义安全护栏实测的相似度,在 CSV 中是一列,在 JSON 中是一个数组。 一次最多导出 50,000 个请求,并按时间从新到旧排列。当匹配结果超过该数量时,控制面会导出最新的 50,000 个请求,并报告完整的匹配总数。请缩小时间范围或筛选条件,以导出其余请求。 ## 审计日志[​](#审计日志 "审计日志的直接链接") 审计日志记录控制面状态变更,用于合规审查和运维调查。它会显示谁创建、更新或删除了环境、模型、API Key、服务提供方密钥、预算、策略和 Admin Token 等资源。 如果配置更新后流量行为发生变化,请使用审计日志。请求日志可以展示请求结果,审计日志则可以确认该结果出现前是否修改了控制面资源。 只有组织 Owner 和 Admin 可以访问审计日志。 条目按时间从新到旧排列,记录列表底部会显示当前筛选条件匹配的条目总数。页码对应完整的已筛选集合,而不是当前已经加载的内容,因此可以从已知位置继续审查。 ### 筛选和搜索审计记录[​](#筛选和搜索审计记录 "筛选和搜索审计记录的直接链接") 记录列表上方的筛选器可以按资源类型、Actor 和时间缩小范围。资源类型列表只提供该组织实际记录过的类型。时间范围提供预设值和 **Custom range**;后者接受明确的开始与结束时间,可将审查锁定到事件发生的精确时间窗口。 搜索框会在条目的可读字段中查找输入文本,且不区分大小写。搜索范围包括变更前后的状态(资源显示名称位于其中)、资源类型和标识符、Action、Actor 标识符、客户端 IP 地址和 User-Agent。如果工单只给出了资源名称,却没有说明是哪次变更影响了它,可以使用搜索功能。 搜索会与筛选器组合,而不是替代筛选器。例如,搜索模型名称并同时选择一个 Actor,只会返回该人员涉及该模型的变更。已知资源类型或 Actor 时,专用筛选器仍是更精确的方式。 ### 导出审计记录[​](#导出审计记录 "导出审计记录的直接链接") **Export** 会下载符合当前筛选条件和搜索内容的所有条目,而不仅是屏幕上的当前页。选择 **CSV** 可在电子表格中审查,选择 **JSON** 可供下游流水线或证据归档使用。JSON 会返回与控制面 API 相同的字段,并包装在包含 `data` 数组和 `total` 总数的对象中。 两种格式都包含条目时间和标识符、Action、资源类型和标识符、客户端 IP 地址和 User-Agent,以及完整的变更前后状态。它们还会同时包含 Actor 的电子邮件地址和 Actor 标识符,使没有控制台访问权限的审查人员也能理解导出文件。CSV 文件采用带字节顺序标记的 UTF-8 编码,因此电子表格应用可以正确读取非 ASCII 资源名称。 一次最多导出 50,000 个条目,并按时间从新到旧排列。当匹配结果超过该数量时,控制面会导出最新的 50,000 个条目,并报告完整的匹配总数。请缩小时间范围或筛选条件,以导出其余条目。 ## 调查请求结果[​](#调查请求结果 "调查请求结果的直接链接") 使用属于同一网关环境的调用方 API Key 和模型别名,通过 AISIX 网关端点发送请求。 请求完成后,在请求日志中检查匹配的请求时间、状态、请求模型和调用方 API Key。如果请求使用了路由或故障转移,请在可用时查看解析后的模型或尝试详情。 上游身份认证、配额或服务提供方侧错误仍可以证明 AISIX 网关路径正常。此时,请求已经到达 AISIX;AISIX 选择了已配置的模型和服务提供方密钥,随后上游服务提供方返回错误。 除非日志显示错误的模型、服务提供方密钥或环境,否则不要把服务提供方错误视为资源投射失败。 ## 调查策略拒绝[​](#investigate-policy-rejections "调查策略拒绝的直接链接") AISIX Cloud 策略可以在 AISIX 调用上游服务提供方前拒绝流量。预算硬性限制会返回预算相关错误,限流策略会返回限流错误;安全护栏可以根据钩子点,在服务提供方调用前或调用后拒绝不安全内容。 请求被拒绝时,请先确认响应来自 AISIX 还是上游服务提供方,再通过请求日志检查状态和请求身份。 对于预算拒绝,请把返回的预算 Scope 与 **Budgets** 视图进行比较。对于限流拒绝,请检查与请求匹配的调用方 API Key、模型、团队或成员策略。对于安全护栏拒绝,请检查安全护栏 Scope,以及触发它的模型或调用方身份。 ## 流量未出现在请求日志中[​](#流量未出现在请求日志中 "流量未出现在请求日志中的直接链接") 如果请求日志中没有预期记录,请先检查请求路径。请求日志只包含选中环境的 AISIX 网关流量,因此发送到其他网关端点或其他环境的请求会显示在对应位置。 如果请求路径正确,请检查 AISIX 网关是否有较新的心跳,并确认它可以访问控制面遥测端点。 其他控制面信号也可以帮助缩小原因: | 信号 | 显示内容 | | ---------------------- | --------------------------------------------------------------------- | | 数据面心跳 | AISIX 网关是否已连接控制面,并且是否从预期环境上报。 | | 用量 | 控制面是否收到了用于汇总用量和预算工作流的 AISIX Cloud 网关遥测数据。 | | 可观测性导出器健康状态 | 网关是否已应用导出器配置,并是否正在上报外部遥测目的地的投递状态。 | ## 外部导出器[​](#external-exporters "外部导出器的直接链接") 请求日志展示控制面对 AISIX Cloud 网关遥测数据的视图。可观测性导出器从环境的 **Observability** 视图配置,并将用量事件从 AISIX 网关发送到你控制的目的地。 当需要将请求遥测发送到外部链路追踪、日志、存储或核算系统时,请使用导出器。导出器由 AISIX 网关直接向目标目的地投递数据。即使外部目的地存在凭证、网络或接收路径问题,请求日志仍然可能存在。 ## 数据保留[​](#数据保留 "数据保留的直接链接") 控制面会根据每个组织的保留窗口保存 AISIX Cloud 网关遥测数据,其中包括 **Request Logs** 和 **Usage** 视图背后的数据。默认情况下,记录会保留 30 天,控制面每天自动移除更早的记录。 组织 Owner 和 Admin 可以在 **Settings** 下的 **Usage log retention** 中,将保留窗口设置为 1 到 3650 天。较长窗口会保留更多历史记录,便于调查和报告;较短窗口会减少存储的数据量。变更只对后续清理生效,并在下一次每日清理时应用。 由于保留策略,较早的流量最终会从请求日志和用量视图中消失。如需在保留窗口之外保存请求遥测,请配置[外部导出器](#external-exporters),在记录被移除前把用量事件投递到你控制的目的地。 ## 下一步[​](#下一步 "下一步的直接链接") 有关支持的自动化操作,请使用 [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)。如需将网关遥测数据投递到自有系统,请继续阅读[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md)。 --- # 成员 成员属于 AISIX Cloud 控制面中的组织,代表负责控制面管理、API Key、用量和限制的人员或服务所有者。 AISIX Cloud 控制面支持两种成员加入方式: * 当成员需要登录控制台时,邀请该成员。 * 当你需要一个不登录控制台的 API Key 所有者时,直接创建成员。 两种方式都会创建组织成员。区别在于该成员是否会收到邀请,并是否可以使用控制台。 ## 邀请成员[​](#邀请成员 "邀请成员的直接链接") 当某个人需要控制台访问权限来管理资源、查看用量或管理组织时,请使用邀请方式。 1. 打开 **Members**,选择 **Invite member**。 2. 输入成员邮箱并选择角色。 3. 发送邀请,并分享一次性邀请链接。 打开链接后,受邀人会看到是谁邀请的、将要加入哪个组织、以及获得什么角色。尚未拥有账号的受邀人可以直接从该页面注册——邮箱已自动填入且不可修改——注册完成后会回到邀请页面。加入组织始终需要显式点击 **Accept invitation**:仅打开链接不会改变成员关系,因此已登录其他组织的用户点开链接也不会被切换过去。 邀请与你填写的邮箱绑定。只有使用该邮箱的账号才能接受邀请;其他账号打开链接时,会看到该邀请是发给哪个邮箱的,并可以切换到该账号登录。在受邀人接受前,该邀请会停留在 **Pending invitations** 标签页。 已经是组织成员的邮箱无法再被邀请。接受邀请不会修改已有成员的角色,这样的邀请不会产生任何效果——请直接在成员列表中修改角色。 ### 邀请有效期[​](#invitation-lifetime "邀请有效期的直接链接") 邀请在发出 7 天后过期。在此之前,它会停留在 **Pending invitations** 标签页,你可以在这里吊销它,使链接立即失效。 该标签页默认只列出仍然有效的邀请。勾选 **Show stale invitations** 后,还会显示已接受、已吊销和已过期的邀请。如果需要清理记录,已过期的邀请也可以在这里吊销。 已过期的邀请不会继续占用该邮箱:再次邀请同一个人会签发新的链接,并作废那条已过期的邀请,后者仍会显示在 **Show stale invitations** 中。只有仍然处于待接受且未过期的邀请,才会阻止对同一邮箱再次发起邀请。 ## 直接创建成员[​](#create-a-member-directly "直接创建成员的直接链接") 当成员只需要拥有 API Key,而不需要控制台访问权限时,可以直接创建成员。典型场景包括服务、应用,或在控制台访问受限的私有化部署中代表开发者。 直接创建的成员: * 会立即激活,不需要邀请链接或确认步骤。 * 可以加入团队并分配 API Key。 * 可以受限流和预算治理。 * 没有密码,因此无法登录控制台。 该成员仍然有名称和邮箱。请使用能够识别责任人、服务或应用所有者的值,以便正确归因用量和限制。 ### 在控制台中操作[​](#在控制台中操作 "在控制台中操作的直接链接") 1. 打开 **Members**,选择 **Create user**。 2. 输入能够识别责任归属的 **Name** 和 **Email**。 3. 选择 **Create user**。 成员会立即出现在列表中。随后你可以[将该成员加入团队](https://docs.apiseven.com/ai-gateway/cloud/teams.md#add-and-manage-members),并从承载其流量的环境中签发 API Key。 ### 使用 API[​](#使用-api "使用 API的直接链接") 当需要通过自动化供应成员时,请使用 API。 使用具有 `write` 权限范围的[组织 Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md)认证。Admin Token 的作用域绑定到一个组织,因此请求不需要额外的组织请求头。 ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" ``` 创建成员: ``` curl -X POST "${AISIX_CP}/members" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "Responsible Person", "email": "svc-payments@example.com" }' ``` 成功调用会返回 `201 Created` 和新成员: ``` { "member": { "id": "8f3b2a1c-9d4e-4f6a-b7c8-1e2d3f4a5b6c", "user_id": "2c7d6e5f-4a3b-4c2d-8e1f-9a0b1c2d3e4f", "email": "svc-payments@example.com", "display_name": "Responsible Person", "role": "member" } } ``` 邮箱地址必须有效,并且在部署内唯一。对于应用所有者,可以使用类似 `svc-payments@example.com` 的合成地址。复用已有邮箱会返回 `409 Conflict`。直接创建的成员始终使用 `member` 角色。 ## 浏览和搜索成员[​](#浏览和搜索成员 "浏览和搜索成员的直接链接") **Members** 列表支持搜索和分页,便于管理大型组织。 * 使用搜索框按名称或邮箱过滤。搜索在服务端执行,因此会匹配所有页面,而不只匹配当前页面中的行。 * 使用列表下方控件调整页面大小或在页面之间切换。 ### 使用 API 列出成员[​](#使用-api-列出成员 "使用 API 列出成员的直接链接") 复用上面导出的 `AISIX_CP` 和 `AISIX_TOKEN`。此请求使用具有 `read` 权限范围的 Token 即可。 ``` curl "${AISIX_CP}/members?page=1&page_size=20&q=payments" \ -H "Authorization: Bearer ${AISIX_TOKEN}" ``` 查询参数都是可选的: * `q`:对成员名称和邮箱执行不区分大小写的匹配。 * `page`:从 1 开始的页码。需要同时设置 `page_size`;单独设置 `page` 会返回 `400`。 * `page_size`:页面大小,最大为 `200`。如果同时省略 `page` 和 `page_size`,则禁用分页,并在单个响应中返回所有成员。 响应会在分页结构中包装成员列表: ``` { "data": [], "total": 128, "page": 1, "page_size": 20, "owner_count": 2 } ``` `total` 是所有页面中匹配过滤条件的成员数量,`owner_count` 是组织中的 Owner 数量。 ## 移除成员[​](#remove-a-member "移除成员的直接链接") 在成员行上选择移除操作。移除成员会一并撤销其组织成员资格、环境级角色绑定,以及在所有团队中的位置。 同时会**禁用该成员拥有的所有 API Key**,并且该变更会传播到网关,因此这些凭证会在网关本身停止工作,而不只是无法在控制台中使用。这与身份提供方通过 [SCIM](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md) 触发的预配撤销是同一套行为——从控制台移除和从目录移除,现在会让组织处于相同的状态。 这些 Key 是被禁用而不是被删除,因此其用量历史仍可用于报表。运维此前手工禁用的 Key 会保留原有的禁用来源。如果这个人离开后其凭证仍需继续承载流量(例如以其账号创建的应用 Key),请在移除成员之前重新绑定或重建它们。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[团队](https://docs.apiseven.com/ai-gateway/cloud/teams.md),了解如何按团队归因并实施共享控制;或继续阅读[角色与自定义角色](https://docs.apiseven.com/ai-gateway/cloud/custom-roles.md),了解如何控制成员权限。如果成员应由身份提供方管理,请使用 [SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)。 --- # 模型定价 AISIX Cloud 控制面根据观测到的用量以及上游模型服务提供方和模型对应的价格计算请求成本。大多数模型按 Token 数计费;按时长计费的模型则按音频时长计价。当模型没有目录价格,或组织采用不同费率时,可以配置价格覆盖项。 定价会影响 **Usage** 中显示的支出和 AISIX Cloud 预算评估的总额。提示词和补全费率也会影响使用 [`least_cost` 路由组](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md#route-by-cost-latency-or-load)时的目标顺序。定价不会改变上游模型服务提供方实际收取的费用。 ## AISIX 如何解析价格[​](#aisix-如何解析价格 "AISIX 如何解析价格的直接链接") AISIX 会直接应用配置费率,不添加隐藏乘数。每个用量事件都会按精确的 `(provider, model name)` 组合解析价格: 1. 与服务提供方和模型名称匹配的组织覆盖价格优先。 2. 否则,AISIX 使用 [models.dev](https://models.dev) 中匹配的目录默认价格。 3. 如果两者都不匹配,用量事件会保留上报的用量,但将支出记录为 `$0.00`。 目录刷新行为取决于定价同步的配置方式。在线模式下,控制面会在启动时以及每 24 小时刷新目录。默认情况下,On-Premises Docker Compose 软件包即使可以访问互联网,也会在启动时加载内置目录快照。若要为该软件包启用在线同步,请参阅[价格目录](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md#pricing-catalog)。 对于匹配的价格,AISIX 会分别计算 Token 成本和时长成本,再将两者相加。Token 定价使用提示词和补全费率,并采用下文所述的缓存和推理回退规则。只有当事件上报了音频时长且 **Audio per minute** 不为零时,才会计入时长成本。 成本在记录用量事件时计算,并与事件一起保存。修改价格只影响修改后记录的事件,不会重新计算历史事件的价格。 ## 识别缺失的价格[​](#识别缺失的价格 "识别缺失的价格的直接链接") 先在[请求日志](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md#request-logs)中展开事件。请求日志会以六位小数显示每个用量事件或路由尝试的成本;聚合 **Usage** 视图会把支出四舍五入到两位小数,并且只显示前 10 个环境/模型组合。因此,看到 `$0.00` 或模型未出现在 Usage 中,并不能证明定价缺失。对于价格很低的请求,应产生足够的 Token 用量后再判断。 以下情况可能缺少目录价格: * 模型运行在 models.dev 未定价的自托管或转售商上游中。 * 配置的模型名称是自定义别名。 * 服务提供方提供了较新的模型,但目录尚未在该服务提供方名下收录该模型。 添加覆盖项前,请准确记录模型配置中的服务提供方和模型名称。任一值不同,定价行都不会匹配用量事件。 ## 添加价格覆盖项[​](#添加价格覆盖项 "添加价格覆盖项的直接链接") 1. 从组织导航中打开 **Model pricing**。 2. 选择 **Add pricing**。 3. 按模型配置中的值准确填写 **Provider** 和 **Model name**。成本会按这一服务提供方与模型名称组合匹配用量事件,因此不匹配的值不会生效。Provider 字段会建议已知目录服务提供方,但也可以输入任意值,包括自定义值。 4. 根据服务提供方的计费依据进行配置: * 对于按 Token 计费的模型,输入每 1M Token 的 USD **Prompt** 和 **Completion** 费率,并将 **Audio per minute** 保持为 `0`。 * 对于按时长计费的语音转文本模型,将 Token 费率保持为 `0`,并输入以 USD/音频分钟为单位的 **Audio per minute** 费率,例如 `0.006`。 5. 对于按 Token 计费的模型,可选:分别设置 **Cache read**、**Cache write** 和 **Reasoning** 费率。 6. 保存覆盖项。 缓存或推理费率为 `0` 表示没有设置独立费率:缓存 Token 回退到提示词费率,推理 Token 回退到补全费率。 ## 为按音频时长计费的模型定价[​](#为按音频时长计费的模型定价 "为按音频时长计费的模型定价的直接链接") 部分语音转文本模型按音频分钟计费,而不是按 Token 计费,并且不会上报 Token 数。此类请求会改为记录音频时长,并使用 **Audio per minute** 费率将时长换算为支出。如果此费率保持为 `0`,模型不会产生基于时长的成本。 当前 AISIX 定价目录不提供时长费率,因此没有可继承的默认值:请使用与模型配置完全一致的服务提供方和模型名称创建定价行。例如,OpenAI 目前列出的 [`whisper-1`](https://developers.openai.com/api/docs/models/whisper-1) 价格为每分钟 `$0.006`。按此费率,60 秒的转录成本为 `$0.006`。 警告 Token 成本和时长成本会相加。如果事件同时包含 Token 用量和音频时长,并且匹配价格中的两类费率均不为零,AISIX 会将两项成本相加。请只配置服务提供方实际采用的计费依据。 ## 验证覆盖项[​](#验证覆盖项 "验证覆盖项的直接链接") 最直接的验证方式是向匹配模型发送一个新请求,然后在 **Request Logs** 中展开事件。对于按 Token 计费的模型,应产生足够的 Token 用量,以显示可见成本。对于按时长计费的模型,应使用时长已知或足够长的音频样本。确认事件显示的模型和事件成本符合预期。Request Logs 当前不显示测得的音频时长,因此请根据样本时长计算预期的时长成本。 如果验证的是路由或合议请求,请找到共享同一请求 ID 的事件或尝试行,将成本相加后再与预期值比较。 Request Logs 显示六位小数。如果预期成本会四舍五入为 `$0.000000`,请增加 Token 用量,使成本在该精度下可见。 产生足够流量后,也可以在 **Usage** 中确认聚合支出。Usage 只显示两位小数和前 10 个模型,因此不适合验证单个低成本请求。 保存覆盖项后,历史记录不会变化。应比较修改后创建的新事件,不要期待先前的 `$0.00` 事件被重新计算。 ## 编辑或重置价格[​](#编辑或重置价格 "编辑或重置价格的直接链接") 编辑定价行可更改后续事件使用的费率。**Reset to catalog default** 会删除组织覆盖价格。如果存在目录价格,则该价格会从下一个用量事件开始重新生效。 手动创建的时长定价行通常没有目录默认值。重置该行会移除其有效价格,因此之后匹配的事件会记录 `$0.00`,直到再次配置覆盖价格。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md),了解如何强制执行支出限制,然后配置[预算告警与通知](https://docs.apiseven.com/ai-gateway/traffic-controls/budget-alerts.md)。使用[日志与审计](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md)调查单个请求的结果。 --- # 离线韧性 临时失去控制面连接时,实时流量路径与管理工作流的行为会有所不同。运行中的 AISIX 网关可以在重新连接期间继续使用最近一次接受的配置提供服务,但无法接收新资源,部分 AISIX Cloud 服务也仍然依赖连接。 离线韧性保护的是依赖网关现有配置的流量。它并不意味着控制面可有可无,也无法让自身发生故障的外部上游恢复可用。 ## 继续使用已接受的配置[​](#continue-serving-accepted-configuration "继续使用已接受的配置的直接链接") 网关应用有效的投射配置后,会将该快照保存在内存中,并在配置连接不可用时继续使用它提供服务。AISIX 不会仅因未收到更新的配置事件就让网关退出流量服务。应将配置新鲜度用于运维告警,而不是用作负载均衡器的健康判定条件。 连接恢复前,资源变更不会到达网关。控制面在中断期间接受的变更会等待投射,不会影响正在提供服务的快照。 ## 从缓存配置重启[​](#restart-from-cached-configuration "从缓存配置重启的直接链接") 在托管模式下,AISIX 每次成功应用配置后,都会将最近一次接受的快照缓存到磁盘。默认路径为 `/var/lib/aisix/config_cache.json`;将 `managed.snapshot_cache_path` 设为空字符串可禁用该缓存。参见 [AISIX Cloud 启动配置](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#aisix-cloud)。 重启后的网关只有在启用缓存且缓存包含有效快照时,才能在重新连接期间提供服务。AISIX 会忽略缺失、不可读、损坏或不兼容的缓存。 没有可用快照时,网关在连接成功并应用有效配置之前没有任何东西可以提供服务,而两个就绪端点对此的表现并不相同。指标/状态监听器上的 `GET /status/ready` 在整个等待期间返回 `503`。`/readyz` 则完全没有响应:承载它的代理监听器在应用第一个配置之前不会绑定,因此针对它的探测得到的是被拒绝的连接,而不是 `503`。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 如果重启后的实例需要恢复快照,请持久化网关状态目录。每个网关实例都应有独立的可写状态目录,不要让多个副本共享同一目录。[`api7/aisix` Helm Chart](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md) 默认使用临时状态,因此替换后的 Pod 必须重新连接并获取配置,才能接收流量。这一点是在套接字层面强制的,而不仅仅在 Service 层面:在第一次应用配置成功之前,该 Pod 没有代理端口。 快照包含未经加密的模型服务提供方凭证和其他敏感配置。请像保护配置存储一样限制缓存目录及其备份的访问权限;Base64 编码不能保护密钥。 ## 依赖连接的工作流[​](#connectivity-dependent-workflows "依赖连接的工作流的直接链接") 网关分别处理以下依赖控制面的工作流: | 工作流 | 断开连接时的行为 | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 资源投射 | 新增和更新的资源不会到达网关,最近一次接受的快照继续提供服务。 | | AISIX Cloud 预算 | AISIX 最多复用上次决策 `AISIX_DP_BUDGET_STALE_MAX_SECONDS` 秒,默认值为 `600`。没有缓存决策时,会拒绝请求。超过该过期窗口后,按上次决策返回的故障模式处理。参见[预算的可用性与缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md#availability-and-caching)。 | | AISIX Cloud 用量遥测 | 失败的批次会被丢弃。AISIX 不会持久化、重试这些批次,也不会在连接恢复后重放它们。实时请求不会为了保留遥测数据而失败或延迟。 | | 外部可观测性导出器 | 网关直接向各个已配置的目标发送数据,因此仅控制面连接中断不会影响导出。导出仍然依赖网关与目标之间的连接。 | | 心跳与证书轮换 | 心跳状态停止更新。证书轮换需要控制面连接;当前证书仍然有效时,网关会继续使用它。 | ## 检测与恢复[​](#detect-and-recover "检测与恢复的直接链接") 正在使用快照提供服务的网关仍处于流量就绪状态。请单独检查管理路径的健康状态: * `GET /status/config` 报告 `source.connected: false`,并保留已应用的版本号和配置哈希。 * `GET /status/ready` 在应用有效配置后仍返回 `200`;重启后没有可用快照时返回 `503`。 * `aisix_config_*` 指标提供连接状态、已应用配置和加载失败信息,可用于告警。 * 心跳停止后,AISIX Cloud 中的网关状态会过期。 完整的状态字段、指标和告警示例参见[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)。指标与状态监听器不提供认证,应仅允许私有网络访问。 恢复时,请恢复网关到 AISIX Cloud 控制面端点的 DNS、网络和 TLS 连接。确认心跳恢复,对比已发布和已应用的版本号,并通过恢复后的网关发送调用方可见的请求。实时请求成功可以确认流量路径恢复,但无法恢复中断期间被丢弃的遥测批次。 ## 下一步[​](#下一步 "下一步的直接链接") 参阅[高可用](https://docs.apiseven.com/ai-gateway/cloud/high-availability.md),了解更全面的故障域设计。参阅[资源投射](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md),验证恢复后的网关是否应用了预期版本。 --- # 组织与环境 组织和环境定义了 AISIX Cloud 控制面的两个主要作用域。组织确定所有权和共享管理边界;环境确定哪些 AISIX 网关会接收投射的配置。 这种划分将账号管理与流量行为分离。成员、账单和模型服务提供方凭证属于组织;模型、调用方 API Key、策略和缓存策略属于承载流量的环境。 对于实时流量,环境通常是最先需要确认的作用域。保存的环境资源只有属于目标 AISIX 网关关联的环境时,才会影响实时流量。 账号作用域**组织** 成员、账单、共享管理和服务提供方凭证。 成员账单服务提供方密钥 环境**开发环境** 模型调用方 API Key策略缓存策略 投射到**开发网关** 环境**生产环境** 模型调用方 API Key策略缓存策略 投射到**生产网关** ## 作用域模型[​](#作用域模型 "作用域模型的直接链接") AISIX Cloud 控制面可以管理多个网关和多组网关资源。组织和环境能清晰表达哪个团队拥有该部署,以及哪个 AISIX 网关接收每个环境级资源。 ## 组织作用域[​](#组织作用域 "组织作用域的直接链接") 组织是 AISIX 控制面中最高层级的所有权边界,也是成员、账单、共享管理和服务提供方凭证的作用域。 组织作用域适合用来理解账号归属和共享管理。当已保存的网关资源没有影响实时流量时,通常不应首先检查组织作用域。 ## 环境作用域[​](#环境作用域 "环境作用域的直接链接") 环境是聚合网关资源并将其投射到关联的一个或多个 AISIX 网关的单位。 环境作用域会把已保存的控制面状态转化为实时网关行为。如果资源属于另一个环境,即使它存在于控制面中,也不会影响你正在测试的网关。 当资源没有按预期影响流量时,请先确认该资源与目标 AISIX 网关属于同一环境。对于模型服务提供方密钥,还需要确认该密钥允许在该环境中使用。 ## 创建或选择环境[​](#创建或选择环境 "创建或选择环境的直接链接") 在控制台中打开 **Environments**。如果你的账号尚未加入组织,控制台会先提示你创建组织。 要创建环境,请选择 **New environment**,输入显示名称,然后选择 **Create environment**。确认页面会显示环境 ID,并提供指向该环境 **Data planes** 视图的链接。模型服务提供方设置示例使用该 ID 作为 `ENV_ID`,请将其复制下来。 要使用现有环境,请从环境列表中将其选中。环境 ID 显示在其显示名称下方。 ## 重命名环境[​](#重命名环境 "重命名环境的直接链接") 在环境列表中选择环境旁边的铅笔图标,输入新名称并保存。名称在组织内唯一,因此与其他环境重名会被拒绝。 环境 ID 不会改变,网关当前承载的任何服务也不会改变。关联的 AISIX 网关通过 ID 识别自己所属的环境,因此重命名只是控制面上的标签变更——运行中的数据面不会重新配置,流量也不会中断。引用 `ENV_ID` 的脚本和设置示例继续有效。 通过环境级角色绑定获得权限的成员无法重命名环境。重命名需要组织级的环境写权限,与创建和删除环境所需的权限相同。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读 [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md),创建模型服务提供方设置示例所使用的组织级凭证。创建 Token 后,请[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)到应接收该配置的环境。 --- # AISIX Cloud AISIX Cloud 是 API7 推出的商业产品,用于跨团队和环境集中管理 AISIX 网关。其管理层与实时 AI 流量路径相互独立,因此组织无需让模型流量经过控制面,即可治理网关集群。 AISIX 网关运行在你的环境中,并连接控制面以接收配置和上报运行信息。实时 AI 流量通过这些网关,而不经过控制面或 API7。 ## 部署选项[​](#部署选项 "部署选项的直接链接") AISIX Cloud 提供 On-Premises 和 Hybrid Cloud 两种部署选项。二者使用相同的资源模型和网关工作流。在这两种选项中,你都通过控制台或 AISIX Cloud Admin API 配置网关资源,并在自己的基础设施中运行 AISIX 网关。两者的区别在于由谁部署和运行控制面服务,以及控制面数据存储在哪里。 * \*\*On-Premises:\*\*由你在自己的基础设施中部署和运行控制面服务,也支持完全离线的内网环境。你可以使用 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)在本地进行试用。 * \*\*Hybrid Cloud:\*\*由 API7 部署和运行控制面服务。Hybrid Cloud 目前不提供公开自助注册;请[联系 API7](https://api7.ai/contact)申请试用或演示。你也可以通过 [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-o7ltvkj4qjnr2) 购买 AISIX Cloud。Marketplace 只改变采购与计费方式,不改变双方的运维职责分工。 ## AISIX Cloud 的工作原理[​](#aisix-cloud-的工作原理 "AISIX Cloud 的工作原理的直接链接") 控制面提供集中式资源管理、证书签发、访问治理、用量与成本控制,以及网关健康状态的可观测性。AISIX 网关作为数据面直接处理应用流量。 ![AISIX Cloud 管理能力,以及通过 AISIX 网关处理的实时 AI 流量](https://static.api7.ai/uploads/2026/07/27/Sa2n147n_aisix-cloud-overview.svg) 每个网关都会主动向控制面发起出站 mTLS 连接,以接收配置更新、上报健康状态和用量,并请求预算决策。临时失去连接时,网关会继续使用最近一次接受的配置提供服务。 对于模型流量,网关会先应用路由、可靠性控制、策略执行和可观测性,再将请求转发到模型 API。网关还可以代理 MCP 和 A2A 流量。 ## 管理 AISIX Cloud[​](#管理-aisix-cloud "管理 AISIX Cloud的直接链接") 控制台是控制面的浏览器界面,可用于管理组织与环境、签发网关证书以及查看用量等交互式任务。 如需自动化,请使用 [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)中记录的操作。该参考是受支持的公共 API 契约;控制台工作流不一定有对应的公共 API 操作。通过任一受支持的界面对网关资源所做的变更都会由控制面存储,并投射到关联了受影响环境的网关。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 继续阅读[组织与环境](https://docs.apiseven.com/ai-gateway/cloud/organizations-and-environments.md),了解 AISIX Cloud 如何划分资源、访问权限和网关的作用域。 --- # Playground Playground 允许你从 AISIX Cloud 控制面测试单目标模型。在通过网关发送应用流量之前,可以使用它确认模型能够访问上游模型服务提供方并返回聊天响应。 ![AISIX Cloud 控制面 Playground 展示成功的模型测试](https://static.api7.ai/uploads/2026/06/23/HssKkly4_cloud-playground.png) ## 在 Playground 中测试模型[​](#在-playground-中测试模型 "在 Playground 中测试模型的直接链接") Playground 请求从控制面发送到上游服务提供方。它适合在 Cloud UI 中验证服务提供方密钥、上游 base URL、模型名称和基础提示词响应。 Playground 会发送 OpenAI 兼容的 Chat Completions 请求。请将它用于单目标模型,并确保该模型的服务提供方密钥指向 OpenAI 兼容的上游 base URL;这也包括通过 OpenAI 兼容端点暴露的 Anthropic 后端模型。 Playground 请求会绕过 AISIX 网关,因此不会记录在 Request Logs、Usage、AISIX 网关指标或外部遥测导出器输出中。在 AISIX Cloud 中配置的预算和限流不会应用到 Playground 请求。每次运行仍会使用模型的服务提供方密钥调用上游模型服务提供方,因此会像普通 API 调用一样消耗服务提供方配额并由服务提供方计费。 AISIX 网关请求会经过应用实际使用的运行时。请通过 AISIX 网关发送流量,以验证调用方 API Key、模型别名、路由规则与故障转移、缓存行为、安全护栏、预算、限流、流式行为、日志、用量上报和指标。当需要验证 Chat Completions 之外的端点族或模型服务提供方专属的协议行为时,也应使用 AISIX 网关流量。 ## 在私有化部署中访问私有网络端点[​](#reach-private-network-endpoints-on-premises "在私有化部署中访问私有网络端点的直接链接") Playground 代理默认拒绝连接私有、内部或 loopback IP 地址。这项服务端请求伪造(SSRF)防护可以避免控制面通过构造的模型端点访问内部网络服务。On-Premises 可能需要访问内部网络中的 LLM 端点,而 Hybrid Cloud 预期使用公共上游端点。被阻止的请求会失败,并返回错误码 `UPSTREAM_PRIVATE_IP_BLOCKED`。 如需允许 Playground 访问私有网络端点,请在控制面 API 服务上设置 `AISIX_PLAYGROUND_ALLOW_PRIVATE_IPS=1` 并重启: * **离线包(Docker Compose):** 在 `.env` 中取消注释 `AISIX_PLAYGROUND_ALLOW_PRIVATE_IPS=1`,然后运行 `docker compose up -d api`。 * **Helm chart:** 设置 `api.playgroundAllowPrivateIPs=true`。 如果模型端点是公开地址,请保留默认配置。该设置只影响 Playground 代理;数据面始终直接访问上游服务提供方,不受此设置影响。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[用量上报](https://docs.apiseven.com/ai-gateway/cloud/usage-reporting.md),了解网关用量、支出和预算相关信号。 --- # 资源投射 AISIX Cloud 会将已保存的资源变更发布到连接该环境的网关。每个网关都会验证新修订版本,并将接受的配置应用于新请求。发布是异步的,因此各网关实例可能会暂时报告不同的修订版本。 控制台或 API 返回成功,只能确认控制面接受了变更。要验证变更已生效,请依次追踪控制面修订版本、网关快照和实时请求。 ## 资源作用域[​](#资源作用域 "资源作用域的直接链接") 资源所有权决定哪些环境会接收资源。资源的挂载、引用或条件进一步决定哪些请求会使用它。 | 资源类别 | 所有权与投射 | 请求作用域 | | --------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 模型和调用方 API Key | 属于一个环境,投射到连接该环境的所有网关。 | 请求的模型和解析出的调用方 API Key 决定适用条目。 | | 模型服务提供方密钥 | 属于组织,仅投射到允许使用它们的环境。 | 模型引用模型服务提供方密钥;透传路由注入上游凭证时也会引用它。 | | MCP 服务器和基于 OpenAPI 的服务器 | 属于组织。已批准的服务器仅投射到允许使用它们的环境;基于 OpenAPI 的服务器是 `type: openapi` 的 MCP 服务器。 | 调用方工具授权和适用的安全护栏挂载控制访问与检查。 | | A2A Agent | 属于组织,仅投射到允许使用它们的环境。 | 调用方 API Key 必须具有该 Agent 的访问权限。 | | 安全护栏及其挂载 | 属于一个环境,一起投射。未挂载的安全护栏不会执行。 | 挂载将安全护栏的作用域限定为环境、模型、调用方 API Key、团队、MCP 服务器或透传路由。 | | 缓存策略 | 属于一个环境,投射到该环境的网关。 | 策略可以覆盖整个环境、某个模型别名或某个调用方 API Key。 | | 限流策略 | 属于一个环境,投射到该环境的网关。 | 条件可以按团队、成员、调用方 API Key、模型、模型名称或服务提供方选择流量。 | | OIDC 提供方与声明映射 | 属于一个环境,投射到该环境的网关。 | 对 JWT 调用方进行认证,并将符合条件的声明解析为调用方 API Key。 | | 透传路由 | 属于一个环境,投射到该环境的网关。 | 路由匹配和调用方 API Key 的路由授权决定访问权限。 | | 可观测性导出器 | 属于一个环境,投射到该环境的网关。 | 每个已启用的导出器会根据自身类型和内容设置接收符合条件的网关遥测数据。 | | MCP 环境访问与认证设置 | 属于一个环境,投射到该环境的网关。 | 环境策略定义默认的工具访问层。认证设置定义 `/mcp` 的 API Key、OAuth 或匿名访问行为。 | | MCP 团队访问策略 | 通过团队归属于组织,投射到该组织的所有环境。 | 团队策略适用于绑定该团队的调用方 API Key,并与环境级和密钥级访问层取交集。 | | 预算 | 保留在 AISIX Cloud 控制面中,不进入投射快照。 | 网关为解析出的调用方 API Key 请求预算决策,并可在中断期间临时使用缓存决策。参见[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md#availability-and-caching)。 | 修改组织级资源允许使用的环境,会从相应快照中添加或移除该资源。写入成功只能确认控制面接受了资源及其目标环境,不能确认所有网关都已接收。 ## 验证投射的变更[​](#验证投射的变更 "验证投射的变更的直接链接") 按顺序检查控制面、网关和实时请求。 ### 1. 比较已发布和已应用的修订版本[​](#1-比较已发布和已应用的修订版本 "1. 比较已发布和已应用的修订版本的直接链接") 设置控制面 API URL、具有 `read` 权限范围的 Admin Token 和环境 ID: ``` # AISIX_CP 包含 /api,末尾不带斜杠 # 本地 On-Premises 快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 比较 `store_revision` 与各节点的 `applied_revision`: ``` curl -sS "${AISIX_CP}/environments/${ENV_ID}/dp_nodes" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ | jq '{ store_revision, nodes: [ .data[] | { hostname, last_heartbeat_at, applied_revision, config_hash } ] }' ``` 当节点的 `applied_revision` 大于或等于 `store_revision` 时,该节点即为最新状态。`config_hash` 相同表示各网关实例接受了相同的配置。 可选的修订版本字段 当修订跟踪不可用,或网关尚未上报相关字段时,控制面可能会省略 `store_revision`、`applied_revision` 或 `config_hash`。此时,请使用下一步中的网关状态端点。心跳按周期上报,因此网关的直接状态也可能比控制面视图更新。 如果网关没有最新心跳,请先排查其管理连接,再检查资源投射。请参阅[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 ### 2. 检查网关快照[​](#2-检查网关快照 "2. 检查网关快照的直接链接") 查询正在处理流量的网关实例上的指标和状态监听器: ``` # AISIX_STATUS_URL 是指标与状态监听器的源地址,不含末尾斜杠或端点路径 # 开源快速入门使用 http://127.0.0.1:9090 export AISIX_STATUS_URL="YOUR_AISIX_STATUS_LISTENER_URL" curl -sS "${AISIX_STATUS_URL}/status/config" \ | jq '{ state, source, applied, rejected, last_failure }' ``` 当 `state` 为 `synced`、`source.connected` 为 `true`、`applied.applied_revision` 反映预期修订版本且 `rejected` 为空时,变更即已完全应用。 如果 `source.connected` 为 `false`,请恢复配置连接。中断期间,网关可以继续使用最近一次接受的快照提供服务,但无法接收新变更。请参阅[离线韧性](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md)。 如果 `state` 为 `degraded` 或 `out_of_sync`,请使用 `rejected` 和 `last_failure` 识别无效资源。有关状态定义、完整响应和 Prometheus 指标,请参阅[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)。 将状态监听器保持在私有网络中 状态监听器不需要身份认证。请确保端口 `9090` 仅对监控网络开放。 ### 3. 验证调用方可见行为[​](#3-验证调用方可见行为 "3. 验证调用方可见行为的直接链接") 网关应用变更后,请通过应用实际使用的同一个网关端点和调用方身份进行验证。 对于模型或调用方访问权限变更,先查询模型发现端点: ``` # AISIX_PROXY 是网关源地址,不含末尾斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" curl -sS "${AISIX_PROXY}/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ | jq -r '.data[].id' ``` 确认预期的模型别名已出现,然后按照相应模型服务提供方或功能指南发送请求。 如果修订版本匹配后结果仍不符合预期,请先确认请求到达了所检查的网关,再检查环境、模型别名、调用方 API Key、模型服务提供方密钥的环境访问权限和策略作用域。 ## 下一步[​](#下一步 "下一步的直接链接") 如果尚未发送实时流量,请[选择模型服务提供方上游](https://docs.apiseven.com/ai-gateway/providers/overview.md),并按照相应的设置指南操作。在将多个网关实例置于生产负载均衡器之前,请阅读[高可用](https://docs.apiseven.com/ai-gateway/cloud/high-availability.md)。 --- # SCIM 目录同步 SCIM 目录同步可以把 AISIX 组织连接到你的身份提供方(IdP),由目录创建、更新和停用成员账号。AISIX 实现 SCIM 2.0 协议(RFC 7643/7644),Okta、Microsoft Entra ID 以及其他企业身份提供方都原生支持该协议。 目录同步适用于需要把网关用量归因到大量人员的组织,包括数百或数千名成员,同时不要求每个成员都登录控制台。 通过这种方式预配的成员,与可[直接创建](https://docs.apiseven.com/ai-gateway/cloud/members.md#create-a-member-directly)的无登录成员相同:他们可以拥有 API Key、携带限流和预算,并出现在用量报表中。他们不能登录控制台。 当某个人在 IdP 中被停用或移除时,AISIX 会停用该成员,并禁用该成员拥有的所有 API Key。该变更会传播到网关数据面,因此这些凭证会在网关本身停止工作,而不只是无法在控制台中使用。 ## 启用目录同步[​](#启用目录同步 "启用目录同步的直接链接") 1. 打开 **Settings**,找到 **Directory sync (SCIM)** 卡片。 2. 开启 **Enable SCIM provisioning**(仅组织 Admin 和 Owner 可操作)。 3. 复制卡片中显示的 **SCIM base URL**,例如: ``` https:///scim/v2 ``` 4. 选择 **Generate SCIM token**(仅组织 Owner 可操作),并在离开页面前复制明文值。该值只会显示一次。 如果要从 shell 测试 SCIM 端点,请导出这些值: ``` export AISIX_SCIM_BASE_URL="https:///scim/v2" export AISIX_SCIM_TOKEN="YOUR_SCIM_TOKEN" ``` 在 IdP 的 SCIM 连接器中配置同一个 base URL,并把该 Token 作为 Bearer 凭证。该 Token 是一个具有独占 `scim` 权限范围的 [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md)。它只能调用 SCIM 端点,在所有其他 AISIX Cloud Admin API 路由上都会被拒绝,因此即使 IdP 凭证泄漏,也不能读取或变更网关资源。 如需轮换凭证,请生成新的 SCIM Token,更新 IdP 连接器,然后在 **Admin tokens** 页面吊销旧 Token。 ## 用户如何映射为成员[​](#用户如何映射为成员 "用户如何映射为成员的直接链接") | SCIM 属性 | AISIX 成员字段 | | ----------------------------- | ------------------------------------------ | | `userName` / `emails[].value` | 邮箱地址(身份标识) | | `displayName` 或 `name` | 显示名称 | | `externalId` | 稳定的 IdP 标识符,在组织内唯一 | | `active` | `false` 会停用成员并禁用其 API Key | | `groups` | 团队成员关系(只读,通过 Groups 端点管理) | 如果要创建的用户邮箱已经属于该组织中的某个成员,AISIX 会返回 `409` 唯一性错误。在控制台中创建的成员仍由控制台管理。它们会出现在 IdP 的列表响应中,但 SCIM 不能修改、停用或删除这些成员。目录同步永远不能修改组织 Owner。 通过 SCIM 删除用户时,AISIX 会先禁用该成员的 API Key,再将成员从所有团队中移除,最后移除成员资格。用量历史会保留用于报表。该邮箱会重新可用,因此后续重新预配会创建一个新的成员。 ### 停用与删除[​](#停用与删除 "停用与删除的直接链接") * `active: false` 会保留成员及其 Key,但这些 Key 会在网关侧被禁用。再次设置 `active: true` 时,只会重新启用目录同步禁用的 Key。由操作人员手动禁用的 Key 会保持禁用状态。 * `DELETE` 会永久移除成员资格。Key 保持禁用,并保留其用量历史。 ## 将组映射到团队和角色[​](#将组映射到团队和角色 "将组映射到团队和角色的直接链接") SCIM 组会同步为 AISIX [团队](https://docs.apiseven.com/ai-gateway/cloud/teams.md):推送一个组会创建同名团队,组成员关系变化会添加或移除团队成员。 **Directory sync (SCIM)** 卡片控制角色映射: * **Default role**:当同步成员不属于任何已映射组时获得的组织角色,可以是 `member`、`admin` 或[自定义角色](https://docs.apiseven.com/ai-gateway/cloud/custom-roles.md)。 * **Group → role mappings**:每个映射将一个目录组的成员分配到一个角色,按组显示名称匹配。任何可分配角色都可以作为目标,包括自定义角色。当成员属于多个已映射组时,`admin` 映射优先;否则使用组名称排序最靠前的映射。 目录同步成员的角色会在每次组变化时重新计算,包括组重命名;映射或默认角色变更时也会重新计算。在控制台中手动修改的角色会在下一次同步时被覆盖,因此应将目录视为同步成员的事实来源。目录同步永远不能分配 `owner` 角色。 ## 使用同步成员进行归因[​](#使用同步成员进行归因 "使用同步成员进行归因的直接链接") 目录同步会创建成员;归因方式与其他成员相同: 1. 创建或更新 API Key,并将其 **owner** 设置为同步成员。 2. 用量和[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)会归因到该成员,同时应用以该成员为作用域的[限流策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md)。 当 IdP 停用该人员时,这些 Key 会在数秒内停止通过网关认证。 ## 支持的端点[​](#支持的端点 "支持的端点的直接链接") SCIM 接口位于 `/scim/v2` 下,并以 `application/scim+json` 响应: | 端点 | 方法 | | ------------------------------------------------------ | ----------------------------------------------------------------------------------- | | `/Users` | `GET`(列表,以及对 `userName`、`emails.value`、`externalId` 的 `eq` 过滤)、`POST` | | `/Users/{id}` | `GET`、`PUT`、`PATCH`、`DELETE` | | `/Groups` | `GET`(列表,以及对 `displayName`、`externalId` 的 `eq` 过滤)、`POST` | | `/Groups/{id}` | `GET`、`PUT`、`PATCH`、`DELETE` | | `/ServiceProviderConfig`、`/ResourceTypes`、`/Schemas` | `GET` | `PATCH` 遵循 SCIM PatchOp 结构,包括 Okta 和 Microsoft Entra ID 会发送的路径形式(`active`、`members[value eq "..."]`,以及不带 `path` 的操作)。列表响应使用 `startIndex` 和 `count` 分页(每页最多 200 条)。没有 AISIX 映射的属性(例如电话号码或地址)会被接受并忽略,因此不需要精简 IdP 属性映射。 示例:使用 `curl` 预配用户: ``` curl -sS "${AISIX_SCIM_BASE_URL}/Users" \ -H "Authorization: Bearer ${AISIX_SCIM_TOKEN}" \ -H "Content-Type: application/scim+json" \ -d '{ "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "userName": "dev@example.com", "displayName": "Developer One", "emails": [ { "value": "dev@example.com", "primary": true } ] }' ``` ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md),将网关接入环境。之后如需调查目录驱动的变更,请使用[日志与审计](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md)。 --- # 团队 团队将组织成员归组,用于责任归属、流量归因和共享治理。预算、限流策略和 MCP 访问策略可以使用团队身份,控制来自已绑定团队的调用方 API Key 的流量。 团队成员关系与调用方 API Key 绑定的用途不同。成员名单用于标识谁属于该团队;只有请求使用的调用方 API Key 显式绑定到该团队时,流量才会计入团队控制。 ## 创建团队[​](#create-a-team "创建团队的直接链接") 1. 打开 **Teams**,选择 **New team**。 2. 输入 **Display name** 和可选的 **Description**。 3. 选择 **Create team**。 团队将显示其成员数量和 **Team ID**。选择团队名称或 **Manage** 可打开团队详情页。 其他指南要求设置 `TEAM_ID` 时,请复制 Team ID。团队详情页 URL 的末尾也包含同一个 UUID。 ``` export TEAM_ID="YOUR_TEAM_ID" ``` ## 添加和管理成员[​](#add-and-manage-members "添加和管理成员的直接链接") 团队成员来自组织成员池。将成员加入团队之前,请先[创建或邀请成员](https://docs.apiseven.com/ai-gateway/cloud/members.md)。 1. 打开团队详情页。 2. 在 **Members** 下选择 **Add member**。 3. 选择 **Org member**,并为其分配团队角色 **Member** 或 **Lead**。 4. 选择 **Add member**。 Member 和 Lead 标签属于团队成员名单,不会取代成员的组织角色。当团队只有一名 Lead 时,需要先将另一名成员提升为 Lead,才能降级或移除唯一的 Lead。 使用成员行中的角色选择器更改其团队角色。选择移除操作可将成员移出团队,但不会移除其组织成员资格。 ## 将调用方 API Key 绑定到团队[​](#bind-caller-api-keys-to-the-team "将调用方 API Key 绑定到团队的直接链接") 仅加入团队不会让流量归因到团队。需要将应使用团队预算、限流或 MCP 访问权限的每个调用方 API Key 绑定到团队: 1. 打开环境,选择 **API keys**。 2. 使用 **New API key** 创建 Key,或编辑已有 Key。 3. 在 **Team** 中选择团队。 4. 可以选择 **Owner**。选择团队后,Owner 列表只包含该团队的成员。 5. 创建 Key 或保存更改。 API Key 所在行会显示其团队绑定。成员出现在团队名单中,并不意味着其个人 Key 的流量会计入该团队。 ## 配置团队控制[​](#configure-team-controls "配置团队控制的直接链接") 团队详情页提供 **Team budget (shared)**、**Per-member budget** 和 **MCP entitlement** 控件。以下指南介绍完整行为: * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)介绍共享团队预算,以及团队中每名成员各自独立的额度。 * [限流策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md)介绍如何匹配团队,并将其配额拆分为按成员计数的配额桶。 * [MCP 访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md#grant-a-team-policy)介绍如何配置团队绑定 Key 可达的 MCP 工具。 请使用控制台创建、编辑和删除团队,以及管理团队成员。公共 AISIX Cloud Admin API 支持团队权益,但其公共契约目前不包含团队生命周期和成员管理操作。 ## 从身份提供方同步团队[​](#sync-teams-from-an-identity-provider "从身份提供方同步团队的直接链接") [SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)会将身份提供方中的组表示为同名团队。组成员关系变化会自动更新团队名单。请在身份提供方中管理目录同步团队的名单,避免后续同步覆盖控制台中的更改。 目录同步团队可以与控制台中创建的团队一样,使用调用方 API Key 绑定、预算、限流策略和 MCP 权益。 ## 编辑或删除团队[​](#edit-or-delete-a-team "编辑或删除团队的直接链接") 打开团队详情页,选择 **Edit** 可更改显示名称或描述。选择 **Delete** 可删除团队及其成员名单。名单中的人员仍然是组织成员。 ## 下一步[​](#next-steps "下一步的直接链接") 继续阅读[调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md),创建绑定到团队的凭证。然后为团队配置[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)、[限流策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md)或 [MCP 访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)。 --- # 用量上报 使用 **Usage** 视图比较各 AISIX 网关环境和模型的请求量、Token 消耗与支出。该视图还汇总组织范围内的语义缓存节省量,可用于调查异常支出或确认用量记录已到达控制面。 ## 用量如何上报[​](#how-usage-is-reported "用量如何上报的直接链接") AISIX 网关在你的运行环境中承载 AI 流量,并将用量事件上报到控制面。它会根据控制面 URL 推导遥测端点,并将用量数据发送到固定的 `/dp/telemetry` 路径。运维人员无需为控制面用量上报单独配置目标。 每个事件可以包含请求状态、延迟、Token 用量和成本。事件还会区分调用方请求的模型别名与实际处理某次尝试的解析模型,这有助于理解路由流量和合议模型流量。流式聊天请求也可以上报首 Token 时间。 当模型服务提供方上报非零 Token 数时,AISIX 会采用该数据。对于流式请求,AISIX 还会要求 OpenAI 兼容上游在最后一个流式数据块中包含用量数据。 Chat Completions、Completions、Messages、Responses 和 Embeddings 端点返回的响应可能会省略部分或全部用量数据。例如,OpenAI 兼容中继从不上报用量、客户端在流式传输中途断开,或上游在返回部分响应后发生错误。此时,AISIX 会使用本地分词器估算缺失或为零的 Token 字段。输入 Token 按发送给上游的请求估算,输出 Token 按传递给调用方的内容估算,同时保留模型服务提供方上报的非零值。 AISIX 会使用估算值发送用量事件,因此请求仍会计入遥测、支出、预算和 Token 限流统计。本地计算的事件会标记为估算值,[请求日志](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md#request-logs)视图会在对应行显示 `estimated` 标记。估算值与 OpenAI 系列模型高度接近;对于使用专有分词器的模型,该值为近似值。估算不会改变返回给调用方的模型服务提供方响应,也不适用于其他端点类型或透传路由。 ## 解读用量[​](#解读用量 "解读用量的直接链接") Usage 视图按滚动 30 天窗口汇总各环境中的 AISIX 网关流量,所有总计和表格都使用同一时间窗口。 ![AISIX Cloud 控制面 Usage 视图展示支出、请求数、Token 总量和按环境统计的用量](https://static.api7.ai/uploads/2026/06/25/9wPdvgfS_usage-screen.png) | 信号 | 可帮助解释的内容 | | ---------------- | ------------------------------------------------------------------------------------------------- | | 请求数 | 流量规模和需求变化。 | | Token 总量 | 服务提供方上报的输入与输出消耗。 | | 支出 | 将匹配的模型费率应用于 Token 数,以及按时长计费的转录或翻译请求所测得的音频时长,由此计算的成本。 | | 缓存节省 | 语义缓存命中避免的上游输入和输出 Token 消耗。 | | 按环境统计的用量 | 哪个部署环境产生了流量和支出。 | | 热门模型 | 按支出排序的前 10 个环境与调用方请求模型别名组合;缺少请求模型值的旧记录回退到解析后的模型。 | | 热门 API Key | 按支出排序的前 10 个环境与调用方 API Key 组合。 | 在支持[本地 Token 估算](#how-usage-is-reported)的情况下,缺失或为零的 Token 数由网关估算。音频端点不会估算缺失的 Token 数;转录和翻译请求可以改为产生基于时长的支出。支出还需要与事件的 `(provider, model name)` 匹配的价格,并且适用计费依据的费率不为零。Usage 会把支出四舍五入到两位小数,因此即使存在匹配价格,低流量也可能显示 `$0.00`。 使用[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)添加或检查价格,并在[请求日志](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md#request-logs)中以六位小数检查事件或尝试成本。价格变更只影响变更后记录的事件。 ## 用量与预算执行[​](#usage-and-budget-enforcement "用量与预算执行的直接链接") 控制面使用 AISIX 网关用量记录评估预算。每个预算都定义作用范围、支出上限、周期和执行模式。 滚动 30 天的 Usage 窗口与预算所配置的周期彼此独立,因此两者的总额可能覆盖不同时间范围。 当硬停止预算被超出时,AISIX 网关可以对匹配的请求返回 HTTP `429`。仅告警预算会显示预算超支状态,但不会阻断流量。 如果预算拒绝不符合预期,请检查返回的预算作用域、配置上限,以及决定团队或成员预算适用范围的调用方 API Key 绑定。完整执行路径请参见[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)。 ## 排查缺失或异常用量[​](#排查缺失或异常用量 "排查缺失或异常用量的直接链接") 按以下顺序检查上报路径: 1. 确认请求经过连接到预期环境的 AISIX 网关。同一组织中经过其他环境的流量会显示在对应环境下;其他组织中的流量会显示在该组织自己的 Usage 视图中。 2. 确认请求已完成并出现在 Request Logs 中。网关会批量刷新遥测,新完成的请求可能需要几秒才会出现。 3. 确认 AISIX 网关有最新心跳。 4. 确认网关能够访问控制面遥测端点。 5. 如果支出为零或不符合预期,请检查 Model Pricing 是否与模型服务提供方和模型名称精确匹配,再确认适用的 Token 费率或 **Audio per minute** 费率不为零。 在控制面短暂失联期间,实时流量可以继续使用最近投射的配置。失联期间发送失败的遥测批次会被丢弃而不会重试,因此连接恢复后相关记录仍可能缺失;新记录会在连接恢复后继续上报。导出器健康、心跳和新的预算决策也依赖控制面连接。预算检查可暂时复用缓存决策,之后再应用配置的失败模式;详见[可用性与缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md#availability-and-caching)。 ## 下一步[​](#下一步 "下一步的直接链接") 当支出为零或与服务提供方的计费依据不一致时,请继续阅读[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)。如需调查单个请求或控制面资源变更,请参阅[日志与审计](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md)。 --- # 配置传播 AISIX 将配置更新与代理请求处理分离。无论动态资源来自哪里,每个网关都使用其最新应用的快照处理请求。 因此,资源更新已接受与代理已就绪并不是同一个状态。请通过应用使用的同一条调用方路径验证重要变更。 ## 更新如何到达网关[​](#更新如何到达网关 "更新如何到达网关的直接链接") 更新触发方式取决于所配置的资源来源: | 资源来源 | 更新如何到达 AISIX | | ---------------------------- | ------------------------------------------------------ | | 声明式 `resources.yaml` 文件 | 网关在启动时加载该文件,并在收到 `SIGHUP` 后重新读取。 | | etcd | 网关监听所配置键空间中的资源变更。 | | AISIX Cloud | 控制面将环境资源投射到已连接的网关。 | 每种来源都进入相同的快照应用路径: AISIX 在成功应用配置后,以原子方式替换已加载配置。新请求使用当前快照;替换之前开始的请求可以继续使用先前的快照。 无效更新不会悄然替换有效快照。根据资源来源和故障类型,AISIX 会应用已接受的子集并报告被拒绝的资源,或继续使用最后已知的有效配置。 ## 重新加载资源文件[​](#reload-a-resources-file "重新加载资源文件的直接链接") 开源 AISIX 网关不会监视 `resources.yaml` 的变更。发送 `SIGHUP` 前,请先验证编辑后的文件,再确认网关已应用新快照。 从挂载到正在运行的网关中的完整资源文件开始。将新增或替换内容合并到该文件中,保留无关条目和集合,并验证组装后的结果。AISIX 不会把较小的文件与当前活动快照合并;成功重新加载后,省略的资源将不再处于活动状态。 以下命令使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md#update-and-reload-the-configuration)中的容器名称和资源路径。如果网关使用其他容器名称或路径,请相应调整。 编辑挂载到正在运行的容器中的资源文件。快速入门提供了一个完整示例:添加第二个模型,并授予现有调用方 API Key 对该模型的访问权限。 ### 添加新的环境变量[​](#add-new-environment-variables "添加新的环境变量的直接链接") 正在运行的容器无法继承之后才在主机上导出的环境变量。如果编辑后的资源文件引入了新的 `${VAR}` 引用,请先在短生命周期容器中使用所有必需变量验证该文件: ``` docker run --rm \ -v "$(pwd):/etc/aisix:ro" \ -e OPENAI_API_KEY \ -e CALLER_API_KEY \ -e PROVIDER_VARIABLE_1 \ -e PROVIDER_VARIABLE_2 \ --entrypoint /usr/local/bin/aisix \ ghcr.io/api7/aisix:1.2.0 \ validate --resources /etc/aisix/resources.yaml ``` 请将服务提供方变量名替换为资源文件实际使用的名称。如果服务提供方只需要一个凭证变量,请从两条命令中删除 `-e PROVIDER_VARIABLE_2`。如果当前 shell 中没有 `OPENAI_API_KEY` 和 `CALLER_API_KEY`,请先重新导出它们。 验证成功后,使用相同的变量重新创建快速入门容器: ``` docker rm -f aisix-quickstart docker run -d --name aisix-quickstart \ -v "$(pwd):/etc/aisix:ro" \ -e OPENAI_API_KEY \ -e CALLER_API_KEY \ -e PROVIDER_VARIABLE_1 \ -e PROVIDER_VARIABLE_2 \ -p 3000:3000 -p 9090:9090 \ ghcr.io/api7/aisix:1.2.0 ``` 挂载的工作目录会在旧容器删除后保留 `resources.yaml`。替换后的容器会在启动时加载已验证的文件,因此无需发送 `SIGHUP`,可直接继续[确认已应用的配置](#confirm-the-applied-configuration)。 ### 使用现有环境变量重新加载[​](#reload-with-existing-environment-variables "使用现有环境变量重新加载的直接链接") 如果编辑后的文件没有引入新的环境变量,请在正在运行的容器中验证它: ``` docker exec aisix-quickstart \ /usr/local/bin/aisix validate --resources /etc/aisix/resources.yaml ``` 此命令会复用正在运行的容器及其环境。验证过程与启动和重新加载使用相同的文件加载流水线,包括环境变量插值、名称引用解析和 schema 验证。无效文件会以非零状态退出并输出完整错误报告。 验证成功时会报告文件已加载,并显示其中的资源数量: ``` OK: /etc/aisix/resources.yaml loaded resource(s) ``` 发送 `SIGHUP` 重新加载文件: ``` docker kill --signal=HUP aisix-quickstart ``` ### 确认已应用的配置[​](#confirm-the-applied-configuration "确认已应用的配置的直接链接") 确认新配置已应用: ``` curl -sS "http://127.0.0.1:9090/status/config" ``` 成功应用时会报告 `"state": "synced"`,且资源计数应反映本次编辑。通过 `SIGHUP` 重新加载后,`apply_seq` 应大于此前的值。如果重新加载失败,网关会继续使用最后一个有效配置提供服务,同时报告 `out_of_sync` 并标识被拒绝的条目。 ## 按顺序应用相关资源[​](#apply-related-resources-in-order "按顺序应用相关资源的直接链接") 动态资源之间可能存在依赖关系。模型可以引用模型服务提供方密钥,调用方 API Key 可以允许使用该模型。当资源来源逐个交付资源时,在包含多个资源的变更期间,一个已接受的资源可能先于另一个资源可见。 请按依赖顺序应用相关资源: 1. 创建或更新模型服务提供方密钥。 2. 创建或更新引用该密钥的模型。 3. 创建或更新可以使用该模型的调用方 API Key。 4. 验证最终的模型和请求路径。 此顺序可减少临时引用失败,但最终的调用方路径检查仍是整个变更的就绪信号。 ## 验证配置变更[​](#验证配置变更 "验证配置变更的直接链接") 对于模型访问权限变更,请使用应用将使用的同一个调用方 API Key 查询模型发现端点: ``` AISIX_API_KEY="YOUR_CALLER_API_KEY" curl -sS "http://127.0.0.1:3000/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ | jq -r '.data[].id' ``` 自动化流程需要等待变更时,请轮询预期的模型别名,不要固定休眠一段时间。别名出现后,通过行为发生变更的确切端点和模型发送请求。 调用方路径探测不仅能确认配置已被接受,还能验证为应用提供服务的网关已加载资源关系,并能解析调用方的访问权限。 ## 检查延迟的变更[​](#检查延迟的变更 "检查延迟的变更的直接链接") 如果预期行为没有出现,请检查受影响网关的配置状态: ``` curl -sS "http://127.0.0.1:9090/status/config" ``` 使用结果定位延迟: * `source` 显示最新观察到的配置;适用时还会显示存储连接状态。 * `applied` 显示 AISIX 当前提供服务的快照。 * `rejected` 标识验证失败的资源。 * `last_failure` 记录最近一次加载错误。 `degraded` 状态表示 AISIX 正在使用已接受的子集,同时报告被拒绝的资源。`out_of_sync` 状态表示最新观察结果被整体拒绝;如果存在最后一个有效配置,AISIX 会继续使用它。 有关完整响应 schema、状态含义、指标和告警,请参阅[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)。 ## 区分传播问题与请求失败[​](#区分传播问题与请求失败 "区分传播问题与请求失败的直接链接") 根据故障发生的位置排查,避免重复提交已经传播的更新: * 如果 `/status/config` 报告资源被拒绝,请修正被拒绝的资源或源文件。 * 如果预期 etcd 变更期间来源修订版本没有前进,请检查存储连接和监听的前缀。 * 如果 `GET /v1/models` 中缺少模型,请检查其别名、类型、调用方访问权限、环境和已应用快照。 * 如果模型已经出现,但模型服务提供方请求失败,请排查该提供方的凭证、端点、配额或网络路径。 * 如果某个网关与其他网关不同,请比较各实例的资源来源和已应用快照。 重复同一写入无法修复收不到配置的网关。再次更改资源前,请先确定故障发生在资源来源、应用步骤、资源关系还是请求路径。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[健康检查](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md),为进程、流量、配置和模型健康选择合适的探针。 --- # IDE AI 流量正向代理 组织可以将 AISIX 部署在终止 TLS 的出口设备之后,以治理必须继续使用官方服务端点的 IDE 和编码 Agent 流量。本指南以 GitHub Copilot IDE 扩展和 Copilot CLI 为例。AISIX 从该设备接收明文 HTTP 流量,在使用员工凭证将各请求转发到官方上游之前,可以执行访问控制、审计、内容检查和请求限制。 AISIX 不会拦截 TLS,也不会签发证书颁发机构证书。客户端继续使用官方服务端点。流量可以通过显式代理配置或透明拦截到达出口设备;当该设备终止 TLS 时,客户端必须信任该设备的证书颁发机构。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 请准备以下内容: * 一个 AISIX 部署: * 对于 AISIX Cloud,需要一个已关联网关的环境,以及一个具有写入权限范围的管理员 Token。 * 对于开源 AISIX 网关,需要将网关配置为加载声明式资源文件。 * 一个能够保留原始 `Host` 请求头并注入 HTTP 请求头的 TLS 终止出口设备。 * 在客户端计算机上配置代理和证书信任的权限。 * 最新的 [GitHub Copilot 允许列表](https://docs.github.com/en/copilot/reference/copilot-allowlist-reference)和 [Copilot 网络设置](https://docs.github.com/en/copilot/concepts/network-settings)。 * `curl` 和 `jq`。本地验证使用 `pipx` 安装 [mitmproxy](https://mitmproxy.org/)。 ## 流量拓扑[​](#流量拓扑 "流量拓扑的直接链接") 客户端将 HTTPS 流量发送到出口设备。该设备终止 TLS,保留原始 `Host`,注入网关 Key 和员工身份,并将解密后的 HTTP 流量发送到 AISIX。AISIX 移除仅供网关使用的请求头,并通过 HTTPS 使用员工的上游凭证转发请求。 网关接受携带原始 `Host` 的 origin-form 请求,透明重定向和代理链均使用这种形式。当代理链中的上游代理未提供 `Host` 时,网关也可以读取 URI authority 来接受 absolute-form 请求目标。与 `hosts` 匹配的路由会先于网关自身的类型化路由执行,因此 `/v1/messages` 等上游路径会被转发,而不会由网关的 Messages 端点处理。 ## 选择要检查的主机[​](#route-the-copilot-hosts "选择要检查的主机的直接链接") 路由示例在路由的 `hosts` 字段中使用以下值,以检查 Copilot 推理、代码建议和选定的 GitHub API 流量: resources.yaml(路由 hosts 字段) ``` hosts: - api.githubcopilot.com - "*.individual.githubcopilot.com" - "*.business.githubcopilot.com" - "*.enterprise.githubcopilot.com" - copilot-proxy.githubusercontent.com - origin-tracker.githubusercontent.com - api.github.com ``` 这并不是完整的 Copilot 网络允许列表。身份认证、资产、遥测、实验和编辑器特定服务可能会使用其他主机。请对照 GitHub 最新的允许列表检查出口策略,再决定设备将哪些主机发送到 AISIX,以及允许哪些主机直接访问。 `api.github.com` 由 Copilot 和其他 GitHub 客户端共享。如果设备分流该主机,所有使用此代理的客户端对该主机发出的请求都可能匹配此路由。如果只有选定的 GitHub API 路径需要经过 AISIX,请从路由中移除该主机,或在设备上缩小分流范围。 ## 配置 Copilot 路由[​](#配置-copilot-路由 "配置 Copilot 路由的直接链接") 该路由使用 `preserve_host`,以便通过一个允许列表转发多个官方主机。`header_key` 使用设备注入的网关凭证,而 `forward_client` 则保留员工的上游 `Authorization`,供 GitHub 使用。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 创建路由: ``` ROUTE_RESPONSE=$(curl --fail-with-body -sS -X POST \ "$AISIX_CP/environments/$ENV_ID/passthrough_routes" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "copilot", "hosts": [ "api.githubcopilot.com", "*.individual.githubcopilot.com", "*.business.githubcopilot.com", "*.enterprise.githubcopilot.com", "copilot-proxy.githubusercontent.com", "origin-tracker.githubusercontent.com", "api.github.com" ], "preserve_host": true, "auth_mode": "header_key", "auth_header_name": "x-aisix-api-key", "credential_mode": "forward_client", "identity_header": "x-aisix-user" }') export ROUTE_ID=$(printf '%s' "$ROUTE_RESPONSE" | jq -er '.passthrough_route.id') printf '%s' "$ROUTE_RESPONSE" | jq '.warnings // []' ``` 如果计划专门为此路由关联安全护栏,请保留 `ROUTE_ID`。 为出口设备创建专用调用方 Key。其明文只会返回一次: ``` CALLER_RESPONSE=$(curl --fail-with-body -sS -X POST \ "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "Copilot egress device", "allowed_models": [], "allowed_routes": ["copilot"] }') export EGRESS_DEVICE_KEY=$(printf '%s' "$CALLER_RESPONSE" | jq -er '.plaintext') printf '%s' "$CALLER_RESPONSE" | jq '.warnings // []' ``` 也可以在控制台中完成相同的操作,入口分别位于环境的 **Passthrough Routes** 页面和调用方 Key 的 **Passthrough route access** 部分。上线前请检查返回的所有兼容性警告。警告仅供参考,因此请通过每个网关验证流量。关联路由范围的安全护栏时,也可能产生相应的警告。 ### 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 选择出口设备要注入的 Key: ``` export EGRESS_DEVICE_KEY="YOUR_GATEWAY_CALLER_KEY" ``` 从网关当前使用的[完整资源文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)开始配置。将路由和调用方 Key 添加到对应的集合中,并保持不相关的资源不变: resources.yaml(Copilot 路由和调用方 Key) ``` passthrough_routes: - name: copilot hosts: - api.githubcopilot.com - "*.individual.githubcopilot.com" - "*.business.githubcopilot.com" - "*.enterprise.githubcopilot.com" - copilot-proxy.githubusercontent.com - origin-tracker.githubusercontent.com - api.github.com preserve_host: true auth_mode: header_key auth_header_name: x-aisix-api-key credential_mode: forward_client identity_header: x-aisix-user api_keys: - display_name: egress-device key_env: EGRESS_DEVICE_KEY allowed_models: [] allowed_routes: [copilot] ``` 验证组装后的完整文件: ``` aisix validate --resources resources.yaml ``` 在进程环境中设置 `EGRESS_DEVICE_KEY`,然后启动或重新创建网关。重新加载无法向已运行的进程添加环境变量。 ## 了解身份认证和归属信息[​](#gateway-authentication-options "了解身份认证和归属信息的直接链接") 员工的上游凭证保留在 `Authorization` 中,因此网关凭证需要使用不同的传递方式: * 上文所示的 **`header_key`** 从 `x-aisix-api-key` 读取网关 Key,并在转发前移除该请求头。员工的 `Authorization` 仍可供 GitHub 使用。 * 当设备无法注入网关 Key 时,可以使用 **`anonymous`**。将路由绑定到专用的调用方 Key 主体,并将 `source_cidrs` 限制为 AISIX 为这些请求解析出的地址:通常是设备地址;如果启用了真实客户端 IP 解析,则为原始客户端网段。 在这两种模式中,解析出的调用方 Key 都必须在 `allowed_routes` 中授予 `copilot`。 ### 按员工追踪流量[​](#按员工追踪流量 "按员工追踪流量的直接链接") AISIX 不会验证 `identity_header` 中的值。出口设备必须验证员工身份,移除客户端提供的所有 `x-aisix-user`,并用可信身份覆盖该请求头。AISIX 将受长度限制的值记录为 `client_identity`,并在转发前移除该请求头。 如果没有此请求头,解析出的来源 IP 通常表示出口设备,而不是员工。要恢复原始客户端地址,请只为确切的可信设备网段和转发请求头配置[真实客户端 IP 解析](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md)。对于匿名路由,还需要在 `source_cidrs` 中允许这些解析出的客户端网段。 ## 应用审计、安全护栏和限制[​](#audit-dlp-and-limits "应用审计、安全护栏和限制的直接链接") 该路由本身不拥有限流或预算配置。控制项从已认证的调用方解析,并在支持时从其他关联范围解析。 ### 请求限制[​](#请求限制 "请求限制的直接链接") 调用方 API Key、团队和成员的请求限制会在分发前应用。透传路由没有限流字段或路由策略范围。如果不同主机组需要不同的请求限制或并发限制,请使用不同的调用方 Key。 从可识别协议载荷中提取的 Token 用量会记录在用量事件中,但不会递增 `tpm` 或 `tpd` 计数器。已经耗尽的共享 Token 计数器可以拒绝请求,但透传流量不会推进该计数器。对于 SSE,AISIX 返回流式响应时会释放并发配额,而不是等到数据流结束时才释放。 ### 预算[​](#预算 "预算的直接链接") 在 AISIX Cloud 中,已经应用于解析后调用方的预算会在分发前检查。透传用量目前没有模型 ID,以零成本记录,也不会向预算账本增加支出。开源 AISIX 网关没有本地预算资源。 ### 安全护栏[​](#安全护栏 "安全护栏的直接链接") 在 AISIX Cloud 中,使用 **Passthrough routes** 范围关联安全护栏,可以只检查此路由。环境、调用方 Key 和团队范围的安全护栏也可能应用。 开源资源文件通过 `guardrail_attachments` 集合声明挂载关系,因此文件中定义的安全护栏只有在 Attachment 将其作用域覆盖到此路由时才会检查该路由的流量:可以使用 `scope_type: env` 覆盖整个环境,也可以使用 `scope_type: passthrough_route` 并指定此路由。 请求被拦截时,会在调用上游之前返回 `422`。缓冲响应会在交付前接受检查。SSE 响应开始后,如果触发拦截,数据流会以 SSE `content_filter` 错误帧结束。启用暂缓发送的安全护栏可能会在检查期间延迟数据帧。 ### 内容和用量导出[​](#内容和用量导出 "内容和用量导出的直接链接") 对于成功转发的流量,配置了 `content_mode: full` 的可观测性导出器会以字符串内容接收请求体,而不是接收服务提供方协议载荷的标准化副本。当缓冲响应符合支持的提取格式时,会记录提取出的文本;否则,会将响应体记录为文本。对于流式响应,会记录累积提取出的文本;不透明的数据载荷也会作为文本保留。所有采集仍受已配置的限制约束。 采集的内容只会发送到支持内容的导出器。用量事件包含匹配的路由、调用方、记录的 Token 数量和 `client_identity`。当前 AISIX Cloud 的 Request Logs 界面会显示调用方和 Token 元数据,但不会显示 `passthrough_route_name` 或 `client_identity`。 ## 了解 Copilot CLI 流量[​](#github-copilot-cli-agent "了解 Copilot CLI 流量的直接链接") GitHub Copilot CLI 是一个能够编辑文件、运行 Shell 命令、选择模型并使用其内置 GitHub MCP 服务器的 Agent。其确切的网络端点和协议载荷选择取决于版本,不属于本 AISIX 配置契约的一部分。 AISIX 会识别 `messages`、`input` 和 `prompt` 请求格式,以便为安全护栏提取内容并提取用量信息。其他流量(包括 JSON-RPC 和普通 GitHub API 调用)均视为不透明流量,并在不转换请求体协议的情况下转发。因此,选定的主机路由不需要协议字段。 GitHub 文档将 `/model`、`/mcp`、`/usage` 和 `/context` 列为 CLI 命令,但具体命令是否发送网络流量可能随客户端版本变化。请在实际环境中验证当前客户端行为,不要依赖固定的端点清单。 ## 使用 mitmproxy 验证开源网关[​](#validate-without-the-production-device "使用 mitmproxy 验证开源网关的�直接链接") 以下本地练习使用 mitmproxy 作为终止 TLS 的设备。本地快速入门网关监听 `127.0.0.1:3000`,mitmproxy 监听 `127.0.0.1:8888`。 1. 使用上面配置的 Copilot 路由、调用方 Key 和 `EGRESS_DEVICE_KEY` 启动网关。 2. 安装并验证 mitmproxy: ``` pipx install mitmproxy mitmdump --version ``` 3. 将以下设备脚本保存为 `mitm_to_aisix.py`。该脚本会分流选定的主机,恢复原始 `Host`,注入网关 Key 和用户身份,并保持 SSE 流式传输: mitm\_to\_aisix.py ``` import os from mitmproxy import http AISIX_HOST, AISIX_PORT = "127.0.0.1", 3000 GATEWAY_KEY = os.environ["EGRESS_DEVICE_KEY"] IDENTITY = os.environ.get("AISIX_CLIENT_IDENTITY", "alice@example.com") COPILOT_HOSTS = { "api.githubcopilot.com", "copilot-proxy.githubusercontent.com", "origin-tracker.githubusercontent.com", "api.github.com", } COPILOT_SUFFIXES = ( ".individual.githubcopilot.com", ".business.githubcopilot.com", ".enterprise.githubcopilot.com", ) def _matches_one_label(host: str, suffix: str) -> bool: if not host.endswith(suffix): return False label = host[: -len(suffix)] return bool(label) and "." not in label def _diverted(host: str) -> bool: return host in COPILOT_HOSTS or any( _matches_one_label(host, suffix) for suffix in COPILOT_SUFFIXES ) def request(flow: http.HTTPFlow) -> None: host = flow.request.pretty_host if not _diverted(host): return flow.request.host = AISIX_HOST flow.request.port = AISIX_PORT flow.request.scheme = "http" flow.request.headers["host"] = host flow.request.headers["x-aisix-api-key"] = GATEWAY_KEY flow.request.headers["x-aisix-user"] = IDENTITY def responseheaders(flow: http.HTTPFlow) -> None: if "text/event-stream" in flow.response.headers.get("content-type", ""): flow.response.stream = True ``` 设置 `flow.request.host` 会改写 `Host` 请求头,因此脚本随后会恢复上游主机。如果没有这一行,请求将无法匹配任何主机路由。响应钩子可防止 mitmproxy 将 SSE 缓冲成一个延迟响应。 4. 在环境中设置网关 Key,并启动代理: ``` export AISIX_CLIENT_IDENTITY="alice@example.com" mitmdump -s mitm_to_aisix.py --listen-port 8888 ``` mitmproxy 第一次启动时,会创建后续步骤使用的本地证书颁发机构。 5. 在另一个终端中,使用已获准执行测试请求的凭证,对代理分流、路由匹配以及到 GitHub 的转发进行冒烟测试: ``` curl -x "http://127.0.0.1:8888" \ --cacert ~/.mitmproxy/mitmproxy-ca-cert.pem \ -H "Authorization: Bearer YOUR_GITHUB_TOKEN" \ "https://api.github.com/user" ``` 如果 `401` 中提到 `x-aisix-api-key`,说明设备 Key 未传入。如果返回 `403`,说明该 Key 未被授予 `copilot`。空的 `404` 通常意味着原始主机与路由不匹配。 6. 配置 Copilot 客户端使用 mitmproxy,并信任其证书颁发机构。Copilot 会检查标准代理变量和 `NODE_EXTRA_CA_CERTS`: ``` export HTTPS_PROXY="http://127.0.0.1:8888" export HTTP_PROXY="http://127.0.0.1:8888" export NODE_EXTRA_CA_CERTS="$HOME/.mitmproxy/mitmproxy-ca-cert.pem" copilot ``` 对于编辑器插件,请配置其 HTTP 代理设置,并让编辑器进程使用同一个证书颁发机构。请按照 GitHub 最新的网络设置文档配置实际使用的客户端。 7. 如有需要,请配置 OTLP/HTTP 导出器,发送一个普通请求并检查导出的 Span。确认其中记录了 `aisix.passthrough.route_name: copilot`,并将注入的身份记录为 `aisix.client_identity`。 若要在开源部署中检查 DLP,请声明关键词安全护栏并添加 Attachment:使用 `scope_type: env` 覆盖整个网关,或使用 `scope_type: passthrough_route` 并指定此路由。在 AISIX Cloud 中,也请先以同样方式将安全护栏挂载到此路由,再测试被拦截的提示词。 ## 适用范围和限制[​](#适用范围和限制 "适用范围和限制的直接链接") * 透传路由不会转发 WebSocket 升级请求;请从设备分流规则中排除相应主机或路径。 * `preserve_host` 以 443 端口上的 `https://` 为目标。 * AISIX 不执行 TLS 拦截,也不提供证书颁发机构工具。 * Copilot 主机和客户端行为会独立于 AISIX 发生变化。部署或升级集成时,请重新检查 GitHub 的允许列表和客户端网络文档。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * 查看所有路由字段和错误行为:[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 * 配置内容控制:[安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md)。 * 导出请求和响应内容:[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md)。 --- # 健康检查 AISIX 为进程、流量、配置和模型状态分别提供健康与状态端点。这些端点同时适用于开源 AISIX 网关和连接 AISIX Cloud 的 AISIX 网关。请使用与所监控条件对应的端点。要验证从调用方到模型服务提供方的完整路径,请通过网关发送测试请求。 | 问题 | 端点 | 监听器 | | -------------------------------- | -------------------- | --------- | | 这个实例是否应该被重启? | `GET /livez` | 代理 | | 此实例是否应接收代理流量? | `GET /readyz` | 代理 | | 此实例是否已应用任何有效配置? | `GET /status/ready` | 指标/状态 | | 此实例当前使用什么配置提供服务? | `GET /status/config` | 指标/状态 | | 模型是否可用于路由? | `GET /status/models` | 指标/状态 | 这些端点不需要身份认证。启用 Prometheus 指标时会提供指标/状态端点;默认情况下已启用。请确保该监听器仅对监控和运维系统开放。 ## 代理存活检查[​](#代理存活检查 "代理存活检查的直接链接") 使用 `/livez` 检查进程存活状态: ``` curl -i "http://127.0.0.1:3000/livez" ``` 健康进程返回 `200 OK`,响应体为 `ok`。 正在排空的实例同样返回 `200`。存活检查决定的是要不要**重启**实例,而排空是有意为之的工作:一个已被告知关闭的实例正在处理完它已经接收的请求,重启它恰好会杀掉这些请求。报告排空状态的是 `/readyz`,这样流量会被撤走,而实例不会在自己仍有进行中请求时被替换掉。 手动排查时可以追加 `?verbose=1`。自动化探针不要依赖 verbose 响应体。 存活检查刻意保持较窄范围。它不能证明模型可用,也不能证明模型服务提供方请求能够成功。 它确实意味着网关已经加载了配置,但这只是承载该端点的监听器何时存在所带来的副作用。从 etcd 或 AISIX Cloud 读取资源的网关,在应用第一个配置之前不会绑定代理监听器,因此在那之前 `/livez` 不是返回 `503`,而是根本不会有响应。参见[启动与第一个配置](#startup-and-the-first-configuration)。 ## 流量就绪[​](#traffic-readiness "流量就绪的直接链接") 使用 `/readyz` 判断实例是否应接收流量: ``` curl -i "http://127.0.0.1:3000/readyz" ``` 实例正在排空时,该端点返回 `503 Service Unavailable`。有效配置可用后,只要网关仍能使用该配置提供服务,实例就会保持就绪。 在应用第一个配置之前,`/readyz` 的表现取决于资源来源;对于使用 etcd 或 AISIX Cloud 的网关,得到的并不是 `503`:承载该端点的代理监听器尚未绑定,探针只会得到被拒绝的连接。要观察这一阶段,请使用指标/状态监听器上的 `GET /status/ready`,参见[启动与第一个配置](#startup-and-the-first-configuration)。 控制面或配置存储中断不会仅仅因为最近没有更新就让运行中的网关变为未就绪。来源停滞通常会影响所有实例,将它们全部移出流量会中断流量路径,而不是把流量转移到健康实例。请单独监控配置新鲜度。 排查实例未就绪的原因时可以追加 `?verbose=1`。自动化探针不要依赖 verbose 响应体。 在 Kubernetes 中,请将存活和就绪探针分别指向代理监听器上的 `/livez` 和 `/readyz`,并在同一个监听器上再配置一个 `startupProbe`,使网关仍在连接配置来源期间另外两个探针都不会动作。该探针需要多大的预算,参见[启动与第一个配置](#startup-and-the-first-configuration)。请为网关留出足够的终止时间,以排空进行中的请求和流式请求。 ## 启动与第一个配置[​](#startup-and-the-first-configuration "启动与第一个配置的直接链接") 资源来自 etcd 或 AISIX Cloud 的网关,只有在应用第一个配置之后才会绑定代理监听器。这是无条件的,也没有对应的开关:从未应用过配置的实例没有任何东西可以提供服务,而把「端口可以连上」当作「这个实例已就绪」的流量层会把调用方路由过来,然后看到每个请求都被拒绝。 有两类启动过程不受影响,会立即绑定监听器,因为在设置监听器时它们已经持有配置:使用[资源文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md)的网关会在启动时加载该文件,加载不成功就退出;以及从[磁盘缓存](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md#restart-from-cached-configuration)恢复了可用快照的 etcd 或 AISIX Cloud 网关。 等待期间,各监听器的表现并不相同: | 监听器 | 等待期间的表现 | | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 代理 | 未绑定。`/livez`、`/readyz` 以及所有面向调用方的端点都会拒绝连接。 | | 指标/状态 | 启用 Prometheus 指标时,进程启动即绑定。`GET /status/ready` 返回 `503 Service Unavailable`,响应体为 `no configuration available`;`GET /status/config` 报告状态 `never_loaded`。 | | Admin | 开源网关启用该监听器时,进程启动即绑定。等待期间它自己的 `/livez` 返回 `200`,`/readyz` 返回 `503`。 | 有一种启动过程根本到不了上面这张表,在把拒绝连接的指标端口当成进程已死之前,值得先知道这一点。设置了 `etcd.user` 时,网关会在创建任何监听器之前先去连接 etcd,而 `etcd.dial_timeout_ms` 默认不设置——因此一个完成了 TCP 连接却不作任何应答的端点,会让进程无限期地停在那里,代理、指标/状态和 Admin 三个监听器都还没有打开。它此时会写出的,是下面表中那条 `still connecting to etcd` 告警,每 10 秒一条,并带上它正在等待的端点。设置 `dial_timeout_ms` 会把这次连接变成一次有界的、网关会重试的失败,此后它就会进入这里描述的等待。 因此,观察冷启动要看指标/状态监听器。连接 AISIX Cloud 的网关从不绑定 Admin 监听器,此时 `GET /status/ready` 是唯一会响应的健康端点,也是区分「网关仍在连接配置来源」与「网关根本没有运行」的唯一手段。绑定了 Admin 监听器的开源网关还能用该监听器上的 `/livez` 和 `/readyz`——但只有指标/状态端点能说明这段等待的原因。 代理地址和 `proxy.tls` 证书材料仍会在等待开始之前于启动阶段校验,因此地址不可用或证书文件不可读仍然是启动失败,而不会被推迟到后面某个时刻。 网关不会放弃。在没有应用任何配置期间,它既不会退出,也不会绑定一个降级的监听器,并会在某次读取成功的那一刻绑定监听器。读取**失败**时,它按指数退避重试,退避从 1 秒增长到 60 秒上限。 有一类故障不在等待之列,区别在于 etcd 作出了怎样的响应。根本连不上的 etcd——连接被拒绝、DNS 失败、TLS 失败,或者建立连接超过了 `etcd.dial_timeout_ms`——正是这段等待所针对的情况,而且无论是否设置 `etcd.user`,行为都一样。etcd 在启动那次连接上作出响应并拒绝的凭据则相反。设置了 `etcd.user` 时,网关会在建立连接的过程中完成认证,因此密码不对——或者把凭据发给了一个根本没有开启认证的集群——会当场被拒绝。等待无法把它变成可用的连接,因此网关会报出这次拒绝并退出,而不是起来之后永远空着。etcd 不再接受的 Token 归入前一类而不是这一类,因为网关靠重新认证就能把它治好;参见 [etcd 配置存储](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#etcd-configuration-store)。 比那次连接更晚到达的拒绝不会结束进程,而这恰恰是更值得认出来的一种情况。etcd 的权限是逐次调用校验的,而不是在认证时校验,因此一个密码正确、却没有 `etcd.prefix` 读权限的用户,会在启动时被接受、在配置读取时被拒绝;而一个在 etcd 不可达时启动的网关,即使密码是错的,也会改为在那里才收到拒绝。这两种都不会退出:网关保持运行、代理监听器不绑定,按同样的退避重试,并在每一次尝试时以 `ERROR` 写出 `etcd refused this gateway's credentials — no configuration can be read until they are fixed; still retrying`。这种情况在 `/status/config` 上表现为 `source.connected: false` 且 `state` 为 `never_loaded`,与来源根本连不上时完全一样,因此把两者区分开的正是这条日志。 被接受却始终没有响应的读取既不算成功也不算失败。它默认不受任何超时限制,会一直处于在途状态,退避重试也就永远等不到一次可供重试的失败。设置 [`etcd.request_timeout_ms`](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#etcd-configuration-store) 可以给配置读取加上上限,把这种挂起变成退避会重试的失败。它同样会限制建立配置 watch 的握手。那是这段等待**之后**一步的故障,而不是这段等待的一部分——读取此时已经成功,第一个配置已经应用,监听器也已经绑定——但它是更危险的那一半:etcd 能正常响应读取、却始终不确认 watch 时,网关本会一直提供这第一份快照,对之后的每一次变更都视而不见,而 `/status/config` 仍然报告来源已连接。已经建立起来的 watch 流则有意不受它约束,因为任何这类上限都会在一段安静到没有产生事件的时间里到期,让网关不断重连而不是持续 watch。设置了 `etcd.user` 时在建立连接过程中进行的认证交互,也不再游离于所有超时设置之外:启动阶段由 `etcd.dial_timeout_ms` 覆盖,之后某次调用需要自行建立连接时由 `request_timeout_ms` 覆盖。不过这两个键默认都不设置,因此在默认部署上,在你设置其中之一以前它仍然不受任何约束。设置该项前请先阅读那里的说明,因为一个相对配置规模过短的上限只会把挂起换成一次永远无法完成的读取。无论哪种情况,网关都会把这段等待记录到自己的日志中: | 日志内容 | 级别 | 写出时机 | | -------------------------------------------------------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `waiting for the first configuration before binding the proxy listener` | `INFO` | 等待开始时写出一次。 | | `proxy listener still not bound: no configuration has been applied yet` | `WARN` | 等待期间每 10 秒写出一次。 | | `first configuration applied — binding the proxy listener` | `INFO` | 监听器绑定时写出一次。 | | `still connecting to etcd — nothing waiting on this connection can proceed until it answers` | `WARN` | 与 etcd 的连接尚未完成期间每 10 秒写出一条,带 `endpoints` 和 `waited_secs`。只有设置了 `etcd.user` 时才会出现,因为没有 etcd 凭据的网关要到第一次读取时才会去连接。 | ### 设置 Kubernetes 启动探针的预算[​](#size-a-kubernetes-startup-probe "设置 Kubernetes 启动探针的预算的直接链接") 代理监听器上的 `startupProbe` 会在整个启动过程(包含上述等待)中挡住存活和就绪探针。它的预算是 `periodSeconds x failureThreshold`,需要覆盖的是连接配置来源并应用其中内容的时间,而不仅仅是进程启动的时间。[`api7/aisix` Helm Chart](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md) 为它预设了 300 秒的预算,即 `periodSeconds: 2` 配合 `failureThreshold: 150`。 设置该预算时,两部分都要考虑到。连接来源指的是 DNS、TLS,以及控制面或 etcd 的可用性。应用其中的内容则是另一部分工作,其耗时会随环境所持有的配置规模增长,而这部分耗时并没有被测量过——因此预设的 300 秒是为大规模配置刻意留出的余量,而不是依据某次实测启动调出来的值。探测周期仍然很短,所以普通启动依然能在几秒内通过,这份余量不会拖慢滚动更新;只有异常情况才会真的等下去。 预算在网关自身重试节奏中的落点同样重要。配置读取失败后按退避重试,退避从 1 秒开始翻倍、以 60 秒封顶,因此各次尝试大致落在 t=0、1、3、7、15、31、63 秒,之后每分钟一次。这个阶梯没有尽头,所以没有任何预算能容纳它的全部;预算应当避免的是恰好在某次尝试之前结束,那会白白浪费已经等过的时间。原来的 60 秒正是如此,比 t≈63 秒那次尝试早了三秒——于是在比如 t=40 秒就已恢复的来源,不会等到那次即将执行的重试,实例先被重启了。 配置来源持续不可达、超过该预算的 Pod,其容器会被 kubelet 杀掉并重启,反复重启会表现为 `CrashLoopBackOff`。这是预期结果,而不是需要绕开的故障:该实例从来就没有可以提供服务的内容。重启后的容器会继续同样的等待,并在来源恢复后立即绑定监听器。请通过 `GET /status/ready` 和上面的日志来定位问题,而不是把探针指向其他监听器。 ## 关闭与排空[​](#shutdown-and-draining "关闭与排空的直接链接") 负载均衡器是在下一次健康检查时才知道某个实例正在退出的,而不是实例作出决定的那一刻。在这两个时间点之间,它仍然会把新连接路由过来。如果网关一收到关闭信号就关闭监听器,这段间隔内被路由过来的连接都会被拒绝,调用方在一次普通的滚动更新或缩容中就会看到网关错误。 因此网关把这两件事分开。收到 `SIGTERM` 或 `SIGINT` 时,它会: 1. 立即让 `/readyz` 返回 `503 Service Unavailable`,使下一次健康检查将其移出流量。`/livez` 保持 `200`:进程是健康的,排空期间不应被重启。 2. 继续接受新连接,至少持续 `shutdown.min_drain_secs`,默认为 30 秒。 3. 为每个 HTTP/1.1 响应加上 `Connection: close`,使使用连接池的客户端在用完连接后主动退役,而不是把空闲连接一直留着。HTTP/2 禁止该头部,因此 HTTP/2 客户端改为在排空开始的那一刻收到 `GOAWAY` 帧。`GOAWAY` 要求对端处理完已经开启的流、不要再开新流;它本身不关闭连接,也不会打断任何进行中的请求。 4. 最小窗口结束后,不设自身期限地等待进行中请求数降为零,然后停止接受新连接。 5. 在保留[快照缓存](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md#restart-from-cached-configuration)的 etcd 或 AISIX Cloud 网关上,再最多等待 5 秒,让仍在途中的快照缓存写入落盘,然后退出。 请把 `min_drain_secs` 设置为大于为该实例做负载均衡的组件的发现延迟。Kubernetes 就绪探针需要 `periodSeconds x failureThreshold`;外部负载均衡器则需要它自身的检查间隔乘以重试次数。设置过小会在流量仍在到达时关闭监听器;设置过大只会延迟退出。 config.yaml ``` shutdown: min_drain_secs: 30 ``` 这个窗口是最小值,而不是期限。窗口结束后,网关仍会等待进行中的请求数降为零,因此比配置更慢的负载均衡器无法让它在流量仍在到达时关闭监听器。设为 `0` 会完全取消该窗口,仅当没有任何组件通过健康检查将流量路由到该实例时才适用。 由于等待进行中工作数降为零的过程没有上限,整个流程的实际上限由部署平台决定——Kubernetes 中是 `terminationGracePeriodSeconds`,systemd 下是 `TimeoutStopSec`。请把它设置为大于 `shutdown.min_drain_secs`、最长请求或流式传输时长,以及 5 秒快照缓存排空这三者之和,并留出运维余量。还应加上任何 `preStop` 钩子的持续时间,因为它会消耗同一个 Kubernetes 终止预算。 最后这一项虽小,却不是可有可无的余量,而且它是额外的时间,不会被在途请求的排空吸收:快照缓存排空要等到进行中请求数降为零之后才开始。网关在应用配置之后会在后台写快照缓存,因此一个刚应用完配置就被停止的实例,可能仍有一次写入没有完成。如果它在写入中途被杀掉,重启时用的就是缓存中此前保存的内容,而不是它刚刚应用的那份配置——如果那次写入本身就是第一次,则根本没有缓存可用。由于代理监听器要等到第一个配置被应用才绑定,没有缓存的网关在重新连上配置来源之前不会再打开端口。这 5 秒是对一次本地文件写入的固定兜底,而不是可调的旋钮,也没有对应的配置项。5 秒过后写入仍在途中时,网关会写出一条 `WARN` 并不再等待;这次写入是被放弃等待而不是被取消,而缓存文件的替换是原子的,因此落到磁盘上的一定是最近某一次应用的结果,绝不会是写了一半的内容。 备注 请把外部负载均衡器的健康检查指向 `/readyz`,而不是单纯的 TCP 连接探测。TCP 探测无法观察到就绪状态,它唯一能得到的信号就是监听器关闭——而这正是排空窗口要避免的那个事件。 ### 在日志中观察排空过程[​](#watch-a-drain-in-the-logs "在日志中观察排空过程的直接链接") 排空过程会记录自身的进展,因为一次请求通常留下的记录是在它结束时才写出的——而在平台的宽限期到期时仍在运行的请求根本走不到那一步。这些日志正是你把网关已经接手的工作,与信号之后仍被路由过来的流量区分开的依据: | 日志内容 | 字段 | 写出时机 | | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------ | | `draining — /readyz now reports 503, still accepting new connections` | `min_drain_secs`、`in_flight`、`open_connections` | 收到信号时写出一次。 | | `still draining in-flight requests` | `in_flight`、`open_connections` | 排空期间周期性写出。 | | `request arrived while draining` | `method`、`path`,以及该请求自身的 `request_id`、`peer` 和 `downstream_request_id` | 信号之后每到达一个请求写一条。 | | `accepted a new downstream connection while draining` | `peer`、`open_connections` | 信号之后每接受一条连接写一条。 | 这两个计数回答的是不同的问题,且无法互相推导。`in_flight` 统计正在处理的请求,流式响应只要还可能有字节流出就一直占着自己的名额;`open_connections` 统计代理监听器上处于打开状态的下游连接,包含连接池中没有承载请求、正处于空闲的那些。因此,`in_flight` 一直不降导致排空迟迟不结束,说明网关在处理自己已经接手的工作;`in_flight` 已降为零而 `open_connections` 仍不降,说明客户端握着用不到的连接不放;`open_connections` 还在上升,则说明仍有组件在往这里路由新连接。 那两条逐事件的日志合起来解释了滚动更新期间失败的请求。一条到达日志若能匹配到 `peer` 相同的接受日志,说明连接本身是在网关已经请求被摘除之后才被路由过来的——负载均衡器还没跟上,而这正是 `min_drain_secs` 要吸收的情况。一条到达日志若匹配不到接受日志,说明该连接早于信号存在,是客户端从自己的连接池中复用的,而这正是 `Connection: close` 响应头负责退役的对象。 不过接受日志本身无法区分你的调用方和你的平台。`/livez` 和 `/readyz` 同样由代理监听器提供服务,探针在整个排空期间会持续以各自独立的连接到达,因此它们会抬高 `open_connections`,也会像其他连接一样产生接受日志。作出这项判断的是到达日志:它知道请求路径,并有意排除这两个探针端点,以免为数不多的真实请求被每隔几秒一次的探针淹没。接受日志则用来看到达日志看不到的情况——一条建立了却从未被使用的连接。 `peer` 和 `downstream_request_id` 就是[指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#collect-access-logs)中描述的那组连接标识。把它们与网关前置组件自己的记录相互匹配,就能证明一条网关日志和一条负载均衡器日志说的是同一条连接。 ## 配置状态[​](#配置状态 "配置状态的直接链接") 指标/状态监听器提供两个配置检查。 `GET /status/ready` 是仅检查配置的启动门禁: * 应用第一个有效配置之前返回 `503 Service Unavailable`; * 有效配置可用后返回 `200 OK`;后续更新失败而 AISIX 使用最后已知的有效快照时也会返回 `200 OK`。 对于使用 etcd 或 AISIX Cloud 的网关,应用第一个配置之前应当观察的就是这个端点,因为在那之前代理监听器尚未绑定。参见[启动与第一个配置](#startup-and-the-first-configuration)。 `GET /status/config` 用于说明 AISIX 观察到和应用的内容: ``` curl -sS "http://127.0.0.1:9090/status/config" ``` 当资源更新没有反映到代理行为中时,请使用该端点。比较来源状态与已应用状态,然后检查被拒绝的资源和最近一次加载失败。有关完整响应字段、状态含义、Prometheus 指标和告警示例,请参阅[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)。 配置状态不能替代调用方路径验证。预期快照应用后,请查询 `GET /v1/models`,并发送行为发生变更的请求。请参阅[配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md)。 ## 按模型检查运行时健康状态[​](#按模型检查运行时健康状态 "按模型检查运行时健康状态的直接链接") 当网关已就绪,但路由避开某个模型或报告没有符合条件的目标时,请使用 `GET /status/models`: ``` curl -sS "http://127.0.0.1:9090/status/models" ``` 每个已配置模型会报告以下高层状态之一: * `healthy`:可用于路由; * `cooldown`:在最近的上游失败后暂时移出路由;只有开启了[冷却](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#direct-models)的模型才会进入该状态; * `unhealthy`:后台模型检查失败后被排除; * `not_applicable`:可用性由其目标决定的虚拟模型。 状态视图有助于识别冷却和后台检查失败,但不会验证调用方访问权限或模型服务提供方凭证。即使模型报告为健康,调用方 API Key、模型服务提供方密钥或上游响应仍可能导致请求失败。 有关完整响应字段,请参阅[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md#get-statusmodels)。 ## 组合健康信号[​](#组合健康信号 "组合健康信号的直接链接") 请从最早失败的层级开始排查: | 信号 | 下一项检查 | | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `/livez` 或 `/readyz` 拒绝连接。 | 代理监听器是否已经绑定。对于使用 etcd 或 AISIX Cloud 的网关,在应用第一个配置之前它不会绑定;请检查 `/status/ready` 和配置来源。 | | `/livez` 失败。 | 进程状态、监听器绑定和监听器 TLS | | `/readyz` 失败。 | 排空状态 | | `/status/ready` 失败。 | 初始配置来源和加载错误 | | `/status/config` 为 `degraded` 或 `out_of_sync`。 | 被拒绝的资源、来源连接和 `last_failure` | | `/status/models` 报告 `cooldown` 或 `unhealthy`。 | 模型服务提供方凭证、提供方可用性、模型检查和出站网络 | | 所有健康端点均成功,但请求失败。 | 调用方访问权限、模型服务提供方路径、策略执行和上游响应 | 最后,请使用与应用相同的路径进行检查: ``` AISIX_API_KEY="YOUR_CALLER_API_KEY" curl -sS "http://127.0.0.1:3000/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 然后通过所需的端点和模型发送真实请求。最后这项探测会验证运行时健康端点刻意不检查的条件。 ## 下一步[​](#下一步 "下一步的直接链接") 使用[故障排除](https://docs.apiseven.com/ai-gateway/deployment/troubleshooting.md),将失败的健康检查或请求路径检查进一步定位到配置、调用方策略、AISIX Cloud 投射或上游模型服务提供方。 --- # 网络与安全 AISIX 网关提供彼此独立的代理监听器和指标/状态监听器。根据资源来源,它还可能连接到 etcd 或 AISIX Cloud。请将部署中存在的每个网络暴露面视为独立的信任区域。这些暴露面承载不同的流量、凭证和状态数据,因此需要根据各自角色制定相应的暴露策略。下表列出了本文介绍的监听器和配置暴露面。 ## 网络边界[​](#网络边界 "网络边界的直接链接") 可以参考下表决定每个网络中允许访问哪些内容: | 暴露面 | 承载内容 | 暴露范围 | | ---------------------- | ------------------------------------------------------- | ------------------------ | | 代理监听器 | 面向调用方的 AI 流量,例如 `/v1/chat/completions` | 预期调用方或入口层 | | 指标/状态监听器 | Prometheus 指标以及配置和模型状态 | 可信监控网络 | | 配置存储 | 通过 etcd 配置的开源 AISIX 网关动态资源 | 仅 AISIX 和配置管理系统 | | AISIX Cloud 控制面连接 | AISIX 网关与 AISIX Cloud 控制面之间经过 mTLS 认证的通信 | 到控制面的出站 mTLS 路径 | 只向调用方暴露代理监听器。将指标/状态监听器和 etcd 保留在私有网络中。指标路径和 `/status/*` 路由不需要身份认证,并通过专用指标/状态监听器提供。模型状态包含模型 ID 和显示名称,因此不要将此监听器暴露到公网。 当网络位置要求加密传输或双向认证传输时,请使用 TLS 或 mTLS。启用 etcd mTLS 时,启动配置必须指向网关进程可读取的 CA、客户端证书和客户端密钥文件。 ## 暴露代理监听器[​](#暴露代理监听器 "暴露代理监听器的直接链接") 除非网关必须直接绑定低于 `1024` 的端口,否则请让网关监听非特权容器端口。通过负载均衡器、Ingress 或 Service 发布面向调用方的端口,不要扩大其他监听器的访问范围。 发布的 AISIX 镜像以非 root 用户(UID `10001`)运行。网关二进制文件具有生效的 `CAP_NET_BIND_SERVICE` 文件能力,因此无需以 root 身份运行即可绑定 `80`、`443` 等端口。如果运行时策略不允许授予该能力,容器可能在启动时失败,并报告 `exec: Operation not permitted`。 请在 AISIX 代理监听器上终止 TLS,或在其前方的可信入口层终止 TLS。当其他代理终止或转发流量时,只为确切的可信代理网段和转发请求头配置真实客户端 IP 解析。 如果要通过终止 TLS 的出口链路将 GitHub Copilot 流量发送到 AISIX,同时让客户端继续使用官方服务端点,请参阅 [IDE AI 流量正向代理](https://docs.apiseven.com/ai-gateway/deployment/forward-proxy.md)。 对于运行在 Kubernetes 上并连接 AISIX Cloud 的 AISIX 网关,请参阅[在 Kubernetes 上部署 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md),了解 Service 暴露、容器能力、自动扩缩容和中断处理。 ## 凭证边界[​](#凭证边界 "凭证边界的直接链接") 调用方凭证和上游服务提供方凭证有不同的存储和转发规则: | 凭证或密钥 | AISIX 如何使用 | 需要保护的内容 | | ------------------ | -------------------------------------------- | ------------------------------------------------------ | | 调用方 API Key | 以哈希形式存储;明文由调用应用持有 | 应用 Secret 存储和 API Key 轮换流程 | | OIDC 签发的 JWT | 验证签名和声明,再将身份映射到调用方 API Key | 应用 Token 存储、OIDC 信任提供方策略和身份提供商可用性 | | 模型服务提供方密钥 | 用于认证上游模型服务提供方请求 | 资源文件或配置存储、环境变量和备份 | | 可观测性导出器凭证 | 发送到配置的遥测目标,或由网关为该目标解析 | 动态资源存储和可观测性配置访问权限 | | AISIX Cloud 证书包 | 用于向控制面认证 AISIX 网关 | 运行时状态目录、信任根和控制面引导流程 | 对于开源 AISIX 网关,模型服务提供方凭证可以在资源文件中引用环境变量,也可以存储在配置存储中。OTLP HTTP 导出器请求头可以存储在动态配置里;对象存储、阿里云 SLS 和 Datadog 导出器使用网关在本地解析的凭证引用。 请将资源文件、etcd、环境变量和备份视为携带 Secret 的暴露面。在 AISIX Cloud 部署中,控制面负责处理模型服务提供方密钥,并将运行时配置投射到 AISIX 网关。 AISIX 使用调用方 API Key 或 OIDC 签发的 JWT 认证每个调用方,并使用服务提供方凭证认证上游请求。经过验证的 JWT 会先映射到调用方 API Key,再由 AISIX 应用访问和流量控制。透传默认会剥离敏感入站请求头。服务提供方密钥的剥离设置会影响转发内容,因此除非特定上游集成要求,否则应继续剥离 `authorization`、`cookie` 和 `x-api-key` 等携带凭证的请求头。 ## 安全基线[​](#安全基线 "安全基线的直接链接") 路由生产流量前,请确认以下控制项: * 代理监听器只能被预期调用方或入口访问。 * 指标端点保持私有。 * 当 etcd 存储开源 AISIX 网关资源时,它应保持私有、持久化、有备份且受访问控制。 * 模型服务提供方密钥 Secret 和导出器凭证被视为敏感运维数据。 * OIDC 信任提供方固定预期的签发者和受众,并将其发现端点和 JWKS 端点作为出站信任目标进行审查。 * 当部署要求加密或双向认证传输时,配置监听器 TLS、etcd mTLS 或 AISIX Cloud mTLS。 * 对于连接 AISIX Cloud 的网关,通过基于证书的引导路径验证网关身份。 * 备份和可观测性流水线不会暴露动态资源载荷或模型服务提供方凭证。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读 [TLS 与 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md),为部署中的每条连接配置传输安全。 --- # 性能与容量规划 AISIX 网关运行时是编译型 Rust 代理,因此自身给请求增加的延迟很低。本页给出参考机器上的实测代理延迟和吞吐量,并提供一个按流量估算 CPU 的公式。 这些数据采用与 Kong、LiteLLM 和 TensorZero 公开基准相同的测试模式,便于横向参考。测试中,AISIX 在专用 AWS `c7i.4xlarge` 上固定使用 **4 vCPU**,代理兼容 OpenAI 的 `/v1/chat/completions` 请求,请求包含约 1000 Token 的提示词。上游是接近零延迟的 mock 服务,且未启用流量控制策略。网关使用共享运行时(`proxy.thread_per_core: false`)。因此,报告的延迟基本就是网关自身开销。 ## 实测网关延迟[​](#实测网关延迟 "实测网关延迟的直接链接") 在低到中等负载下,网关自身处理延迟保持在**亚毫秒**级;随着 CPU 使用率升高,延迟也会增长。由于测试上游约 0.07 ms 即返回,下表中的网关延迟可以视为 AISIX 叠加到真实上游调用上的额外开销: | 输入负载 | 吞吐量(req/s) | 网关延迟 p50 / p95 / p99 | | --------------- | --------------- | ------------------------ | | 轻负载(20%) | 5,700 | 0.31 / 0.51 / 0.59 ms | | 中等负载(40%) | 11,300 | 0.52 / 0.89 / 1.04 ms | | 繁忙负载(60%) | 17,000 | 0.82 / 1.37 / 1.69 ms | | 高负载(80%) | 22,600 | 1.12 / 2.14 / 2.54 ms | | 饱和 | 28,300 | — | 也可以通过减去同速率下直连上游的延迟来隔离网关开销。按这种方式计算,轻负载下 p50 开销为 **0.24 ms**,高负载下为 **0.99 ms**。真实 LLM 调用通常需要数百毫秒到数秒,因此端到端看,这部分网关开销可以忽略不计。 ## 吞吐量与 CPU[​](#吞吐量与-cpu "吞吐量与 CPU的直接链接") 在 4 vCPU 上,单个 AISIX 实例可以为该工作负载支撑约 **28,300 req/s**。CPU 使用率几乎随请求速率线性增长: ``` CPU% ≈ 14 + 0.0144 × (req/s) # 每个实例,以单个 vCPU 的百分比计 ``` 这大约等价于每个请求消耗 **0.14 ms 的单核 CPU 时间**,再叠加少量固定运行时成本。该线性拟合适用于测试中的 20-80% 负载区间。 接近饱和时,曲线会受到 4 vCPU 上限影响而变平。28,300 req/s 峰值约消耗 383% CPU,而不是朴素外推得到的约 421%。这也是容量规划应低于饱和点的原因之一。吞吐量可以水平扩展:可以给实例增加 vCPU,也可以在负载均衡器后增加副本。实例如何把 vCPU 转化为吞吐能力取决于其 Worker 池;请参阅[每核一线程 Worker](https://docs.apiseven.com/ai-gateway/deployment/thread-per-core-workers.md)。 ## 流式响应[​](#流式响应 "流式响应的直接链接") 在未启用策略的基准测试中,AISIX 会在上游的服务器发送事件(SSE)Token 到达时立即将其转发给客户端,而不是缓冲完整响应。首 Token 时间的额外开销约为 **0.65 ms**,总流持续时间与上游一致。输出安全护栏则可能按窗口暂存流式内容,或者先完整缓冲响应再释放。请参阅[流式输出](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#streaming-output)。 ## 规划部署规格[​](#规划部署规格 "规划部署规格的直接链接") 对于上述共享运行时基准,可以用以下公式估算单个实例在目标请求速率 `Q`(req/s)下所需的 vCPU: ``` vCPUs ≈ (14 + 0.0144 × Q) / 100 ``` | 目标吞吐量 | vCPU(约) | | ------------- | ---------- | | 5,000 req/s | \~0.9 | | 10,000 req/s | \~1.6 | | 25,000 req/s | \~3.7 | | 50,000 req/s | \~7.3 | | 100,000 req/s | \~14.5 | 请结合以下建议使用该估算结果: * 预留余量。按约 70-80% 饱和度规划,而不是按 100% 饱和度规划,这样突发流量下延迟仍能保持较低水平。 * 通过扩容保障高可用和总吞吐。在负载均衡器后运行多个副本;增加副本时,单实例开销仍保持稳定。 * 考虑流量控制成本。上述数据是纯代理基线。认证、限流、安全护栏、缓存和请求日志都会增加每个请求的处理工作。请在启用实际策略集后重新测量。 * 使用有代表性的请求形态做基准测试。更大的提示词和响应体会增加单请求成本;流式和非流式也不同。确定容量前,请使用有代表性的流量做基准测试。 ## 测试环境[​](#测试环境 "测试环境的直接链接") 参考机器是专用 AWS `c7i.4xlarge`(16 vCPU)。AISIX 固定运行在 4 vCPU 上,负载生成器和接近零延迟的固定响应模拟上游运行在独立 CPU 核上。这样的隔离可以避免上游和负载生成器成为瓶颈。报告的延迟是在未附加策略的情况下,给定速率下网关自身的开销。实际结果会随硬件、请求形态和已启用策略而变化。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[启动配置](https://docs.apiseven.com/ai-gateway/deployment/startup-configuration.md),配置资源来源、监听器、共享运行时状态和进程可观测性。 --- # 生产就绪 在应用流量通过每个 AISIX 网关之前,请先为生产环境做好准备。无论它作为开源网关从文件或 etcd 加载资源,还是从 AISIX Cloud 接收配置,都适用相同的运行时检查。配置方式和运维责任存在差异时,本页会明确说明。 本页提供生产基线。本节其余页面会详细说明容量、启动配置、网络安全、传输安全、配置更新和健康检查。 ## 规划容量与可用性[​](#规划容量与可用性 "规划容量与可用性的直接链接") 请根据具有代表性的请求和响应大小、流式传输行为及已启用策略,估算每个网关实例的容量。为突发流量预留余量,不要按实测饱和点配置容量。参考基准测试和估算公式请参阅[性能与容量估算](https://docs.apiseven.com/ai-gateway/deployment/performance-and-sizing.md)。 如果流量路径必须在进程或主机故障时继续可用,请运行多个实例。将其置于负载均衡器之后,分散到服务所需的故障域,并确保每个实例收到相同的动态资源。 基于内存的限流计数器和缓存条目只属于单个网关进程。如果限流或缓存响应必须在多个实例间保持一致,请使用共享 Redis 部署。对于连接 AISIX Cloud 的网关,请参阅[高可用](https://docs.apiseven.com/ai-gateway/cloud/high-availability.md),了解更完整的流量和管理拓扑。 ## 准备配置和依赖[​](#准备配置和依赖 "准备配置和依赖的直接链接") 部署副本前,请确认网关如何接收动态资源: * 开源 AISIX 网关可以加载声明式 `resources.yaml` 文件,并在收到 `SIGHUP` 时重新加载。 * 通过 etcd 配置的开源 AISIX 网关会监听一个 etcd 键空间。 * 连接 AISIX Cloud 的网关接收控制面投射的环境资源。 监听器、资源来源、Redis 连接和可观测性等进程设置请保留在[启动配置](https://docs.apiseven.com/ai-gateway/deployment/startup-configuration.md)中。不要在同一个网关上配置多个动态资源来源。 保护每个携带 Secret 的配置来源。资源文件应通过环境变量引用凭证,不要包含明文值。由你管理的 etcd 部署需要持久化、备份、访问控制和私有网络路径。连接 AISIX Cloud 的网关需要保护证书包和运行时状态目录,并确保重启后仍然可用。 当缓存策略或限流选择 Redis 时,请将 Redis 视为运行时依赖。使用符合可用性要求的拓扑,并确认每个网关实例都指向预期的 Redis 部署。 ## 保护运行时暴露面[​](#保护运行时暴露面 "保护运行时暴露面的直接链接") 只向预期调用方或网关前方的入口层暴露代理监听器。 将以下暴露面保留在私有网络中: * 指标/状态监听器及其无需身份认证的 `/metrics` 和 `/status/*` 路由; * 由你管理的 etcd 端点; * 包含模型服务提供方凭证或 AISIX Cloud 证书的文件和目录。 当 AISIX 终止 HTTPS 时,请配置监听器 TLS。为相应的管理连接配置 etcd mTLS 或 AISIX Cloud mTLS。暴露网关前,请查看[网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md)及 [TLS 与 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md)。 ## 路由流量前验证[​](#路由流量前验证 "路由流量前验证的直接链接") 存活检查只能证明进程正在运行,不能证明经过授权的请求可以到达模型服务提供方。请从最窄的信号开始,逐步验证到完整请求路径。 设置代理和指标/状态 URL: ``` PROXY_URL="https://gateway.example.com" METRICS_URL="http://gateway.internal.example.com:9090" ``` 检查进程存活和流量就绪状态: ``` curl -i "${PROXY_URL}/livez" curl -i "${PROXY_URL}/readyz" ``` 使用 etcd 或 AISIX Cloud 作为资源来源时,在网关应用第一个配置之前,这两条命令得到的是被拒绝的连接而不是响应,因为在那之前代理监听器尚未绑定。出现这种情况时,请先检查 `${METRICS_URL}/status/ready`——它在整个过程中都会响应——再考虑更改监听器设置。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 检查配置和模型状态: ``` curl -sS "${METRICS_URL}/status/config" curl -sS "${METRICS_URL}/status/models" ``` 然后验证健康端点无法证明的行为: * 使用应用将要使用的调用方 API Key 调用 `GET /v1/models`。 * 通过计划暴露的每个端点类型发送由模型服务提供方处理的请求。 * 在日志、指标、用量上报或已配置的导出器中找到该请求。 * 使用无效的调用方 API Key 发送请求,并确认 AISIX 将其拒绝。 请使用[健康检查](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md)选择并解读运维探针。如果配置变更尚未到达代理路径,请参阅[配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md)。 ## 规划关闭与恢复[​](#规划关闭与恢复 "规划关闭与恢复的直接链接") AISIX 将 `SIGINT` 和 `SIGTERM` 作为优雅关闭信号。排空开始时,`/readyz` 会立即返回 `503`,使流量层可以将实例移出流量;`/livez` 则继续报告健康,避免实例在排空期间被重启。代理会继续接受新连接,至少持续 `shutdown.min_drain_secs`;最小窗口结束且进行中请求数降为零后,才停止接受新连接。完整流程和负载均衡器时序指南请参阅[关闭与排空](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#shutdown-and-draining)。 请为负载均衡器或编排平台留出足够时间,在进程退出前停止分配连接。终止宽限期应长于 `shutdown.min_drain_secs`、你希望保留的最长请求或流式传输时长,以及随后网关留给在途快照缓存写入落盘的 5 秒这三者之和,并为关闭和负载均衡器时序额外预留余量。最后这一项为什么重要,请参阅[关闭与排空](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#shutdown-and-draining)。 记录每种部署恢复配置的方式: * 保留并验证资源文件; * 当 etcd 提供网关资源时,备份和恢复 etcd; * 按部署设计保留 AISIX Cloud 证书包、网关身份和最近一次接受的配置。 在故障恢复真正依赖这些机制前,请测试重启和替换行为。 ## 生产检查清单[​](#生产检查清单 "生产检查清单的直接链接") 扩大流量前,请确认: * 容量包含余量,并运行预期数量的网关实例。 * 每个实例都使用预期的启动配置和动态资源来源。 * 需要跨实例限流或共享缓存条目时,已配置共享 Redis。 * 代理、指标/状态和配置存储暴露面具有预期的网络访问范围。 * TLS、mTLS、证书路径和运行时状态权限有效。 * 网关至少可以使用一个模型服务提供方密钥、模型别名和调用方 API Key。 * 模型别名出现在面向调用方的代理路径中。 * 使用真实模型服务提供方的请求成功。 * 日志、指标、用量上报或导出器包含验证请求。 * 关闭、替换和配置恢复已经过测试。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[性能与容量估算](https://docs.apiseven.com/ai-gateway/deployment/performance-and-sizing.md)规划网关容量,然后使用[启动配置](https://docs.apiseven.com/ai-gateway/deployment/startup-configuration.md)配置运行时。 --- # 启动配置 启动配置定义 AISIX 在提供流量服务前所需的进程级设置。它控制网关如何接收动态资源、绑定哪些监听器、使用哪些共享后端,以及如何连接 AISIX Cloud。 动态资源单独配置。模型、模型服务提供方密钥、调用方 API Key、安全护栏、缓存策略、限流策略和可观测性导出器来自资源文件、配置存储或 AISIX Cloud 控制面。 ## 了解配置来源[​](#了解配置来源 "了解配置来源的直接链接") AISIX 为不同职责使用不同配置来源: | 配置 | 适用对象 | 来源 | | ---------------------- | ---------------------------- | ------------------------------------- | | 进程设置 | 每个网关 | 启动配置文件,可选择使用环境变量覆盖 | | 动态网关资源 | 开源 AISIX 网关 | 声明式 `resources.yaml` 文件或 etcd | | 动态网关资源 | 连接 AISIX Cloud 的网关 | AISIX Cloud 控制面 | | On-Premises 控制面设置 | On-Premises AISIX Cloud 部署 | Docker Compose 环境变量或 Helm values | 本页介绍网关启动配置。有关 On-Premises 控制面设置,请参阅 [On-Premises 配置参考](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md)。 ## 选择动态资源来源[​](#选择动态资源来源 "选择动态资源来源的直接链接") 网关从一个来源读取动态资源。在配置监听器和运行时依赖之前,请先在启动配置中选择该来源。 ### 资源文件[​](#资源文件 "资源文件的直接链接") 开源网关的常规工作流使用声明式资源文件: config.yaml ``` resources_file: /etc/aisix/resources.yaml proxy: addr: "0.0.0.0:3000" admin: enabled: false observability: metrics: prometheus: enabled: true path: "/metrics" addr: "0.0.0.0:9090" ``` 网关在启动时加载该文件,并在收到 `SIGHUP` 后重新加载。应用资源变更前,请先进行验证: ``` aisix validate --resources /etc/aisix/resources.yaml ``` 完整工作流请参阅[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md),受支持的资源类型请参阅[资源文件参考](https://docs.apiseven.com/ai-gateway/reference/resources-file.md)。 ### 配置存储[​](#配置存储 "配置存储的直接链接") 当现有自动化系统通过共享存储管理开源 AISIX 网关资源时,请使用 etcd: config.yaml ``` etcd: endpoints: - "http://127.0.0.1:2379" prefix: "/aisix" ``` 对于应接收相同资源的网关实例,请保持前缀稳定。只有当配置系统写入环境级键时才使用 `env_id`。存储要求 mTLS 时,请配置 `etcd.tls`。 `etcd.dial_timeout_ms` 和 `etcd.request_timeout_ms` 都是可选的,默认不设置;不设置即不施加任何超时,设为 `0` 含义相同。`dial_timeout_ms` 限制建立连接的整个过程——TCP 连接、TLS 握手,以及设置了 `etcd.user` 时进行的认证交互。这两个键都够不到的只有已经建立起来的配置 watch 流,而这是有意为之——但**创建**该 watch 的握手会受 `request_timeout_ms` 限制。除非你希望缓慢的 etcd 快速失败,否则请保持 `request_timeout_ms` 不设置。它限制的是配置读取,而配置读取的耗时会随资源规模增长,并且会在每一次 watch 重连时再次执行:一个读取无法在其中完成的上限,会让没有快照缓存的网关永远无法绑定代理监听器;而在已经开始提供服务的网关上,它会让已应用的配置悄悄落后于存储。参见 [etcd 配置存储](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#etcd-configuration-store)。 无论是否设置 `etcd.user`,网关连不上 etcd 都不会终止启动:进程照常启动,让代理监听器保持关闭,并在某次读取成功时完成绑定。而在启动那次连接上被 etcd 拒绝的凭据会终止启动,因为等待并不能把它们修好。更晚到达的拒绝——例如一个通过了认证、却读不了该前缀的用户——则会被重试,网关保持运行,代理监听器不绑定。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 不要同时配置 `resources_file` 和 `etcd`;AISIX 会在启动时拒绝这种组合。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 生成的网关安装片段会将 `managed.enabled` 设置为 `true`,并提供控制面端点、证书包、运行时状态目录和网关身份路径。之后,网关会从控制面接收环境资源。 不要将 `managed.enabled: true` 与 `resources_file` 组合使用。有关证书签发和完整连接流程,请参阅[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 ## 配置共享运行时状态[​](#配置共享运行时状态 "配置共享运行时状态的直接链接") AISIX 始终提供进程内响应缓存。当缓存策略需要在多个网关实例之间共享条目时,请配置 Redis: config.yaml ``` cache: redis: mode: single url: "redis://127.0.0.1:6379" ``` 配置 `cache.redis` 后,缓存策略即可使用 Redis。每个缓存策略会选择内存或 Redis。 限流计数器默认使用进程内存。当请求、Token 或并发限制必须作用于多个实例时,请配置共享 Redis 后端: config.yaml ``` ratelimit: backend: redis redis: mode: single url: "redis://127.0.0.1:6379" ``` 缓存和限流 Redis 连接支持单节点、Cluster 和 Sentinel 部署。当任一功能属于生产流量路径时,请使用符合可用性要求的 Redis 拓扑。 ## 配置运行时监听器[​](#配置运行时监听器 "配置运行时监听器的直接链接") AISIX 将调用方流量与运维状态分离: | 监听器 | 用途 | 暴露范围 | | --------- | ----------------------------------------------- | ------------------ | | 代理 | 面向调用方的 AI API,以及 `/livez` 和 `/readyz` | 预期调用方或入口层 | | 指标/状态 | Prometheus 指标和 `/status/*` 路由 | 可信监控网络 | 请设置显式代理地址。指标/状态路由不需要应用身份认证,因此绝不能将该监听器暴露到公网。 这两个监听器的启动时机也不同。指标/状态监听器在进程启动时即绑定。使用 etcd 或 AISIX Cloud 作为资源来源时,代理监听器只有在网关应用第一个配置之后才会绑定;使用资源文件时则立即绑定。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 只有当 AISIX 应直接终止 HTTPS 时,才使用监听器 TLS。只有网关运行在可信负载均衡器或 Ingress 之后时,才解析转发的客户端地址。暴露模型请参阅[网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md),独立 TLS 上下文请参阅 [TLS 与 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md)。 ## 配置进程可观测性[​](#配置进程可观测性 "配置进程可观测性的直接链接") 启动期可观测性设置控制进程日志和指标/状态监听器: config.yaml ``` observability: service_name: "aisix" log_level: "info" metrics: prometheus: enabled: true path: "/metrics" addr: "0.0.0.0:9090" ``` 这些设置不同于动态可观测性导出器。启动设置控制进程和本地 Prometheus 监听器。运行时遥测投递请通过[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md)配置。 ## 配置关闭行为[​](#配置关闭行为 "配置关闭行为的直接链接") 收到 `SIGTERM` 时,网关会立即把自己报告为未就绪,但仍会继续接受新连接一段时间,让前面的负载均衡器有时间在监听器关闭之前把它移出流量: config.yaml ``` shutdown: min_drain_secs: 30 ``` 请把该窗口设置为大于为该实例做负载均衡的组件的发现延迟,并为随后的进行中请求排空留出足够的平台终止时间。参见[关闭与排空](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#shutdown-and-draining)。 ## 加载并验证配置[​](#加载并验证配置 "加载并验证配置的直接链接") AISIX 先应用内置默认值,再加载启动配置文件,最后应用 `AISIX_` 环境变量覆盖项。嵌套字段名之间使用 `__`: ``` export AISIX_PROXY__ADDR="0.0.0.0:3000" ``` 有关文件格式、字段行为、文件选择和加载优先级,请参阅[启动配置参考](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md)。有关覆盖语法,请参阅[环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 启动网关后,请先在指标/状态监听器上确认 AISIX 已应用有效配置。该监听器在进程启动时即绑定,因此无论资源来源处于什么状态,它都会响应: ``` curl -sSi "http://127.0.0.1:9090/status/ready" curl -sS "http://127.0.0.1:9090/status/config" ``` `/status/ready` 返回 `200` 后,再检查代理监听器: ``` curl -i "http://127.0.0.1:3000/livez" curl -i "http://127.0.0.1:3000/readyz" ``` 使用 etcd 或 AISIX Cloud 作为资源来源时,在应用第一个配置之前,这两条命令得到的是被拒绝的连接而不是响应,因为在那之前代理监听器尚未绑定。使用资源文件的网关则会立即绑定。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 如果代理监听器有响应,但资源没有出现,请检查所配置的资源来源,不要更改监听器设置。如果它拒绝连接,则说明网关还没有应用任何配置——请检查它能否连上该来源。使用[配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md)追踪变更从来源到面向调用方路径的过程。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[每核一线程 Worker](https://docs.apiseven.com/ai-gateway/deployment/thread-per-core-workers.md),确定代理监听器背后的 Worker 池规模,然后阅读[网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md),保护此处配置的监听器、存储和凭证。 --- # 每核一线程 Worker AISIX 网关使用一组 Worker 线程处理流量。两个启动设置控制该线程池:`proxy.workers` 设置处理流量的 Worker 线程数,`proxy.thread_per_core` 决定这些 Worker 如何共享代理监听器和上游连接。本页介绍这两个设置及其默认值,说明如何验证正在运行的网关使用哪种模式,并介绍独立 Worker 服务模式带来的行为。 ## 了解服务模式[​](#understand-the-serving-modes "了解服务模式的直接链接") 在每核一线程服务模式下,每个 Worker 都是独立线程,拥有自己的运行时、`proxy.addr` 监听器和上游连接池。Worker 通过 `SO_REUSEPORT` Socket 选项共享代理地址,内核根据连接的地址和端口进行哈希,将每个新客户端连接分配给一个 Worker。请求随后由单个线程接受、处理和响应,其发起的上游调用也始终在该线程上执行。 当 `proxy.thread_per_core: false` 时,网关改用一个共享运行时:单个监听器接受连接,Worker 线程通过工作窃取在彼此之间平衡任务。请求在处理过程中可能在线程之间迁移,例如上游响应到达的线程与请求发起线程不同时。每次迁移都会产生一次线程唤醒和上下文切换。每核一线程服务模式让请求从头到尾留在同一线程上,因此不会发生这些交接。 每核一线程服务模式在 **Linux 上默认启用**,在其他平台上默认关闭,因为它依赖 Linux 内核的连接分配行为。在该模式的验证基准中,与共享运行时相比,它在使用 4 个 Worker 的 x86 虚拟机上每秒处理的请求数提高了 54–88%,在 Arm(AWS Graviton)硬件上提高了 28–42%。两种平台在负载下的 p99 延迟均大约减半。差异体现在网关吞吐能力上;无论使用哪种模式,模型服务提供方延迟都在端到端请求时间中占主导地位。 ## 配置 Worker 池[​](#configure-the-worker-pool "配置 Worker 池的直接链接") 这两个设置都位于启动配置的 `proxy` 块中: config.yaml ``` proxy: addr: "0.0.0.0:3000" thread_per_core: true workers: 4 ``` | 字段 | 默认值 | 说明 | | ----------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `proxy.thread_per_core` | Linux 上为 `true`,其他平台为 `false` | 使用各自具有监听器和上游连接池的独立 Worker 提供服务。设置为 `false` 可在任何平台上改用单个共享运行时。 | | `proxy.workers` | 进程可用的并行度 | 在任一模式下处理流量的 Worker 线程数。最小值为 `1`。 | 这两个设置都只在进程启动时读取一次。更改任一设置都会在网关下次重启时生效。 大多数部署无需设置 `proxy.workers`。默认值会跟随进程实际可用的并行度,因此容器 CPU limit、`cgroup` 配额或 `taskset` CPU 亲和性掩码都可以确定线程池大小,无需在配置中重复声明数量。即使主机有 16 个 CPU 核心,限制为 4 vCPU 的网关也会启动 4 个 Worker。只有当网关应使用少于其可运行线程数的线程时才显式设置,例如网关需要与 Sidecar 共享 CPU 配额时。 AISIX 会在启动时拒绝 `proxy.workers: 0`,因为零个 Worker 不会绑定任何监听器。请省略该字段以使用默认值。 这两个字段都遵循标准环境变量覆盖形式,嵌套字段名之间使用双下划线: ``` export AISIX_PROXY__THREAD_PER_CORE=false export AISIX_PROXY__WORKERS=8 ``` 通过环境变量注入全部启动配置的部署(例如 Kubernetes 安装)会以这种方式设置字段。有关覆盖机制,请参阅[环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 ## 验证当前模式[​](#verify-the-active-mode "验证当前模式的直接链接") 无需专用端点即可查看服务模式。 启动时,处于每核一线程模式的网关会为每个 Worker 记录一行 `aisix listening (http, thread-per-core)` 日志,每行都包含其 Worker 索引;如果代理监听器终止 TLS,则记录 `(https, thread-per-core)`。共享运行时只记录一行 `aisix listening (http)`。 在运行中的进程上列出其线程: ``` ps -T -p "$(pgrep -x aisix)" ``` 在每核一线程模式下,Worker 线程命名为 `tpc-0` 至 `tpc-`,每个 Worker 对应一个线程: ``` PID SPID TTY TIME CMD 23110 23110 ? 00:00:00 aisix 23110 23111 ? 00:00:00 tokio-runtime-w 23110 23112 ? 00:00:00 tokio-runtime-w 23110 23115 ? 00:00:41 tpc-0 23110 23116 ? 00:00:40 tpc-1 23110 23117 ? 00:00:41 tpc-2 23110 23118 ? 00:00:39 tpc-3 ``` 在此模式下,一个小型控制运行时负责指标监听器、信号处理和后台导出工作。它的 `tokio-runtime-w` 线程会与 Worker 一同显示,但不计入 `proxy.workers`。当 `thread_per_core: false` 时,不会出现 `tpc-` 线程,所有服务线程都使用默认运行时线程名 `tokio-runtime-w`。 ## 考虑各 Worker 的连接池[​](#account-for-per-worker-connection-pools "考虑各 Worker 的连接池的直接链接") 在每核一线程服务模式下,每个 Worker 都维护自己的上游主机连接池。池化连接绝不会在 Worker 之间移交:持有某个模型服务提供方空闲连接的 Worker 会复用该连接,没有连接的 Worker 则会自行建立连接。 这会带来两个容量规划影响: * `upstream.pool_max_idle_per_host` **对每个 Worker** 分别生效。一个具有 8 个 Worker 且 `pool_max_idle_per_host: 32` 的网关,对单个模型服务提供方主机最多可保留 256 个空闲连接。如果要限制整个进程的连接总数,请用预期总数除以 Worker 数量。 * 进程持有的空闲上游连接数会随 Worker 数量增加。当模型服务提供方、NAT 网关或企业出站代理限制每个客户端的连接数时,需要将这一点计入规划。 连接池超时的含义保持不变;有关这些连接池设置,请参阅[调优上游连接层](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#tune-the-upstream-connection-layer)。 ## 规划低并发流量[​](#plan-for-low-concurrency-traffic "规划低并发流量的直接链接") 内核在 Worker 之间分配的是客户端连接,而不是单个请求。连接数量较多时分配会比较均匀,数量较少时则可能不均匀。当每个 Worker 对应的客户端连接少于约 **4 个** 时,一些 Worker 可能空闲,而其他 Worker 同时承载多个连接。在这种情况下,吞吐量可能低于共享运行时,因为共享运行时平衡的是单个请求,而不是连接。 关键是网关自身接受的连接数,而不是终端客户端数量。来自大量客户端的直接流量会远高于该阈值。不过,按照[网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md)的建议,在网关面向调用方的端口前部署 L7 负载均衡器或 Ingress 时,前置层可能把许多客户端请求汇聚到少量面向网关的连接上。只使用少量长连接驱动网关的基准测试也属于同一情况:用 8 个连接测试具有 8 个 Worker 的网关,测量的是连接分配情况,而不是网关容量。 如果网关只通过少量长连接接收流量,请增加前置层到网关的连接数,或减少 `proxy.workers`,确保每个 Worker 仍能收到多个连接,也可以设置 `proxy.thread_per_core: false`。 ## 了解监听器共享[​](#understand-listener-sharing "了解监听器共享的直接链接") 每核一线程 Worker 通过 `SO_REUSEPORT` Socket 选项共享一个代理地址。运维或审计网关主机时,需要了解该选项的两个特性。 **端口冲突仍会在启动时明确失败。** 网关在绑定各 Worker 监听器之前,会先使用普通绑定探测地址。因此,如果另一个进程(包括第二个网关)占用了该地址,网关会在启动时失败,与使用单监听器的进程完全相同。该探测存在一个理论上的间隙:同时启动的两个网关可能都通过探测并绑定同一地址。编排器执行的顺序重启不会遇到该窗口;请避免刻意让两个网关同时在同一地址上启动。 **网关运行时,同一用户的进程可以加入监听器。** 网关提供服务期间,以相同有效用户 ID 运行且自身设置了 `SO_REUSEPORT` 的任何进程,都可以绑定代理地址并接收一部分新连接。内核只允许相同有效用户 ID 的进程加入,因此这不是跨用户风险。不过,审计网关主机上运行的进程时需要记住此模式特性:如果某些连接看起来绕过了网关,请检查是否有其他进程绑定代理端口,例如使用 `ss -tlpn`。 ## 下一步[​](#next-steps "下一步的直接链接") 继续阅读[网络与安全](https://docs.apiseven.com/ai-gateway/deployment/network-and-security.md),保护代理和指标监听器;也可以返回[性能与容量规划](https://docs.apiseven.com/ai-gateway/deployment/performance-and-sizing.md),根据请求量规划 CPU。 --- # TLS 与 mTLS AISIX AI 网关会在四个不同位置使用 TLS。请配置部署连接所涉及的每个区域。 | 连接 | 配置区域 | 用途 | | ------------------ | ---------------------------------- | --------------------------------------- | | 调用方到 AISIX | `proxy.tls` | 在代理监听器上终止 HTTPS | | AISIX 到上游 | `upstream.tls`、`provider_key.tls` | 决定 AISIX 调用上游时信任哪些证书 | | AISIX 到 etcd | `etcd.tls` | 验证 etcd 服务器并提供 AISIX 客户端身份 | | AISIX 网关到控制面 | `managed.*` 证书包字段 | 向 AISIX Cloud 控制面认证 AISIX 网关 | 这些设置彼此独立。在代理监听器上启用 HTTPS 不会配置 etcd mTLS;信任上游的私有证书颁发机构不会影响 etcd;AISIX Cloud 证书包也不会替代监听器 TLS。 ## 配置监听器 TLS[​](#配置监听器-tls "配置监听器 TLS的直接链接") 当 AISIX 需要直接在代理监听器上终止 HTTPS 时,请使用监听器 TLS。 在代理监听器上配置 TLS: config.yaml ``` proxy: addr: "0.0.0.0:3000" tls: cert_file: "/etc/aisix/tls/proxy.crt" key_file: "/etc/aisix/tls/proxy.key" ``` 监听器 TLS 保护进入该监听器的入站流量,但不能证明 AISIX 可以连接 etcd、访问 AISIX Cloud 控制面或向上游模型服务提供方认证。 ## 信任使用私有证书颁发机构的上游[​](#trust-an-upstream-behind-a-private-certificate-authority "信任使用私有证书颁发机构的上游的直接链接") AISIX 会使用平台的证书颁发机构验证出站连接。由自有证书颁发机构签发证书的自托管端点不在默认信任范围内,因此对它的请求会失败: ``` transport error: error sending request for url (https://internal-llm.example:8443/v1/chat/completions): client error (Connect): invalid peer certificate: UnknownIssuer ``` 出站传输方式决定它可以应用哪些部署级 `upstream.tls` 字段: | 出站传输 | `ca_file` | 客户端证书和密钥 | `verify: false` | | -------------------------------------------------------------------------------------------------------- | --------- | ---------------- | -------------------------------- | | HTTP 模型服务提供方、HTTP 安全护栏、MCP 和 A2A 上游、OIDC 和 JWKS 请求,以及 OTLP、SLS 和 Datadog 导出器 | 生效 | 生效 | 生效 | | Realtime WebSocket | 生效 | 忽略 | 生效 | | Amazon Bedrock 模型和安全护栏 | 生效 | 忽略 | 忽略;Bedrock 始终验证服务器证书 | | 对象存储导出器 | 生效 | 忽略 | 生效 | 每个模型服务提供方 Key 的 `tls` 设置适用范围更窄。它们适用于 HTTP 提供方分发,包括兼容 REST 端点和透传请求,但不适用于 Amazon Bedrock 或 Realtime WebSocket。Realtime 应使用部署级 CA 和验证设置;Bedrock 仅应用部署级 `ca_file` 设置。 将 `upstream.tls.ca_file` 指向该证书颁发机构的证书,可以为整个部署解决此问题: config.yaml ``` upstream: tls: ca_file: "/etc/aisix/tls/private-ca.pem" ``` 该文件使用 PEM 编码,可以包含多个证书,因此可在一个 bundle 中提供完整证书链。这些证书会在平台自带证书之外额外受信任,因此添加私有证书颁发机构不会导致公共模型服务提供方不可达。 如果 AISIX 无法读取该文件,或文件中不包含证书,启动会失败并在消息中指出路径,而不是等到每个请求建立连接时才失败。 ### 提供客户端证书[​](#提供客户端证书 "提供客户端证书的直接链接") 部分 HTTP 上游还要求调用方使用证书进行身份认证。请同时设置以下两个字段: config.yaml ``` upstream: tls: ca_file: "/etc/aisix/tls/private-ca.pem" client_cert_file: "/etc/aisix/tls/client.crt" client_key_file: "/etc/aisix/tls/client.key" ``` 只设置其中一个字段会在启动时被拒绝。 Realtime、Bedrock 和对象存储导出器连接不会提供该客户端证书。不要将这些字段用作上述传输的 mTLS 控制。 ### 为每个端点信任不同的证书颁发机构[​](#为每个端点信任不同的证书颁发机构 "为每个端点信任不同的证书颁发机构的直接链接") 添加以下模型服务提供方 Key 条目,为单个端点信任不同的证书颁发机构。证书随资源保存,而不是保存在网关配置中: resources.yaml(模型服务提供方 TLS) ``` provider_keys: - display_name: internal-llm provider: openai api_key: "sk-..." api_base: "https://internal-llm.example:8443/v1" tls: ca_cert: | -----BEGIN CERTIFICATE----- MIIB... -----END CERTIFICATE----- ``` 在 AISIX Cloud 中,相同设置位于控制台中模型服务提供方密钥的 **Endpoint TLS** 部分。 在受支持的 HTTP 路径上,某个模型服务提供方 Key 配置的证书只适用于该 Key 的端点。各 Key 不会合并为一个信任存储,因此由不同证书颁发机构签发的两个端点需要分别配置。 Bedrock 和 Realtime 会接受模型服务提供方 Key 来选择凭证和端点,但其分发传输不会读取该 Key 的 `tls` 配置块。请改用上表中适用的部署级设置。 ### 在测试环境中跳过验证[​](#在测试环境中跳过验证 "在测试环境中跳过验证的直接链接") 可以在部署级或单个模型服务提供方密钥上关闭证书验证: config.yaml ``` upstream: tls: verify: false ``` 危险 这会接受受影响连接的任何证书,包括已过期证书、为其他主机签发的证书,以及拦截者提供的证书。任何能够拦截连接的人都可以读取和改写经过连接的提示词、响应和上游 API Key。在需要防范这些风险的环境中,请使用 `ca_file` 或 `ca_cert`。 `upstream.tls.verify: false` 适用于 HTTP 请求路径、Realtime WebSocket 和对象存储导出器,但不适用于 Amazon Bedrock。AWS SDK 支持添加信任根,但不允许 AISIX 禁用证书验证。因此 Bedrock 仍会验证服务器证书,网关会在首次构建 Bedrock 客户端时记录警告。每个模型服务提供方 Key 的 `tls.verify` 字段同样不适用于 Bedrock 或 Realtime。 ### 改用环境变量[​](#改用环境变量 "改用环境变量的直接链接") AISIX 会采用 `SSL_CERT_FILE` 和 `SSL_CERT_DIR`,并将其添加到平台证书颁发机构之外。无需修改配置文件时,可以通过这种方式信任私有证书颁发机构。 这些变量作用于整个进程,因此无法表达“仅此端点信任此证书颁发机构”。如需显式指定部署级证书颁发机构,请使用 `upstream.tls.ca_file`;如需为一个受支持的 HTTP 模型服务提供方端点指定证书颁发机构,请使用模型服务提供方 Key 的 `tls.ca_cert`。 备注 使用 `update-ca-certificates` 将证书安装到容器的系统信任存储**不会生效**。镜像以非特权 `aisix` 用户运行,因此该命令会因权限错误而失败,bundle 保持不变,网关仍会拒绝证书,但表面上看起来证书颁发机构已经安装。 ### 配置 Redis 后端[​](#配置-redis-后端 "配置 Redis 后端的直接链接") 共享缓存和限流后端使用独立的信任设置,因为它通常位于你的部署内部,且证书颁发机构与模型端点不同。其字段与 `upstream.tls` 相同,并且只适用于 `rediss://` URL: config.yaml ``` ratelimit: backend: redis redis: mode: single url: "rediss://redis.internal:6379" tls: ca_file: "/etc/aisix/tls/redis-ca.pem" ``` 在 Sentinel 模式下,`ca_file` 不生效。客户端库不接受为其发现的主节点配置自定义信任根,因此请将证书放入系统信任存储,或改为通过 `SSL_CERT_FILE` 指定。该模式下设置 `ca_file` 时,网关会在启动时记录警告。`verify` 在 Sentinel 模式下仍然生效。 ## 配置 etcd mTLS[​](#configure-etcd-mtls "配置 etcd mTLS的直接链接") 当配置存储要求 mTLS 时,请使用 `etcd.tls`。AISIX 要求同时提供 CA 证书、客户端证书和客户端密钥。 配置 etcd 信任和客户端身份: config.yaml ``` etcd: endpoints: - "https://etcd.internal.example.com:2379" prefix: "/aisix" tls: ca_cert_file: "/etc/aisix/etcd/ca.crt" client_cert_file: "/etc/aisix/etcd/client.crt" client_key_file: "/etc/aisix/etcd/client.key" ``` AISIX 使用 CA 文件验证 etcd 服务器证书,并向 etcd 提供客户端证书和私钥。三个文件都必须在启动时可被 AISIX 进程读取。 当 etcd 证书使用的服务器名称与端点主机名不同时,请显式设置 `domain_name`: config.yaml ``` etcd: endpoints: - "https://10.0.0.10:2379" tls: ca_cert_file: "/etc/aisix/etcd/ca.crt" client_cert_file: "/etc/aisix/etcd/client.crt" client_key_file: "/etc/aisix/etcd/client.key" domain_name: "etcd.internal.example.com" ``` 如果省略 `domain_name`,AISIX 会从第一个 etcd 端点推导。 ## 配置 AISIX Cloud mTLS[​](#配置-aisix-cloud-mtls "配置 AISIX Cloud mTLS的直接链接") AISIX 网关使用证书包向控制面进行身份认证。这与开源 AISIX 网关的监听器 TLS 和 etcd mTLS 相互独立。 将 `managed.enabled` 设置为 `true`,提供控制面连接设置和证书包: config.managed.yaml ``` managed: enabled: true cp_base_url: "https://dpm.example.com:7944" mtls_dir: "/var/lib/aisix/mtls" dp_id_file: "/var/lib/aisix/dp_id" cp_cert_file: "/etc/aisix/mtls/client.crt" cp_key_file: "/etc/aisix/mtls/client.key" cp_ca_file: "/etc/aisix/mtls/ca.crt" ``` AISIX Cloud 证书包必须包含证书、私钥和 CA bundle。示例使用文件路径;AISIX 也接受内联 PEM 值。请用同一种形式提供三个值,并且不要为同一个证书、密钥或 CA 角色同时设置内联和文件路径变体。 大多数 AISIX 网关会从 `cp_base_url` 推导控制面 etcd 端点。只有当控制面部署公开了单独且已知的 etcd 端点时,才设置 `cp_etcd_endpoint`。 AISIX 会将证书包实体化到 `mtls_dir`,并在重启时复用持久化 bundle。运行时状态目录必须可被网关进程写入。 有关完整的 AISIX Cloud 连接流程,请参阅[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 ## 检查正确连接[​](#检查正确连接 "检查正确连接的直接链接") 请从失败连接开始,检查对应配置区域。 如果进程运行时 HTTPS 调用方流量失败,请检查 `proxy.tls`、证书和私钥可读性,以及面向客户端的主机名。 如果启动时连接 etcd 失败,请检查 `etcd.tls`、etcd 网络可达性和证书信任。如果启动后预期配置变更停止应用,请继续检查 etcd 连接和配置监听的健康状态。 如果对模型服务提供方的请求因 `invalid peer certificate: UnknownIssuer` 失败,说明端点证书由 AISIX 不信任的证书颁发机构签发。请检查 `upstream.tls.ca_file`;对于 HTTP 模型服务提供方端点,如果只影响该端点,请检查其模型服务提供方 Key 自己的 `tls.ca_cert`。 如果 AISIX Cloud 心跳、遥测、预算检查或证书轮换失败,请检查证书包、信任根、运行时状态目录和 `managed.cp_base_url`。 每个 TLS 区域都使用独立的证书上下文。监听器证书、上游信任设置、etcd 客户端证书和 AISIX Cloud 控制面证书会分别配置和验证。 ## 下一步[​](#下一步 "下一步的直接链接") 继续阅读[配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md),了解已验证的更新如何成为生效的网关快照。 --- # 故障排除 修改资源前,请先将 AISIX 故障范围缩小到启动、配置、调用方策略、模型服务提供方路径或 AISIX Cloud 投射。请按顺序执行检查,直到明确失败层级,再根据对应章节决定下一步操作。 ## 快速排查[​](#快速排查 "快速排查的直接链接") 修改配置前,请先从运行时路径开始检查。 先检查监听器健康状态: ``` curl -i "http://127.0.0.1:3000/livez" ``` 这里连接被拒绝本身就是一个信号,而不是命令执行失败。使用 etcd 或 AISIX Cloud 作为资源来源时,网关在应用第一个配置之前不会绑定代理监听器,因此从未连上该来源的实例根本没有代理端口可以响应。参见[进程在运行但代理端口拒绝连接](#gateway-never-binds)。 启用 Prometheus 指标时,请在私有指标/状态监听器上检查最新观察到和已应用的配置;该监听器在进程启动时即绑定,因此在上述情况下同样会响应: ``` curl -sSi "http://127.0.0.1:9090/status/ready" curl -sS "http://127.0.0.1:9090/status/config" ``` 使用应用实际使用的同一个调用方 API Key 验证模型发现: ``` AISIX_API_KEY="YOUR_CALLER_API_KEY" curl -sS "http://127.0.0.1:3000/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 然后向失败端点发送一次真实请求。例如,使用调用方 API Key 检查 OpenAI 兼容聊天路径: ``` curl -sS "http://127.0.0.1:3000/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [ { "role": "user", "content": "Say hello." } ] }' ``` 根据响应状态、错误类型和关联响应头选择下一步检查。 | 信号 | 下一步检查 | | ---------------------------------------- | ------------------------------------------------------------------------------- | | 监听器健康检查被拒绝而不是返回响应。 | 网关是否应用过任何配置:先看指标/状态监听器上的 `/status/ready`,再看配置来源。 | | 监听器健康检查失败。 | 进程、监听器绑定、启动配置和 TLS。 | | 配置状态为 `degraded` 或 `out_of_sync`。 | 被拒绝的资源、最近一次加载失败和配置来源。 | | 配置状态没有反映预期的直接 etcd 变更。 | etcd 可达性、监听的前缀和配置来源状态。 | | 模型发现没有显示预期别名。 | 调用方 API Key 访问权限、模型类型和配置可见性。 | | 真实代理请求在分发到上游前失败。 | 调用方身份认证、模型访问、安全护栏、限流或预算。 | | 真实代理请求到达模型服务提供方后失败。 | 模型服务提供方密钥、base URL、上游模型 ID、配额、服务故障或出站网络路径。 | 请求关联请使用 `x-aisix-request-id`,AISIX 会将其添加到各端点类型的代理响应中。成功的 Chat Completions 响应还包含 `x-aisix-call-id`。精确响应头范围请参阅[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md#proxy-response-headers)。 ## 验证配置可见性[​](#验证配置可见性 "验证配置可见性的直接链接") 当资源最近刚创建或更新,或代理表现得像仍在使用旧配置时,请执行这一步。 | 信号 | 检查项 | 处理方式 | | -------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | 进程在启动期间失败。 | 动态资源来源、网络可达性、TLS 证书路径、文件权限和启动配置语法。 | 修复启动配置或资源来源后重启网关。 | | 进程在运行,但代理端口拒绝连接。 | 指标/状态监听器上的 `/status/ready` 和 `/status/config`,然后确认网关能否连上其配置来源。 | 恢复配置来源。网关会持续重试,并在某次读取成功后立即绑定监听器;参见[进程在运行但代理端口拒绝连接](#gateway-never-binds)。 | | 配置状态为 `never_loaded`、`degraded` 或 `out_of_sync`。 | `/status/config` 的 `source`、`applied`、`rejected` 和 `last_failure` 字段。 | 恢复来源或修正被拒绝的配置,再确认下一次加载状态为 `synced`。 | | 直接 etcd 变更没有反映在代理流量中。 | 已应用的网关配置快照、存储连接和监听的前缀。 | 快照更新后验证最终代理路径;参见[配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md)。 | | 模型发现缺少新别名。 | 调用方 API Key 允许列表、模型类型和快照新鲜度。 | 修正模型或调用方 API Key,然后再次查询模型发现。 | | 错误提到缺少模型服务提供方密钥或未知资源。 | 模型服务提供方密钥、模型和调用方 API Key 引用。 | 按顺序创建或修正依赖资源,然后发送真实代理请求。 | 对于使用存储的网关,etcd 提供动态资源来源。如果加载快照后 etcd 不可用,网关可以继续使用该快照,但在配置连接恢复前无法接收新增或更新的动态资源。 ## 进程在运行但代理端口拒绝连接[​](#gateway-never-binds "进程在运行但代理端口拒绝连接的直接链接") 当进程处于运行状态——既没有退出,也没有报出错误——但发往代理端口的所有请求(包括 `/livez`)都被拒绝时,请执行这一步。 从 etcd 或 AISIX Cloud 读取资源的网关,只有在应用第一个配置之后才会绑定代理监听器。在那之前端口并不存在,因此现象看起来像进程从未启动,而不像它正在等待。它确实是在等待:它不会退出,不会绑定一个降级的监听器,也不会退化成什么都不提供。唯一的例外是启动那次连接本身被来源响应并拒绝——etcd 凭据不正确,或者把凭据发给了一个没有开启认证的集群——这种情况会带着那个错误终止启动,因为等待修不好它们。比那次连接更晚到达的拒绝(包括用户在 `etcd.prefix` 上没有权限)则仍然停留在这段等待里。它会在某次读取成功的那一刻绑定监听器;读取**失败**时按指数退避重试,退避从 1 秒增长到 60 秒上限。完整契约参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 请在全程保持绑定的指标/状态监听器上确认这一判断: ``` curl -sSi "http://127.0.0.1:9090/status/ready" curl -sS "http://127.0.0.1:9090/status/config" ``` 返回 `503` 且响应体为 `no configuration available`,同时 `/status/config` 中 `state` 为 `never_loaded`,就是这种情况。网关日志中同样有记录:等待开始时写出一条 `waiting for the first configuration before binding the proxy listener`,随后每 10 秒写出一条 `proxy listener still not bound: no configuration has been applied yet`,直到等待结束。 | 信号 | 检查项 | 处理方式 | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/status/config` 报告 `source.connected: false` 且 `state` 为 `never_loaded`。 | etcd 端点或 AISIX Cloud 端点、DNS 解析、mTLS 证书材料,以及网关与该来源之间的网络策略。 | 恢复可达性。某次读取成功后,网关无需重启即会绑定监听器。 | | `/status/config` 报告 `state` 为 `empty`,且监听器已绑定。 | 所配置的 `etcd.prefix` 和 `env_id`。 | 来源可以连上,但其中没有属于该网关的资源;应修正前缀而不是排查连接。 | | 网关日志出现每 10 秒一条 `proxy listener still not bound` 告警,但 `/status/config` 没有记录任何连接失败。 | 所配置的端点是否只接受连接却不返回响应——死掉的配置存储前面挂着负载均衡器时就是这种表现。 | 修复到来源的链路。除非设置了 [`etcd.request_timeout_ms`](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#etcd-configuration-store),配置读取不受任何超时限制,因此默认情况下被接受的读取会一直处于在途状态,只产生告警而没有可供重试的显式失败。设置该项会给读取加上上限,把这种挂起变成退避会重试的失败;取值请依据那里的说明,而不是依据你愿意等多久。它覆盖的是配置读取,以及建立配置 watch 的握手。卡在建立连接时的认证交互上同样在覆盖范围之内——启动阶段由 `etcd.dial_timeout_ms` 覆盖,之后某次调用需要自行建立连接时由 `etcd.request_timeout_ms` 覆盖——不过这两个键默认都不设置,因此在你设置其中之一以前,它不受任何约束。设置了 `etcd.user` 时,以这种方式卡住的连接还会每 10 秒写出一条 `still connecting to etcd — nothing waiting on this connection can proceed until it answers`,并点名它正在等待的端点。 | | 指标/状态监听器同样拒绝连接。 | 进程是否在运行、`observability.metrics.prometheus.enabled`,以及设置了 `etcd.user` 时网关是否仍停在第一次连接里。 | 通常不是上述等待——请按进程或启动配置失败来排查。例外是配置了 etcd 凭据、且 `etcd.dial_timeout_ms` 未设置的网关:它的第一次连接发生在创建任何监听器之前,此时它会每 10 秒写出一条 `still connecting to etcd — nothing waiting on this connection can proceed until it answers`,并且不会打开任何端口。设置 `dial_timeout_ms` 会给这次连接加上上限,使网关进入上述等待。 | | 进程在启动阶段退出,并报告 etcd 拒绝了连接。 | 所配置的 `etcd.user`、`etcd.password_env` 中的密码,以及集群是否开启了认证。 | 这同样不是上述等待。连不上的 etcd 会被一直等待;而在启动那次连接上被拒绝的凭据会有意终止启动,以免一个写错的密码表现为一个起来了却永远空着的网关。 | | 网关在运行,等待却始终不结束,日志反复以 `ERROR` 写出 `etcd refused this gateway's credentials — no configuration can be read until they are fixed; still retrying`。 | 该用户在 `etcd.prefix` 上的权限;如果网关是在 etcd 不可达时启动的,还要查凭据本身。 | etcd 的权限是逐次调用校验的,而不是在认证时校验,因此拒绝可能在启动那次连接之后才到达——而更晚到达的拒绝会被重试,不会致命。此时 `/status/config` 的表现与来源不可达完全一样,区分两者靠的正是这条日志。 | | 在 Kubernetes 中,Pod 反复重启并报告 `CrashLoopBackOff`。 | 同样的可达性检查;启动探针的预算正在按设计发挥作用。 | 恢复配置来源。不要用调大预算来掩盖来源不可达,也不要把探针改指向其他监听器。 | 从磁盘缓存恢复了可用快照的网关,以及使用资源文件的网关,会立即绑定监听器,不会进入这种状态。参见[离线韧性](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md#restart-from-cached-configuration)。 ## 验证调用方访问与策略[​](#验证调用方访问与策略 "验证调用方访问与策略的直接链接") 当 AISIX 在调用服务提供方前拒绝请求,或不同调用方 API Key 的模型发现结果不一致时,请执行这一步。 | 信号 | 检查项 | 处理方式 | | -------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------- | | 身份认证错误。 | 应用发送的是明文调用方 API Key,而不是存储哈希或上游模型服务提供方密钥。 | 更新应用 Secret 或 Authorization 请求头。 | | 权限或模型访问错误。 | 请求的模型别名是否被调用方 API Key 允许。 | 将别名加入调用方 API Key,或请求已允许的模型。 | | 内容策略错误。 | 已启用的安全护栏、各护栏运行阶段,以及触发的提示词或响应内容。 | 视情况调整提示词、安全护栏规则或故障放行行为。 | | 限流或预算错误。 | 重试提示、API Key 限制、模型限制、共享策略、AISIX Cloud 预算状态和副本本地计数器。 | 等待重试窗口、提高限制或调整匹配策略。 | 精确代理错误信封、状态码和重试响应头请参见[代理错误与重试](https://docs.apiseven.com/ai-gateway/routing/proxy-errors-and-retries.md)。 当不同网关实例的限流结果不一致时,请先确定计数器后端,再修改策略。内存计数器为各进程本地所有。Redis 会共享计数器,但运行时 Redis 故障会回退到进程本地执行。恢复后,故障期间的计数不会合并回 Redis;请先恢复 Redis,并等待活动窗口滚动结束,再判断计数器是否重新对齐。 ## 验证服务提供方链路[​](#验证服务提供方链路 "验证服务提供方链路的直接链接") 当 AISIX 已认证调用方、解析模型别名并开始向已配置服务提供方调度后,请执行这一步。 | 信号 | 检查项 | 处理方式 | | --------------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------- | | `502` 或 `upstream_error`。 | 服务提供方密钥 Secret、base URL、上游模型 ID、服务提供方配额、服务故障和出站网络路径。 | 修复上游访问问题后再次发送同一代理请求。 | | `503` 且服务提供方不可用。 | 服务提供方适配器可用性,以及解析出的适配器是否支持请求路由。 | 使用受支持的服务提供方、适配器、端点或模型。 | | `503` 且所有候选不可用。 | 多目标模型健康状态、冷却状态和路由过滤条件。 | 恢复健康目标或调整路由行为。 | | 模型健康状态降级或不可用。 | 最近连续上游失败、服务提供方故障、配额、出站网络路径和凭证有效性。 | 恢复服务提供方可达性,或将流量路由到健康目标。 | 当问题与服务提供方有关时,请对照对应服务提供方上游指南检查失败路由。 ### 解读传输错误[​](#解读传输错误 "解读传输错误的直接链接") 传输错误表示请求未在 HTTP 层完成,因此没有可供解读的上游状态码。网关日志会在消息旁记录原因链,可据此区分故障: | 日志行中的原因 | 含义 | 检查位置 | | ------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dns error: failed to lookup address information` | 无法解析模型服务提供方主机名。 | DNS 配置、`api_base` 主机名和出站 DNS 策略。 | | `tcp connect error: Connection refused` | 该主机和端口上没有程序接受连接。 | `api_base` 端口,以及中间代理是否正在监听。 | | `tcp connect error: Connection timed out` | 连接尝试被网络路径丢弃。 | 路径上的防火墙、安全组和出站规则。 | | `connection closed before message completed` 或发送期间发生连接重置 | 对端在请求完成前关闭了池化连接。 | `upstream.pool_idle_timeout_secs`;参见[调整上游连接层](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#tune-the-upstream-connection-layer)。 | | TLS 或证书错误 | 与模型服务提供方或拦截代理的握手失败。 | 信任根,以及终止 TLS 的代理是否重新签发流量证书。 | 如果仅在服务提供方整体健康时偶发错误,通常是连接复用问题,而非模型服务提供方故障。将 `pool_idle_timeout_secs` 降到路径上最短空闲超时以下,然后重新检查。 入站侧也可能发生对称故障。如果 AISIX **前方**的网关或负载均衡器在 AISIX 健康时偶发报告连接重置或 502,请检查 `downstream.idle_timeout_secs` 是否低于该节点自身的连接池空闲超时;此时 AISIX 会关闭前方节点仍视为可用的连接。保持默认值 `0` 可排除此问题。参见[调整下游连接层](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#%E8%B0%83%E6%95%B4%E4%B8%8B%E6%B8%B8%E8%BF%9E%E6%8E%A5%E5%B1%82)。 ### 将上游错误归因到正确的网络跳点[​](#将上游错误归因到正确的网络跳点 "将上游错误归因到正确的网络跳点的直接链接") 当记录的消息为 `upstream returned HTTP : ` 时,状态和正文来自响应 `api_base` 的组件;只有当其前方没有任何中间组件时,该组件才是模型服务提供方。如果响应正文使用某个代理自身的术语,则错误由中间跳点而非模型服务提供方生成: * 包含 `reset reason` 的 `upstream connect error or disconnect/reset before headers`,或 `exceeded request buffer limit while retrying upstream`,由基于 Envoy 的代理、服务网格和 API 网关生成。 * 通用 HTML 错误页由反向代理或负载均衡器生成,不是模型服务提供方的 JSON API。 在建模路由上,网关会记录这些响应体用于诊断,但不会返回给调用方:上游 `5xx` 响应会以通用 `502` 错误封装到达应用。[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md#errors)则会转发上游提供方原生的状态和响应体。请使用每次尝试记录识别失败的 `provider_key_id` 和目标模型,再与 `api_base` 所配置上游端点的访问日志对照。 ## 验证 AISIX Cloud 投射[​](#验证-aisix-cloud-投射 "验证 AISIX Cloud 投射的直接链接") 当控制面状态与实时网关行为不一致,或 AISIX 网关无法接收投射配置时,请执行此步骤。 | 信号 | 检查项 | 处理方式 | | -------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | AISIX Cloud 心跳失败。 | 证书身份、信任根、运行时状态、控制面 URL 和出站网络路径。 | 先恢复 AISIX Cloud 连接,再排查资源投射;参见[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 | | 控制面显示资源,但实时流量没有使用它。 | 处理流量的网关对应的环境作用域和投射状态。 | 将资源移到正确环境,或等待投射完成。 | | AISIX Cloud 预算检查失败或看似不可用。 | 控制面连接、预算策略目标和预算检查响应详情。 | 恢复预算检查连接,或修正 AISIX Cloud 策略。 | | Playground 成功,但实时流量结果不同。 | 实时网关、环境、模型别名、调用方 API Key 和模型服务提供方目标。 | 通过预期 AISIX 网关和环境发送实时请求。 | 识别失败层级后,请使用相关功能指南或参考页面。每次修正后重新运行面向调用方的请求,以验证完整路径,而不仅是刚刚失败的组件。 --- # URL 重写 AISIX AI 网关可以在路由前重写请求路径。代理监听器入口处会按顺序执行重写规则列表:第一条 `match` 正则表达式与请求路径匹配的规则会重写该路径,之后请求进入正常端点流程——认证、访问控制、限流和遥测的应用方式与客户端直接发送重写后路径时完全相同。 当现有客户端配置了 AISIX 原生不提供的 URL 形式时,可使用 URL 重写。例如,某些网关为每台 MCP 服务器暴露一个 URL,或者外部监控已经探测某个内部约定的健康检查路径。 ## 配置重写规则[​](#configure-rewrite-rules "配置重写规则的直接链接") 重写规则是 `config.yaml` 中 `proxy` 块下的启动配置: ``` proxy: addr: "0.0.0.0:3000" url_rewrites: - name: per-server-mcp-compat match: "^/mcp-servers/([^/]+)/mcp$" rewrite: "/mcp/$1" ``` | 字段 | 是否必需 | 说明 | | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | 否 | 规则触发时在网关日志中使用的标签。 | | `match` | 是 | 针对原始、百分号编码的请求路径进行测试的正则表达式(不包含查询字符串),且不会执行解码或规范化。使用 `^` 和 `$` 锚定整个路径。 | | `rewrite` | 是 | 用于替换路径匹配部分的内容。`$1` … 会展开编号捕获组,`${server}` 会展开 `match` 中定义为 `(?P…)` 的命名组。当引用后紧跟字面文本时,请使用带花括号的形式(`${1}text`)。不得包含 `?`、`#` 或空白字符——查询字符串会自动保留。 | 与其他启动配置一样,更改规则需要重启网关。启动验证会拒绝错误规则,并在错误中指出规则名称,包括无效正则表达式、引用了模式中未定义的捕获组、模板中包含禁用字符,以及可能匹配空字符串的模式。这样,拼写错误会立即暴露,而不会悄然将流量路由到错误位置。 如果网关完全通过环境变量配置,例如由 Helm 管理的部署,请将整个列表设置为一个 JSON 数组: ``` export AISIX_PROXY__URL_REWRITES='[{"name":"per-server-mcp-compat","match":"^/mcp-servers/([^/]+)/mcp$","rewrite":"/mcp/$1"}]' ``` ## 规则的应用方式[​](#how-rules-are-applied "规则的应用方式的直接链接") * 规则按声明顺序执行;**第一条**匹配的规则生效且只应用**一次**——重写后的路径不会再次进入规则列表。 * `rewrite` 会替换路径中匹配的部分。如果 `match` 未使用锚点,未匹配的前缀和后缀会保留。 * 查询字符串会按原样保留。 * 未匹配任何规则的请求会原样通过,规范路径可以与重写形式同时正常工作。 * 重写适用于代理监听器上的所有请求,不影响 Admin 和指标监听器。 重写用于选择处理请求的网关端点,绝不会绕过治理。重写后的请求由目标端点进行认证和授权,指标与访问日志会记录重写后的路由。 ## 示例:提供按服务器划分的 MCP URL[​](#example-serve-per-server-mcp-urls "示例:提供按服务器划分的 MCP URL的直接链接") 一些网关会在独立 URL 上暴露每台 MCP 服务器,例如 `/mcp-servers/github/mcp`,客户端则使用工具的原始名称调用工具。AISIX 通过[按服务器划分的 MCP 端点](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md#per-server-endpoints) `/mcp/{server}` 原生提供此约定——一条重写规则即可将旧版 URL 形式连接到该端点: ``` proxy: url_rewrites: - name: per-server-mcp-compat match: "^/mcp-servers/([^/]+)/mcp$" rewrite: "/mcp/$1" ``` 配置了 `https://gateway.example.com/mcp-servers/github/mcp` 的客户端现在会访问 `/mcp/github`。AISIX 通常以原始名称列出 `github` 服务器的工具并接受使用这些名称的调用,因此无需更改客户端。如果原始名称与已注册服务器的前缀存在歧义,AISIX 会公布仍可调用的带命名空间名称。调用方 API Key 的工具访问权限、限流、预算和安全护栏也会照常应用。 只有声明的 URL 形式会得到服务:使用上述规则时,`/mcp-servers/github/sse` 不匹配任何内容并返回 404,而不会被悄然路由。 ## 示例:为任意路径设置别名[​](#example-alias-an-arbitrary-path "示例:为任意路径设置别名的直接链接") 规则并非 MCP 专用。任何路径都可以映射到任意代理端点: ``` proxy: url_rewrites: - name: legacy-health match: "^/healthz-compat$" rewrite: "/livez" ``` --- # Anthropic 风格 Messages API Anthropic 风格代理路由适合已经发送 Anthropic Messages 请求,并希望由 AISIX 管理网关侧认证、模型别名、路由和策略的应用。 客户端保持 Anthropic 风格请求和响应格式。AISIX 成为客户端调用的端点,上游服务提供方可以是 Anthropic,也可以是其它受支持的服务提供方协议族。 本指南说明代理 API 行为。可运行的客户端集成请参见 [Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md)。 ## 客户端发送的内容[​](#客户端发送的内容 "客户端发送的内容的直接链接") 客户端会发送三个由 AISIX 管理的值: * base URL 是 AISIX 网关 Origin,末尾不包含斜杠或端点路径。 * API Key 是 AISIX 调用方 API Key。 * model 值是 AISIX 模型别名,例如 `claude-prod`。 请求体保持 Anthropic Messages 格式,包括 `messages`、`max_tokens`、`tools` 和 `stream`。调用方使用 AISIX 调用方 API Key,而不是上游 Anthropic 服务提供方密钥。 对于会发送这种形态的客户端,AISIX 也接受 `messages[]` 中的 `system` role。当上游路径需要 Anthropic 原生格式时,AISIX 会将开头的 system messages 映射到 Anthropic 顶层 `system` 字段。 Anthropic SDK 会以 `x-api-key` 发送调用方 API Key。对于直接 HTTP 客户端,AISIX 也接受 Bearer Token。 导出以下示例使用的网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="claude-prod" ``` ## Messages 请求[​](#messages-请求 "Messages 请求的直接链接") 通过 AISIX 发送 Messages 请求: ``` curl -sS -X POST "${AISIX_PROXY}/v1/messages" \ -H "x-api-key: ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "max_tokens": 128, "messages": [ { "role": "user", "content": "Say hello from AISIX." } ] }' ``` 成功响应使用 Anthropic Messages 格式。请求中的 `model` 值是 AISIX 模型别名,不一定是上游服务提供方模型 ID。 ## 选择上游路径[​](#选择上游路径 "选择上游路径的直接链接") 与其它 AISIX 代理 API 一样,`/v1/messages` 让客户端请求格式在上游服务提供方变化时保持稳定。对于 Anthropic 风格请求,上游选择很重要,因为原生 Anthropic 协议路由会比转换后的上游保留更多 Anthropic 专属行为。 | 上游路径 | 能提供什么 | 适用场景 | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | 原生 Anthropic 协议路由 | 原生 Anthropic 请求和响应行为,同时由 AISIX 处理调用方 API Key、服务提供方密钥和模型别名。包括使用 `anthropic` 适配器的服务提供方密钥,以及声明了 [`apis.messages`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#declare-the-api-surfaces)的密钥。 | 应用依赖思考块、图片块、缓存控制或精确工具使用语义等 Anthropic 专属行为。 | | 转换后的上游 | 客户端侧保持 Anthropic 风格,AISIX 背后接入非 Anthropic 上游。 | 应用需要保持 Anthropic 风格客户端,同时由 AISIX 将流量路由到另一个受支持服务提供方协议族。 | 转换路径端到端支持文本、视觉和工具调用流程。`text`、`image`(base64 和 URL)以及 `document` 块会转换为上游线路上的多模态内容部分。assistant 的 `tool_use` 历史会变成上游工具调用,`tool_result` 块会变成上游期望的工具响应轮次,因此多轮工具循环能够跨服务提供方保留历史。 `thinking` 和 `redacted_thinking` 历史块在转换时会被丢弃,因为其他厂商无法重放 Anthropic 的签名推理块。当应用依赖这些推理块或其他服务提供方专属请求字段时,建议优先使用原生 Anthropic 协议路由。 ### Anthropic 归属标识行[​](#anthropic-attribution-line "Anthropic 归属标识行的直接链接") Anthropic 自家的客户端(包括 Claude Code)会在系统提示词最前面加上一行归属标识。它以 `x-anthropic-billing-header:` 开头,携带的是只有 Anthropic 自己的 API 才会读取的计费和遥测元数据。只要解析出的目标不是 Anthropic 自己的 API,AISIX 就会在构造上游请求之前移除这一行。 这一行位于系统提示词的最开头,而且在部分部署中它的取值会逐个请求变化。把它转发给其他服务提供方,就会改变每个提示词的前缀,从而让该服务提供方的提示词缓存在整段会话中全部失效:本应命中缓存并且命中量逐轮增长的会话,每一轮都只会报告 0 个缓存 Token。而这一行对该服务提供方毫无意义,因此 AISIX 会将其丢弃。 客户端发送: ``` { "system": [ { "type": "text", "text": "x-anthropic-billing-header: cc_entrypoint=cli; cch=7f3a91" }, { "type": "text", "text": "你是一个乐于助人的助手。", "cache_control": { "type": "ephemeral" } } ] } ``` AISIX 用剩下的内容构造上游请求: ``` { "system": [ { "type": "text", "text": "你是一个乐于助人的助手。", "cache_control": { "type": "ephemeral" } } ] } ``` Anthropic 协议的上游会原样收到这个 `system` 字段。在转换路径上,AISIX 随后会把它转换成上游协议族自己使用的系统字段或系统消息,与转换其他请求内容的方式一致。 * 只移除这一行,而不是移除承载它的容器。同一个块中跟在它后面的文本会被保留,该块的 `cache_control` 标记也会保留。被移空的块会被删除;`system` 若因此没有任何内容,则整个字段不会出现在上游请求中。`system` 的纯字符串形态按同样规则处理。 * 匹配依据是开头的 `x-anthropic-billing-header:` 标记,忽略前导空白并且不区分大小写。 * `messages` 永远不会被改动。如果调用方在会话内容中引用了这一行,它仍会照常发往上游——在那里移除它会改变提问本身的含义。 * 豁免范围很窄:只有当目标模型的 `provider` 为 `anthropic`**并且**其服务提供方密钥以原生方式访问 Anthropic API 时,这一行才会被保留。其余情况一律适用:转换路径、通过 `byo` + `anthropic` 适配器或通过声明了 `apis.messages` 的服务提供方密钥接入的第三方 Anthropic 兼容服务提供方,以及 Bedrock、Vertex AI 和 Azure OpenAI 平台适配器——平台密钥即使配在 `provider: anthropic` 之下,同样会被移除这一行。指向 Anthropic 官方 API 的 `byo` 密钥也不在豁免之列,因为豁免判断读取的是模型的 `provider` 取值。 * `POST /v1/messages/count_tokens` 采用同样的移除逻辑,因此它返回的计数就是 `/v1/messages` 实际发送的请求体所对应的计数。 该行为没有任何配置项。 ### 转换路径上的请求字段[​](#转换路径上的请求字段 "转换路径上的请求字段的直接链接") 当服务提供方密钥没有选择原生 Anthropic 协议路由时,AISIX 会将 Anthropic 请求字段改写为上游协议族期望的形态,而不是原样转发: | Anthropic 字段 | 转换行为 | | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tools`, `tool_choice` | 转换为 OpenAI 工具调用形态。 | | `stop_sequences` | 作为 `stop` 发送。 | | `metadata.user_id` | 作为 `user` 发送。 | | `thinking`、`output_config.effort` | 映射为 `reasoning_effort`。解析顺序以及 AISIX 转发哪些档位,见[推理力度](#reasoning-effort)。 | | `output_format`、`output_config.format` | `json_schema` 块会以 OpenAI 的 `json_schema` 形式作为 `response_format` 发送,并启用严格模式。严格模式要求 schema 中的每个对象都封闭其属性,因此 AISIX 会在每一层对象上加入 `additionalProperties: false`,并把所有已声明的属性列入 `required`。其他形状一律丢弃。请求同时携带这两个字段时,以 `output_format` 为准。 | | `context_management`, `top_k`, `mcp_servers`, `container`, `service_tier`, `betas` 以及其他 Anthropic 专属字段 | 丢弃。直接转发会让兼容 OpenAI 的上游因未知参数失败;丢弃后,较新的 Anthropic SDK 增加字段时请求仍能继续工作。 | 原生 Anthropic 协议路由不会经过这层转换,因此每个 Anthropic 字段在该路径上都保持原生行为。AISIX 仍然会把 `model` 别名改写为上游模型 ID;在目标不是 Anthropic 自己的 API 时移除 [Anthropic 归属标识行](#anthropic-attribution-line)中描述的那一行;应用模型上配置的[推理力度映射](https://docs.apiseven.com/ai-gateway/models/reasoning-effort-mapping.md);以及应用服务提供方密钥上配置的 `request` 覆盖设置。其余字段都按客户端发送的原样发往上游。 #### 推理力度[​](#reasoning-effort "推理力度的直接链接") Anthropic 请求可以在两个位置携带推理深度。`output_config.effort` 是当前的控制字段,也是 Claude Opus 4.7 及以后的模型唯一接受的字段;`thinking.budget_tokens` 是更早的字段,在 Claude Opus 4.6 上已废弃。兼容 OpenAI 的上游只有 `reasoning_effort` 一个字段承载两者,因此 AISIX 按以下顺序解析: 1. `thinking.type: disabled` 发送 `reasoning_effort: none`。显式关闭推理是比深度档位更强的指令,同时出现的 `output_config.effort` 不会覆盖它。 2. `output_config.effort` 原档位发送为 `reasoning_effort`。 3. `thinking.type: enabled` 按 `budget_tokens` 映射档位:`0-1023` 为 minimal,`1024-2047` 为 low,`2048-4095` 为 medium,`4096` 及以上为 high。 4. `thinking.type: adaptive` 且未指定 `output_config.effort` 时发送 `reasoning_effort: high`,这也是请求省略 effort 时 Anthropic 自身采用的档位。 AISIX 按请求所要求的档位转发,不会拿它和上游模型的能力做校验。Anthropic 模型接受 `max`、`xhigh` 等档位,而许多兼容 OpenAI 的模型并不接受,上游不接受某个档位时会拒绝该请求。这个拒绝是有意为之:替换成上游恰好能接受的档位,会悄悄改变应用所要求的推理深度,而这比一个报错难发现得多。请选择上游模型支持的档位,具体范围以该服务提供方自己的文档为准。 完全不支持推理的上游模型会拒绝 `reasoning_effort` 字段本身,因此 thinking 和 effort 字段只应发送给具备推理能力的模型。 流式与非流式请求使用同一套转换逻辑。 ## 路由行为[​](#路由行为 "路由行为的直接链接") `/v1/messages` 可以使用直接和路由模型别名。非流式请求在遇到可重试上游失败时,可以故障转移到下一个目标。 流式请求可以在 AISIX 向客户端发送响应字节之前执行故障转移。客户端可见的流开始后,AISIX 不会切换目标。通用流式行为请参见[流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md)。 `POST /v1/messages/count_tokens` 使用同一个 AISIX 调用方 API Key,并接受 Anthropic Token 计数请求格式。该路由只使用服务提供方密钥采用 `anthropic` 适配器或声明了 `apis.messages` 的目标。一项声明同时覆盖两条 Messages 路由,因此请确认上游也实现了 `/v1/messages/count_tokens`;否则,请为 `/v1/messages` 使用转换后的模型,或通过透传路由访问服务提供方的原生 Messages API。如果没有可用的原生 Anthropic 协议目标,AISIX 会拒绝请求。 ## 处理错误[​](#handle-errors "处理错误的直接链接") Messages 路由会以 Anthropic 风格信封返回错误。错误类型遵循与 Anthropic SDK 兼容的状态映射,因此 Anthropic 客户端可以用处理服务提供方错误的同一路径解析网关生成的错误。 原生 Anthropic 上游错误可能包含 `request_id`。AISIX 不会为网关生成的 Anthropic 风格错误添加该字段。 当输出安全护栏保留流式输出时,缓冲区中 AISIX 无法解析的帧会被丢弃,而不是未经扫描就放行。如果因此没有任何内容可返回,响应会以一个终止性 SSE `error` 事件结束。该事件和这条路由上的其他错误一样使用 Anthropic 信封。因此它携带的是 Anthropic 合法的 `error.type` 且没有 `code` 字段,而不是 OpenAI 风格路由会返回的 `content_filter`。原因写在消息里。参见 [AISIX 无法扫描的帧](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#frames-aisix-cannot-scan)和[安全护栏拒绝](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md#guardrail-refusals)。 完整错误和响应头参考请参见[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md)。服务提供方定义的错误类型请参见 Anthropic 的[错误文档](https://docs.anthropic.com/en/api/errors)。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 Anthropic 风格客户端如何调用 AISIX。当应用依赖相关行为时,请继续阅读[流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md)、[工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md)或[代理错误与重试](https://docs.apiseven.com/ai-gateway/routing/proxy-errors-and-retries.md)。 --- # 语音与音频 应用可以通过音频转录或翻译录制的语音、生成语音输出、在一次模型轮次中加入音频,或维持实时对话。这些工作流需要不同的请求和交付模型。 AISIX 为每种工作流提供独立接口。对于所有这些接口,网关都会认证调用方、解析模型别名、应用该接口所支持的访问限制和限流,并记录请求遥测。 ## 选择音频接口[​](#choose-an-audio-interface "选择音频接口的直接链接") 请根据应用交互方式选择接口: | 需求 | 使用的接口 | | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | 转录或翻译已录制的音频文件 | `POST /v1/audio/transcriptions` 或 `POST /v1/audio/translations` | | 从文本生成独立语音文件或音频流 | `POST /v1/audio/speech` | | 在一条聊天消息中发送录音,或在完整聊天响应中接收生成的音频 | [`POST /v1/chat/completions`](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md) | | 建立交互式双向 WebSocket 音频会话 | [`GET /v1/realtime`](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md) | 本页其余部分介绍用于转录、翻译和语音生成的独立 `/v1/audio/*` 路由。 AISIX 会解析面向调用方的模型别名,执行访问检查和受支持的文本安全护栏,再将请求转发到支持相同音频路由的上游。它会保留端点专属的请求和响应结构,而不会将其转换为聊天风格格式。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由支持目标音频路由的服务提供方和模型支撑的模型别名。 导出示例使用的网关连接和调用方 API Key: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" ``` ## 发送转录请求[​](#发送转录请求 "发送转录请求的直接链接") 转录请求使用 `multipart/form-data` 上传,而不是 JSON 请求体。请在 `file` 字段中发送音频文件,并在 `model` 字段中发送 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/audio/transcriptions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -F "file=@meeting.wav" \ -F "model=transcribe-prod" ``` 请求成功时,上游会返回转录文本: ``` { "text": "The quick brown fox jumps over the lazy dog." } ``` AISIX 会使用上游模型 ID 重建 multipart form,并保留其余字段。配置的输入安全护栏可以在 AISIX 将表单发送到上游前,阻断或屏蔽携带文本的 `prompt` 字段。 如果要把非英语语音翻译为英语文本,请将同一表单发送到 `/v1/audio/translations`。 ### 选择响应格式[​](#选择响应格式 "选择响应格式的直接链接") 可选的 `response_format` 字段用于选择转录文本的表示形式。对于成功请求,除非配置的输出安全护栏阻断或屏蔽了转录文本,否则 AISIX 会保留上游响应体及其内容类型。因此在安全护栏未更改响应时,请求的表示形式会保持不变: | `response_format` | 响应内容类型 | 响应体 | | ----------------- | ------------------ | ---------------------------------------------------- | | `json`(默认) | `application/json` | `{"text": "..."}` | | `verbose_json` | `application/json` | 转录文本以及 `duration`、`language` 和各分段时间信息 | | `text` | `text/plain` | 仅包含转录文本 | | `srt` | `text/plain` | 包含提示时间的 SubRip 字幕 | | `vtt` | `text/plain` | 包含提示时间的 WebVTT 字幕 | 请根据内容类型处理转录响应,不要假定响应一定是 JSON。只有 `json` 和 `verbose_json` 会生成 JSON 响应体: ``` curl -sS -X POST "${AISIX_PROXY}/v1/audio/transcriptions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -F "file=@meeting.wav" \ -F "model=transcribe-prod" \ -F "response_format=srt" ``` 格式支持取决于上游模型,而不是 AISIX。如果模型拒绝某种格式,请检查 AISIX 返回的错误以及服务提供方的模型文档。不要依赖错误响应体与上游响应逐字节完全一致。 ### 转录流式传输[​](#transcription-streaming "转录流式传输的直接链接") 部分转录模型接受 `stream=true` 并返回服务器发送事件。AISIX 会在上游产生这些事件的同时转发它们,因此客户端可以逐步收到转录文本,而不必等待整个请求结束。转发的事件与上游原样一致,AISIX 在事件流经时从最终事件中读取用量。 例外情况是能够阻断或脱敏转录文本的输出安全护栏。这类护栏必须在任何内容到达调用方之前检查完整的转录文本,因此 AISIX 会先缓冲响应、完成检查,然后放行或阻断——与非流式请求获得的保护完全相同。监控模式下的护栏永远不会阻断,因此也不会缓冲响应,它会在流结束后再观察转录文本。 流式支持取决于具体模型。例如,OpenAI 的[文件转录指南](https://developers.openai.com/api/docs/guides/speech-to-text#streaming-transcriptions)使用 `gpt-transcribe` 模型进行流式传输,而[官方 SDK 规范](https://github.com/openai/openai-python/blob/main/src/openai/types/audio/transcription_create_params.py)指出 `whisper-1` 会忽略 `stream`。依赖流式转录事件前,请先检查上游模型文档。 ## 发送语音请求[​](#发送语音请求 "发送语音请求的直接链接") 通过网关代理发送语音生成请求,并在请求体中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/audio/speech" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "tts-prod", "input": "Hello from AISIX.", "voice": "alloy" }' \ --output aisix-speech.mp3 ``` 请求成功时,输出文件应包含上游服务提供方返回的音频字节。请将响应作为二进制文件处理,而不是聊天风格 JSON 响应。AISIX 会在服务提供方生成音频的同时转发,因此播放该响应的客户端可以从最初的字节开始播放,而不必等待整个文件。 检查文件是否已写入为音频输出: ``` file aisix-speech.mp3 ``` 你应看到表明该文件为音频的输出。具体文字取决于操作系统和上游响应格式: ``` aisix-speech.mp3: MPEG ADTS, layer III, v2, 160 kbps, 24 kHz, Monaural ``` ## 音频端点行为[​](#音频端点行为 "音频端点行为的直接链接") 不同音频端点不一定使用相同请求或响应形态: | 端点 | 请求体 | 响应体 | | ---- | ------------------------------------------- | ------------------------------------------- | | 转录 | 包含音频文件和模型别名的 multipart form | 采用请求的 `response_format` 的上游转录结果 | | 翻译 | 包含音频文件和模型别名的 multipart form | 采用请求的 `response_format` 的上游翻译结果 | | 语音 | 包含模型别名、文本输入和 voice 的 JSON body | 二进制音频字节 | 对于转录和翻译请求,AISIX 会在转发前使用上游模型 ID 重建 multipart form。其它表单字段会被保留,包括上传文件名和内容类型(如果存在)。 对于语音请求,AISIX 会改写 JSON body 中的 model 字段,并将其余请求字段转发给上游服务提供方。 对于成功请求,除非转录文本安全护栏更改或阻断了输出,否则网关会保留上游响应体和内容类型。客户端应根据请求的 `response_format` 处理转录和翻译响应,并将语音响应作为二进制音频输出处理。 ## 服务提供方支持[​](#服务提供方支持 "服务提供方支持的直接链接") 音频支持取决于解析出的服务提供方和模型。AISIX 不会在不同服务提供方族之间转换音频格式。 请将这些路由用于暴露匹配 OpenAI 风格音频端点的上游。如果上游不支持请求的音频路由,该失败通常是服务提供方能力或 base URL 问题,而不是调用方认证问题。 ## 用量与安全护栏行为[​](#usage-and-guardrail-behavior "用量与安全护栏行为的直接链接") 成功的音频请求会归因到网关用量事件中。只有当上游响应包含可识别的 Token 用量时,才会填充 Token 计数。 转录和翻译请求还可以上报音频时长。AISIX 会从受支持的上游响应中读取时长,必要时则测量上传文件。这样,AISIX Cloud 可以为按时长而不是按 Token 计费的模型定价,包括使用非 JSON `response_format` 的请求。请在[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)中设置费率。语音请求不会上报音频时长,因此 AISIX 时长定价不适用于这类请求。 输入安全护栏可以在 AISIX 调用服务提供方前检查、阻断或屏蔽语音请求的 `input` 文本,以及转录和翻译请求中可选的 `prompt` 字段。输出安全护栏可以检查、阻断或屏蔽转录文本。如果输出安全护栏阻断了转录文本,AISIX 仍会记录已计费用量,因为上游已经处理了音频。 上传的音频字节和生成的语音字节不会作为文本扫描。 ## 排查音频请求[​](#troubleshoot-audio-requests "排查音频请求的直接链接") 如果语音请求成功但客户端期望 JSON,请调整响应处理逻辑。语音端点返回的是音频字节。 如果转录或翻译请求从 AISIX 或上游返回 400,请检查 multipart form 构造。请求必须包含 model 字段和预期的音频文件字段。 如果语音安全护栏没有阻断请求,请检查请求文本。语音安全护栏检查的是输入文本,而不是生成后的音频字节。 如果请求的转录格式失败,请确认解析出的服务提供方和模型支持该格式。如果流式转录事件只在请求完成后到达,请检查该模型是否挂载了会阻断或脱敏转录文本的输出安全护栏——这类护栏按设计会缓冲响应;同时还应确认上游模型支持 `stream=true`。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 AISIX 如何转发独立的 OpenAI 风格音频请求,以及音频响应处理与 JSON 代理路由的差异。 如需在聊天轮次中发送或接收音频,请参阅[使用 Chat Completions 输入和输出音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md)。如需交互式语音会话,请参阅 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md)。当需要访问 AISIX 尚未直接建模的服务提供方原生路由时,请继续阅读[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 --- # Batch、Files 与 Fine-tuning AISIX AI 网关将兼容 OpenAI 的 Files、Batch 和 Fine-tuning API 作为一等代理路由暴露。客户端继续使用标准 OpenAI SDK 调用,由网关负责调用方认证、服务提供方凭证和已完成批处理的用量归因。 本指南将演示如何上传批处理输入文件、创建和跟踪批处理任务,并了解网关如何把每次调用路由到正确的服务提供方。 ## 支持的代理路由[​](#支持的代理路由 "支持的代理路由的直接链接") | 类型 | 路由 | | ----------- | --------------------------------------------------------------------------------------------------------------------------------- | | Files | `POST /v1/files`、`GET /v1/files`、`GET /v1/files/{id}`、`DELETE /v1/files/{id}`、`GET /v1/files/{id}/content` | | Batch | `POST /v1/batches`、`GET /v1/batches`、`GET /v1/batches/{id}`、`POST /v1/batches/{id}/cancel` | | Fine-tuning | `POST /v1/fine_tuning/jobs`、`GET /v1/fine_tuning/jobs`、`GET /v1/fine_tuning/jobs/{id}`、`POST /v1/fine_tuning/jobs/{id}/cancel` | 目前支持兼容 OpenAI 的服务提供方(适配器为 `openai`,包括自定义 `api_base` 部署)和 Azure OpenAI(适配器为 `azure-openai`,使用资源作用域路由和 `api-key` 认证)。Vertex AI、Bedrock 和 Anthropic 原生批处理流程使用不同的传输协议和存储模型,暂不通过这些路由提供。 ## 前提条件[​](#前提条件 "前提条件的直接链接") 开始前请准备: * 一个可处理代理请求的 AISIX 网关。 * 一个可访问目标模型别名的调用方 API Key。 * 一个由兼容 OpenAI 或 Azure OpenAI 服务提供方支持的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` ## AISIX 如何路由 Files 和 Jobs[​](#aisix-如何路由-files-和-jobs "AISIX 如何路由 Files 和 Jobs的直接链接") 创建批处理任务时,请求引用的是之前上传的文件 ID,请求体中没有可供网关路由的 `model` 字段,因此 AISIX 使用网关编码的资源 ID: 1. 上传文件时,通过 `model` multipart 字段、`?model=` 查询参数或 `x-aisix-model` 请求头指定一次路由模型。 2. 网关返回的文件 ID(`aisix-…`)会编码该模型。之后任何引用这个 ID 的调用都会自动路由,包括创建批处理、查询或下载文件、Fine-tuning 的 `training_file`。 3. 创建和查询响应返回的 ID(批处理 ID、输出文件 ID、Fine-tuning 任务 ID)也使用相同方式编码,后续调用不需要额外提示。 原始服务提供方 ID 仍然可用:网关会依次回退到显式 `model` 查询参数或请求头,再回退到调用方 Key 可访问的第一个兼容 OpenAI 模型。生产流量建议显式传入模型,确保路由可预测。 ## 上传文件并运行批处理[​](#上传文件并运行批处理 "上传文件并运行批处理的直接链接") 通过网关上传批处理输入文件,并在请求中指定路由模型: ``` curl -sS -X POST "${AISIX_PROXY}/v1/files" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "x-aisix-model: ${AISIX_MODEL}" \ -F purpose=batch \ -F file=@batch-input.jsonl ``` 响应中的 `id` 以 `aisix-` 开头,并包含路由模型信息。使用该 ID 创建批处理任务: ``` curl -sS -X POST "${AISIX_PROXY}/v1/batches" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "input_file_id": "aisix-…", "endpoint": "/v1/chat/completions", "completion_window": "24h" }' ``` 使用创建请求返回的 batch ID 跟踪批处理: ``` curl -sS "${AISIX_PROXY}/v1/batches/aisix-…" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 批处理完成后,使用 batch 响应中的 `output_file_id` 下载结果文件: ``` curl -sS "${AISIX_PROXY}/v1/files/aisix-…/content" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 官方 OpenAI SDK 可以保持原有调用方式。将 `base_url` 指向网关,并在 `files.create` 请求头中传入路由提示。 ## Fine-tuning 任务[​](#fine-tuning-任务 "Fine-tuning 任务的直接链接") Fine-tuning 任务通过编码后的 `training_file` ID 路由。任务请求体中的 `model` 字段是服务提供方要微调的基础模型,会原样转发;它不是网关模型别名。返回的任务对象中的模型名称同样是服务提供方的基础模型,而不是网关别名:网关在任一方向上都不会转换该字段,因此任务对象中的值是服务提供方针对你所提交模型记录的内容: ``` curl -sS -X POST "${AISIX_PROXY}/v1/fine_tuning/jobs" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini-2024-07-18", "training_file": "aisix-…" }' ``` ## 用量与成本归因[​](#用量与成本归因 "用量与成本归因的直接链接") 文件和任务管理调用(例如上传、创建、列表和取消)会记录 0 Token 的用量事件,便于在日志中追踪。 当批处理查询首次观察到 `status: "completed"` 时,网关会下载批处理输出文件,并按服务提供方计费模型汇总每一行的 Token 用量。AISIX 随后会发出包含真实 Token 数的用量事件。这些事件使用确定性的请求 ID(`batch-`),因此重复查询或网关重启不会重复计量。 ## 网关策略行为[​](#网关策略行为 "网关策略行为的直接链接") 调用方 API Key 认证和模型访问列表、按模型的客户端 IP 限制以及限流适用于这一组的每条路由。匹配的 AISIX Cloud 预算同样适用。 安全护栏的覆盖范围有所不同。输入和输出扫描在 `/v1/batches` 和 `/v1/fine_tuning/jobs` 上运行,扫描调用方提交的 JSON 正文和服务提供方返回的 JSON,而不是任务引用的文件。五条 Files 路由在两个方向上都不运行安全护栏检查。上传和下载的文件会未经筛查直接中继,并且这一组路由不会筛查批处理任务处理的 JSONL 记录。参见 [Files 路由不做筛查](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#files-routes-are-not-screened)。 上游调用遵循模型的请求超时时间。模型启用冷却及其传输错误触发条件时,连接失败、请求超时和响应读取失败可使模型进入冷却;这些路由上的上游 HTTP 状态响应不会触发冷却。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经通过网关运行了文件上传、批处理和 Fine-tuning 任务。接下来可阅读[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),了解该接口面之外的服务提供方原生端点。 --- # 使用 Chat Completions 输入和输出音频 支持音频的聊天模型可以接收消息中的录制音频,并在同一个 Chat Completions 响应中返回生成的音频。这适合需要模型理解音频或以音频回答,同时保持兼容 OpenAI 的 `POST /v1/chat/completions` 请求形态的轮次式应用。 如需独立转录、翻译或语音生成,请使用[语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md)。如需交互式双向会话,请使用 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md)。 当所选上游使用兼容的 OpenAI 形态 API 时,AISIX 会保留 OpenAI 聊天音频请求和响应字段。它不会将这些字段转换为其他服务提供方的原生音频协议。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由支持音频的 Chat Completions 模型支撑的模型别名。其服务提供方密钥必须使用 `openai` 或 `azure-openai` 适配器,且上游必须实现 OpenAI 聊天音频请求和响应形态。 * 一个名为 `question.wav` 的本地 WAV 录音,用于音频输入示例。 * 示例所需的 `curl`、`jq`、Python 3,以及 `base64`、`file` 和 `tr` 命令行工具。 如果尚未配置上游,请参阅 [OpenAI](https://docs.apiseven.com/ai-gateway/providers/openai.md)、[Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md)或[自带端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)。选择上游当前支持的音频模型,并为其创建 AISIX 别名。 对于路由别名,每个符合条件的目标都必须使用上述适配器之一,并支持相同的聊天音频字段。如果故障转移到仅支持文本或形态不同的服务提供方,音频内容可能丢失,或请求可能在上游失败。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="audio-chat-prod" ``` ## 生成音频响应[​](#generate-an-audio-response "生成音频响应的直接链接") 同时请求文本和音频输出,然后保存完整响应: ``` curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "modalities": ["text", "audio"], "audio": { "voice": "alloy", "format": "wav" }, "messages": [ { "role": "user", "content": "Say: Your AISIX audio route is working." } ] }' > chat-audio-response.json ``` AISIX 会在分发前将别名替换为上游模型 ID。上游决定接受哪些声音和输出格式。 检查返回的音频元数据,但不打印 base64 载荷: ``` jq '{ model, audio: (.choices[0].message.audio | { id, transcript, expires_at, encoded_characters: (.data | length) }) }' chat-audio-response.json ``` 响应中的 `model` 会保持为 AISIX 别名。如果上游返回相应字段,`audio` 对象会包含服务提供方的音频标识、base64 数据、转录文本和过期时间戳。 使用 Python 标准库解码生成的 WAV 文件: ``` python3 - <<'PY' import base64 import json with open("chat-audio-response.json", encoding="utf-8") as response_file: response = json.load(response_file) audio = response["choices"][0]["message"]["audio"] with open("aisix-chat-audio.wav", "wb") as audio_file: audio_file.write(base64.b64decode(audio["data"])) print(audio.get("transcript", "")) PY file aisix-chat-audio.wav ``` 最后一条命令应将其识别为 WAV 文件。如果请求了其他格式,请使用匹配的文件名和媒体播放器。 ## 在消息中发送音频[​](#send-audio-in-a-message "在消息中发送音频的直接链接") 编码本地录音,并将其放入 `input_audio` 内容块。此示例要求模型以音频回答,以便使用与上一个请求相同的响应处理方式: ``` base64 < question.wav | tr -d '\n' | \ jq -Rs \ --arg model "$AISIX_MODEL" \ '{ model: $model, modalities: ["text", "audio"], audio: { voice: "alloy", format: "wav" }, messages: [ { role: "user", content: [ { type: "text", text: "Answer the question in this recording." }, { type: "input_audio", input_audio: { data: ., format: "wav" } } ] } ] }' > chat-audio-input.json curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ --data @chat-audio-input.json \ > chat-audio-response.json ``` AISIX 会通过兼容 OpenAI 的适配器原样转发带类型的内容块。它不会解码录音,也不会将其转换为其他服务提供方的音频输入形态。 ## 了解当前行为[​](#understand-current-behavior "了解当前行为的直接链接") 聊天音频使用普通 Chat Completions 的身份认证、模型访问、路由、重试和请求遥测路径。音频专属行为存在以下边界: * **使用非流式请求。** 省略 `stream` 或将其设为 `false`。AISIX 会在完整响应中保留 `message.audio`,但目前不会返回流式 `delta.audio` 分片。 * **保持服务提供方协议兼容。** `openai` 和 `azure-openai` 适配器会保留音频请求字段及非流式 `message.audio` 对象。其他适配器可能会将带类型的消息内容缩减为文本,且不会把音频字段转换为服务提供方原生语音 API。 * **区分文本与音频的安全护栏行为。** 输入安全护栏可以检查文本内容块,输出安全护栏可以检查普通的返回消息文本。它们不会检查 `input_audio` 中的字节、生成的音频数据,或嵌套在 `message.audio` 中的转录文本。 * **将 Cloud 音频成本视为上游细节。** AISIX 会记录上游报告的标准化提示词和补全总量,但不会保留单独的音频 Token 数。因此,AISIX Cloud 定价无法对同一个 Chat Completions 请求分别应用文本 Token 和音频 Token 费率。 音频以 base64 编码在 JSON 中,因此请求体和响应体会大于底层二进制文件。设置客户端、代理或负载均衡器的请求体和响应体大小限制时,请计入这部分膨胀。 ## 排查聊天音频问题[​](#troubleshoot-chat-audio "排查聊天音频问题的直接链接") 如果响应成功但没有 `message.audio`,请检查请求是否包含音频模态和 `audio` 对象,并确认上游模型支持通过 Chat Completions 输出音频。仅支持文本的模型可能接受 HTTP 请求,但会在上游拒绝或忽略不受支持的音频字段。 如果 AISIX 返回上游解码错误或服务提供方错误,请按照服务提供方文档中说明的请求格式直接调用同一个上游模型。更改网关策略前,请先确认模型 ID、声音、格式和音频输入编码。 如果请求在非流式模式下正常工作,但启用 `stream` 后不产生音频,请保持非流式请求。当应用需要增量双向音频时,请使用 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md)。 ## 下一步[​](#next-steps "下一步的直接链接") 你现在已经在兼容 OpenAI 的聊天请求中发送和接收音频。如需独立转录或语音合成,请继续阅读[语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md);如需交互式语音会话,请阅读 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md)。 --- # 向量嵌入 向量嵌入会把文本转换为向量,供应用用于语义搜索、检索流水线、聚类和相似度计算。AISIX AI 网关允许向量嵌入客户端继续使用 OpenAI 兼容的请求和响应格式,同时由网关管理调用方认证、模型别名、上游凭证和策略。 本指南将通过 AISIX 发送一次向量嵌入请求,并说明该端点需要关注的服务提供方行为。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由支持向量嵌入的服务提供方和模型支撑的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="text-embedding-prod" ``` ## 发送向量嵌入请求[​](#发送向量嵌入请求 "发送向量嵌入请求的直接链接") 通过网关代理发送向量嵌入请求,并在请求体中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/embeddings" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "input": [ "hello", "world" ] }' ``` AISIX 会解析模型别名、检查调用方 API Key、改写上游模型 ID,并将向量嵌入请求转发给服务提供方。 响应会保持 OpenAI 兼容的向量嵌入格式: ``` { "object": "list", "data": [ { "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, 0.0789] }, { "object": "embedding", "index": 1, "embedding": [0.0234, -0.0567, 0.0891] } ], "model": "text-embedding-prod", "usage": { "prompt_tokens": 2, "total_tokens": 2 } } ``` 向量值可能是浮点数组,也可能是 base64 字符串,具体取决于请求的编码格式和上游响应。 ## 服务提供方与请求行为[​](#服务提供方与请求行为 "服务提供方与请求行为的直接链接") Embeddings 路由接受 OpenAI 兼容的请求形态,并在需要时将其转换为服务提供方的原生 embeddings API: | 服务提供方协议族 | 上游 API | 说明 | | ------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | | OpenAI 兼容(适配器 `openai`) | `POST {api_base}/embeddings` | 以 OpenAI 形态转发,包括自定义 `api_base` 部署。 | | Vertex AI / Gemini(适配器 `vertex`) | google-publisher `:predict` | `dimensions` 映射为 `outputDimensionality`;每个输入的 Token 计数会汇总到用量中。 | | Bedrock(适配器 `bedrock`) | `InvokeModel` | `amazon.titan-embed-*`(每个输入一次调用;`dimensions` 仅在 V2 模型上支持)和 `cohere.embed-*`(整批一次调用)。 | | Anthropic | 不提供 embeddings API | 请求返回 501。 | AISIX 接受单个字符串或字符串数组形式的嵌入输入。转发到上游时会保留调用方的输入形态。调用方无需为单条输入和批量输入编写不同客户端逻辑。 输入安全护栏可以在 AISIX 调用服务提供方之前检查这些受支持输入形式中的文本。当前该网关路由不支持 Token 数组输入。 当上游返回 Token 用量时,网关会记录用量。该代理路径下,向量嵌入不会使用 completion Token、响应缓存、流式响应或输出安全护栏。 ## 排查向量嵌入[​](#排查向量嵌入 "排查向量嵌入的直接链接") 如果 AISIX 返回 501,表示解析出的服务提供方没有 embeddings API(例如 Anthropic)。请使用由上表中某个服务提供方协议族支撑的模型。 对于批量请求,响应应为每个输入项返回一个向量条目。如果返回的向量数量更少,请检查上游响应和网关日志,确认是否存在服务提供方专属的批处理行为。 如果输入安全护栏没有阻断请求,请检查输入是否包含可检查文本。AISIX 可以扫描单个字符串或字符串数组。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 AISIX 如何代理向量嵌入请求,以及服务提供方支持可能存在差异的位置。当应用需要对检索到的文档进行排序时,请继续阅读[重排序](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md)。 --- # 图像编辑 图像编辑允许应用通过 AISIX 发送源图片、可选蒙版和文本指令,并将调用方认证、模型别名、上游凭证和请求侧策略保留在同一条网关路径中。 AISIX 为使用 OpenAI 服务提供方配置的模型别名公开 OpenAI 的 multipart 图像编辑路由。`gpt-image-2` 等编辑模型会在同一个 `multipart/form-data` 请求体中接收图片、提示词和调节参数。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个配置服务提供方为 OpenAI、上游 `model_name` 为图像编辑模型(如 `gpt-image-2`)的模型别名。示例使用别名 `image-edit-prod`。 * 一张待编辑的源图片文件。示例使用 `original.png`。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="image-edit-prod" ``` ## 发送图像编辑请求[​](#发送图像编辑请求 "发送图像编辑请求的直接链接") 以 multipart 表单形式通过网关代理发送编辑请求,并在 `model` 字段中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/images/edits" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -F "model=${AISIX_MODEL}" \ -F "image=@original.png" \ -F "prompt=Add a red hat to the subject" \ -F "size=1024x1024" \ -o aisix-image-edit-response.json ``` AISIX 会解析模型别名、检查调用方 API Key,并对提示词执行受支持的输入策略检查。它把 `model` 表单字段替换为上游模型 ID,然后重建并转发 multipart 请求体。源图片和蒙版会保留其字节、文件名及各部分的顺序,其他所有字段都会原样转发。只有已配置的脱敏动作安全护栏规则可以修改提示词。 响应保持 OpenAI 图片格式。编辑模型返回 Base64 图片数据和一个 Token 用量块: ``` { "created": 1710000000, "data": [ { "b64_json": "..." } ], "usage": { "input_tokens": 50, "output_tokens": 1056, "total_tokens": 1106 } } ``` 检查响应中包含一条图片记录: ``` jq '.data | length' aisix-image-edit-response.json ``` 命令应输出: ``` 1 ``` ## 请求字段[​](#request-fields "请求字段的直接链接") 该路由只接受 `multipart/form-data`。JSON 请求体会返回网关错误信封中的 `400`。 | 字段 | 必填方 | 含义 | | -------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | | `model` | 网关 | AISIX 模型别名。AISIX 唯一必定改写的字段;配置了脱敏动作的安全护栏规则还可能改写 `prompt`。 | | `image` | 服务提供方 | 源图片文件。对于接受多张输入图片的模型,该字段可以重复出现;AISIX 会按原顺序转发每个部分,字节和文件名保持不变。 | | `prompt` | 服务提供方 | 编辑指令。输入安全护栏会在请求发往上游之前检查并可脱敏该文本。 | | `mask` | — | 可选的蒙版图片,其透明区域标记要编辑的范围。原样转发。 | 其余所有表单字段——`n`、`size`、`quality`、`background`、`input_fidelity`,以及服务提供方后续新增的任何参数——都会原样转发,因此上游新增参数不需要升级网关。未设置的字段不会出现在上游请求中。 备注 该路由不支持 `stream=true`。编辑模型可以用服务器发送事件流式返回部分图片,但 AISIX 尚未中继该数据流,因此会直接返回 `400`,而不是静默缓冲。 ## OpenAI 服务提供方要求[​](#openai-provider-requirement "OpenAI 服务提供方要求的直接链接") 图像编辑路由是服务提供方专属路由。只有当解析到的模型配置的服务提供方为 OpenAI 时,AISIX 才会接受请求。 这比使用兼容 OpenAI 的适配器更严格。一个兼容 OpenAI 的供应商可以在聊天补全路由上正常工作,但由于其配置的服务提供方不是 OpenAI,仍会在图像编辑路由上被拒绝。 当解析到的模型配置的服务提供方不是 OpenAI 时,AISIX 会在向上游发送任何内容之前返回 `400`。 上游 URL 的推导方式与其他 OpenAI 路由一致:未设置 `api_base` 时解析到标准 OpenAI API;`api_base` 为不带路径的主机时会在端点路径前追加 `/v1`。 ## 图像编辑行为[​](#image-editing-behavior "图像编辑行为的直接链接") 输入安全护栏会在 AISIX 调用服务提供方之前检查每一个 `prompt` 表单字段,脱敏动作规则会就地改写提示词文本。被阻断的提示词会在任何上游调用之前返回 `422`,且不占用模型限流容量。图片和蒙版字节不是可扫描文本,输出安全护栏也不会扫描生成后的图片字节。 提交会同时计入调用方 API Key 各层限流和模型限流。当上游响应包含 Token 用量块时——`gpt-image` 系列模型会返回——AISIX 会记录这些 Token 并计入基于 Token 的限流;不含用量块的响应按零 Token 记录。图片数量、尺寸和质量等按图片计费的细节不会在此代理路径中推断。 ## 错误[​](#errors "错误的直接链接") 失败会返回网关的 JSON 错误信封。服务提供方返回的 `4xx`——例如模型拒绝的 `size` 取值——会携带服务提供方自己的状态码和消息原样中继,不在下表范围内;下表只覆盖 AISIX 自身生成的状态码。 | 状态码 | 触发场景 | | ------ | ---------------------------------------------------------------------------------------------------------------------- | | `400` | 请求体不是有效的 `multipart/form-data`、缺少 `model` 字段、设置了 `stream=true`,或解析到的模型服务提供方不是 OpenAI。 | | `401` | 调用方 API Key 缺失或无效。 | | `403` | 调用方 API Key 无权使用该模型别名,或请求来自模型允许列表之外的客户端 IP。 | | `404` | 模型别名无法解析。 | | `413` | 请求体超过配置的请求体大小限制。 | | `422` | 输入安全护栏阻断了提示词。不会向服务提供方发送请求。 | | `429` | 限流或 AISIX Cloud 预算拒绝了该请求。 | | `502` | 服务提供方返回服务端错误、响应不是有效 JSON,或无法连接。 | | `504` | 服务提供方未在模型的请求超时时间内应答。 | ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经了解 AISIX 如何代理 OpenAI 图像编辑请求,以及 multipart 表单如何经过网关。接下来可以查看[图像生成](https://docs.apiseven.com/ai-gateway/endpoints/image-generation.md)了解提示词生成图片路由,或查看[语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md)了解其他 multipart 端点。 --- # 图像生成 图片生成允许应用通过 AISIX 发送提示词生成图片请求,并将调用方认证、模型别名、上游凭证和请求侧策略保留在同一条网关路径中。 AISIX 为配置服务提供方为 OpenAI 的模型别名暴露 OpenAI 图片生成路由。它会解析面向调用方的模型别名,只将 model 字段改写为上游模型 ID,并返回服务提供方的 JSON 图片响应。 本指南将通过 AISIX 发送图片生成请求,并说明该端点的服务提供方要求。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个配置服务提供方为 OpenAI,且适配器支持图片生成的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="image-prod" ``` ## 发送图像请求[​](#发送图像请求 "发送图像请求的直接链接") 通过网关代理发送图片生成请求,并在请求体中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/images/generations" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "prompt": "A minimal illustration of an AI gateway" }' \ -o aisix-image-response.json ``` AISIX 会解析模型别名、检查调用方 API Key、对提示词执行受支持的输入策略检查,只将 model 字段改写为上游模型 ID,并将请求转发到上游图片生成端点。 响应保持 OpenAI 图片生成格式: ``` { "created": 1710000000, "data": [ { "url": "https://example.com/generated-image.png" } ] } ``` 某些 OpenAI 图片模型会根据请求和上游模型行为返回 base64 图片数据,而不是 URL。 检查响应是否包含一个图片条目: ``` jq '.data | length' aisix-image-response.json ``` 命令应输出: ``` 1 ``` 备注 该路由不支持 `stream: true`。图像模型可以用服务器发送事件流式返回部分图片,但 AISIX 尚未中继该数据流,因此会在联系服务提供方之前直接返回 `400`,而不是静默缓冲: ``` { "error": { "message": "request payload is invalid: `stream` is not supported on /v1/images/generations", "type": "invalid_request_error" } } ``` 设置 `stream: false` 或未包含 `stream` 字段的请求不受影响,仍按原有方式转发。 ## OpenAI 服务提供方要求[​](#openai-服务提供方要求 "OpenAI 服务提供方要求的直接链接") 图像生成路由与服务提供方强相关。只有当解析出的模型配置为 OpenAI 服务提供方时,AISIX 才会接受该请求。 这比使用 OpenAI 兼容适配器更严格。某个 OpenAI 兼容厂商可能可以用于 Chat Completions 路由,但仍会在图像生成路由被拒绝,因为其配置的服务提供方不是 OpenAI。 当解析出的模型没有配置为 OpenAI 服务提供方时,AISIX 会在发送到上游前返回 400。 如果解析出的 OpenAI 服务提供方桥接未实现图像生成,AISIX 会返回 501。这是服务提供方能力问题,不是调用方认证问题。 ## 图像生成行为[​](#图像生成行为 "图像生成行为的直接链��接") 输入安全护栏可以在 AISIX 调用服务提供方之前检查提示词。输出安全护栏不会扫描生成后的图片字节。 当上游图像响应包含可识别的 Token 用量时,AISIX 会记录该用量。有些图像模型不会返回 Token 用量,这类成功请求仍会以零 Token 计数显示;但该代理路径不会推断图片数量、尺寸、质量等单图成本细节。 如果安全护栏没有阻断请求,请检查提示词文本是否包含已配置安全护栏可以检查的内容。生成后的图片字节不会被输出安全护栏检查。 如果请求返回 400,请检查请求是否设置了 `stream: true`,以及解析出的模型是否配置为 OpenAI 服务提供方。如果请求返回 501,请检查解析出的 OpenAI 服务提供方桥接是否支持图像生成。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 AISIX 如何代理 OpenAI 图像生成请求,以及为什么该能力对服务提供方支持保持较窄范围。接下来可以阅读[图像编辑](https://docs.apiseven.com/ai-gateway/endpoints/image-editing.md),在同一条网关路径上编辑图片;或阅读[语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md),了解音频请求通过 AISIX 时的行为。 --- # OpenAI 客户端接入 Anthropic 上游 AISIX 允许应用继续使用 OpenAI Chat Completions 请求格式,同时由网关调用 Anthropic 上游模型。当应用代码已经围绕兼容 OpenAI 的 SDK 构建,但平台团队希望把这类流量路由到 Claude 时,可以使用这一模式。 AISIX 会解析模型别名,将请求转换为 Anthropic Messages 格式,使用已保存的服务提供方凭证调用 Anthropic,并把响应转换回兼容 OpenAI 的 Chat Completions 格式。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个由 Anthropic 支持,且接受兼容 OpenAI 的 Chat Completions 请求的模型别名。 * 一个有权使用该模型别名的调用方 API Key。 * 如需运行 SDK 示例,请准备 Node.js 20 LTS 或更新版本以及 `npm`;如需运行 HTTP 示例,请准备 `curl`。 如果尚未配置模型别名和调用方 API Key,请按照 [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md) 文档为 AISIX Cloud 或开源 AISIX 网关完成配置。 ## 请求流程[​](#请求流程 "请求流程的直接链接") 应用继续保持兼容 OpenAI 的客户端契约。服务提供方选择和协议转换都留在网关中完成。 应用将模型别名和调用方 API Key 发送到 AISIX。网关会解析上游模型、提供已保存的 Anthropic 凭证,并转换请求和响应。应用仍然发送和接收兼容 OpenAI 的数据。 ## 调用模型别名[​](#调用模型别名 "调用模型别名的直接链接") 导出两个请求示例都会用到的调用方 API Key 和模型别名: ``` export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="claude-sonnet-prod" ``` ### OpenAI SDK[​](#openai-sdk "OpenAI SDK的直接链接") 安装 OpenAI SDK: ``` npm install openai ``` 设置兼容 OpenAI 的基础 URL。OpenAI SDK 要求 URL 中包含 `/v1` 路径: ``` # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" ``` 创建一个最小化 Chat Completions 客户端: anthropic-via-openai-sdk.mjs ``` import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.AISIX_API_KEY, baseURL: process.env.AISIX_BASE_URL, }); const completion = await client.chat.completions.create({ model: process.env.AISIX_MODEL, messages: [{ role: "user", content: "Say hello from AISIX." }], }); console.log(completion.choices[0]?.message.content); console.log(completion.usage); ``` 在已设置 AISIX 相关值的 Shell 中运行示例: ``` node anthropic-via-openai-sdk.mjs ``` ### HTTP[​](#http "HTTP的直接链接") 如需在不使用 SDK 的情况下查看响应,请导出网关源站地址,并使用 curl 发送相同的请求: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 发送请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "'"$AISIX_MODEL"'", "messages": [{"role":"user","content":"Say hello from AISIX."}] }' ``` 两个示例都会返回兼容 OpenAI 的 Chat Completions 结构。调用方不会收到 Anthropic 风格的内容块: ``` { "object": "chat.completion", "model": "claude-sonnet-prod", "choices": [ { "message": { "role": "assistant", "content": "Hello from AISIX." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 9, "completion_tokens": 5, "total_tokens": 14 } } ``` ## 转换行为[​](#转换行为 "转换行为的直接链接") 协议转换会保留常见聊天应用所依赖的兼容 OpenAI 契约: | 行为 | AISIX 的处理方式 | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 模型与身份验证 | 将模型别名解析到已配置的 Anthropic 模型,对调用方进行身份验证,并使用已保存的服务提供方凭证发送上游请求。 | | 消息与工具 | 将开头的系统消息、用户和助手消息、函数工具、工具调用及工具结果映射为 Anthropic Messages 结构。 | | 响应 | 将 Anthropic 文本和工具使用内容块、停止原因、Token 用量及流式事件转换回兼容 OpenAI 的字段。 | | 输出长度限制 | 当兼容 OpenAI 的请求未指定输出长度限制时,自动提供 `max_tokens: 4096`,因为 Anthropic 要求必须设置这一字段。 | | 推理力度 | 将 `reasoning_effort` 发送为 Anthropic 当前的深度控制字段 `output_config.effort`。`minimal` 映射为 Anthropic 的下限档位 `low`;`none` 则转为 `thinking: {"type": "disabled"}`,因为 Anthropic 没有 `none` 这一档。其余情况下 AISIX 不会额外添加 `thinking` 块:请求要的是深度而不是思考模式,当前的 Anthropic 模型会采用自己的默认模式。取值不在上述集合内时该设置整体丢弃:它对应不到任何已知的 Anthropic 档位,而原字段本身也无法代为转发,因为 `/v1/messages` 会拒绝未知的顶层字段。请求自己携带的 `output_config` 或 `thinking` 保持原样,并优先于该转换。 | 警告 当 OpenAI Chat Completions 消息使用带类型的内容部分时,Anthropic 转换会保留文本部分,但会丢弃图片和音频等非文本部分。如果必须将图片或文档内容发送到 Anthropic 上游,请使用 Anthropic 风格的 `/v1/messages` 路由。 如需了解完整的工具调用循环,请参阅[工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md)。AISIX 还可以为符合条件的 Chat Completions 请求添加 Anthropic Prompt Cache 标记;请参阅 [Anthropic Prompt Caching](https://docs.apiseven.com/ai-gateway/traffic-controls/prompt-caching.md)。 当应用必须保持 Anthropic 请求和响应格式,特别是使用服务提供方专属内容或 thinking blocks 时,请使用 Anthropic 风格的 `/v1/messages` 路由。有关原生客户端契约及其兼容性边界,请参阅 [Anthropic 风格的 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)。 ### Token 用量[​](#token-usage "Token 用量的直接链接") Anthropic 与 OpenAI 对 Prompt Cache Token 的计数方式不同,因此 AISIX 会转换这些计数,而不是原样透传。Anthropic 的 `input_tokens` 表示**未命中缓存**的输入,`cache_creation_input_tokens` 和 `cache_read_input_tokens` 是与之并列的独立计数器。OpenAI 的口径只有一个 `prompt_tokens`,它**已经包含**缓存命中的部分,并通过 `prompt_tokens_details.cached_tokens` 标明。OpenAI 完全没有缓存写入这一概念,因此 AISIX 把写入也折进 `prompt_tokens`(它属于计费输入),并与命中并列单独报告。 上游返回以下用量时: ``` { "usage": { "input_tokens": 40, "output_tokens": 10, "cache_creation_input_tokens": 30, "cache_read_input_tokens": 70 } } ``` 兼容 OpenAI 的调用方会收到: ``` { "usage": { "prompt_tokens": 140, "completion_tokens": 10, "total_tokens": 150, "prompt_tokens_details": { "cached_tokens": 70, "cache_creation_tokens": 30 } } } ``` 调用方可以依赖以下规则: * `prompt_tokens` 是模型读取的完整输入,包含缓存读取和缓存写入。 * `total_tokens` 等于 `prompt_tokens + completion_tokens`。 * `cached_tokens` 是 `prompt_tokens` 的子集,只统计缓存**读取**。 * `cache_creation_tokens` 是缓存**写入**,同样是 `prompt_tokens` 的子集。它属于计费输入但不是缓存命中,因此单独报告而不计入 `cached_tokens`。OpenAI 没有缓存写入这一概念,所以该字段仅在上游报告了写入时出现——这一点很重要,因为服务提供方对写入的计费通常高于普通输入。在缓存会话的第一轮(只写不读)中,它是唯一能表明缓存参与了本次请求的信号。 流式响应,以及经由 Anthropic 上游的 [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md),都适用同样的转换。 日志、指标和消费统计不做转换:它们保留 Anthropic 自身的计数器,因此同一次调用无论用哪种协议发起,成本都相同。记录侧的口径请参阅 [Anthropic Prompt Caching](https://docs.apiseven.com/ai-gateway/traffic-controls/prompt-caching.md)。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经将兼容 OpenAI 的客户端路由到 Anthropic 上游。请参阅[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)了解面向调用方的路由行为。当你希望端到端使用 Anthropic 请求和响应结构时,请参阅 [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md);如需了解端点与服务提供方支持边界,请查看[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 --- # 兼容 OpenAI 的 Chat Completions 采用 OpenAI Chat Completions 格式的应用可以将同样受支持的请求形态发送到 AISIX 网关的 `POST /v1/chat/completions`。网关会认证调用方、解析模型别名、应用网关策略,并通过所选服务提供方适配器分发请求。 这种兼容性面向客户端:上游既可以是 OpenAI,也可以是其他受支持的服务提供方。网关会返回受支持的 OpenAI 兼容响应形态,而适配器负责服务提供方协议转换。 本指南说明 Chat Completions 的代理行为。可运行的 SDK 配置请参见 [OpenAI SDK](https://docs.apiseven.com/ai-gateway/getting-started/openai-sdk.md)。 ## 客户端发送的内容[​](#客户端发送的内容 "客户端发送的内容的直接链接") 客户端会发送三个面向网关的值: * base URL 是 AISIX 代理 API 根路径,即网关 Origin 后跟 `/v1`。 * API Key 是 AISIX 调用方 API Key。 * model 值是 AISIX 模型别名,例如 `gpt-4o-prod`。 请求体保持 OpenAI 兼容格式,包括 `messages`、`tools`、流式选项,以及受支持的多模态字段。服务提供方凭证、上游模型 ID、路由策略、限流、安全护栏和其它网关策略都留在 AISIX 中。有关聊天消息中的音频,请参阅[使用 Chat Completions 输入和输出音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md)。 使用标准 Bearer Token 格式发送调用方 API Key: ``` Authorization: Bearer YOUR_CALLER_API_KEY ``` 为兼容性,AISIX 也接受 `x-api-key: YOUR_CALLER_API_KEY`。当 OpenAI 兼容客户端支持时,建议使用 Bearer Token 格式。 导出以下示例使用的网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` ## 发送 Chat Completions 请求[​](#send-a-chat-completions-request "发送 Chat Completions 请求的直接链接") 对于兼容 OpenAI 的聊天客户端,请将 `POST /v1/chat/completions` 作为默认路由。 通过 AISIX 发送 Chat Completions 请求: ``` curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "messages": [ {"role": "user", "content": "Hello from AISIX."} ] }' ``` 成功响应使用兼容 OpenAI 的 Chat Completions 格式,响应中的 `model` 会保持为请求中面向调用方的别名。 ## 发现可用模型[​](#发现可用模型 "发现可用模型的直接链接") `GET /v1/models` 会返回调用方 API Key 可见的每个具体模型别名,包括直接、路由、语义和合议别名。通配符别名是模式而非具体模型名称,因此不会列出。允许所有模型的 API Key 可以看到每个具体别名;受限 API Key 只能看到其允许列表许可的别名。 列出该调用方 API Key 可见的模型别名: ``` curl -sS "${AISIX_PROXY}/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` ## 处理错误[​](#处理错误 "处理错误的直接链接") 兼容 OpenAI 的 Chat Completions 路由会以 OpenAI 风格信封返回错误。需要区分调用方认证、模型访问、策略拦截、限流和上游失败时,请优先使用错误类型,再看状态码。 完整错误和响应头参考请参见[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md)。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解兼容 OpenAI 的客户端如何通过 Chat Completions 调用 AISIX。请继续阅读[使用 Chat Completions 输入和输出音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md)、[流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md)和[工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md)。 如果应用需要保持 OpenAI 兼容客户端形态,但由 AISIX 调用 Anthropic 上游,请阅读 [OpenAI 客户端接入 Anthropic 上游](https://docs.apiseven.com/ai-gateway/endpoints/openai-client-to-anthropic.md)。 --- # 支持的端点 AISIX 会暴露应用团队已经熟悉的代理端点。选择服务提供方、模型别名或流量策略前,可以先从本页确认客户端应该调用哪一种 API 形态。 如需为编码工具和应用框架配置客户端,请参阅[集成指南](https://docs.apiseven.com/ai-gateway/integrations.md)。 ## 主要 API 类型[​](#主要-api-类型 "主要 API 类型的直接链接") | API 类型 | 路由 | 适用场景 | | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | [聊天补全](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md) | `POST /v1/chat/completions` | 兼容 OpenAI 的聊天请求、[音频输入和输出](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md)、文本流式输出、工具调用、路由模型和合议模型。 | | [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md) | `POST /v1/messages`、`POST /v1/messages/count_tokens` | Anthropic 风格消息请求,以及面向 Anthropic 后端模型的 Token 计数。 | | [Responses](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md) | `POST /v1/responses` | Responses API 客户端,以及跨服务提供方的 Agent 风格响应流程。 | | [文本补全](https://docs.apiseven.com/ai-gateway/endpoints/text-completions.md) | `POST /v1/completions` | 兼容 OpenAI 的旧版文本补全客户端。 | | [向量嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md) | `POST /v1/embeddings` | 通过支持的服务提供方生成向量嵌入。 | | [重排序](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md) | `POST /v1/rerank` | 通过支持的服务提供方对文档进行重排序。 | | [图像生成](https://docs.apiseven.com/ai-gateway/endpoints/image-generation.md) | `POST /v1/images/generations` | 文生图请求。 | | [图像编辑](https://docs.apiseven.com/ai-gateway/endpoints/image-editing.md) | `POST /v1/images/edits` | multipart 形式的"图片 + 提示词"编辑请求。 | | [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md) | `POST /v1/videos`、`GET /v1/videos/{video_id}`、`GET /v1/videos/{video_id}/content` | 异步文生视频任务:提交任务、轮询状态并下载结果。 | | [语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md) | `POST /v1/audio/transcriptions`、`POST /v1/audio/translations`、`POST /v1/audio/speech` | 语音转文字、翻译和文字转语音请求。 | | [Batch、Files 与 Fine-tuning](https://docs.apiseven.com/ai-gateway/endpoints/batch-files-fine-tuning.md) | `POST /v1/files`、`POST /v1/batches`、`POST /v1/fine_tuning/jobs` 及其查询、列表、取消和内容读取路由 | 兼容 OpenAI 的批处理、文件管理和微调任务,由网关管理服务提供方路由。 | | [Realtime](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md) | `GET /v1/realtime`(WebSocket) | 通过 WebSocket 转发 OpenAI Realtime 客户端请求,并跟踪会话用量。 | | [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md) | 已配置的路径前缀和 host | 经显式配置路由中继的服务提供方专属调用,应用 AISIX 认证和策略,但不做请求体规范化。 | | [MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md) | `ANY /mcp`、`ANY /mcp/{server}` | 通过所有允许的 MCP 服务器或一个指定服务器执行 Agent 工具调用,并按调用方 API Key 控制工具访问。 | | [Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/overview.md) | `POST /a2a/{agent}`、`GET /a2a/{agent}/.well-known/agent-card.json` | 对已注册上游 Agent 发起 A2A JSON-RPC 调用,并进行需要调用方身份认证的 Agent Card 发现。 | ## 发现与健康检查[​](#发现与健康检查 "发现与健康检查的直接链接") | 端点 | 适用场景 | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `GET /v1/models` | 返回当前调用方 API Key 可访问的模型别名。客户端需要发现网关侧模型名时使用。 | | `GET /livez` | 检查代理监听端是否存活。用于代理监听端健康检查,不代表模型或服务提供方就绪。 | | `GET /readyz` | 检查实例是否应该接收流量。实例正在排空时返回 503。对于使用 etcd 或 AISIX Cloud 的网关,首次应用配置之前代理监听器未绑定,因此在那之前该路由是被拒绝而不是返回响应;参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 | ## 网关行为[​](#网关行为 "网关行为的直接链接") 建模代理路由共享同一套核心网关行为:AISIX 会认证调用方 API Key,检查模型访问权限,解析请求中的模型别名,并应用已配置的流量控制策略。 随后,AISIX 会把请求转发到选中的上游服务提供方;当请求能够归因到模型时,还会记录用量和遥测数据。 部分行为与具体路由相关。例如,请求匹配缓存策略时,响应缓存适用于聊天补全;合议模型也只作用于聊天补全。 MCP 工具调用使用调用方 API Key 的工具访问权限;Token 计数目前限定在 Anthropic 后端模型。服务提供方和路由限制请参见[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 精确的请求和响应结构请参见[代理 API 参考](https://docs.apiseven.com/ai-gateway/reference/proxy-api.md)。 --- # 透传路由 透传路由(passthrough route)将匹配到的请求转发到一个上游目标,不转换请求正文。它适用于 AISIX 尚未建模为一等路由的服务提供方原生端点,也适用于携带原始 `Host` 请求头的正向代理流量。 每条路由定义流量如何匹配、发送到何处、AISIX 如何认证调用方,以及 AISIX 是注入服务提供方凭证还是转发调用方凭证。AISIX 仍可围绕中继流量实施调用方访问控制、请求限制、护栏和遥测。 必须显式配置路由 原有的隐式 `/passthrough//...` 通道已被移除。未被任何路由认领的 `/passthrough/*` 路径遵循普通的空正文 `404` 处理流程。请先创建并验证替代路由,再迁移客户端流量。 透传路由不会改写模型标识符。如果服务提供方原生请求在正文、路径、查询参数或请求头中指定模型,请发送该服务提供方预期的标识符。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 请准备以下内容: * 一个 AISIX 部署: * 对于 AISIX Cloud,需要一个已挂载网关的环境和具备写入权限的管理员 Token。 * 对于开源 AISIX 网关,需要一个已配置为加载声明式资源文件的网关。 * `inject` 路由所需的上游服务提供方凭证。示例使用 OpenAI;`forward_client` 路由则会中继调用方的上游凭证。 * `curl` 和 `jq`。 ## 了解透传流程[​](#understand-the-passthrough-flow "了解透传流程的直接链接") AISIX 保留请求正文,同时处理网关身份认证、目标构造、有意的请求头过滤、护栏和遥测: 路由匹配分两个阶段进行: 1. 入站 `Host` 命中某条路由 `hosts` 白名单的请求,会在网关的类型化路由之前分发。这样,正向代理便可中继 `/v1/messages` 之类的上游路径,而不会被网关当作自身端点处理。 2. 路径前缀匹配在类型化路由之后运行,因此纯路径路由无法遮蔽网关的 `/v1`、`/mcp` 或 `/a2a` 端点。 多条路由同时匹配时,主机名匹配优先于纯路径匹配,较长的匹配前缀优先于较短的前缀。 ## 配置服务提供方原生路由[​](#create-a-passthrough-route "配置服务提供方原生路由的直接链接") 以下示例在 `/passthrough/openai/v1/models` 暴露 OpenAI 的原生模型列表端点。AISIX 注入已配置的 OpenAI 凭证,并要求调用方 Key 已获得 `openai-tunnel` 授权。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 导出 AISIX Cloud 连接信息和服务提供方凭证: ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" export OPENAI_API_KEY="YOUR_OPENAI_API_KEY" ``` 创建一个可供该环境使用的 OpenAI 服务提供方 Key: ``` PROVIDER_KEY_ID=$(curl --fail-with-body -sS -X POST \ "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "OpenAI passthrough", "provider": "openai", "api_key": "'"${OPENAI_API_KEY}"'", "api_base": "https://api.openai.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id') ``` 使用服务提供方 Key ID 创建路由: ``` ROUTE_RESPONSE=$(curl --fail-with-body -sS -X POST \ "$AISIX_CP/environments/$ENV_ID/passthrough_routes" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "openai-tunnel", "path_prefix": "/passthrough/openai", "target_url": "https://api.openai.com/v1", "credential_mode": "inject", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }') export ROUTE_ID=$(printf '%s' "$ROUTE_RESPONSE" | jq -er '.passthrough_route.id') printf '%s' "$ROUTE_RESPONSE" | jq '.warnings // []' ``` 保留 `ROUTE_ID`,以便更新路由或挂载路由作用域的护栏。 创建专用调用方 Key,并在同一请求中授予该路由。明文 Key 只返回一次: ``` CALLER_RESPONSE=$(curl --fail-with-body -sS -X POST \ "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "OpenAI passthrough caller", "allowed_models": [], "allowed_routes": ["openai-tunnel"] }') export AISIX_API_KEY=$(printf '%s' "$CALLER_RESPONSE" | jq -er '.plaintext') printf '%s' "$CALLER_RESPONSE" | jq '.warnings // []' ``` 控制平面会将服务提供方 Key、路由和调用方授权下发到已挂载的网关。上线前请检查返回的所有兼容性警告。警告仅供参考,因此请通过每个网关验证流量。在控制台中,可分别通过 **Provider keys**、环境的 **Passthrough Routes** 以及调用方 Key 的 **Passthrough route access** 部分完成相同操作。 如果改为授权现有调用方,请包含其应保留的全部路由授权。更新 `allowed_routes` 字段时,AISIX Cloud Admin API 会替换完整列表。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX 网关的直接链接") 在[完整资源文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中准备一个 `openai-prod` 服务提供方 Key,然后选择一个专用调用方凭证: ``` export PASSTHROUGH_CALLER_KEY="YOUR_CALLER_API_KEY" ``` 将路由和调用方条目添加到相应集合中。保持服务提供方 Key 和其他资源不变: resources.yaml(路由和调用方 Key) ``` passthrough_routes: - name: openai-tunnel path_prefix: /passthrough/openai target_url: https://api.openai.com/v1 provider_key: openai-prod api_keys: - display_name: passthrough-caller key_env: PASSTHROUGH_CALLER_KEY allowed_models: [] allowed_routes: [openai-tunnel] ``` AISIX 加载文件时,会将 `provider_key` 名称解析为服务提供方 Key 的派生 ID。未知名称会导致验证失败。`allowed_routes` 中的精确条目也会根据文件中定义的路由进行检查;允许使用通配符模式。 加载前,验证组装好的完整文件: ``` aisix validate --resources resources.yaml ``` 由于本示例引入了 `PASSTHROUGH_CALLER_KEY`,请在网关进程环境中设置该变量,然后启动或重新创建网关。加载完成后,使用同一个值进行验证请求: ``` export AISIX_API_KEY="$PASSTHROUGH_CALLER_KEY" ``` ## 验证路由[​](#verify-the-route "验证路由的直接链接") 导出末尾不带斜杠的网关源地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 请求 OpenAI 的原生模型列表: ``` curl --fail-with-body -sS \ "$AISIX_PROXY/passthrough/openai/v1/models" \ -H "Authorization: Bearer $AISIX_API_KEY" ``` 该路由会剥离其 `path_prefix`,避免重复添加 `target_url` 中已有的 `/v1` 路径段,注入 OpenAI 服务提供方凭证,并中继上游响应。 ## 比较 Cloud 与资源文件引用[​](#compare-cloud-and-resources-file-references "比较 Cloud 与资源文件引用的直接链接") 大多数路由字段在两种管理方式中使用相同名称。服务提供方凭证和调用方凭证的引用方式有所不同: | 用途 | AISIX Cloud Admin API | 推荐的资源文件字段 | 资源文件接受的显式 ID | | -------------------- | -------------------------- | --------------------------------- | --------------------- | | 注入的服务提供方凭证 | `provider_key_id`(UUID) | `provider_key`(`display_name`) | `provider_key_id` | | 匿名调用方主体 | `anonymous_key_id`(UUID) | `anonymous_key`(`display_name`) | `anonymous_key_id` | 资源文件中的名称引用在加载时会受到更严格的检查,引用未知时还会给出候选名称。应优先使用名称引用,而非显式 ID。AISIX Cloud 会验证服务提供方 Key 对该环境可见,并验证匿名调用方 Key 属于该环境。 在 AISIX Cloud 中,路由 `name` 创建后便固定不变。在资源文件中,更改名称会改变路由身份,因此必须同时更新每个调用方的 `allowed_routes` 条目。 ## 配置参考[​](#configuration-reference "配置参考的直接链接") | 字段 | 行为 | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | 路由身份,由调用方的 `allowed_routes` 模式引用,并记录在用量事件中。 | | `path_prefix` | 网关路径前缀,按路径段边界匹配。`target_url` 路由会先剥离前缀,再将剩余路径拼接到目标;`preserve_host` 路由则保留完整路径。纯路径路由不能占用 `/v1`、`/mcp`、`/a2a`、`/admin`、`/livez`、`/readyz` 或 `/metrics`;同时匹配 `hosts` 的路由可以使用这些归上游所有的路径。 | | `hosts` | 入站 `Host` 白名单,不区分大小写并忽略端口。前导 `*.` 通配符匹配一个额外标签,且必须保留至少两个字面标签。 | | `target_url` | 显式上游基础 URL。必须且只能配置一种目标形式:`target_url` 或 `preserve_host: true`。 | | `preserve_host` | 将 `https://` 推导为目标。仅可与 `hosts` 一同配置,由 `hosts` 限定推导出的目的地。 | | `auth_mode` | `gateway_key`(默认)、`header_key` 或 `anonymous`。 | | `auth_header_name` | `header_key` 模式下包含网关凭证的小写专用请求头。除非 `forward_client_headers` 完整写出它的名称,否则 AISIX 会在转发前将其剥离;`x-*` 这类通配符触及不到它。`authorization`、`proxy-authorization`、`cookie`、`set-cookie` 和 `x-api-key` 会被拒绝。 | | `source_cidrs` | 客户端来源白名单。`anonymous` 模式要求该列表非空;其他模式可将其作为可选的安全加固措施。 | | `credential_mode` | `inject`(默认)或 `forward_client`。 | | `forward_client_headers` | 即使该路由本会剥离,也仍要中继给上游的入站客户端请求头,取值为精确名称或含一个 `*` 的通配符,匹配不区分大小写。默认为空。PATCH 会整体替换已存储的列表;发送 `null` 可清空。在控制台中,它是 **Advanced** 下的 **Forward client headers**,每行一个条目。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#forward-client-headers)。 | | `identity_header` | 可选的小写设备注入身份请求头。AISIX 将长度受限的值记录为 `client_identity`,并在转发前剥离该请求头(除非 `forward_client_headers` 完整写出它的名称;`x-*` 这类通配符触及不到它)。仅应在可信设备之后配置,并由该设备删除并替换客户端提供的任何值。`authorization`、`proxy-authorization`、`cookie`、`set-cookie` 和 `x-api-key` 会被拒绝。 | | `timeout_ms` | 限制上游响应头和非 SSE 正文的读取时长,不限制健康的 SSE 中继。 | | `enabled` | 停用的路由不匹配任何请求。默认值:`true`。 | 必须至少配置一个匹配维度:`path_prefix` 或 `hosts`。同时配置两者时,请求必须同时满足两项条件。 ## 网关身份认证模式[​](#gateway-authentication-modes "网关身份认证模式的直接链接") * **`gateway_key`** 从 `Authorization: Bearer` 或 `x-api-key` 读取标准网关凭证。 * **`header_key`** 从 `auth_header_name` 读取网关凭证,从而将 `Authorization` 留给调用方的上游凭证。这是正向代理中 `forward_client` 的标准搭配。 * **`anonymous`** 不接收网关凭证。请求以配置的调用方 Key 主体运行,并且必须来自 `source_cidrs` 范围内。 解析出的任一主体仍须通过 `allowed_routes` 获得路由名称授权;`*` 授予全部路由。有效 Key 缺少匹配授权时会收到 `403`。 在 AISIX Cloud 中,已适用于解析后调用方的预算会在分发前检查。透传用量目前不携带模型 ID,按零成本记录,也不会增加这些预算的支出。开源 AISIX 网关没有本地预算资源。 ## 上游凭证模式[​](#upstream-credential-modes "上游凭证模式的直接链接") * **`inject`** 剥离入站凭证请求头,并注入已配置的服务提供方 Key。对于 Anthropic,AISIX 使用 `x-api-key` 和 `anthropic-version`;对于其他服务提供方,则使用 `Authorization: Bearer`。服务提供方 Key 上配置的请求头剥离规则和 TLS 设置也会生效。 * **`forward_client`** 在网关凭证通过 `header_key` 传入或路由为匿名模式时,转发调用方的上游凭证。使用 `gateway_key` 时,AISIX 会删除 `Authorization` 和 `x-api-key`,因为任一请求头都可能携带网关凭证。 路由默认中继调用方的其他请求头,只剥离一小部分:逐跳请求头和传输请求头、`host`、`content-length`、`x-aisix-*` 命名空间、`proxy-authorization`,以及调用方的 W3C 链路请求头。AISIX 会使用有效的 W3C 上下文建立自身的 [OTLP 链路](https://docs.apiseven.com/ai-gateway/observability/exporters.md#understand-otlp-trace-structure),并向上游发送网关请求 ID。 `forward_client_headers` 会覆盖该剥离行为,也是把路由本会移除的请求头放回去的唯一方式。因此,在 `auth_mode: gateway_key` 下点名 `authorization`,会中继调用方自己的凭证——正是网关刚刚用来认证该调用方的那个请求头——取代注入的那份;这就是让按最终用户授权的内网服务能够继续这样工作的方式。无论模式如何,`host`、`content-length`、逐跳请求头和 `x-aisix-*` 都会被剥离;凭证或链路上下文请求头必须[精确点名](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#headers-that-must-be-named-exactly),通配符不会匹配到它们。路由自己的 `auth_header_name` 和 `identity_header` 同理:AISIX 会消费掉这两个请求头,因此通配符触及不到,完整写出名称才会转发它。路由剥离的其他任何名称,通配符都足以放回去,包括服务提供方密钥 `strip_headers` 里的条目——不过该列表四个默认值中有三个(`authorization`、`cookie`、`x-api-key`)属于凭证槽位,仍需单独点名,只有 `set-cookie` 是通配符能放回的默认项。 凭证不存在回退机制:`inject` 路由没有可解析的服务提供方 Key 时会拒绝请求,`forward_client` 路由则不能携带服务提供方 Key 引用。 ## 信封识别与用量[​](#envelope-detection-and-token-usage "信封识别与用量的直接链接") AISIX 识别请求形态仅用于提取;识别不会改变中继的正文。如果出现多个可识别的载体字段,则按以下顺序识别: 1. `messages`,用于 OpenAI 兼容聊天或 Anthropic Messages 流量。 2. `input`,用于 OpenAI Responses 形态。 3. `prompt`,用于旧式 completions 或 fill-in-the-middle 流量。 4. 其余所有正文均按不透明内容处理,包括 JSON-RPC、REST、非 JSON 和空正文。 识别结果决定提供给护栏的文本以及记录到用量事件中的 Token 字段。如果识别出的形态没有生成文本,AISIX 会改为扫描完整正文。请求和响应正文仍不经 Schema 转换便直接中继。 不透明的缓冲响应不会进行推测性 Token 提取。不透明的 SSE 流可通过顶层 `usage` 对象,或 `event: usage` / `event: token_usage` 帧中的扁平 Token 报告来上报用量。 ## 限流[​](#rate-limits "限流的直接链接") 调用方 API Key、团队和成员的请求限制会在分发前生效。在 `inject` 路由上,如果顶层 JSON `model` 解析为同一服务提供方下已配置的 AISIX 模型,还会预留该模型的请求限制。`forward_client` 路由不执行此模型查找。 AISIX 会强制执行请求数维度限制(`rps`、`rpm`、`rph` 和 `rpd`)。当适用的 `tpm` 或 `tpd` 计数器已经耗尽时,AISIX 也会拒绝请求,但透传 Token 用量不会增加这些计数器。记录的用量应只用于遥测,而不是透传 Token 配额执行。 并发检查在向上游分发之前执行。对于 SSE,AISIX 返回流式响应时便会释放预留,而不是等到流结束。 透传路由没有限流字段或策略作用域。若要对不同路由应用不同的请求限制,请将路由授予不同的调用方 Key,并为这些调用方身份配置限制。 ## 护栏与流式传输[​](#guardrails-and-streaming "护栏与流式传输的直接链接") 在 AISIX Cloud 中,可以通过选择 **Passthrough routes** 作用域,将护栏挂载到一条透传路由。挂载使用路由 UUID。环境、调用方 Key 和团队护栏也可同时生效。 开源资源文件通过 `guardrail_attachments` 集合声明挂载关系,因此文件中定义的安全护栏只有在绑定将其作用域覆盖到透传流量时才会生效:可以使用 `scope_type: env` 覆盖整个环境,也可以使用 `scope_type: passthrough_route` 并指定该路由。 输入护栏在向上游分发前运行。拦截会返回 `422`,且不会联系上游。缓冲响应在交付前检查。SSE 响应一旦开始,拦截会以 SSE `content_filter` 错误帧结束流,无法再将 HTTP 状态码改为 `422`。 除非安全护栏暂存帧以进行检查,否则 SSE 响应会增量中继。AISIX 不会改写服务提供方原生正文来应用脱敏。对于内置 `pii` 护栏,仅配置掩码动作时,匹配内容会在不掩码的情况下转发;如果匹配内容不得发送到上游,请使用拦截动作。Presidio 和 Lakera 等其他护栏类型在透传没有回写通道时,会改为拦截可掩码的结果。 ## 审计捕获[​](#audit-capture "审计捕获的直接链接") 对于成功中继的流量,配置了 `content_mode: full` 的可观测性导出器会以字符串形式接收请求正文,并受导出器内容上限约束。缓冲响应与受支持的提取形态匹配时记录提取出的文本,否则将正文记录为文本。流式响应记录累积的提取文本;不透明数据载荷保留为文本。捕获的内容仅发送给导出器,绝不会通过 AISIX Cloud 遥测路径发送。 用量事件包含路由名称、调用方、记录的 Token 数量和 `client_identity`。外部导出器可以公开这些值。当前 AISIX Cloud **Request Logs** UI 显示调用方和 Token 元数据,但不显示 `passthrough_route_name` 或 `client_identity`。 ## 从已移除的隐式通道迁移[​](#migrate-from-the-implicit-tunnel "从已移除的隐式通道迁移的直接链接") 已移除的通道通过可访问的模型间接选择服务提供方 Key。显式路由以固定的目标和凭证绑定取代了这种含糊的选择。 对于客户端仍在使用的每个服务提供方前缀: 1. 使用旧路径前缀和预期的上游目标创建显式路由。 2. 在 `inject` 模式下绑定预期的服务提供方 Key。 3. 将路由名称授予应保留访问权限的每个调用方。 4. 迁移或重启客户端前验证路由。 显式路由认领相同前缀后,客户端可以继续使用现有的 `/passthrough//...` URL。在该路由生效前,请求会返回普通 `404`。 原有通道的两项行为不会保留:透传路由只尝试一次上游请求,不会进行传输重试;路由失败也不会将已配置模型标记为冷却状态。 ## 错误[​](#errors "错误的直接链接") | 状态码或信号 | 含义 | | ----------------------- | ------------------------------------------------------------------------- | | `401` | 按路由身份认证模式缺失或提供了无效的网关凭证。 | | `403` | 解析出的调用方 Key 未授予该路由,或客户端来源不在 `source_cidrs` 范围内。 | | `404` | 未被认领的 `/passthrough/*` 路径进入普通的空正文未找到处理流程。 | | `422` | 护栏在分发前拦截了请求,或在交付前拦截了缓冲响应。 | | SSE `content_filter` 帧 | 护栏在流开始后拦截了内容。 | | `429` | 网关请求限制或预算检查拒绝了请求,或上游返回了被中继的 `429`。 | | 其他上游状态码 | AISIX 过滤响应头后,中继上游状态码和正文。 | 未匹配的 `404` 响应正文为空。AISIX 生成的其他失败使用网关错误信封;上游错误状态码和正文经过响应头过滤后中继。 ## 下一步[​](#next-steps "下一步的直接链接") * 使用主机名匹配路由接收经 TLS 终止的 IDE 流量:[IDE AI 流量正向代理](https://docs.apiseven.com/ai-gateway/deployment/forward-proxy.md)。 * 配置护栏行为:[护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md)。 * 导出请求和响应内容:[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md)。 --- # Realtime API AISIX AI 网关在 `GET /v1/realtime` 通过 WebSocket 转发 OpenAI Realtime API。网关会在接受连接前完成客户端认证、模型别名解析、访问控制和限流策略检查,然后在客户端与服务提供方之间双向转发事件。 本指南将演示如何通过网关连接 Realtime 客户端,并说明该端点的关键会话行为。 ## 前提条件[​](#前提条件 "前提条件的直接链接") 开始前请准备: * 一个可处理代理请求的 AISIX 网关。 * 一个可访问目标模型别名的调用方 API Key。 * 一个由支持 OpenAI Realtime 协议的服务提供方支持的模型别名。 导出服务器端示例使用的网关连接和请求值: ``` # AISIX_PROXY 使用 http 或 https,且不含尾部斜杠或端点路径。 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="realtime-prod" ``` 目前支持兼容 OpenAI 的服务提供方(适配器为 `openai`,包括自定义 `api_base` 部署)和 Azure OpenAI(适配器为 `azure-openai`,使用 `/openai/realtime` 和 `api-key` 认证)。Gemini Live 和 Bedrock 使用不同的实时事件协议,不通过该端点提供。 ## 连接客户端[​](#连接客户端 "连接客户端的直接链接") 通过 `model` 查询参数选择模型。服务端客户端使用标准请求头认证: ``` import WebSocket from "ws"; const realtimeUrl = new URL("/v1/realtime", process.env.AISIX_PROXY); realtimeUrl.protocol = realtimeUrl.protocol === "https:" ? "wss:" : "ws:"; realtimeUrl.searchParams.set("model", process.env.AISIX_MODEL); const ws = new WebSocket(realtimeUrl, { headers: { Authorization: `Bearer ${process.env.AISIX_API_KEY}` }, }); ``` 浏览器客户端无法设置 WebSocket 请求头。可以像 OpenAI 浏览器示例一样,把调用方 API Key 作为子协议项传入。网关会回显 `realtime` 子协议: ``` // 使用不含端点路径的绝对 HTTP(S) 网关 URL,例如 https://gateway.example.com const aisixProxy = "YOUR_AISIX_GATEWAY_URL"; const aisixApiKey = "YOUR_CALLER_API_KEY"; const aisixModel = "realtime-prod"; const realtimeUrl = new URL("/v1/realtime", aisixProxy); realtimeUrl.protocol = realtimeUrl.protocol === "https:" ? "wss:" : "ws:"; realtimeUrl.searchParams.set("model", aisixModel); const ws = new WebSocket(realtimeUrl, [ "realtime", `openai-insecure-api-key.${aisixApiKey}`, ]); ``` 连接建立后,可以像直接连接服务提供方一样收发 Realtime 事件。AISIX 转发 `session.update`、音频缓冲区、`response.create` 和服务端事件等事件时不会改变其结构。 AISIX 唯一会改写的值是会话对象中的模型名称。`session.created` 和 `session.updated` 事件中的模型名称是客户端连接时使用的模型别名,而不是服务提供方自身的模型 ID。客户端把该别名通过 `session.update` 发回时,会在转发到上游前被转换回服务提供方的模型 ID,因此客户端可以直接回传收到的会话对象。 ## 认证与策略[​](#认证与策略 "认证与策略的直接链接") 认证、模型访问检查、客户端 IP 限制和限流会在 WebSocket 升级完成**前**执行。AISIX Cloud 预算检查也在此时执行。任何一项检查失败都会在 HTTP 握手阶段被拒绝(401、403 或 429),客户端会看到连接建立失败。 会话期间,已配置的安全护栏会扫描双向文本事件。被阻断的事件会产生 OpenAI 风格的 `error` 事件,随后连接关闭。 ## 用量跟踪[​](#用量跟踪 "用量跟踪的直接链接") 网关会从服务提供方的 `response.done` 事件中提取用量信息;转录会话还会从转录完成事件中提取用量。每个会话会记录一个聚合用量事件,包括缓存 Token 数。会话总 Token 会计入基于 Token 的限流。 ## 会话限制[​](#会话限制 "会话限制的直接链接") AISIX 会对两个方向的事件间隔应用空闲上限。系统依次从直接模型的 `stream_timeout`、该模型的 `timeout`,以及部署级 `upstream.stream_timeout_ms` 或 `upstream.timeout_ms` 默认值解析此上限。部署默认上限为 6000 秒。静默时间超过解析后截止时间的会话将以代码 `1001` 和原因 `idle timeout` 关闭。 要让某个模型不受部署级兜底值影响,请设置 `timeout: 0`,并确保该模型未设置非零 `stream_timeout`。部署运维人员也可以将两个上游超时默认值均设置为 `0`。有关完整优先级规则,请参阅[超时之间的关系](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#how-the-timeouts-relate)。上游连接失败会以代码 `1011` 关闭会话;模型开启冷却后,这类失败会计入模型冷却。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经通过网关连接了 Realtime 客户端。接下来可阅读[语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md),了解非 Realtime 音频端点。 --- # 请求生命周期 AISIX 位于应用和 AI 服务提供方之间。应用携带调用方凭证和模型别名向代理 API 发送请求,AISIX 会据此执行访问控制、解析上游目标、应用 AI 流量策略,并记录请求过程中发生的事件。 每个请求都会经历以下阶段: 调用方**应用请求** AISIX 网关 **调用方身份认证**通过哈希值验证调用方 API Key,或将 JWT 映射到调用方 Key **模型解析**将别名解析为直接、路由、语义或合议形态 **请求控制**输入安全护栏、AISIX Cloud 预算、限流和缓存查找——请求被拒绝或缓存命中时会提前结束 **服务提供方分发**服务提供方凭证、上游模型名称和服务提供方适配器 上游 · 网关之外**服务提供方模型 API**重试与故障转移 **响应处理**输出安全护栏、用量和遥测 调用方**返回响应** ## 调用方认证[​](#调用方认证 "调用方认证的直接链接") 每个代理请求都会提供调用方 API Key,或由已配置的 OIDC 提供方签发的 JWT。对于明文 Key,AISIX 会通过其哈希值查找;对于 JWT,AISIX 会验证签发者、签名和必需 Claim,再将外部身份映射到与之绑定的调用方 API Key。 完成身份认证后,两条路径都会使用解析出的调用方 API Key 作为授权身份。该 Key 控制调用方可以使用哪些模型别名以及应用哪些流量控制,因此应用团队不需要直接持有服务提供方凭证。明文网关凭证请参阅[调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md),外部身份提供商凭证请参阅 [JWT 身份认证](https://docs.apiseven.com/ai-gateway/traffic-controls/jwt-authentication.md)。 ## 模型解析[​](#模型解析 "模型解析的直接链接") 请求中的 model 值是面向调用方的别名。AISIX 会将该别名解析为以下四种分发形态之一: * 直接模型:通过一个服务提供方凭证指向一个上游模型。当语义路由器使用直接模型进行相似度比较时,该模型还可以包含向量嵌入元数据。 * 路由模型:允许 AISIX 通过故障转移、加权轮询、一致性哈希、成本、延迟或负载选择一个目标模型。 * 语义模型:通过比较请求文本和配置的路由示例选择目标模型。 * 合议模型:将聊天请求发送给多个合议成员,并使用评审模型综合生成最终响应。 一个模型资源只能配置一种分发形态。有关完整资源关系,请参阅[模型和服务提供方](https://docs.apiseven.com/ai-gateway/models/resource-model.md)。 ## 请求控制[​](#请求控制 "请求控制的直接链接") AISIX 可以在请求到达服务提供方之前将其停止。输入安全护栏可以检查并拒绝不安全内容,AISIX Cloud 部署可以执行请求预算,调用方 API Key 和模型别名也可以携带限流策略。响应缓存可以在调用上游前直接返回已保存的聊天补全结果。如需按阶段了解各项控制的作用位置,请参阅[流量控制](https://docs.apiseven.com/ai-gateway/traffic-controls/overview.md)中的请求链路图。 ## 服务提供方转发[​](#服务提供方转发 "服务提供方转发的直接链接") 请求被允许后,AISIX 会使用运维人员配置的服务提供方密钥和适配器,将请求调度到选中的服务提供方。应用可以保持面向网关的 API 形态,而由 AISIX 处理服务提供方凭证、上游模型名称、base URL 和服务提供方专属请求行为。 ## 响应处理[​](#响应处理 "响应处理的直接链接") 服务提供方响应会经由 AISIX 返回。输出安全护栏可以在响应到达调用方之前检查生成文本。调用方通过身份认证且请求解析完成后,无论请求成功还是失败,AISIX 都会记录用量和遥测。运维人员可以查看请求别名、解析后的模型、服务提供方尝试、Token 用量、延迟和错误。 ## 部署边界[​](#部署边界 "部署边界的直接链接") 对于开源 AISIX 网关,运维人员可以在 `resources.yaml` 文件中声明网关资源。使用 AISIX Cloud 时,控制面负责资源管理,并将已接受的配置投射到 AISIX 网关。从调用方视角看,代理请求生命周期保持一致:应用调用代理 API,AISIX 应用已配置的模型访问、路由、控制策略和可观测性行为。 --- # 重排序 Rerank 请求会在应用将候选文档用于搜索、检索或 RAG 工作流前,根据查询对这些文档重新排序。 AISIX AI 网关暴露 `POST /v1/rerank`,让 rerank 流量可以与其它网关流量路径使用相同的调用方 API Key、模型别名、上游凭证和请求侧策略。 本指南将通过 AISIX 发送 rerank 请求,并说明该端点的服务提供方要求。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个配置服务提供方标签为 OpenAI、Cohere 或 Jina 的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="rerank-prod" ``` ## 发送重排序请求[​](#发�送重排序请求 "发送重排序请求的直接链接") 通过网关代理发送 rerank 请求,并在请求体中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/rerank" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "query": "gateway docs", "documents": ["doc a", "doc b", "doc c"] }' \ -o aisix-rerank-response.json ``` AISIX 会解析模型别名、检查调用方 API Key、对查询和文档文本执行受支持的输入策略检查,只将 model 字段改写为上游模型 ID,并将请求转发到上游 rerank 端点。 响应保持上游 rerank 响应形态: ``` { "results": [ { "index": 1, "relevance_score": 0.95 }, { "index": 0, "relevance_score": 0.42 }, { "index": 2, "relevance_score": 0.18 } ] } ``` 部分服务提供方会包含响应 ID、模型名称、用量或元数据等额外字段。 检查响应是否包含排序结果: ``` jq '.results | length' aisix-rerank-response.json ``` 命令应输出返回结果数量: ``` 3 ``` ## 服务提供方要求[​](#服务提供方要求 "服务提供方要求的直接链接") 只有当解析出的模型配置为 OpenAI、Cohere 或 Jina 服务提供方标签时,AISIX 才会接受 rerank 请求。这些服务提供方适配器共享 model、query 和 documents 等通用 rerank 字段。可选 rerank 字段会原样转发,不会跨服务提供方标准化。 当解析出的模型使用其它服务提供方标签时,AISIX 会在发送到上游前返回 400,避免将 rerank 请求发送到不使用预期 rerank 格式的服务提供方路由。 Voyage AI 也暴露 rerank API,但其请求和响应字段与当前受支持的 rerank 格式不同。AISIX 需要专门适配器后才会将其视为兼容。 对于 Cohere 和 [Jina](https://docs.apiseven.com/ai-gateway/providers/jina.md#add-a-rerank-model),请根据服务提供方参考文档配置服务提供方密钥的 base URL。AISIX 会追加 rerank 路径,并在 base URL 已以版本前缀结尾时避免重复追加常见 API 版本片段。 ## 重排序行为[​](#重排序行为 "重排序行为的直接链接") AISIX 转发请求体时只改写 model 字段,不会添加 Chat Completions 字段,也不会转换服务提供方专属 rerank 参数。 输入安全护栏可以在 AISIX 调用服务提供方之前检查 query 和文档文本。输出安全护栏不会检查该路径上的重排序响应内容,因为响应包含的是排序结果,而不是生成文本。 成功的 rerank 响应会以原上游内容类型和字节返回,只有一处例外:当上游响应在顶层携带 `model` 字段时,AISIX 会将其改写为请求所使用的模型别名,使响应中的模型名称与调用方请求的一致,而不是上游模型 ID;顶层不含 `model` 字段的响应不会被添加该字段,嵌套在响应其它位置的模型名称也会保持服务提供方写入的原值。AISIX 只会尽力解析用量用于遥测;如果用量缺失或格式无法识别,AISIX 仍会原样返回上游响应的其余部分。 如果安全护栏没有阻断请求,请检查已配置安全护栏是否能检查 query 或文档文本。如果请求在到达服务提供方前返回 400,请检查解析出的模型服务提供方标签。如果上游返回 404,请检查服务提供方密钥的 base URL。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 AISIX 如何代理 rerank 请求,以及为什么该能力对服务提供方支持保持较窄范围。接下来请阅读[图像生成](https://docs.apiseven.com/ai-gateway/endpoints/image-generation.md),了解另一类服务提供方专属端点。 --- # Responses API 代理 Responses API 是 OpenAI 面向使用输入/输出项格式而不是 Chat Completions 消息格式的应用提供的响应生成端点。AISIX AI 网关为 Responses API 客户端暴露该路由,同时将调用方认证、模型别名、上游凭证和网关策略保留在网关中。 当应用或工具已经使用 Responses API 时,请使用该路由。当模型的上游自身提供 Responses API 时,AISIX 会把请求转发过去;否则 AISIX 会通过服务提供方适配器转换请求,并向调用方返回 Responses API 结果。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由原生提供 Responses API 或支持转换后请求形态的上游支撑的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` ## 发送 Responses 请求[​](#发送-responses-请求 "发送 Responses 请求的直接链接") 通过网关代理发送请求,并在请求体中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "input": "Say hello from AISIX." }' ``` AISIX 会解析模型别名,并为选中模型选择服务提供方路径。当服务提供方密钥选择原生 Responses 协议面时,AISIX 会直接转发请求,不转换请求体;否则会使用跨服务提供方桥接。 响应体会以 Responses API 格式返回: ``` { "id": "resp_***", "object": "response", "model": "gpt-4o-prod", "output": [ { "type": "message", "role": "assistant", "content": [ { "type": "output_text", "text": "Hello from AISIX." } ] } ], "usage": { "input_tokens": 12, "output_tokens": 5, "total_tokens": 17 } } ``` ## 服务提供方行为[​](#服务提供方行为 "服务提供方行为的直接链接") AISIX 通过两种方式处理 Responses 请求: | 上游 | 行为 | | ------------------ | --------------------------------------------------------------------------------------------------------------------- | | 提供 Responses API | AISIX 将请求 model 改写为上游模型 ID,并将请求转发到上游 Responses API。当上游支持时,上游专属 Responses 能力会透传。 | | 不提供 | AISIX 将受支持 Responses 字段转换为网关聊天格式,通过服务提供方适配器调度,并返回 Responses API 结果。 | 走哪一条按服务提供方密钥逐个决定。没有协议面声明时,AISIX 对 `openai` 服务提供方原生转发,对其它服务提供方一律转换。这个默认判断对某些端点在两个方向上都会出错:通过 `openai` 服务提供方 + 自定义 `api_base` 接入的 OpenAI 兼容端点可能根本没有 `/v1/responses`,而其它服务提供方的端点反而可能有。声明该密钥的 API 协议面即可说明属于哪一种,见[声明 API 协议面](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#declare-the-api-surfaces)。 桥接路径支持常见的文本、工具调用、工具结果、采样和流式字段。它会把 `reasoning.effort` 带入规范化聊天请求的 `reasoning_effort`;支持推理力度控制的服务提供方适配器再将其转换为对应的线上字段。例如,Anthropic 收到的是 `output_config.effort`。你还可以通过[推理力度映射](https://docs.apiseven.com/ai-gateway/models/reasoning-effort-mapping.md)按直连模型重写该值。只属于 OpenAI Responses、且没有服务提供方中立聊天等价语义的能力,不会在桥接路径中转发。 经过转换的请求会忽略以下字段: * `reasoning` 中除 `effort` 外的成员,例如 `summary` * `store` * `previous_response_id` * `web_search`、`file_search`、`code_interpreter` 等托管工具 * `text`、`metadata`、`service_tier` 以及其它 OpenAI 专属控制项 ## 策略与用量行为[​](#策略与用量行为 "策略与用量行为的直接链接") 输入安全护栏可以在 AISIX 调用服务提供方之前检查请求文本。输出安全护栏可以在非流式响应到达调用方之前检查响应内容。 如果输出安全护栏阻断响应,AISIX 会向调用方返回内容策略错误,并记录该阻断请求以便观测。 对于流式请求,AISIX 会保持 Responses SSE 形态。原生 Responses 目标可以直接透传上游 SSE;桥接目标则由 AISIX 把服务提供方流式分片编码为 Responses 事件。如果启用了输出安全护栏,AISIX 会先缓冲流内容进行策略检查,再决定返回或阻断。缓冲区中 AISIX 无法解析的帧会被丢弃,而不是未经扫描就放行;如果因此没有任何内容可返回,响应会被以 `422` 拒绝。参见 [AISIX 无法扫描的帧](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#frames-aisix-cannot-scan)。 对于成功响应,当上游响应包含 Token 用量时,网关会记录用量。流式用量会在 AISIX 从流中收到终止用量信息后发出。 对于 Token 计数方式与 OpenAI 不同的桥接服务提供方,AISIX 会将计数转换为 Responses API 的形式:`input_tokens` 是完整输入,`input_tokens_details.cached_tokens` 是其中缓存读取的子集,`input_tokens_details.cache_creation_tokens` 是缓存写入的子集(仅在上游报告了写入时出现),`total_tokens` 等于 `input_tokens + output_tokens`。以 Anthropic 上游为例的完整说明,请参阅 [Token 用量](https://docs.apiseven.com/ai-gateway/endpoints/openai-client-to-anthropic.md#token-usage)——那里用的是 Chat Completions 的字段名,与这里一一对应(`prompt_tokens` 对应 `input_tokens`,`completion_tokens` 对应 `output_tokens`,`prompt_tokens_details` 对应 `input_tokens_details`,`completion_tokens_details` 对应 `output_tokens_details`)。有一处形态差异:`output_tokens_details.reasoning_tokens` 在 Responses 响应中恒存在,包括值为 `0` 时;而 Chat Completions 会整块省略。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解何时通过 AISIX 使用 Responses API,以及直接转发和桥接时的服务提供方处理差异。旧版 completions 路由请继续阅读[文本补全](https://docs.apiseven.com/ai-gateway/endpoints/text-completions.md);如果 Responses API 客户端依赖 SSE 行为,请继续阅读[流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md)。 --- # 流式响应 AISIX AI 网关可以向期望 Server-Sent Events 的客户端流式返回代理响应。流式响应不会改变网关职责:AISIX 仍会认证调用方 API Key、解析模型别名、应用受支持策略,并将请求转发到选中的上游服务提供方。 流式端点会保留各路由面向客户端的流格式,但网关策略可能影响投递。 本指南将发送一次 OpenAI 兼容流式请求,并说明不同端点族中的流式行为差异。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由支持流式响应的服务提供方和模型支撑的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` ## 发送流式请求[​](#发送流式请求 "发送流式请求的直接链接") 请求会将 model 值保持为 AISIX 模型别名,并要求上游流式返回响应: ``` curl -sS -N -X POST "${AISIX_PROXY}/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "stream": true, "messages": [ {"role": "user", "content": "Stream a short greeting."} ] }' ``` 响应是 OpenAI 风格 SSE 流。直接 HTTP 客户端会看到类似下面的 `data:` 帧: ``` data: {"id":"***","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hello"}}]} data: [DONE] ``` OpenAI 兼容 SDK 会通过其常规流式 API 读取同一个流。 ## 选择流式响应路径[​](#选择流式响应路径 "选择流式响应路径的直接链接") 请选择与客户端响应格式匹配的代理端点: | 客户端格式 | 代理路径 | 行为 | | -------------------- | ---------------------- | ------------------------------------------------------------------------------------------------ | | OpenAI 兼容聊天 | `/v1/chat/completions` | 为 OpenAI 兼容 SDK 和直接 SSE 消费者返回 OpenAI 风格 SSE 分片。 | | Anthropic Messages | `/v1/messages` | 返回 Anthropic 风格 SSE 事件。提供该路由的上游原生流式返回,其余上游通过转换实现流式返回。 | | OpenAI Responses API | `/v1/responses` | 返回 Responses SSE 事件。提供该路由的上游原生流式返回,其余上游通过 Responses 桥接实现流式返回。 | 哪些上游可以原生流式返回,按服务提供方密钥逐个决定,见[声明 API 协议面](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#declare-the-api-surfaces)。 请以客户端格式作为选择依据,不要只因为上游服务提供方变化就切换到 `/v1/messages` 或 `/v1/responses`。 Chat Completions 音频输出是一个例外。AISIX 会在完整的非流式响应中保留 `message.audio`,但目前不会保留流式 `delta.audio` 分片。请保持[使用 Chat Completions 输入和输出音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md)的请求为非流式;如需增量双向音频,请使用 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md)。 ## 查看流式行为[​](#查看流式行为 "查看流式行为的直接链接") AISIX 接受请求并选定目标后才会开始流式返回。如果客户端在响应中途断开流,网关仍会保持健康,并继续处理后续请求。 流式 Chat Completions 不会被缓存。即使存在缓存策略,每个流式请求也都会调度到上游。 对于多目标模型,在任何流式字节发送给客户端之前,AISIX 可以重试或故障转移。一旦字节已经到达客户端,选中的上游就继续负责该流,AISIX 不会再切换目标。 如果启用了输出安全护栏,AISIX 可能会根据端点和安全护栏策略暂存、扫描或终止流式输出。对于 Chat Completions 和 Messages 流,被阻断的输出可以通过终止 SSE 错误事件表示,而不是正常完成流。对于 Responses API 流式响应,AISIX 可以先缓冲流内容进行策略检查,再决定返回或阻断。 当上游在流式响应中途断开时,除非特定端点的客户端契约另有说明,否则应将部分流视为未完成。 如果没有收到分片,请确认请求包含示例中的流式标志,并确认客户端按 Server-Sent Events 方式读取。对于 Responses API 流式响应,请检查选中的服务提供方是否支持转换后的请求形态。 如果流提前结束,请检查上游服务提供方状态、网关日志以及已配置的流式超时。 当模型尚未生成任何内容时,网关每隔 `downstream.sse_keepalive_interval_secs`(默认 15 秒)发送一条 SSE 注释,避免客户端与网关之间的代理将首 Token 较慢的模型视为已放弃连接。符合规范的 SSE 客户端会忽略这些注释。参见[调整下游连接层](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#%E8%B0%83%E6%95%B4%E4%B8%8B%E6%B8%B8%E8%BF%9E%E6%8E%A5%E5%B1%82)。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 AISIX 不同端点族之间的流式行为差异。主要 OpenAI 风格路径请参见 [OpenAI 兼容 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)。Anthropic 风格事件请参见 [Anthropic 风格 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)。流式错误和响应头请参见[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md)。 --- # 文本补全 有些应用会发送单个提示词,并期望收到文本补全响应,而不是聊天消息响应。AISIX AI 网关通过 completions 代理路由支持这种 OpenAI 兼容请求形态。 文本补全主要适用于已有的基于提示词的客户端。对于新的对话式应用,Chat Completions 路由通常能提供更广泛的服务提供方支持和更适合聊天场景的客户端能力。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由支持文本补全的服务提供方和模型支撑的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="text-prod" ``` ## 发送文本补全请求[​](#发��送文本补全请求 "发送文本补全请求的直接链接") 通过网关代理发送请求,并在请求体中使用 AISIX 模型别名: ``` curl -sS -X POST "${AISIX_PROXY}/v1/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "prompt": "Write one sentence about API gateways.", "max_tokens": 40 }' ``` AISIX 会解析模型别名、检查调用方 API Key、改写上游模型 ID,并将剩余请求体转发到服务提供方的 completions 端点。 响应会保持 OpenAI 兼容的文本补全格式: ``` { "id": "cmpl-***", "object": "text_completion", "model": "text-prod", "choices": [ { "text": "API gateways help manage, secure, and observe traffic between clients and services.", "index": 0, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 7, "completion_tokens": 13, "total_tokens": 20 } } ``` ## 服务提供方与网关行为[​](#服务提供方与网关行为 "服务提供方与网关行为的直接链接") Text Completions 路由是 OpenAI 兼容代理路径。支持 completions 的服务提供方可以通过已配置适配器接收请求。不支持 completions 的服务提供方会返回 501,错误类型为 `not_implemented`。 该路由不支持流式。设置了 `stream: true` 的请求会在 AISIX 调用服务提供方之前被拒绝并返回 `400`,因此服务提供方不会生成响应,也不会因此产生费用: ``` { "error": { "message": "request payload is invalid: `stream` is not supported on /v1/completions; use /v1/chat/completions for streaming", "type": "invalid_request_error" } } ``` 设置 `stream: false` 或未包含 `stream` 字段的请求不受影响,仍按原有方式转发。需要流式输出时,请使用 [OpenAI 兼容 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)。 输入安全护栏可以在 AISIX 调用服务提供方之前检查字符串提示词。包含字符串的提示词数组也可以被检查。Token ID 提示词会被转发,但其中不包含可供安全护栏扫描的文本。 输出安全护栏会在 AISIX 返回补全文本前扫描它,行为与 Chat Completions 路径相同。如果输出安全护栏阻断响应,AISIX 会返回 `422`。此时服务提供方已经生成响应并产生费用,因此该请求的 Token 用量仍会被记录。 成功响应会保持 OpenAI 兼容的 completions 响应格式。当上游响应包含 Token 用量时,AISIX 会记录该请求的用量。 ## 文本补全行为[​](#文本补全行为 "文本补全行为的直接链接") 当应用可以发送基于 role 的消息、使用工具、流式返回 assistant 输出,或希望覆盖最广泛的服务提供方后端时,建议使用 Chat Completions。 如果请求返回 501,说明解析出的服务提供方适配器不支持文本补全。请使用由支持 completions 的服务提供方支撑的模型,或将应用迁移到 Chat Completions。 如果输入安全护栏没有阻断提示词,请检查提示词是否包含可检查文本。字符串提示词和字符串数组可以被扫描;Token ID 提示词数组不会向输入安全护栏暴露文本。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解何时通过 AISIX 使用文本补全,以及为什么新集成通常更适合默认选择 Chat Completions。主要聊天链路请参见 [OpenAI 兼容 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)。 --- # 工具调用 工具调用允许模型要求应用运行一个具名函数,例如查询天气、查询数据库、调用内部服务或执行业务逻辑。模型不会亲自运行工具,而是返回结构化工具调用;应用解析参数、运行函数,并把结果发回模型,以便模型继续对话。 AISIX AI 网关通过 OpenAI 兼容 Chat Completions 路径承载这些工具调用请求,并在 OpenAI 风格和 Anthropic 风格工具格式之间进行有针对性的转换。应用可以把服务提供方凭证和模型路由留在 AISIX 后面,同时保留 SDK 或智能体框架期望的工具循环。 本指南将通过 AISIX 发送工具定义,查看后续工具循环,并选择与客户端格式匹配的请求路由。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问该模型别名的调用方 API Key。 * 一个由支持工具调用的服务提供方和模型支撑的模型别名。 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` ## 发送工具调用请求[​](#发送工具调用请求 "发送工具调用请求的直接链接") 下面示例使用 OpenAI 兼容 Chat Completions 路径。它发送函数定义,并要求模型调用该函数: ``` curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "messages": [ {"role": "user", "content": "What is the weather in Paris? Use the tool if needed."} ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Get weather for a city.", "parameters": { "type": "object", "properties": { "city": {"type": "string"} }, "required": ["city"] } } } ], "tool_choice": { "type": "function", "function": {"name": "get_weather"} } }' ``` 响应仍保持 OpenAI 兼容格式。你应在 assistant message 中看到工具调用: ``` { "choices": [ { "message": { "role": "assistant", "tool_calls": [ { "id": "call_***", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } } ] } } ] } ``` 如果模型返回普通文本,请先确认选中的上游模型支持工具调用,并且请求确实要求工具调用。 ## 继续工具调用循环[​](#继续工具调用循环 "继续工具调用循环的直接链接") 模型返回工具调用后,应用解析工具参数、运行函数,并通过同一个 Chat Completions 路由发回结果。请使用 assistant message 返回的 `tool_call_id`,让模型能够将工具结果关联到原始调用。 将工具结果作为后续消息发送: ``` curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "messages": [ {"role": "user", "content": "What is the weather in Paris? Use the tool if needed."}, { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_***", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } } ] }, { "role": "tool", "tool_call_id": "call_***", "content": "Sunny, 21 C." } ] }' ``` 对于后续请求,网关会保持相同的调用方认证和模型别名行为。服务提供方凭证和上游模型 ID 仍留在 AISIX 内部。 ## 选择工具调用路径[​](#选择工具调用路径 "选择工具调用路径的直接链接") 请选择与你的应用当前客户端格式匹配的路径: | 客户端格式 | 代理路径 | 行为 | | ---------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------ | | OpenAI 兼容工具 | `/v1/chat/completions` | 适用于 OpenAI SDK、OpenAI 风格智能体框架,以及期望 OpenAI 风格工具调用和后续工具消息的应用。 | | Anthropic 风格工具 | `/v1/messages` | 适用于已经围绕 Anthropic Messages 构建的客户端。Anthropic 上游比转换后的上游能保留更多原生行为。 | | 模型化路由之外的服务提供方原生工具 | 透传路由 | 仅当 AISIX 一等路由尚未建模所需服务提供方端点时使用。 | 对于生产环境工具循环,建议尽可能优先选择服务提供方原生工具调用路径,并验证计划使用的客户端、服务提供方、模型、流式模式和工具 schema 的完整组合。 ## 查看工具调用行为[​](#查看工具调用行为 "查看工具调用行为的直接链接") 当客户端格式和上游服务提供方格式一致时,工具调用行为最可预测。Anthropic 原生上游比转换后的上游能保留更丰富的 Anthropic 行为,而 OpenAI 兼容上游会直接保留 OpenAI 风格工具循环。 发往 Anthropic 上游模型的 OpenAI 风格请求,可以将函数工具、工具选择、assistant 工具调用和后续工具消息转换为 Anthropic Messages API 结构。 发往非 Anthropic 上游的 Anthropic 风格请求,可以将顶层 tools 和 tool choice 转换为 OpenAI 风格函数工具。当非 Anthropic 上游返回工具调用时,AISIX 可以将其渲染回 Anthropic 风格 tool-use 块。 跨服务提供方转换可以覆盖常见工具定义、工具选择、assistant 工具调用和后续工具结果,但不保证完全等价。流式工具调用还可能以部分参数片段形式到达,因此在生产环境依赖转换后的工具调用前,需要验证准确的流式行为。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经了解 AISIX 如何处理工具调用请求和转换后的工具定义。默认 OpenAI 风格聊天路径请参见 [OpenAI 兼容 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)。Anthropic 风格请求请参见 [Anthropic 风格 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)。 --- # 视频生成 视频生成功能允许应用通过 AISIX 提交提示词生成视频任务,同时在同一网关路径中统一处理调用方身份认证、模型别名、上游凭证、限流和内容安全护栏。 AISIX 提供兼容 OpenAI 的视频接口,其中三条路由对应模型服务提供方侧的异步工作流:提交任务、轮询状态和下载结果。网关不保存任务状态;返回的视频 ID 已编码 AISIX 将后续状态查询和下载调用路由到正确模型服务提供方所需的全部信息。 本指南将使用 Alibaba Model Studio 视频模型通过 AISIX 生成视频,并持续跟踪任务直至结果可下载。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 一个可以处理代理请求的 AISIX 网关。 * 一个可以访问视频模型别名的调用方 API Key。 * 一个已配置受支持视频模型服务提供方的模型别名(参见[端点行为](#endpoint-behavior))。除 OpenAI 外,每个模型服务提供方都需要配置 `api_base` 可访问其 API 的密钥;这些服务提供方没有内置默认 Base URL。如果 OpenAI 模型未设置 `api_base`,则回退到标准 OpenAI Base URL。以下示例使用 Alibaba Model Studio 模型。 示例使用如下模型别名。上游模型名称来自模型服务提供方目录中的文生视频模型: ``` { "display_name": "wan-video-prod", "model_name": "wan2.7-t2v", "provider_key_id": "YOUR_PROVIDER_KEY_ID" } ``` 导出网关连接和请求值: ``` # AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="wan-video-prod" ``` ## 创建视频生成任务[​](#创建视频生成任务 "创建视频生成任务的直接链接") 使用模型别名、提示词以及可选的视频时长(秒)提交任务: ``` curl -sS -X POST "${AISIX_PROXY}/v1/videos" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${AISIX_MODEL}"'", "prompt": "A miniature city built from cardboard comes alive at night.", "seconds": 5 }' ``` AISIX 会解析别名,对提示词执行输入安全护栏检查,预留限流容量,并向模型服务提供方异步提交任务。响应是一个视频任务对象: ``` { "id": "bW9kZWwtaWQtMTpkMkZ1TFhacFpHVnZMWEJ5YjJROnRhc2stMDE", "object": "video", "model": "wan-video-prod", "status": "queued", "progress": 0, "created_at": 1753257600, "seconds": "5" } ``` `id` 是由网关签发的不透明视频 ID。请保存该值,状态和下载路由会将其用作路径参数。 请求字段: | 字段 | 必填 | 含义 | | --------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | 是 | AISIX 模型别名。 | | `prompt` | 是 | 用于生成视频的文本提示词。 | | `seconds` | 否 | 视频时长(秒),可以是整数或数字字符串。转发为各模型服务提供方自己的时长参数,参见[参数映射](#parameter-mapping)。 | | `size` | 否 | 像素尺寸,格式为 `WIDTHxHEIGHT`,例如 `1280x720`。各模型服务提供方表达输出尺寸的方式不同,并会按其各模型的取值列表校验该值,因此设置前请查阅[参数映射](#parameter-mapping)和该模型服务提供方的模型文档。 | 未设置的可选字段会从上游请求中完全省略。 ## 轮询任务状态[​](#轮询任务状态 "轮询任务状态的直接链接") 使用视频 ID 轮询任务,直到状态达到终态: ``` curl -sS "${AISIX_PROXY}/v1/videos/YOUR_VIDEO_ID" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 任务完成时状态为 `completed`;如果模型服务提供方返回了实际视频时长,响应也会包含该值: ``` { "id": "bW9kZWwtaWQtMTpkMkZ1TFhacFpHVnZMWEJ5YjJROnRhc2stMDE", "object": "video", "model": "wan-video-prod", "status": "completed", "progress": 100, "created_at": 0, "seconds": "5" } ``` `status` 是包含四个值的枚举: | 状态 | 含义 | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `queued` | 模型服务提供方已接受任务,但尚未开始。 | | `in_progress` | 模型服务提供方正在生成视频。 | | `completed` | 视频已可下载。 | | `failed` | 生成失败、任务已取消,或模型服务提供方已无法识别该任务(例如任务已过期)。如果模型服务提供方提供了错误信息,响应会包含带有其 `code` 和 `message` 的 `error` 对象。 | AISIX 会把各模型服务提供方自己的任务状态归一化到该枚举。有些模型服务提供方没有单独的排队状态,其任务提交后直接进入 `in_progress`: | `provider` 值 | `queued` | `in_progress` | `completed` | `failed` | | ------------- | ------------------------------------- | ------------- | ----------- | ------------------------------------------- | | `alibaba` | `PENDING` | `RUNNING` | `SUCCEEDED` | `FAILED`、`CANCELED`、`UNKNOWN` 或其他状态 | | `zhipuai` | 不返回,任务直接从 `in_progress` 开始 | `PROCESSING` | `SUCCESS` | `FAIL` 或其他状态 | | `volcengine` | `queued` | `running` | `succeeded` | `failed`、`cancelled`、`expired` 或其他状态 | | `runwayml` | `PENDING`、`THROTTLED` | `RUNNING` | `SUCCEEDED` | `FAILED`、`CANCELLED` 或其他状态 | | `openai` | `queued` | `in_progress` | `completed` | `failed` 或其他状态 | 对于会返回真实完成百分比的模型服务提供方(OpenAI Sora),`progress` 会显示该值。对于不提供百分比的服务,该值在任务完成前为 `0`,完成后为 `100`。由于网关不存储任务状态,只有提交响应会填充 `created_at`;轮询响应会返回 `0`。 ## 下载视频[​](#下载视频 "下载视频的直接链接") 当状态为 `completed` 时,请求内容路由。请使用 `curl -L`,使该命令适用于所有模型服务提供方。AISIX 会根据模型服务提供方交付成品文件的方式,重定向到其下载 URL,或自行流式传输视频: ``` curl -sS -L -o video.mp4 \ "${AISIX_PROXY}/v1/videos/YOUR_VIDEO_ID/content" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 两种路径保存的 MP4 相同,但在脚本处理响应时存在以下区别: | 交付方式 | 模型服务提供方 | 内容路由返回值 | | ------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 重定向 | Alibaba、Zhipu、Volcengine Ark、Runway | 返回 `302`,`Location` 响应头指向模型服务提供方签名的下载 URL。文件直接从模型服务提供方的存储传输到客户端,不经过网关。AISIX 仅重定向到绝对 `http` 或 `https` URL。 | | 网关流式传输 | OpenAI | 返回 `200` 和 MP4 字节、模型服务提供方的 `Content-Type`(通常为 `video/mp4`)以及用于标记附件的 `Content-Disposition` 响应头。模型服务提供方要求使用其凭证下载文件,因此 AISIX 会使用配置的模型服务提供方密钥获取文件并流式转发字节。调用方不会接触到模型服务提供方凭证。 | 流式响应逐块经过网关,不会完整保存在内存中,因此大文件不会增加网关内存用量。每次分块读取受模型的流超时限制:如果较慢的上游停滞,传输会在正文中途终止。模型服务提供方声明 `Content-Length` 时,网关会原样转发;此时中断的传输会被客户端识别为长度不足,请重试内容请求。 如需检查某个模型服务提供方使用的路径,请让 curl 在不跟随重定向的情况下输出状态: ``` curl -sS -o /dev/null -w "%{http_code} %{redirect_url}\n" \ "${AISIX_PROXY}/v1/videos/YOUR_VIDEO_ID/content" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 使用重定向的模型服务提供方会输出重定向状态和由其托管的 URL: ``` 302 https://provider-cdn.example.com/videos/task-01/out.mp4 ``` 使用网关流式传输的模型服务提供方会输出 `200`,重定向 URL 为空。在该路径上,此探测会将完整文件传输到 `/dev/null`,因此请使用较小的任务: ``` 200 ``` 如果任务尚未完成,内容路由返回 `400`,并提示调用方继续轮询。如果任务失败,它会返回 `400` 和模型服务提供方的失败详情。模型服务提供方下载端点返回的错误始终使用 JSON 错误封装,不会表现为截断的视频正文。 ## 限流和安全护栏[​](#限流和安全护栏 "限流和安全护栏的直接链接") 提交路由会在任务到达模型服务提供方之前,像其他建模路由一样预留调用方 API Key 各层级和模型限制的容量。模型限制包括内联 `rate_limit` 以及模型作用域的限流策略。参见 [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md)和[限流策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md)。 状态和内容路由仅预留调用方 API Key 各层级的容量。任务轮询特意不受模型级限制:客户端提交任务后即使触及模型提交上限,仍可轮询该任务直到完成。对于经网关流式传输的模型服务提供方,这也意味着视频字节经过网关时不计入模型限制,因此应相应规划网关的出口带宽。 该请求解析到的输入[安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md),无论关联在模型、调用方 API Key、团队还是环境上,都会在提交前扫描提示词。被阻断的提示词不会创建任何模型服务提供方任务,也不会占用模型限流容量。 ## 端点行为[​](#endpoint-behavior "端点行为的直接链接") * 如果模型服务提供方密钥的 `api_base` 以其兼容 OpenAI 或带版本的后缀结尾(Alibaba 使用 `/compatible-mode/v1`、`/api/v1` 或 `/v1`;Zhipu 使用 `/api/paas/v4`;Volcengine Ark 使用 `/api/v3`),AISIX 会自动推导服务提供方根路径,因此为聊天流量配置的现有密钥可直接使用。Runway 文档中的 Base URL 是不带路径的主机,OpenAI 则同时接受不带路径的主机和 `/v1` Base URL。 * 提交路由要求 JSON 媒体类型,例如 `application/json`。OpenAI Python SDK 中的视频创建方法每次调用都会发送 `multipart/form-data`,即使没有参考素材也一样,因此无法驱动该路由,请改用普通 HTTP 客户端提交。两条 GET 路由是普通 GET 请求,不受此限制。 * OpenAI 是唯一具有内置默认 Base URL 的视频模型服务提供方:未设置 `api_base` 的 OpenAI 模型会解析到标准 OpenAI API。其他模型服务提供方都要求在密钥上设置 `api_base`。 * 每次到达模型服务提供方的提交都会以零 Token 记录在用量日志中。在分发前就被拒绝的请求(JSON 格式错误,或模型服务提供方不在允许列表内)不会产生用量记录。基于视频时长的成本核算尚未应用到 AISIX Cloud 预算。 * 提交不保证至多一次。AISIX 会重试发送阶段的传输失败和上游 `5xx`,而首次尝试是否已到达模型服务提供方是无法确知的,因此重试可能创建第二个计费任务,且调用方永远看不到它的 ID。上游已经响应、只是响应正文读取或解析失败时,AISIX 特意不重试。 ### 支持的模型服务提供方[​](#supported-providers "支持的模型服务提供方的直接链接") AISIX 按模型别名自身的 `provider` 值分发视频路由,而不是按上游模型名称;别名关联的密钥只提供凭证和 `api_base`。这些路由只接受直连别名——路由模型或合议模型别名会返回 `400`。 AISIX 不维护模型 ID 允许列表,只会把别名中配置的上游模型名称按下表的固定映射转发出去,因此能否生成成功仍取决于该模型是否接受转发后的请求形态。创建别名前请查阅该模型服务提供方的最新模型列表以及该模型自身的参数规则。 | `provider` 值 | 配置指南 | 视频模型 | 交付方式 | | ----------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------ | | `alibaba` | [Qwen(阿里云)](https://docs.apiseven.com/ai-gateway/providers/qwen.md) | Model Studio Wan 和 HappyHorse 文生视频,例如 `wan2.7-t2v`、`wan2.2-t2v-plus` 和 `happyhorse-1.1-t2v` | 重定向 | | `zhipuai`(也接受 `zhipu`) | [Zhipu AI](https://docs.apiseven.com/ai-gateway/providers/zhipuai.md) | CogVideoX,例如 `cogvideox-3` | 重定向 | | `volcengine` | [Volcengine Ark](https://docs.apiseven.com/ai-gateway/providers/volcengine-ark.md) | Ark Seedance,例如 `doubao-seedance-2-0-260128` | 重定向 | | `runwayml`(也接受 `runway`) | [RunwayML](https://docs.apiseven.com/ai-gateway/providers/runwayml.md) | 文生视频端点上的 Runway Gen 系列和由 Runway 托管的模型,例如 `gen4.5`、`veo3.1` 和 `seedance2` | 重定向 | | `openai` | [OpenAI](https://docs.apiseven.com/ai-gateway/providers/openai.md) | Sora:`sora-2` 和 `sora-2-pro` | 网关流式传输 | 警告 OpenAI 已于 2026 年 3 月 24 日[弃用 Videos API 和 Sora 2 系列模型](https://developers.openai.com/api/docs/deprecations),并将于 2026 年 9 月 24 日将其从 API 中移除。届时以 `sora-2` 或 `sora-2-pro` 为上游的别名将停止工作。 模型别名的模型服务提供方不在上表中时,提交会返回 `501 not_implemented`。此时请通过[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)访问其原生视频 API。 有两个可用于聊天流量的 `provider` 值被特意排除在外:`alibaba-cn` 和 `zai`。它们访问的 API 根路径与各自支持视频的对应值不同,因此视频别名必须使用 `alibaba` 或 `zhipuai`。 ### 参数映射[​](#parameter-mapping "参数映射的直接链接") AISIX 会把统一请求中的 `seconds` 和 `size` 映射到各模型服务提供方自己的参数上。该映射按模型服务提供方划分,而非按模型:AISIX 不会判断别名指向哪个模型系列,因此当某个模型服务提供方的新模型改用了别的参数时,省略统一字段是调用方自己的责任。模型服务提供方完全无法表达的字段会被丢弃,而不会被改写成语义不同的另一个参数;模型服务提供方会按其各模型的取值列表校验收到的值。 | `provider` 值 | `seconds` 映射为 | `size` 映射为 | | ------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `alibaba` | `parameters.duration` | `parameters.size`,格式为 `WIDTH*HEIGHT`。该参数对应 Wan 2.6 及更早版本的请求协议。Wan 2.7 模型已改用 `resolution` 和 `ratio` 档位,而 AISIX 仍会原样转发你发送的值,因此 Wan 2.7 别名请自行省略 `size`,由模型服务提供方使用默认值。 | | `zhipuai` | `duration` | `size`,格式为 `WIDTHxHEIGHT`,原样转发 | | `volcengine` | `duration` | 不转发。Ark 使用 `resolution` 和 `ratio` 档位表达输出尺寸,无法承载任意 `WIDTHxHEIGHT`。AISIX 会校验格式后丢弃该值,由模型服务提供方使用默认值。提交响应仍会回显你发送的 `size`,但这并不代表 Ark 使用了它;轮询响应不返回该字段。 | | `runwayml` | `duration` | `ratio`,格式为 `WIDTH:HEIGHT`。AISIX 只替换分隔符,具体取值由 Runway 按其各模型的分辨率列表校验。 | | `openai` | `seconds`,以字符串形式发送。OpenAI 的视频创建 schema 接受 `4`、`8` 或 `12`。 | `size`,格式为 `WIDTHxHEIGHT`,原样转发。schema 列出 `720x1280`、`1280x720`、`1024x1792` 和 `1792x1024`,但 OpenAI 各模型页面公布的取值范围更窄,请查阅对应模型页面。AISIX 只校验 `WIDTHxHEIGHT` 格式。 | ### 路由未建模的请求字段[​](#request-fields-the-routes-do-not-model "路由未建模的请求字段的直接链接") 这些路由只覆盖文生视频。除 `model`、`prompt`、`seconds` 和 `size` 之外的字段会被忽略而不是拒绝,因此携带这些字段的请求仍会生成视频,但只依据提示词生成。 * `input_reference` 会被忽略。这些路由未建模图生视频和视频生视频。 * 模型服务提供方原生的生成控制参数,例如负向提示词、随机种子、参考图,或 Wan 2.7 的 `resolution` 和 `ratio` 档位,都没有对应的统一字段,不会被转发。 * AISIX 只提供 `POST /v1/videos`、`GET /v1/videos/{video_id}` 和 `GET /v1/videos/{video_id}/content` 三条建模视频路由。模型服务提供方用于列出、删除、混剪、编辑或延长视频的路由均未建模,生成之外的其他模型服务提供方专有路由同样未建模。 调用方需要上述任一能力时,请配置[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md):它直达模型服务提供方的原生视频 API,同时仍由网关持有凭证并执行调用方 API Key 的访问规则。 ### 错误[​](#errors "错误的直接链接") 下表列出的是 AISIX 自身产生的状态码。模型服务提供方返回的 `4xx` 会保留其状态码,以上游错误封装转发;模型服务提供方的 `5xx`、传输失败,或 AISIX 无法解析的响应会转为 `502`;上游超时转为 `504`;请求正文超过大小上限转为 `413`。 下载失败的表现取决于交付方式。网关流式传输时,AISIX 会在开始传输前检查模型服务提供方的内容端点,因此该端点返回的错误是 JSON 错误封装;而响应头发出之后被中断的流不是,此时若模型服务提供方声明了 `Content-Length`,调用方看到的是长度不足。重定向交付时,AISIX 从不获取文件:它只把模型服务提供方给出的绝对 `http` 或 `https` URL 原样返回、不做校验,因此客户端跟随重定向之后的任何失败都来自模型服务提供方或其 CDN,格式也由对方决定。 | 状态码 | 触发场景 | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `400` | 请求格式错误:`seconds` 不是正整数,或 `size` 不是 `WIDTHxHEIGHT`。此外,任务仍在进行时内容路由返回 `400` 并提示调用方继续轮询;任务失败时返回 `400` 和模型服务提供方的失败详情。 | | `401` | 调用方 API Key 缺失或无效。 | | `403` | 提交时调用方 API Key 无权使用该模型别名,或请求来自模型允许列表之外的客户端 IP。错误类型为 `permission_denied`;IP 被拒时还会携带 `ip_restricted` 错误码。 | | `404` | 提交时 `model` 未匹配到网关已知的任何别名,错误类型为 `model_not_found`。GET 路由上则是视频 ID 未知或格式错误,或该 ID 属于调用方 API Key 无法访问的模型,错误类型为 `video_not_found`。GET 路由会把访问被拒和未实现的模型服务提供方一并折叠为 `404`,因此无法用 ID 探测有哪些模型存在。 | | `422` | 输入安全护栏阻断了提示词。此时不会创建模型服务提供方任务,也不会占用限流容量。 | | `429` | 请求被限流或 AISIX Cloud 预算拒绝。提交同时计入调用方 API Key 各层级和模型限制;状态和内容调用只计入调用方 API Key 各层级。AISIX Cloud 会在三条路由上检查调用方预算,因此超预算的调用方无法轮询或下载自己已付费提交的任务。 | | `501` | 模型别名解析到的模型服务提供方不在视频路由的允许列表内。错误类型为 `not_implemented`。 | 模型服务提供方报告任务失败时,状态路由不会返回 HTTP 错误:`GET /v1/videos/{video_id}` 返回 `200`,其中 `"status": "failed"`,并带有承载模型服务提供方 `code` 和 `message` 的 `error` 对象。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已经通过网关的建模视频接口生成视频。对于 AISIX 尚未建模的模型服务提供方视频 API,请配置一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md);在 inject 模式路由上,当请求正文指定已配置模型时,模型级限流同样适用。 --- # AISIX Cloud 快速入门 在本快速入门中,你将在一台机器上使用 Docker Compose、随附的 PostgreSQL 数据库和本地端点评估 AISIX Cloud。你将启动控制面和控制台、连接 AISIX 网关、配置 OpenAI 模型,并通过网关发送请求。 本地设置将控制面服务、控制台和 PostgreSQL 作为一个管理栈运行。AISIX 网关独立运行,使配置路径和实时流量路径相互分离: 本快速入门通过 AISIX Cloud Admin API 配置资源,使工作流可复现,并为后续指南准备环境。AISIX Cloud 会把这些资源发送到网关。之后,客户端请求会通过网关到达 OpenAI,而不经过控制面;控制台则提供网关状态、日志和用量信息。 许可证 AISIX Cloud 控制面和控制台是商业软件。开发、测试和评估可以免费使用部分功能,但生产使用需要商业许可证。如需在生产环境运行控制面,请[联系 API7](https://api7.ai/contact)或发送邮件至 。 ## 准备工作[​](#准备工作 "准备工作的直接链接") * 安装带有 Docker Compose V2 的 [Docker](https://docs.docker.com/get-docker/)。 * 安装 [cURL](https://curl.se/)、[jq](https://jqlang.github.io/jq/)、`tar` 和 OpenSSL。 * 确保安装主机可以访问 `run.api7.ai`、Docker Hub 和 OpenAI。 * 确保安装主机上的 `5432`、`8080`、`7944` 和 `3000` 端口可用。 * 使用可以访问安装主机 `8080` 端口的浏览器。 * 准备用于本快速入门所配置模型的 OpenAI API Key。 ## 启动控制面[​](#step-1--start-aisix-cloud "启动控制面的直接链接") 在安装了 Docker 且可以访问互联网的主机上运行: ``` curl -fsSL "https://run.api7.ai/aisix-self-hosted/quickstart" | bash ``` 安装程序会将当前 On-Premises 软件包下载到 `./aisix-self-hosted`,生成包含全新 Secret 的 `.env` 文件,拉取容器镜像并启动管理栈。默认控制台 URL 为 `http://localhost:8080`。 对于本单主机快速入门,请打开 `./aisix-self-hosted/.env`,并将数据面管理器 URL 设置为: ``` AISIX_CLOUD_DPMGR_BASE_URL=https://host.docker.internal:7944 ``` 重新创建 `api` 和 `dpm` Docker Compose 服务,使控制台使用更新后的端点,并让 `dp-manager` 为该端点签发 TLS 证书: ``` cd aisix-self-hosted docker compose up -d api dpm ``` 检查控制面健康检查端点: ``` curl -fsS "http://127.0.0.1:8080/healthz" ``` 该命令应返回 `{"status":"ok"}`。其余 shell 命令继续在 `aisix-self-hosted` 目录中的此终端运行。 ## 创建 Admin Token[​](#step-2--create-an-admin-token "创建 Admin Token的直接链接") AISIX Cloud Admin API 使用组织级 Admin Token 进行身份认证。请在控制台中创建 Token: 1. 在浏览器中打开 `http://localhost:8080`,然后选择 **Create an account**。 2. 注册第一个用户、接受用户协议,并创建第一个组织。 3. 在组织导航中打开 **Admin tokens**,然后选择 **New token**。 4. 输入名称 `quickstart-admin`、选择到期时间,并启用 **write** Scope。 5. 创建 Token,并在离开页面前复制明文值。该值只显示一次。 在终端中导出控制面 API URL 和 Token: ``` export AISIX_CP="http://localhost:8080/api" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" ``` 有关 Token Scope、到期和轮换的详细信息,请参阅 [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md)。 ## 创建网关资源[​](#step-3--create-an-environment-a-model-and-a-caller-api-key "创建网关资源的直接链接") 通过 Admin API 创建环境、模型服务提供方密钥、模型和调用方 API Key。控制台也可以使用对应字段创建相同资源,但本快速入门使用 API 请求提供一套可复制的工作流,并保留后续指南会用到的 ID。 创建 `prod` 环境: ``` ENV_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/environments" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"display_name": "prod"}') export ENV_ID=$(echo "$ENV_RESPONSE" | jq -er '.environment.id') echo "$ENV_RESPONSE" | jq ``` 创建一个保存 OpenAI 凭证且允许在该环境中使用的模型服务提供方密钥: ``` export OPENAI_API_KEY="YOUR_OPENAI_API_KEY" PROVIDER_KEY_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "provider": "openai", "display_name": "OpenAI", "api_key": "'"${OPENAI_API_KEY}"'", "api_base": "https://api.openai.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }') export PROVIDER_KEY_ID=$(echo "$PROVIDER_KEY_RESPONSE" | jq -er '.provider_key.id') echo "$PROVIDER_KEY_RESPONSE" | jq ``` 创建由该模型服务提供方密钥支持的 `gpt-4o-mini` 模型: ``` MODEL_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gpt-4o-mini", "model_name": "gpt-4o-mini", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }') export MODEL_ID=$(echo "$MODEL_RESPONSE" | jq -er '.model.id') echo "$MODEL_RESPONSE" | jq ``` 创建允许使用该模型的调用方 API Key。明文密钥只返回一次,请将其保存: ``` API_KEY_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "display_name": "quickstart-caller", "allowed_models": ["'"${MODEL_ID}"'"] }') export API_KEY_ID=$(echo "$API_KEY_RESPONSE" | jq -er '.api_key.id') export AISIX_API_KEY=$(echo "$API_KEY_RESPONSE" | jq -er '.plaintext') echo "$API_KEY_RESPONSE" | jq ``` 每条命令都会保存下一步或后续指南所需的资源 ID。如果 `curl` 或 `jq` 报错,请先停止并修正问题;缺少 ID 会导致后续命令失败。 ## 连接 AISIX 网关[​](#step-4--attach-a-gateway "连接 AISIX 网关的直接链接") 控制面负责管理网关配置,但不承载 AI 流量。请将一个网关连接到 `prod` 环境: 1. 在控制台中打开 `prod` 环境,选择 **Data planes**,然后选择 **Issue certificate**。 2. 打开 **Docker** 标签页并复制生成的命令片段。该片段包含网关证书和私钥,因此请将其作为 Secret 处理。 3. 在 Linux 上,将 `--add-host host.docker.internal:host-gateway` 添加到生成的 `docker run` 命令。Docker Desktop 会自动解析 `host.docker.internal`。 4. 运行该命令片段。它会启动名为 `aisix-dp` 的容器,把代理发布到端口 `3000`,并持续输出连接日志。日志显示 `etcd connected` 后按 **Ctrl+C**;网关会继续在后台运行。 5. 返回 **Data planes**,刷新页面,并确认页面报告一个已连接的网关实例。 有关证书处理、生成的部署命令、网络和连接故障排查,请参阅[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 ## 发送并验证请求[​](#step-5--send-a-request "发送并验证请求的直接链接") 导出本地网关源站地址,再检查网关是否存活: ``` export AISIX_PROXY="http://127.0.0.1:3000" ``` 检查代理监听器: ``` curl -fsS "$AISIX_PROXY/livez" ``` 该命令应返回 `ok`。连接 AISIX Cloud 的网关在从控制面应用第一个配置之前不会绑定代理监听器,因此如果这条命令报告连接被拒绝,说明网关还没有收到该配置。它的日志会记录这段等待,要找的是 `first configuration applied — binding the proxy listener` 这一行。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 然后确认已配置模型已经到达网关: ``` curl -fsS "$AISIX_PROXY/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` `data` 数组应包含 `gpt-4o-mini`。资源投射是异步的;如果模型尚未列出,请等待几秒后重新运行命令。在模型出现之前不要继续。 然后发送聊天请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [ {"role": "user", "content": "Say hello from AISIX AI Gateway."} ] }' ``` 你应收到兼容 OpenAI 的响应,并在 `choices[0].message` 中看到助手消息。在控制台中,打开 `prod` 环境的 **Logs** 检查该请求,再打开组织导航中的 **Usage** 查看其用量数据。 ## 清理[​](#清理 "清理的直接链接") 如果计划继续阅读其它 AISIX Cloud 指南,请保留示例资源和 Admin Token。否则,请按依赖顺序删除资源: ``` curl -fsS -X DELETE \ "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer ${AISIX_TOKEN}" | jq curl -fsS -X DELETE \ "$AISIX_CP/environments/$ENV_ID/models/$MODEL_ID" \ -H "Authorization: Bearer ${AISIX_TOKEN}" | jq curl -fsS -X DELETE \ "$AISIX_CP/provider_keys/$PROVIDER_KEY_ID" \ -H "Authorization: Bearer ${AISIX_TOKEN}" | jq ``` API 清理完成后,如果不再需要 `quickstart-admin`,请在控制台中将其撤销。然后删除网关容器: ``` docker rm -f aisix-dp ``` 停止并删除控制面容器: ``` ./run.sh down ``` 该操作会保留 PostgreSQL 数据卷。 ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经通过连接本地控制面的网关发送了请求。接下来可以: * 按照 [On-Premises 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md)选择安装方式,并准备持久化环境。 * 使用 [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)和本快速入门中创建的 Admin Token 自动执行控制面操作。 * 阅读[资源模型](https://docs.apiseven.com/ai-gateway/models/resource-model.md),了解模型服务提供方密钥、模型和调用方 API Key 如何配合工作。 * 通过 [OpenAI SDK](https://docs.apiseven.com/ai-gateway/getting-started/openai-sdk.md) 或 [Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md) 指南,在应用代码中调用网关。 --- # Anthropic SDK 将 Anthropic Python SDK 指向 AISIX AI 网关,在保留 Anthropic Messages 请求格式的同时,由网关管理调用方身份认证、模型别名、路由和策略。 SDK 只需要网关 base URL、AISIX 调用方 API Key,以及可通过 `/v1/messages` 使用的模型别名。该别名可以直接使用 Anthropic,也可以通过 AISIX 转换使用其他受支持的模型服务提供方。 ## 准备工作[​](#准备工作 "准备工�作的直接链接") * 应用可以访问的、正在运行的 AISIX 网关。 * 可通过 `/v1/messages` 使用的已配置模型别名。 * 允许使用该模型别名的调用方 API Key。 * Python 3.9 或更新版本。 如果你的组织已部署 AISIX,请向负责管理的团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作;如需使用 Hybrid Cloud,请[联系 API7](https://api7.ai/contact)。 如需为任一产品配置由 Anthropic 支持的模型别名,请按照 [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md) 指南操作。AISIX Cloud 与开源 AISIX 网关的 SDK 客户端配置相同。 ## 请求流程[​](#请求流程 "请求流程的直接链接") 保留 Anthropic SDK 客户端,但将请求发送到网关,而不是直接调用上游模型服务提供方:
应用发送调用方 API Key 和 AISIX 模型别名。AISIX 对调用方进行授权、解析别名,并在调用上游模型时提供已保存的模型服务提供方凭证。 ## 配置 SDK[​](#配置-sdk "配置 SDK的直接链接") 设置调用方 API Key、模型别名和网关 base URL: ``` # AISIX_BASE_URL 是网关源地址,不含末尾斜杠或 /v1 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="claude-sonnet-prod" ``` Anthropic SDK 会将 `/v1/messages` 追加到 base URL。不要在 `AISIX_BASE_URL` 中包含 `/v1`。 ### 安装 Anthropic SDK[​](#安装-anthropic-sdk "安装 Anthropic SDK的直接链接") 创建并激活 Python 虚拟环境: ``` python3 -m venv .venv . .venv/bin/activate ``` 安装 Anthropic SDK: ``` python -m pip install anthropic ``` ### 创建客户端示例[​](#创建客户端示例 "创建客户端示例的直接链接") 创建以下客户端: anthropic-sdk-example.py ``` import os from anthropic import Anthropic client = Anthropic( api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], ) message = client.messages.create( model=os.environ["AISIX_MODEL"], max_tokens=128, messages=[{"role": "user", "content": "Say hello from AISIX."}], ) print(message.content[0].text) ``` 运行示例: ``` python anthropic-sdk-example.py ``` 你应该会看到一段简短的助手回复。具体文本取决于上游模型。 SDK 使用 AISIX 模型别名发送 `POST /v1/messages` 请求。AISIX 对调用方 API Key 进行身份认证、检查模型允许列表、解析别名,并返回 Anthropic 风格的 message 响应。 ## 兼容性边界[​](#兼容性边界 "兼容性边界的直接链接") `POST /v1/messages` 既可以解析由 Anthropic 支持的模型别名,也可以解析非 Anthropic 支持的模型别名。由 Anthropic 支持的别名最能直接保留 Anthropic 特有的请求和响应行为。 当你需要稳定的 Anthropic 风格客户端入口时,非 Anthropic 转换很有用,但它并不与原生 Anthropic 行为完全等价。如果应用依赖工具结果往返、思考块、图片块或其它 Anthropic 特有内容块,建议优先使用由 Anthropic 支持的别名,并验证完整流程。 完整端点行为请参阅 [Anthropic 风格 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)。 ## 如果 SDK 请求失败[​](#如果-sdk-请求失败 "如果 SDK 请求失败的直接链接") 先使用相同的调用方 API Key 和模型别名直接请求 `/v1/messages`。如果直接请求成功,请确认 `AISIX_BASE_URL` 指向网关根路径,并且不以 `/v1` 结尾。 如果 AISIX 返回 `404`,说明请求的模型别名未配置。如果 AISIX 返回 `403`,说明调用方 API Key 存在,但没有权限使用该别名。如果上游身份认证或模型发生错误,请验证模型服务提供方配置,不要替换调用方 API Key。 ## 清理[​](#清理 "清理的直接链接") 删除本页创建的 Python 环境: ``` deactivate rm -rf .venv ``` 本示例使用的网关资源在本页之外创建。使用 AISIX Cloud 时,请在控制台中删除调用方 API Key、模型别名和模型服务提供方密钥。使用开源 AISIX 网关时,请从 `resources.yaml` 中移除相应条目并重新加载。 ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经通过 Anthropic SDK 客户端调用了 AISIX。接下来可阅读 [Anthropic 风格 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)了解端点行为,阅读[流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md)了解流式响应,或阅读 [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md) 配置上游。 --- # 开源 AISIX 网关快速入门 使用本快速入门,在单个 Docker 容器中运行开源 AISIX 网关,并通过该网关发送第一个 AI 请求。你将在一个 `resources.yaml` 文件中声明必需的模型服务提供方密钥、模型和调用方 API Key,启动网关,再通过兼容 OpenAI 的 API 验证请求。 此设置不需要控制台、控制面或独立配置存储,是在本地评估网关的最快方式。示例使用 OpenAI 作为上游服务提供方。客户端使用调用方 API Key 向 AISIX 认证,网关则使用单独的模型服务提供方密钥向 OpenAI 认证。 请求遵循以下路径: 当客户端请求 AISIX 模型名称 `gpt-4o-mini` 时,网关会使用调用方 API Key 认证请求,并使用已保存的模型服务提供方密钥调用 OpenAI。上游 OpenAI Key 绝不会暴露给客户端。 ## 前提条件[​](#前提条件 "前提条件的直接链接") * 安装 [Docker](https://docs.docker.com/get-docker/),用于运行 AISIX AI 网关容器。 * 安装 [cURL](https://curl.se/),用于向网关发送请求。 * 准备一个可以访问 `gpt-4o-mini` 且有可用配额的 OpenAI API Key。 ## 创建资源文件[​](#create-the-resources-file "创建资源文件的直接链接") 首先创建工作目录: ``` mkdir aisix-quickstart cd aisix-quickstart ``` 模型服务提供方密钥、模型和调用方 API Key 统一声明在一个 `resources.yaml` 文件中。创建该文件: resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-main provider: openai adapter: openai api_key: ${OPENAI_API_KEY} api_base: https://api.openai.com/v1 models: - display_name: gpt-4o-mini provider: openai model_name: gpt-4o-mini provider_key: openai-main api_keys: - display_name: quickstart-caller key_env: CALLER_API_KEY allowed_models: - gpt-4o-mini ``` ❶ `_format_version: "1"` 为必填项,且必须是带引号的字符串。它会固定文件格式,避免未来版本悄然错误解读此文件。 ❷ 加载文件时会从网关环境中解析 `${OPENAI_API_KEY}`,因此文件本身不会包含上游凭证。引用的变量未设置或为空会导致加载失败。 ❸ `provider_key` 通过 `display_name` 引用上方的模型服务提供方密钥。引用未定义名称会导致加载失败,因此拼写错误不会变成无提示的运行时故障。 ❹ `key_env` 指定保存明文调用方 API Key 的环境变量。网关会在加载时计算该值的哈希,并且只存储哈希。变量名不要以 `AISIX_` 开头,因为该前缀保留给[启动配置覆盖项](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。如需提供预先计算的 SHA-256 哈希,请使用 `key_hash` 代替 `key_env`。 网关会根据资源名称生成稳定 ID,因此每个名称在其集合中必须唯一。 ## 创建启动配置[​](#创建启动配置 "创建启动配置的直接链接") 创建 `config.yaml` 文件,使网关指向资源文件: config.yaml ``` resources_file: /etc/aisix/resources.yaml proxy: addr: "0.0.0.0:3000" admin: enabled: false ``` ❶ `resources_file` 将该文件选作网关的资源来源。使用此设置时,网关不使用外部配置存储,因此省略 `etcd` 部分。两者互斥。 ❷ `proxy.addr` 监听所有容器接口上的 `3000` 端口。下方 Docker 命令会把该端口发布到主机的 `http://127.0.0.1:3000`。 其他启动选项请参阅[启动配置参考](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md)。 ## 启动 AISIX AI 网关[​](#start-aisix-ai-gateway "启动 AISIX AI 网关的直接链接") 导出 `resources.yaml` 引用的两个值和本地网关源站地址: ``` # 替换为你的 OpenAI API Key。 export OPENAI_API_KEY="YOUR_PROVIDER_API_KEY" # 为客户端请求选择调用方 API Key。 export CALLER_API_KEY="YOUR_CALLER_API_KEY" # 本快速入门将网关发布在此源站地址。 export AISIX_PROXY="http://127.0.0.1:3000" ``` 启动网关前,请在短生命周期容器中验证 `resources.yaml`。这样可以在不启动监听器的情况下发现插值、引用和 schema 错误: ``` docker run --rm \ -v "$(pwd):/etc/aisix:ro" \ -e OPENAI_API_KEY \ -e CALLER_API_KEY \ --entrypoint /usr/local/bin/aisix \ ghcr.io/api7/aisix:1.2.0 \ validate --resources /etc/aisix/resources.yaml ``` 该命令应报告文件已加载三个资源。然后启动网关,并挂载整个工作目录,使后续编辑仍可在正在运行的容器中看到: ``` docker run -d --name aisix-quickstart \ -v "$(pwd):/etc/aisix:ro" \ -e OPENAI_API_KEY \ -e CALLER_API_KEY \ -p 3000:3000 -p 9090:9090 \ ghcr.io/api7/aisix:1.2.0 ``` 如果任何资源条目无效,容器会在启动时退出。`docker logs aisix-quickstart` 会报告所有无效的资源类型、条目和字段,而不是在第一个错误处停止。 ## 验证网关[​](#验证网关 "验证网关的直接链接") 检查代理监听器是否存活: ``` curl -sS "$AISIX_PROXY/livez" ``` 该命令应返回 `ok`。 列出该调用方 API Key 可见的模型: ``` curl -sS "$AISIX_PROXY/v1/models" \ -H "Authorization: Bearer ${CALLER_API_KEY}" ``` `data` 数组应包含 `gpt-4o-mini`。 通过网关发送聊天请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${CALLER_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [ {"role": "user", "content": "Say hello from AISIX AI Gateway."} ] }' ``` 响应应采用 OpenAI Chat Completions 格式,并在 `choices[0].message` 中包含助手消息。 ## 更新并重新加载配置[​](#update-and-reload-the-configuration "更新并重新加载配置的直接链接") 运行中的网关不会监听 `resources.yaml`。如需在不重启容器的情况下应用变更,请编辑已挂载的文件、验证它,然后向网关进程发送 `SIGHUP`。 例如,更新 `resources.yaml`,添加第二个模型,并允许现有调用方 API Key 使用该模型: resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-main provider: openai adapter: openai api_key: ${OPENAI_API_KEY} api_base: https://api.openai.com/v1 models: - display_name: gpt-4o-mini provider: openai model_name: gpt-4o-mini provider_key: openai-main - display_name: gpt-4o provider: openai model_name: gpt-4o provider_key: openai-main api_keys: - display_name: quickstart-caller key_env: CALLER_API_KEY allowed_models: - gpt-4o-mini - gpt-4o ``` 在正在运行的容器中验证编辑后的文件: ``` docker exec aisix-quickstart \ /usr/local/bin/aisix validate --resources /etc/aisix/resources.yaml ``` 该命令应报告文件已加载四个资源。如果验证失败,请先修正报告的条目再继续。 重新加载文件: ``` docker kill --signal=HUP aisix-quickstart ``` 确认调用方可以看到两个模型: ``` curl -sS "$AISIX_PROXY/v1/models" \ -H "Authorization: Bearer ${CALLER_API_KEY}" ``` `data` 数组应同时包含 `gpt-4o-mini` 和 `gpt-4o`。有关配置状态、被拒绝资源的详细信息和其它资源来源,请参阅[配置传播](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md)。 ## 清理[​](#清理 "清理的直接链接") 完成后停止并删除快速入门网关: ``` docker rm -f aisix-quickstart ``` 工作目录中的 `config.yaml` 和 `resources.yaml` 文件不会被修改。 ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经通过一个声明式文件运行了开源 AISIX 网关,并通过它发送了由模型服务提供方处理的请求。接下来可以: * 阅读[资源模型](https://docs.apiseven.com/ai-gateway/models/resource-model.md),了解模型服务提供方密钥、模型和调用方 API Key 如何配合工作。 * 使用 [CLI 参考](https://docs.apiseven.com/ai-gateway/reference/cli.md)在 CI 中检查资源文件。 * 按照 [OpenAI SDK](https://docs.apiseven.com/ai-gateway/getting-started/openai-sdk.md) 或 [Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md) 指南,在应用代码中调用同一个网关。 * 在部署网关承载生产流量前,查看[生产就绪](https://docs.apiseven.com/ai-gateway/deployment/production.md)。 --- # OpenAI SDK 本指南会把官方 OpenAI SDK 指向 AISIX AI 网关,而不是直接向上游服务提供方发送请求。这种方式适合已经使用兼容 OpenAI Chat Completions 格式、并希望尽量少改客户端代码的应用。 示例会使用调用方 API Key 向 AISIX 认证,把请求发送到 AISIX 代理 API 根路径,使用 AISIX 模型别名,并接收兼容 OpenAI 的 Chat Completions 响应。只要配置的模型别名和服务提供方支持对应请求格式,上游服务提供方仍可在网关后切换。 ## 准备工作[​](#准备工作 "准备工作的直接链接") * 应用可以访问的、正在运行的 AISIX 网关。 * 已配置且接受兼容 OpenAI Chat Completions 请求的模型别名。 * 允许使用该模型别名的调用方 API Key。 * 安装带有 `npm` 的 Node.js 20 LTS 或更新版本。 如果你的组织已部署 AISIX,请向负责管理的团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作;如需使用 Hybrid Cloud,请[联系 API7](https://api7.ai/contact)。 ## 配置 SDK[​](#配置-sdk "配置 SDK的直接链接") 创建一个小型 Node.js 项目,安装 SDK,并将其指向 AISIX 代理 API 根路径。 ### 安装 SDK[​](#安装-sdk "安装 SDK的直接链接") 创建一个小型演示项目: ``` mkdir aisix-openai-demo && cd aisix-openai-demo npm init -y ``` 在演示项目中安装 OpenAI SDK: ``` npm install openai ``` 设置调用方 API Key、模型别名和网关 base URL: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-mini" ``` ### 创建聊天示例[​](#创建聊天示例 "创建聊天示例的直接链接") 使用 `.mjs` 扩展名,这样 Node 无需额外配置即可把顶层 `await` 和 `import` 当作 ES 模块处理。 openai-sdk-example.mjs ``` import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.AISIX_API_KEY, baseURL: process.env.AISIX_BASE_URL, }); const response = await client.chat.completions.create({ model: process.env.AISIX_MODEL ?? "gpt-4o-mini", messages: [{ role: "user", content: "Say hello from AISIX." }], }); console.log(response.choices[0]?.message.content); ``` ### 运行示例[​](#运行示例 "运行示例的直接链接") 在演示项目中运行聊天示例: ``` node openai-sdk-example.mjs ``` 你应该会看到一段简短的助手回复。具体文本取决于上游模型。 当网关能够解析 `gpt-4o-mini` 且上游服务提供方可访问时,SDK 会返回包含助手消息的标准 OpenAI Chat Completions 对象。AISIX 会解析模型别名,并在调用上游服务提供方前注入已保存的服务提供方凭证。 ## 流式响应[​](#流式响应 "流式响应的直接链接") 同一个 `baseURL` 也适用于流式响应。 openai-sdk-streaming.mjs ``` import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.AISIX_API_KEY, baseURL: process.env.AISIX_BASE_URL, maxRetries: 0, }); const stream = await client.chat.completions.create({ model: process.env.AISIX_MODEL ?? "gpt-4o-mini", messages: [{ role: "user", content: "Stream a short greeting." }], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` 在演示项目中运行流式响应示例: ``` node openai-sdk-streaming.mjs ``` 你应该会看到终端中持续打印流式文本。 ## 生产环境配置模式[​](#生产环境配置模式 "生产环境配置模式的直接链接") 在大多数部署中,应用代码只需要网关 base URL、调用方 API Key 和 AISIX 模型别名。上游凭证、服务提供方 base URL、上游模型 ID、路由策略、限流、安全护栏和可观测性挂钩都保留在网关后。 这种解耦让你可以轮换服务提供方凭证、变更上游模型 ID,或新增网关策略,而无需修改 SDK 调用点。 ## 如果 SDK 请求失败[​](#如果-sdk-请求失败 "如果 SDK 请求失败的直接链接") 先使用直接请求检查调用方 API Key、网关 base URL 和 AISIX 模型别名,再在 SDK 中使用相同的值。 如果 SDK 仍然把流量直接发送到 OpenAI,请检查 `baseURL`。它必须指向 AISIX 代理 API 根路径,而不是上游 OpenAI API URL。 如果 AISIX 返回 `404`,说明请求的模型别名未配置。如果 AISIX 返回 `403`,说明调用方 API Key 已存在,但没有权限使用该别名。 ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经通过 OpenAI SDK 客户端调用了 AISIX。接下来可阅读[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)了解代理行为。关于 SSE 响应和工具定义,请参阅[流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md)和[工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md)。如果应用需要 Claude 风格请求,请继续阅读 [Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md)。 --- # AISIX 产品与部署选项 AISIX 既提供开源 AISIX 网关,也提供 API7 的商业产品 AISIX Cloud。开源网关无需控制面即可独立运行。AISIX Cloud 增加了用于管理 AISIX 网关的控制面;你可以在自己的基础设施中托管控制面,也可以由 API7 托管。 无论采用哪种方式,AISIX 网关都运行在你自己的环境中。本页对比开源 AISIX 网关与 AISIX Cloud 的两种控制面部署选项,帮助你选择合适的产品和部署方式。 ## 对比可选方案[​](#对比可选方案 "对比可选方案的直接链接") | 产品 | 控制面部署选项 | 控制面托管方 | 网关位置 | | ------------------- | -------------- | ------------ | ------------ | | **开源 AISIX 网关** | 不适用 | 无 | 你的基础设施 | | **AISIX Cloud** | On-Premises | 你 | 你的基础设施 | | **AISIX Cloud** | Hybrid Cloud | API7 | 你的基础设施 | ## 对比管理能力[​](#对比管理能力 "对比管理能力的直接链接") AISIX 网关在所有选项中处理相同的流量路径。AISIX Cloud 在网关之外增加共享管理和治理能力。 | 领域 | 开源 AISIX 网关 | AISIX Cloud | | ---------------- | ---------------------------------------------------------- | -------------------------------------------------------------------- | | 资源管理 | 由你运维声明式 `resources.yaml` 文件及自动化 | 通过控制台和 AISIX Cloud Admin API 投递环境级配置 | | 组织与访问权限 | 不提供组织或成员管理层;需集成自己的访问工作流 | 组织、环境、成员、团队和角色 | | 凭证生命周期 | 通过自己的配置和 Secret 系统管理模型服务提供方及调用方凭证 | 加密且只写的模型服务提供方 Secret,以及托管的调用方 API Key 生命周期 | | 网关连接与可见性 | 使用自己的工具部署、保护、监控和升级网关实例 | 仍由你运维网关;控制面增加证书、注册、配置投递、心跳和状态可见性 | | 用量、成本与治理 | 将日志和指标导出到你运维的系统 | 集中的请求日志、用量与成本视图、模型定价、预算和审计历史 | 这些控制面能力不会让控制面进入实时 AI 流量路径。在所有选项中,应用都直接调用 AISIX 网关。 ## 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 开源 AISIX 网关采用 Apache License 2.0,无需控制面即可运行。你在 [`resources.yaml` 文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md)中声明模型服务提供方、模型、调用方 API Key 和策略;网关在启动时加载该文件,并在收到 `SIGHUP` 时重新加载。 * \*\*适合以下情况:\*\*你希望使用开源网关,将自行构建或集成管理与自动化能力,并且不需要组织、用量上报或预算等 AISIX Cloud 功能。 * \*\*由你运维:\*\*网关进程、资源文件和升级。 * \*\*开始使用:\*\*按照[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)声明 `resources.yaml` 文件、启动网关并发送第一个请求。 ## AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") On-Premises 和 Hybrid Cloud 是 AISIX Cloud 的两种控制面部署选项。它们使用相同的控制台、AISIX Cloud Admin API、资源模型和网关工作流。区别在于由谁托管控制面以及控制面数据存储在哪里。具体商业能力可能因部署选项和版本而异。 ### On-Premises[​](#on-premises "On-Premises的直接链接") 你在自己的基础设施中托管 AISIX Cloud 控制面,包括完全隔离的内网环境。你通过与 Hybrid Cloud 相同的控制台或 AISIX Cloud Admin API 管理资源。 * \*\*适合以下情况:\*\*数据驻留、网络隔离、合规或内网要求意味着控制面也必须运行在你的环境中。 * \*\*由你运维:\*\*包含控制面和网关的完整私有部署。 * \*\*开始使用:\*\*按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)启动控制面、创建环境、连接网关并发送第一个请求。 ### Hybrid Cloud[​](#hybrid-cloud "Hybrid Cloud的直接链接") API7 托管 AISIX Cloud 控制面;你在自己的环境中部署网关并将其连接到控制面,控制面再将环境资源投射到网关。你通过控制台或 AISIX Cloud Admin API 管理资源。 * \*\*适合以下情况:\*\*你希望获得集中管理、用量上报、预算和治理能力,但不想运维控制面。AI 流量仍保留在你的环境中。 * \*\*由你运维:\*\*网关;控制面由 API7 运维。 * \*\*获取访问权限:\*\*Hybrid Cloud 目前不提供公开自助注册。请[联系 API7](https://api7.ai/contact)申请试用或演示。你也可以通过 [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-o7ltvkj4qjnr2) 购买 AISIX Cloud。Marketplace 只改变采购与计费方式,不改变 Hybrid Cloud 架构或双方的运维职责。API7 提供控制面访问权限后,请继续阅读 [AISIX Cloud 概览](https://docs.apiseven.com/ai-gateway/cloud/overview.md),创建或选择环境、连接网关、配置模型服务提供方并发送第一个请求。 ## 规划迁移[​](#规划迁移 "规划迁移的直接链接") 所有选项使用相同的网关运行时和代理 API。更改网关的管理方式时,应用仍可沿用相同的 AISIX 端点约定和模型别名。 管理路径会发生变化:开源网关从 `resources.yaml` 文件加载动态资源,而连接 AISIX Cloud 的网关接收控制面投射的资源。迁入或迁出 AISIX Cloud 控制面时,请规划重新创建网关资源,不要把它当作启动配置的原地切换。 --- # 集成 AISIX 通过直接配置客户端或由运维人员管理的正向代理,与开发者工具、应用框架、AI 应用平台和语音 Agent 平台集成。在这两种模式中,客户端都保持原生请求格式,而 AISIX 会应用访问控制、策略和遥测。 大多数集成会将客户端指向 AISIX API 端点,并使用 AISIX 调用方 Key 和模型别名替换服务提供方 API Key 和模型名称。这种直接连接模式适用于支持自定义端点的客户端,包括兼容 OpenAI 的 Chat Completions、OpenAI Responses API 和兼容 Anthropic 的请求。 有些工具必须继续使用其官方服务端点和上游凭证。对于这类工具,终止 TLS 的出口设备可以将选定流量发送到按主机匹配的 AISIX 透传路由。[IDE AI 流量正向代理](https://docs.apiseven.com/ai-gateway/deployment/forward-proxy.md)以 GitHub Copilot 为例介绍了这一模式。 采用这两种模式,团队都无需重写应用代码或更换编码工具。客户端继续使用熟悉的 SDK、CLI 或框架,而网关策略和可观测性集中在 AISIX 中管理。直接集成还会将路由和服务提供方凭证移至 AISIX 模型别名之后。 对于新的 OpenAI 协议族集成,如果客户端当前推荐的 API 仍能指向自定义 AISIX 基础 URL,请优先使用该 API。当框架原生提供 Responses 客户端时,请使用 Responses API;当客户端只说明了 OpenAI 兼容服务提供方路径,或现有工作流依赖 Chat Completions 兼容性时,请使用 Chat Completions。有关 AISIX 向客户端公开的 API 类型,请参阅[支持的端点](https://docs.apiseven.com/ai-gateway/endpoints/overview.md)。 ## 集成如何使用 AISIX[​](#集成如何使用-aisix "集成如何使用 AISIX的直接链接") 直接集成使用以下三个 AISIX 值: * 代理 API 基础 URL。 * 调用方 API Key。 * 调用方 API Key 有权访问的模型别名。 许多客户端将第三个值称为自定义模型、模型 ID、模型名称或公开模型名称。在 AISIX 中,该字段应填写模型别名。AISIX 会验证调用方 API Key,将别名解析为上游服务提供方配置,应用策略并记录网关遥测数据。 在 GitHub Copilot 正向代理模式中,透传路由会将来自可信出口设备的流量解析到一个专用的调用方 Key 主体。在主要的 `header_key` 配置中,出口设备提供网关凭证;匿名路由则可以绑定该主体,并通过来源 CIDR 限制流量。客户端保留官方端点和上游凭证;出口设备还可以附加可信的员工身份,以便追踪流量来源。 ## 集成类型[​](#集成类型 "集成类型的直接链接") | 客户端类型 | 适用场景 | 指南 | | --------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 客户端 SDK | 现有应用代码使用兼容 OpenAI 或 Anthropic 的客户端。 | [OpenAI SDK](https://docs.apiseven.com/ai-gateway/getting-started/openai-sdk.md)、[Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md) | | 编码 Agent | 本地编辑器、AI CLI、远程开发环境或自动化任务需要通过 AISIX 发送请求。 | [编码 Agent](https://docs.apiseven.com/ai-gateway/integrations/coding-agents.md) | | 框架与库 | 应用框架、Agent 框架或 AI 库需要从应用代码调用 AISIX。 | [LangChain 和 LangGraph](https://docs.apiseven.com/ai-gateway/integrations/frameworks/langchain.md)、[LlamaIndex](https://docs.apiseven.com/ai-gateway/integrations/frameworks/llamaindex.md)、[Haystack](https://docs.apiseven.com/ai-gateway/integrations/frameworks/haystack.md)、[Vercel AI SDK](https://docs.apiseven.com/ai-gateway/integrations/frameworks/vercel-ai-sdk.md)、[Pydantic AI](https://docs.apiseven.com/ai-gateway/integrations/frameworks/pydantic-ai.md)、[Instructor](https://docs.apiseven.com/ai-gateway/integrations/frameworks/instructor.md)、[OpenAI Agents SDK](https://docs.apiseven.com/ai-gateway/integrations/frameworks/openai-agents-sdk.md)、[CrewAI](https://docs.apiseven.com/ai-gateway/integrations/frameworks/crewai.md)、[Microsoft Agent Framework](https://docs.apiseven.com/ai-gateway/integrations/frameworks/microsoft-agent-framework.md) | | AI 应用平台 | 可视化应用、工作流或聊天平台需要通过 AISIX 发送模型请求。 | [AI 应用平台](https://docs.apiseven.com/ai-gateway/integrations/application-platforms.md) | | 语音 Agent 平台 | 托管平台或语音框架需要使用 AISIX 处理文本 LLM 环节,同时保留自己的音频和会话流水线。 | [语音 Agent 平台](https://docs.apiseven.com/ai-gateway/integrations/voice-agents.md) | ## 前置条件[​](#前置条件 "前置条件的直接链接") 直接连接客户端的指南假设网关已为客户端路径创建以下资源: * 用于应用、开发者或自动化配置的调用方 API Key。 * 调用方 API Key 有权访问的模型别名。 * 与客户端兼容的代理 API 路由,例如兼容 OpenAI 的 Chat Completions、OpenAI Responses API 或 Anthropic Messages。 如果组织中已经部署 AISIX,请向管理该部署的团队获取网关 URL、模型别名和调用方 API Key。否则,请完成[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md),或[联系 API7](https://api7.ai/contact)申请混合云访问权限。 正向代理指南具有不同的前置条件,包括终止 TLS 的出口设备、配置客户端代理和证书信任的权限,以及上游服务最新的允许列表。 [模型与服务提供方](https://docs.apiseven.com/ai-gateway/providers/overview.md)下的指南介绍上游特定配置。 --- # AI 应用平台 AI 应用平台将模型访问与用户界面、可视化工作流、Agent、工具、检索和应用状态结合起来,让团队无需在应用代码中逐一组装所有组件,即可构建和运行 AI 应用。 当平台支持兼容 OpenAI 的端点时,其语言模型请求可以经由 AISIX 进行调用方身份认证、模型别名管理、路由、策略执行和遥测。平台继续负责应用工作流和用户体验,AISIX 则治理从平台到已配置模型服务提供方的请求路径。 ## 选择平台指南[​](#选择平台指南 "选择平台指南的直接链接") 各平台通过不同的配置入口连接 AISIX: | 平台 | 集成入口 | 指南 | | ---------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------- | | Open WebUI | 兼容 OpenAI 的连接 | [Open WebUI](https://docs.apiseven.com/ai-gateway/integrations/application-platforms/open-webui.md) | | n8n | OpenAI Chat Model 子节点 | [n8n](https://docs.apiseven.com/ai-gateway/integrations/application-platforms/n8n.md) | | Dify | OpenAI-API-compatible 模型服务提供方插件 | [Dify](https://docs.apiseven.com/ai-gateway/integrations/application-platforms/dify.md) | 这些平台是 AISIX 的客户端,而非上游模型服务提供方。请在 AISIX 中配置服务提供方凭证和上游模型 ID,并向平台提供 AISIX 调用方 API Key 和模型别名。 ## 准备 AISIX[​](#准备-aisix "准备 AISIX的直接链接") 各平台都需要以下网关连接信息: * 平台部署环境可访问的 AISIX 代理 URL。 * 专用于平台或应用的 AISIX 调用方 API Key。 * 支持聊天的模型别名,且调用方密钥可通过 `POST /v1/chat/completions` 访问该别名。 如果组织已部署 AISIX,请向管理团队获取这些信息。否则,请按照[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)进行配置,或[联系 API7](https://api7.ai/contact)获取混合云访问权限。 将调用方密钥的访问范围限制为平台所需的模型别名。共享的平台连接通常向 AISIX 标识平台或应用,而非使用界面的每个用户。除非已单独设计并验证逐用户身份转发,否则请在应用平台中管理最终用户的授权和审计上下文。 ## 了解职责边界[​](#了解职责边界 "了解职责边界的直接链接") 应用平台完成提示词组装、上下文检索或工具选择后,AISIX 才会收到模型请求。AISIX 不会替代平台的工作流引擎、用户账户、对话状态、知识库、向量存储或工具执行。 网关策略作用于到达 AISIX 且受支持的内容。平台还可能为标题、摘要、记忆、检索或 Agent 规划发起额外的模型调用。在将网关遥测或限额视为平台活动的完整记录之前,请确认哪些调用使用了已配置的 AISIX 连接。 AISIX 模型发现会返回调用方密钥可访问的所有别名,包括用于非聊天端点的别名。请在每个应用平台中选择为 Chat Completions 配置的别名。 工具调用也需要两个产品共同完成。AISIX 必须保留模型返回的兼容 OpenAI 的工具调用响应,应用平台则必须执行工具,并在后续请求中发送工具结果。请测试一次完整的工具调用往返,不要仅凭文本响应成功就判断工具兼容性。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 使用一个简短的平台工作流确认完整路径: 1. 平台通过已配置的 AISIX 连接发送提示词。 2. AISIX 为预期的调用方密钥和模型别名记录 `POST /v1/chat/completions` 请求。 3. 平台展示或处理模型响应。 首次成功后,再验证应用依赖的流式响应、工具、检索和后台模型调用。 ## 相关指南[​](#相关指南 "相关指南的直接链接") 选择上方的平台指南进行配置。以下指南介绍各集成共用的网关行为: * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看面向网关的请求格式。 * [流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):了解流式响应行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证完整的工具调用循环。 * [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):限制平台流量。 --- # Dify [Dify](https://docs.dify.ai/) 是一个 AI 应用平台,可用于构建聊天应用、工作流、Agent、检索流水线、工具和模型驱动的 API。其官方 OpenAI-API-compatible 模型服务提供方插件支持在工作区中添加通过自定义 API 端点提供的模型。 为该插件配置 AISIX 代理 URL、调用方 API Key 和模型别名。随后,Dify 可以在应用和工作流的模型节点中使用该别名,由 AISIX 管理上游服务提供方凭证、路由、策略和遥测。 在此集成中,Dify 是 AISIX 的客户端,而非上游模型服务提供方。AISIX 不会替代 Dify 的工作流引擎、应用状态、知识库、工具或已发布的应用 API。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始之前,请准备以下内容: * 具有插件安装和模型服务提供方配置权限的 Dify 工作区。 * Dify 部署环境可访问的 AISIX 代理 URL。 * 专用于 Dify 或应用的 AISIX 调用方 API Key。 * 支持聊天的模型别名,且调用方密钥可通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md) 访问该别名。 * AISIX 别名后所有可选目标均支持的上下文窗口和最大输出 Token 限制。 ## 安装模型服务提供方插件[​](#安装模型服务提供方插件 "安装模型服务提供方插件的直接链接") 在 Dify Marketplace 中查找并安装由 `langgenius` 发布的官方 [OpenAI-API-compatible 模型服务提供方插件](https://marketplace.dify.ai/plugins/langgenius/openai_api_compatible)。 该插件的版本独立于 Dify 应用版本。测试集成或排查问题时,请同时记录 Dify 和插件的版本,避免将后续插件变更误认为 AISIX 的行为变化。 ## 添加 AISIX 模型[​](#添加-aisix-模型 "添加 AISIX 模型的直接链接") 在工作区中打开 **Integrations → Model Provider**,选择 **OpenAI-API-compatible**,并使用以下值添加模型: | 字段 | 值 | | --------------------------- | -------------------------------------------------------------------------- | | Model Type | **LLM** | | Model Name | AISIX 模型别名,例如 `support-agent-prod` | | API Key | AISIX 调用方 API Key | | API Base URL | 包含 `/v1` 的 AISIX 代理 API 根路径,例如 `https://gateway.example.com/v1` | | model name for API endpoint | 如果 **Model Name** 已是 AISIX 别名,则留空 | | Completion mode | **Chat** | | API Type | **Chat Completions API (/chat/completions)** | | Model context size | 别名后所有可选目标中最低的上下文限制 | | Upper bound for max tokens | 别名后所有可选目标中最低的最大输出限制 | | Function Call Type | 初次文本测试时选择 **Not Support** | 保存模型配置。插件将 API Key 用作 Bearer 凭证,并将配置的模型名称发送到兼容 OpenAI 的端点。不要在 **API Base URL** 后追加 `/chat/completions`。 ## 验证应用请求[​](#验证应用请求 "验证应用请求的直接链接") 创建或打开一个 Dify 聊天应用或工作流,选择已配置的 AISIX 模型,并使用简短提示词运行预览。 确认以下结果: * Dify 显示模型响应。 * AISIX 记录一条成功的 `POST /v1/chat/completions` 请求。 * 记录中的调用方密钥和模型与 Dify 模型服务提供方配置一致。 Dify 应用可能为 Agent 规划、问题分类、参数提取或其他工作流节点发起额外的模型调用。请为所有需要使用 AISIX 的模型节点进行配置,并检查完整工作流,不要假定所有模型流量均使用同一个连接。 ## 启用工具调用[​](#启用工具调用 "启用工具调用的直接链接") 文本请求成功后,如果 Dify 应用使用 Agent 工具,请编辑模型服务提供方配置,将 **Function Call Type** 设置为 **Tool Call**。只有当选定的模型别名和上游模型均支持兼容 OpenAI 的流式工具调用时,才将 **Stream function calling** 设置为 **Support**。 运行一次完整的 Agent 工具测试,确认 Dify 执行预期工具、向模型返回工具结果,并生成最终回答。文本请求成功并不能验证这些额外请求或工具调用流。 如果工具行为不一致,请将 **Function Call Type** 恢复为 **Not Support**,同时检查 Dify 插件、AISIX 和上游模型的日志。不要仅因为存在配置字段,就将模型标记为支持工具调用。 ## Dify 请求故障排查[​](#dify-请求故障排查 "Dify 请求故障排查的直接链接") | 现象 | 检查项 | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------ | | 模型验证失败 | 确认 **API Base URL** 可访问 AISIX,且使用 `/v1` API 根路径,不包含 `/chat/completions`。 | | 请求返回 `401` | 确认 **API Key** 填写的是 AISIX 调用方密钥,而非上游服务提供方密钥。 | | 请求返回 `403` | 确认调用方密钥可访问 **Model Name** 中填写的别名。 | | 请求使用了错误的模型 | 将 **model name for API endpoint** 留空,或明确设置为同一个 AISIX 别名。 | | Agent 未调用工具 | 确认 **Function Call Type** 为 **Tool Call**,并验证选定的上游模型支持 Dify 工具 Schema。 | | 非流式工具调用成功,但流式调用失败 | 将 **Stream function calling** 设置为 **Not Support**,然后对照 AISIX 工具调用约定检查插件的流式请求与响应。 | ## 下一步[​](#下一步 "下一步的直接链接") * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看 Dify 调用的端点。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证模型和网关的工具调用约定。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):在 AISIX 中检查 Dify 模型流量。 --- # n8n [n8n](https://docs.n8n.io/) 是一个工作流自动化平台,提供用于 Agent、链、模型、记忆、工具和数据源的可视化 AI 节点。其 OpenAI Chat Model 子节点可以使用自定义的兼容 OpenAI 的端点,而非直接调用 OpenAI。 当 n8n AI Agent 或链需要使用网关管理的凭证、模型别名、路由、策略和遥测时,可以将该模型子节点连接到 AISIX。n8n 继续运行工作流和执行工具,AISIX 则治理已配置子节点发出的模型请求。 此集成适用于 **OpenAI Chat Model** 子节点,不代表 n8n 通用 OpenAI 应用节点的所有操作均兼容;后者还会调用服务提供方专用的文件、图像、音频、助手及其他 API。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始之前,请准备以下内容: * 具有凭证创建和工作流编辑权限的 n8n 项目。 * n8n 部署环境可访问的 AISIX 代理 URL。 * 专用于工作流或 n8n 项目的 AISIX 调用方 API Key。 * 支持聊天的模型别名,且调用方密钥可通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md) 访问该别名。 ## 创建 OpenAI 凭证[​](#创建-openai-凭证 "创建 OpenAI 凭证的直接链接") 在 OpenAI Chat Model 子节点中为 AISIX 连接创建凭证: 1. 在工作流中添加或打开 **OpenAI Chat Model** 子节点。 2. 在 **Credential to connect with** 下创建 **OpenAI** 凭证。 3. 将 **API Key** 设置为 AISIX 调用方 API Key。 4. 将 **Base URL** 设置为包含 `/v1` 的 AISIX 代理 API 根路径,例如 `https://gateway.example.com/v1`。 5. 将 **Organization ID** 留空。 6. 保存凭证。 n8n 通过 `GET /v1/models` 验证凭证。AISIX 对调用方密钥进行身份认证,并返回该密钥可访问的别名。 ## 配置聊天模型[​](#配置聊天模型 "配置聊天模型的直接链接") 选择 AISIX 连接和 Chat Completions 路径: 1. 选择连接 AISIX 的 OpenAI 凭证。 2. 在 **Model** 下选择网关返回的、支持聊天的 AISIX 模型别名。如果未显示,请选择模型 ID 输入模式,并准确输入别名。 3. 关闭 **Use Responses API**,使子节点发送 `POST /v1/chat/completions` 请求。 4. 将模型输出连接到需要使用 AISIX 的 AI Agent 或链的 **Chat Model** 输入。 请显式设置 **Use Responses API**,不要依赖随版本变化的默认值。对于本文介绍的 Chat Completions 路径,必须将其关闭。 在此配置中,不要启用 Web Search、File Search 或 Code Interpreter 等 OpenAI 托管的内置工具。这些工具属于 OpenAI 的 Responses 服务,而非 n8n 工作流的工具调用循环。 模型值应为 AISIX 别名,而非上游服务提供方的模型 ID。n8n 向 AISIX 发送提示词和工具定义,工作流继续负责节点执行、记忆、分支、重试和数据流转。 ## 测试模型连接[​](#测试模型连接 "测试模型连接的直接链接") 进行最小交互测试时,将 **Chat Trigger** 连接到 **AI Agent**,附加已配置的 **OpenAI Chat Model**,然后运行工作流聊天。要验证增量输出,请将 Chat Trigger 的响应模式设置为 **Streaming**。 发送简短提示词,并确认以下结果: * n8n 聊天界面显示模型响应。 * AISIX 记录一条成功的 `POST /v1/chat/completions` 请求。 * 记录中的调用方密钥和模型与 n8n 凭证及所选别名一致。 如果工作流由 Webhook、调度或其他触发器启动,请单独验证该执行路径。测试和生产执行可能使用不同的凭证或工作流版本。 ## 验证 Agent 工具[​](#验证-agent-工具 "验证 Agent 工具的直接链接") 向 AI Agent 附加一个结果确定的 n8n 工具,例如 Calculator,并提出需要使用该工具的问题。确认 Agent 调用工具、接收结果并返回最终回答。 使用工具的一个对话轮次通常至少产生两个模型请求:第一个返回工具调用,下一个包含工具结果。设置 AISIX 限流和检查用量时,请考虑这种请求增多的情况。使用 AISIX Cloud 时,设置预算也应将其计入。 ## 模型故障排查[​](#模型故障排查 "模型故障排查的直接链接") | 现象 | 检查项 | | -------------------------- | ------------------------------------------------------------------------ | | 凭证验证失败 | 确认 **Base URL** 以 `/v1` 结尾,且 `GET /v1/models` 接受调用方密钥。 | | 模型列表为空 | 确认调用方密钥可访问至少一个 AISIX 别名,或通过模型 ID 模式输入别名。 | | 请求到达 `/v1/responses` | 关闭 OpenAI Chat Model 子节点上的 **Use Responses API**。 | | 请求返回 `403` | 确认 n8n 凭证中的调用方密钥可访问所选别名。 | | Agent 未使用工具就直接回答 | 确认工具已附加到 AI Agent,且所选上游模型支持兼容 OpenAI 的工具调用。 | | 通用 OpenAI 节点操作失败 | 此集成仅用于 OpenAI Chat Model 子节点,除非已单独验证所需的 AISIX 端点。 | ## 下一步[​](#下一步 "下一步的直接链接") * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看模型子节点使用的请求路径。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证 Agent 工具定义和结果。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):使用 AISIX Cloud 统计多请求 Agent 工作流的预算。 --- # Open WebUI [Open WebUI](https://docs.openwebui.com/) 是一个 Web 界面,可用于与模型聊天、管理对话、附加知识和使用工具。它通过基于协议的连接访问模型服务,包括兼容 OpenAI 的 API。 Open WebUI 管理员可以将 AISIX 添加为兼容 OpenAI 的连接。随后,Open WebUI 会发现 AISIX 调用方密钥可用的模型别名,并通过网关发送聊天请求。AISIX 治理模型请求路径,Open WebUI 则继续管理用户、聊天、知识、工具和界面行为。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始之前,请准备以下内容: * 具有管理员权限的 Open WebUI 账户。 * Open WebUI 部署环境可访问的 AISIX 代理 URL。 * 专用于 Open WebUI 的 AISIX 调用方 API Key。 * 支持聊天的模型别名,且调用方密钥可通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md) 访问该别名。 如果 Open WebUI 在容器中运行,则无法通过 `localhost` 访问容器宿主机上的 AISIX 网关。请使用可在 Open WebUI 容器内解析的主机名,例如共享容器网络中的网关服务名。 ## 添加 AISIX 连接[​](#添加-aisix-连接 "添加 AISIX 连接的直接链接") 将 AISIX 配置为标准的兼容 OpenAI 的连接: 1. 在 Open WebUI 中打开 **Settings → Admin → Connections**。 2. 在 **Manage OpenAI API Connections** 下选择 **Add Connection**。 3. 将 **URL** 设置为包含 `/v1` 的 AISIX 代理 API 根路径,例如 `https://gateway.example.com/v1`。 4. 保持 **Auth** 为 **Bearer**,将 **API Key** 设置为 AISIX 调用方 API Key。 5. 保持 **API Type** 为 **Chat Completions**,使 Open WebUI 向 `/v1/chat/completions` 发送请求。 6. 在 **Advanced** 下保持 **Provider** 为 **Default**。 7. 将 **Model IDs** 留空,让 Open WebUI 发现调用方密钥可访问的别名。 8. 选择 **Save**。 Open WebUI 使用调用方密钥请求 `GET /v1/models`。AISIX 只返回该密钥可用的模型别名,因此 Open WebUI 的模型选择器遵循网关的访问策略。 如果只想展示返回列表中的部分模型,请在 **Model IDs** 下添加选定的 AISIX 别名。此筛选仅缩小 Open WebUI 的展示范围,不会授予 AISIX 调用方密钥原本没有的访问权限。 ## 验证聊天和流式响应[​](#验证聊天和流式响应 "验证聊天和流式响应的直接链接") 开始新聊天,选择支持聊天的 AISIX 模型别名,并发送简短提示词,例如“用一句话介绍 AI 网关”。 确认以下结果: * Open WebUI 显示流式响应。 * AISIX 记录一条成功的 `POST /v1/chat/completions` 请求。 * 记录中的调用方密钥和模型与 Open WebUI 连接及所选别名一致。 除了可见的聊天,Open WebUI 还可能使用模型执行后台任务。如果为任务、嵌入、图像生成、语音或重排配置了单独的模型或端点,请分别验证这些路径,再判断 Open WebUI 的所有模型流量是否均由 AISIX 治理。 ## 单独验证工具[​](#单独验证工具 "单独验证工具的直接链接") Open WebUI 的原生工具调用路径要求使用兼容 OpenAI 的流式工具调用片段。每个片段都必须保留工具调用的 `index`,以便 Open WebUI 在执行工具之前组装函数名称和参数。 AISIX 在 Chat Completions 路径上保留带索引的工具调用流。上游模型也必须支持请求的工具,且 Open WebUI 必须启用并授权该工具。请运行一个实际使用工具的对话轮次,并确认以下结果: * Open WebUI 执行预期工具。 * AISIX 记录生成工具调用的模型请求,以及包含工具结果的后续请求。 * 聊天界面显示最终回答。 纯文本聊天成功并不能证明这个多请求工具调用循环正常工作。 ## 连接故障排查[​](#连接故障排查 "连接故障排查的直接链接") | 现象 | 检查项 | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------- | | 未显示模型 | 确认 URL 以 `/v1` 结尾、调用方密钥有效,且 `GET /v1/models` 返回预期别名。确认请求路径后,再向 **Model IDs** 添加别名。 | | 连接返回 `401` | 确认 **API Key** 填写的是 AISIX 调用方密钥,而非上游服务提供方密钥。 | | 聊天返回 `403` | 确认调用方密钥可访问所选 AISIX 模型别名。 | | 聊天返回 `404` | 从 **URL** 中移除 `/chat/completions`。Open WebUI 会将该路径追加到 `/v1` API 根路径。 | | 容器部署无法连接 | 使用 Open WebUI 容器可访问的网关主机名,而非 `localhost`。 | | 工具调用轮次返回空回复 | 验证所选模型会输出带索引的兼容 OpenAI 的工具调用流片段,再检查 AISIX 和 Open WebUI 中该工具请求的日志。 | ## 下一步[​](#下一步 "下一步的直接链接") * [流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):查看网关的流式响应行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):了解兼容 OpenAI 的工具调用循环。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):监控来自 Open WebUI 的请求。 --- # 编码 Agent 编码 Agent 可能会从开发环境频繁发起模型和工具请求,或调用官方 AI 服务。当平台团队需要对开发者 AI 工具实行统一的访问控制、策略管理和遥测时,可以通过 AISIX 路由这些流量。 这些指南涵盖直接连接 AISIX 的编码工具,以及通过运维人员管理的正向代理继续使用官方服务端点的工具。客户端可以运行在本地编辑器、CLI、远程开发环境或自动化任务中。 ## 为什么通过 AISIX 路由编码 Agent[​](#为什么通过-aisix-路由编码-agent "为什么通过 AISIX 路由编码 Agent的直接链接") 一种常见的落地方式是由平台团队将 AISIX 作为开发者 AI 工具获准使用的网关。对于直接集成,开发者为 Codex、Claude Code、Cline、Cursor 或其他客户端配置 AISIX 代理 URL、调用方 API Key 和自定义模型值,而不是直接配置服务提供方凭证。自定义模型值就是 AISIX 模型别名。 对于 GitHub Copilot 等需要继续使用官方服务端点的工具,由运维人员管理的出口设备可以终止 TLS,并将选定流量发送到 AISIX 透传路由。该路由会解析到一个专用的调用方 Key 主体。在主要的 `header_key` 配置中,出口设备提供网关凭证;匿名路由则可以绑定该主体,并通过来源 CIDR 限制流量。客户端保留上游凭证;完成相应配置后,出口设备还可以附加可信的员工身份。 在这两种模式中,编码 Agent 都继续使用原生配置和请求格式。AISIX 会在转发选定流量前执行访问控制、策略检查和遥测记录。直接模型和 MCP 路径使用模型或工具授权;正向代理路径使用调用方 Key 主体及路由授权。只有配置了可信身份请求头时,才会记录员工身份。 当团队需要以下能力时,这种方式很有用: * 不在直接配置的编辑器和 CLI 客户端中保存服务提供方凭证。 * 使用调用方 API Key 验证每位开发者、项目、自动化任务或共享工具配置,或将正向代理流量绑定到专用的调用方 Key 主体。 * 使用模型别名控制直接配置的客户端可访问的上游模型。 * 在支持的编码 Agent 路径中执行请求限制和安全护栏、记录用量,并将匹配的 AISIX Cloud 预算应用于归因到调用方 API Key 的模型调用、MCP 工具调用和透传请求。 * 在不要求直接集成用户重新配置工具的前提下,更换别名背后的上游服务提供方或模型。 ## 敏感代码和凭证[​](#敏感代码和凭证 "敏感代码和凭证的直接链接") 编码 Agent 可能会在任务中发送源代码、配置片段、堆栈信息或终端输出。这些上下文可能包含 API Key、客户数据、个人信息或内部标识符。 AISIX 位于编码 Agent 与上游模型、MCP 服务器或官方服务之间,团队可以在网关层检查和控制这些流量。对于支持回写脱敏结果的路由,敏感值需要脱敏或拦截时,请使用 [PII 检测与脱敏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/pii.md)。透传路由不会改写服务提供方的原生请求体,因此,当匹配的内容不得离开网络时,请配置拦截操作。需要更广泛的请求与响应策略检查时,请使用[安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/overview.md)。 ## 选择客户端指南[​](#选择客户端指南 "选择客户端指南的直接链接") 请从要通过 AISIX 路由的编码工具指南开始: | 客户端 | 主要 AISIX 路径 | 指南 | | --------------- | ------------------------------------ | --------------------------------------------------------------------------------------------- | | Codex | OpenAI Responses API | [Codex](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/codex.md) | | Claude Code | Anthropic Messages | [Claude Code](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/claude-code.md) | | Cline | 兼容 OpenAI 的 API | [Cline](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/cline.md) | | Cursor Ask 模式 | 兼容 OpenAI 的 API | [Cursor](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/cursor.md) | | GitHub Copilot | 通过出口代理访问按主机匹配的透传路由 | [IDE AI 流量正向代理](https://docs.apiseven.com/ai-gateway/deployment/forward-proxy.md) | 直接连接客户端的指南假设 AISIX 网关已为客户端要使用的路由创建模型别名和调用方 API Key。在客户端 UI 或配置文件中,该别名可能称为自定义模型、模型 ID 或模型名称。GitHub Copilot 指南单独列出了正向代理的前置条件。 对于直接集成,如果组织中已经部署 AISIX,请向管理该部署的团队获取网关 URL、模型别名和调用方 API Key。如果尚未部署 AISIX,请完成[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md),或[联系 API7](https://api7.ai/contact)申请混合云访问权限。正向代理指南单独列出了出口、网络和路由方面的前置条件。 ## 编码 Agent 如何使用 AISIX[​](#编码-agent-如何使用-aisix "编码 Agent 如何使用 AISIX的直接链接") 编码 Agent 可以通过直接模型和工具 API,或可信正向代理连接到 AISIX: | 客户端路径 | AISIX 路由 | 适用场景 | | ------------ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------ | | 模型请求 | 兼容 OpenAI 的 Chat Completions 或 Responses API 路由,或 Anthropic Messages | Agent 需要使用 AISIX 调用方 API Key 和模型别名调用模型。 | | 工具请求 | `/mcp` 上的 MCP 网关 | Agent 需要通过 AISIX 的工具访问控制发现和调用上游 MCP 工具。 | | 正向代理请求 | 按主机匹配的透传路由 | 工具必须继续使用官方服务端点,而出口设备会将选定流量发送到 AISIX。 | 这三种路径都以 AISIX 作为编码工具与上游服务之间的边界。每个客户端都保持原生请求格式。直接集成使用 AISIX 调用方 Key 以及模型或工具授权。正向代理集成从设备凭证或受来源限制的匿名绑定中解析调用方 Key 主体,再应用路由授权。流量控制和安全护栏会根据所选路由和调用方 Key 主体应用。可观测性数据还可以包含可信设备提供的员工身份。 直接模型和工具路径如下所示: 有关 MCP 专项治理,请参阅 [MCP 网关概览](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md)。有关可用的代理 API 类型,请参阅[支持的端点](https://docs.apiseven.com/ai-gateway/endpoints/overview.md)。 --- # Claude Code Claude Code 可以从环境变量或设置文件读取端点和认证设置。当 Claude Code 需要通过兼容 Anthropic 的 AISIX 网关而非直接调用 Anthropic 时,可使用这些设置。 本指南将 Claude Code 指向 AISIX,并使用 AISIX 调用方 API Key 认证。你还需要选择一个可通过 Anthropic Messages 路由访问的 AISIX 模型别名。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 安装 Claude Code。 * 一个正在运行且 Claude Code 可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可以通过 [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md) 访问的 AISIX 模型别名。请使用 Anthropic 支持的别名,以保留 Anthropic 特有的请求和响应行为。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Claude Code[​](#配置-claude-code "配置 Claude Code的直接链接") 启动 Claude Code 前,设置端点、调用方 API Key 和模型别名: ``` # ANTHROPIC_BASE_URL 是网关源地址,不含末尾斜杠或 /v1 # 本地快速入门使用 http://127.0.0.1:3000 export ANTHROPIC_BASE_URL="YOUR_AISIX_GATEWAY_URL" export ANTHROPIC_AUTH_TOKEN="YOUR_CALLER_API_KEY" export ANTHROPIC_MODEL="claude-sonnet-prod" export ANTHROPIC_DEFAULT_HAIKU_MODEL="claude-sonnet-prod" claude ``` `ANTHROPIC_BASE_URL` 将 Claude Code 指向 AISIX。Claude Code 会把 `ANTHROPIC_AUTH_TOKEN` 作为 Bearer Token 发送,因此 AISIX 将其作为调用方 API Key 接收。`ANTHROPIC_MODEL` 和 `ANTHROPIC_DEFAULT_HAIKU_MODEL` 应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。两个变量可以指向同一别名,也可以为 Claude Code 的后台行为配置一个独立的快速别名。 若要让这些设置在每次启动 Claude Code 时生效,请将其写入 Claude Code 设置文件的 `env` 块: \~/.claude/settings.json ``` { "model": "claude-sonnet-prod", "env": { "ANTHROPIC_BASE_URL": "YOUR_AISIX_GATEWAY_URL", "ANTHROPIC_AUTH_TOKEN": "YOUR_CALLER_API_KEY", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-sonnet-prod" } } ``` ## 验证集成[​](#验证集成 "验证集成的直接链接") 启动 Claude Code 并发送一条简短提示词。 请求成功后,请确认以下结果: * Claude Code 输出模型响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/messages` 请求。 AISIX 会验证调用方 API Key、检查模型访问权限、解析模型别名、应用策略,并将请求分发到别名背后的上游服务提供方。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 ## 排查 Claude Code 请求[​](#排查-claude-code-请求 "排查 Claude Code 请求的直接链接") Claude Code 可能发送 Anthropic 特有字段和 Beta 请求头。请使用由 Anthropic 支持的 AISIX 模型别名以获得直接的协议兼容性,并验证团队计划部署的 Claude Code 工作流。 如果 Claude Code 报告端点、认证或模型错误,请检查以下内容: | 现象 | 检查项 | | ------------------------- | ------------------------------------------------------------------------------------------------------ | | 认证失败 | 确认 `ANTHROPIC_AUTH_TOKEN` 是 AISIX 调用方 API Key,且该 Key 可以访问所选模型别名。 | | 找不到模型 | 确认 `ANTHROPIC_MODEL` 与 `ANTHROPIC_DEFAULT_HAIKU_MODEL` 是该调用方 API Key 可访问的 AISIX 模型别名。 | | 请求到达 AISIX 但上游失败 | 确认别名指向兼容的上游模型和服务提供方 Key。 | | 工具或 Beta 行为失败 | 确认所选 AISIX 路由和上游服务提供方是否支持相应 Anthropic 特性。 | 有关端点行为,请参阅 [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md):查看路由行为和兼容性边界。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):确认网关侧请求指标和日志。 * [安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/overview.md):添加请求或响应策略检查。 --- # Cline Cline 支持配置自定义基础 URL、API Key 和模型 ID 的兼容 OpenAI 服务提供方。当 Cline 需要通过 AISIX 发送模型请求时,应选择这一服务提供方类型。 本指南将 Cline 配置为使用 AISIX 调用方 API Key 调用 AISIX 兼容 OpenAI 的代理 API。Cline 中的模型 ID 应填写 AISIX 模型别名。此配置使请求端点、API Key 和模型别名均由 AISIX 控制。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 已在编辑器中安装 Cline。 * 一个代理监听器可用的运行中 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个可通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Cline[​](#配置-cline "配置 Cline的直接链接") 打开 Cline 设置,选择兼容 OpenAI 的服务提供方,然后设置以下值: | Cline 设置 | AISIX 值 | 说明 | | ------------ | --------------------------- | ---------------------------------------------------------------------------------------------------- | | API provider | OpenAI Compatible | 使用 Cline 可配置的兼容 OpenAI 客户端。 | | Base URL | `YOUR_AISIX_GATEWAY_URL/v1` | AISIX 代理 API 根路径,包含 `/v1`,且末尾不带斜杠。本地快速入门部署使用 `http://127.0.0.1:3000/v1`。 | | API key | `YOUR_CALLER_API_KEY` | AISIX 调用方 API Key。 | | Model ID | `gpt-4o-prod` | AISIX 模型别名,而不是上游服务提供方模型 ID。请将示例替换为调用方 API Key 有权访问的别名。 | Cline 还提供 OpenAI 特定的服务提供方选项。经网关路由的流量请选择 `OpenAI Compatible`。基于 OpenAI 账号和 OAuth 的服务提供方路径可能绕过 AISIX 策略。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 使用 Cline 的服务提供方验证操作确认端点、Key 和模型别名,然后从 Cline 发送一条简短提示词。 请求成功后,请确认以下结果: * Cline 输出模型响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/chat/completions` 请求。 AISIX 会验证调用方 API Key、检查模型访问权限、解析模型别名、应用策略,并将请求分发到别名背后的上游服务提供方。 如果请求失败,请检查以下内容: | 现象 | 检查项 | | -------------------------- | ----------------------------------------------------------------- | | 认证失败 | 确认 Cline 中的 API Key 是 AISIX 调用方 API Key。 | | 找不到模型 | 确认 Cline 中的模型 ID 是该调用方 API Key 可见的 AISIX 模型别名。 | | Cline 报告路由或请求体错误 | 确认所选模型别名支持兼容 OpenAI 的聊天请求。 | | 请求绕过 AISIX | 确认 **Base URL** 指向 AISIX 代理 API 根路径,并包含 `/v1`。 | ## 添加网关策略[​](#添加网关策略 "添加网关策略的直接链接") Cline 流量到达 AISIX 后,可使用与其他兼容 OpenAI 客户端相同的控制措施: * 使用[调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md)隔离开发者、团队、项目或自动化配置。 * 使用 [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md)控制高频编码 Agent 流量。AISIX Cloud 部署还可以执行[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)。 * 当提示词或响应需要内容检查时,使用[安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/overview.md)。 * 使用[指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md)查看请求量、延迟和状态。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看面向网关的请求行为。 * [流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):如果 Cline 工作流依赖流式输出,请确认流式行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):查看通过 AISIX 的兼容 OpenAI 工具调用行为。 --- # Codex Codex 支持在配置文件中定义自定义模型服务提供方。当 Codex 需要将 Responses API 请求发送到 AISIX 而非直接调用模型服务提供方时,请使用自定义服务提供方。 本指南将 Codex 指向 AISIX 代理 API 根路径,并使用 AISIX 调用方 API Key 认证。Codex 的自定义模型值应填写 AISIX 模型别名。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 已安装 Codex,且可以读取 `~/.codex/config.toml`。 * 一个代理监听器可用的运行中 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可访问且支持 [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md) 的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Codex[​](#配置-codex "配置 Codex的直接链接") 在运行 Codex 的环境中设置调用方 API Key: ``` # 请替换为实际值 export AISIX_API_KEY="YOUR_CALLER_API_KEY" ``` 在 `~/.codex/config.toml` 中添加 AISIX 模型服务提供方: \~/.codex/config.toml ``` model = "gpt-4o-prod" # 使用 AISIX 模型别名,而不是上游服务提供方模型 ID。 model_provider = "aisix" [model_providers.aisix] name = "AISIX AI Gateway" # 包含 /v1,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 base_url = "YOUR_AISIX_GATEWAY_URL/v1" env_key = "AISIX_API_KEY" # 从环境变量读取 AISIX 调用方 API Key。 wire_api = "responses" ``` ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 `AISIX_API_KEY` 的 Shell 中启动 Codex: ``` codex ``` 提出一个需要模型响应的简短问题。 请求成功后,请确认以下结果: * Codex 输出模型响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 AISIX 会验证调用方 API Key、检查模型访问权限、解析模型别名、应用策略,并将请求分发到别名背后的上游服务提供方。 ## 排查 Codex 请求[​](#排查-codex-请求 "排查 Codex 请求的直接链接") 如果 Codex 无法连接 AISIX,请检查以下内容: | 现象 | 检查项 | | ------------------ | -------------------------------------------------------------------------------------------------------- | | 认证失败 | 确认 `AISIX_API_KEY` 已在运行 Codex 的同一 Shell 或环境中设置。 | | 找不到模型 | 确认 `config.toml` 中的 `model` 是调用方 API Key 可见的 AISIX 模型别名。 | | Responses 请求失败 | 确认所选模型别名可用于 AISIX Responses API。某些服务提供方支持的别名并不支持全部 OpenAI Responses 特性。 | | 请求绕过 AISIX | 确认生效的 Codex 配置层中包含 `model_provider = "aisix"`。 | 有关端点行为和服务提供方边界,请参阅 [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看 AISIX 如何处理 Responses API 请求。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):确认网关侧请求指标和日志。 * [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):为编码 Agent 流量添加调用方或模型限流。 --- # Cursor Cursor 支持为标准聊天模型配置自定义 API Key、OpenAI base URL 覆盖值和自定义模型名称。配置这些设置后,可通过 AISIX 发送 Cursor Ask 模式的请求。 本指南将使用 AISIX 调用方 API Key 配置 Cursor,并将 AISIX 模型别名用作自定义模型名称。随后,AISIX 会认证调用方、应用网关策略,并将请求转发到为该别名配置的上游模型。 信息 此配置适用于 Ask 模式。Agent 模式、嵌套智能体、后台智能体、Tab Completion、行内编辑以及其他使用 Cursor 专用模型的功能会使用 Cursor 管理的路径,而不是 AISIX base URL。要通过 AISIX 路由 Agent 模式的 MCP 工具调用,请参阅[将 Cursor 连接到 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/cursor.md)。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * Cursor Pro 或更高套餐。免费套餐可以保存 API Key、base URL 和自定义模型,但必须升级后才能在 Chat 中选择自定义模型。 * 已运行且 Cursor 可以访问其代理 URL 的 AISIX 网关。 * AISIX 调用方 API Key。 * 调用方 API Key 可通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 设置网关源地址和调用方 API Key,然后在配置 Cursor 前确认 AISIX 已公开该别名: ``` # AISIX_PROXY 不含末尾斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" curl -sS "${AISIX_PROXY}/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` ## 配置 Cursor[​](#配置-cursor "配置 Cursor的直接链接") 1. 打开 **Cursor Settings**,选择 **Models**。 2. 在 **OpenAI API Key** 字段中输入 AISIX 调用方 API Key。 3. 在 **Override OpenAI Base URL** 中输入 AISIX 代理 API 根路径,并包含 `/v1`。例如: ``` YOUR_AISIX_GATEWAY_URL/v1 ``` 4. 在 **Add or search model** 中输入 AISIX 模型别名并按 **Enter**。例如,输入 `aisix_cursor`。 5. 启用该自定义模型。 6. 打开 Cursor Chat,选择 Ask 模式,然后选择该自定义模型。 请使用既不包含服务提供方模型 ID、也不与其相似的中性模型别名。例如,使用 `aisix_cursor`,而不是 `gpt-4o-prod`。否则 Cursor 可能会将别名解释为内置模型,并以不同方式路由或格式化请求。Cursor 发送的自定义模型名称必须与 AISIX 模型别名一致,而不是上游服务提供方的模型名称。 Cursor 设置与 AISIX 的映射如下: | Cursor 设置 | AISIX 值 | | ------------------------ | ---------------------------- | | OpenAI API Key | AISIX 调用方 API Key | | Override OpenAI Base URL | 包含 `/v1` 的 AISIX 代理 URL | | Custom model | AISIX 模型别名 | ## 验证集成[​](#验证集成 "验证集成的直接链接") 在 macOS 上使用 `Cmd+L`,或在 Windows 和 Linux 上使用 `Ctrl+L` 打开 Ask 模式。选择自定义模型,然后发送一条简短提示词,例如让模型返回一个指定单词或短语。 请求成功后,请验证以下结果: * Cursor Chat 显示预期响应。 * AISIX 记录成功的 `POST /v1/chat/completions` 请求。 * AISIX 请求记录标识预期的调用方 API Key 和模型别名。 AISIX 会将别名解析为已配置的上游服务提供方和模型。Cursor 不需要上游服务提供方凭证或上游模型名称。 ## 排查 Cursor 请求问题[​](#排查-cursor-请求问题 "排查 Cursor 请求问题的直接链接") 如果请求失败,请检查以下事项: | 现象 | 检查项 | | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | 打开模型选择器时 Cursor 提示升级 | 确认正在使用 Cursor Pro 或更高套餐。免费套餐可以保存配置,但不能选择自定义模型。 | | 认证失败 | 确认 **OpenAI API Key** 中的值是 AISIX 调用方 API Key,而不是上游服务提供方 Key。 | | 找不到模型 | 确认自定义模型名称与调用方可用的 AISIX 模型别名完全一致。 | | Cursor 报告连接或端点错误 | 确认 Cursor 可以访问 base URL,该 URL 在环境要求时使用 HTTPS,并以 `/v1` 结尾。 | | 请求使用了非预期模型或负载 | 使用不包含服务提供方模型 ID 的中性别名,然后在 Ask 模式中明确选择该别名。 | | 内置模型返回错误 | 切回内置模型时清除 **Override OpenAI Base URL**。该覆盖值全局应用于兼容 OpenAI 的请求。 | | AISIX 日志中没有请求 | 确认已配置 **Override OpenAI Base URL**,并在 Ask 模式中选择了自定义模型。Agent 模式、Tab Completion 和其他专用功能不使用此路径。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看面向网关的请求格式。 * [指标和日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):确认网关侧请求指标和日志。 * [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):为 Cursor 聊天流量添加调用方或模型限流。 * [Cursor API Keys](https://docs.cursor.com/settings/api-keys):查看哪些 Cursor 模型和功能支持自定义 API Key。 --- # CrewAI [CrewAI](https://docs.crewai.com/) 是用于构建多 Agent 系统的框架,涵盖 Agent、任务、团队、流程、工具和记忆。AISIX 位于模型请求边界,而 CrewAI 继续负责 Agent 协作和任务执行。 CrewAI 文档中适合网关的路径是使用带自定义 `base_url` 的 `LLM` 配置。当 CrewAI 应用需要通过 AISIX 发送兼容 OpenAI 的聊天请求时,请使用此设置。 本指南使用带自定义 `LLM` 的 CrewAI。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置 LLM。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [CrewAI](https://docs.crewai.com/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 CrewAI[​](#配置-crewai "配置 CrewAI的直接链接") 如果应用尚未包含 CrewAI,请先安装: ``` pip install crewai ``` 设置 CrewAI 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 使用 AISIX 值创建 CrewAI `LLM`,并将其传递给 Agent: ``` import os from crewai import Agent, Crew, LLM, Task llm = LLM( model=os.environ["AISIX_MODEL"], provider="openai", api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], ) writer = Agent( role="Writer", goal="Write concise explanations.", backstory="You explain technical systems clearly.", llm=llm, ) task = Task( description="Write one sentence about governed multi-agent systems.", expected_output="One concise sentence.", agent=writer, ) crew = Crew( agents=[writer], tasks=[task], ) print(crew.kickoff()) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。`provider` 值告诉 CrewAI 使用其兼容 OpenAI 的客户端访问自定义端点。AISIX 管理模型请求路径,而 CrewAI 继续负责 Agent、任务、团队、流程、记忆和工具编排。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出团队结果。 * AISIX 为所选模型别名记录一条或多条成功的 `POST /v1/chat/completions` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `base_url` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 多 Agent 工作流可能因规划、委派、工具使用、记忆和任务执行而发起多次模型调用。为每个应使用 AISIX 的 Agent 或团队级 LLM 配置 AISIX,并在配置限流和审查用量时考虑额外请求。使用 AISIX Cloud 时,还应在设置预算时考虑这些请求扇出。 CrewAI 当前尚未在文档中提供与此处 `base_url` 路径等价的稳定原生 OpenAI Responses API 配置。除非你的 CrewAI 版本公开并记录了 Responses API 客户端路径,否则请继续使用 AISIX 的兼容 OpenAI 路由。如果切换,请先验证实际的 Agent、工具和记忆工作流。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看面向网关的请求行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):在启用 CrewAI 工具前确认工具调用行为。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):在 AISIX Cloud 支出控制中考虑多 Agent 请求扇出。 --- # Haystack [Haystack](https://docs.haystack.deepset.ai/) 是用于构建 LLM 应用的框架,涵盖管道、检索、索引、文档处理、Agent 和生成器。AISIX 位于模型请求边界,而 Haystack 继续负责管道执行和检索。 Haystack 的 `OpenAIResponsesChatGenerator` 组件通过 `api_base_url` 支持自定义兼容 OpenAI 的部署。当 Haystack 管道需要通过 AISIX 发送 Responses API 请求时,请使用此设置。 本指南使用 `OpenAIResponsesChatGenerator`。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置生成器。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [Haystack](https://docs.haystack.deepset.ai/docs/installation) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Haystack[​](#配置-haystack "配置 Haystack的直接链接") 如果应用尚未包含 Haystack,请先安装: ``` pip install haystack-ai ``` 设置 Haystack 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 使用 AISIX 值创建 `OpenAIResponsesChatGenerator`: ``` import os from haystack.components.generators.chat import OpenAIResponsesChatGenerator from haystack.dataclasses import ChatMessage from haystack.utils import Secret generator = OpenAIResponsesChatGenerator( model=os.environ["AISIX_MODEL"], api_base_url=os.environ["AISIX_BASE_URL"], api_key=Secret.from_token(os.environ["AISIX_API_KEY"]), ) response = generator.run([ ChatMessage.from_user("Write one sentence about retrieval pipelines."), ]) print(response["replies"][0].text) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 管理模型请求路径,而 Haystack 继续负责管道组件、提示词构建器、检索器、排序组件和响应处理。 Haystack 还提供用于 Chat Completions 的 [`OpenAIChatGenerator`](https://docs.haystack.deepset.ai/docs/openaichatgenerator)。当管道需要广泛的兼容 OpenAI 聊天支持,而不是 Responses 特有功能时,请使用该组件。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出聊天响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `api_base_url` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 Haystack 应用通常会组合生成器、检索器、排序组件、工具和结构化输出。依赖网关对流式传输、工具调用或结构化输出执行策略或采集遥测前,请先验证实际管道。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的 Responses 行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当工作流需要广泛的兼容 OpenAI 支持时使用 Chat Completions。 * [向量嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md):当 Haystack 工作流通过 AISIX 使用嵌入时配置嵌入流量。 * [重排序](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md):当 Haystack 管道通过 AISIX 使用重排序模型时配置重排序流量。 --- # Instructor [Instructor](https://python.useinstructor.com/) 是一个 Python 库,可使用 Pydantic 模型从 LLM 响应中提取结构化数据。它在服务提供方客户端之上提供响应模型校验与重试能力。 Instructor 可以包装已指向 AISIX 的兼容 OpenAI 客户端。当应用需要保留 Instructor 的响应模型工作流,同时通过网关路由模型流量时,请使用此配置。 本指南将 Instructor 与 OpenAI Responses API 结合使用。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置 OpenAI Python 客户端,再将其交给 Instructor。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [Instructor](https://python.useinstructor.com/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Instructor[​](#配置-instructor "配置 Instructor的直接链接") 如果应用尚未包含相应 Python 包,请先安装: ``` pip install instructor openai "pydantic>=2" ``` 设置应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 创建指向 AISIX 的 OpenAI 客户端,再以 Responses 模式传递给 Instructor: ``` import os import instructor from instructor import Mode from openai import OpenAI from pydantic import BaseModel class Ticket(BaseModel): category: str priority: str openai_client = OpenAI( base_url=os.environ["AISIX_BASE_URL"], api_key=os.environ["AISIX_API_KEY"], ) client = instructor.from_openai( openai_client, mode=Mode.RESPONSES_TOOLS, ) ticket = client.responses.create( model=os.environ["AISIX_MODEL"], response_model=Ticket, input="Classify this ticket: production login failures for all users.", ) print(ticket.model_dump_json(indent=2)) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 负责模型请求路径:验证调用方 API Key、解析别名、应用策略、记录遥测数据,并将请求分发到别名背后的服务提供方。Instructor 仍负责 Schema 校验和重试。 Instructor 还通过 `client.chat.completions.create(...)` 支持 [Chat Completions 模式](https://python.useinstructor.com/integrations/openai/)。当工作流需要广泛的兼容 OpenAI 聊天支持时,请使用这些模式。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出通过校验的 Pydantic 对象。 * AISIX 为所选模型别名记录一条或多条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 OpenAI 客户端使用 AISIX 的 `base_url`。 当校验失败时,Instructor 可能会重试请求。配置限流和审查用量时应考虑这些重试。使用 AISIX Cloud 时,还应在设置预算时考虑这些重试。如果持续重试,请检查上游模型是否能满足 Schema,以及所选 Instructor 模式是否受 AISIX 路由支持。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的 Responses 行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当工作流需要广泛的兼容 OpenAI 支持时使用 Chat Completions。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):在 AISIX Cloud 支出控制中考虑校验重试。 --- # LangChain 和 LangGraph [LangChain](https://docs.langchain.com/) 是用于构建 LLM 应用的框架,涵盖链、Agent、检索工作流和工具调用工作流。[LangGraph](https://docs.langchain.com/oss/python/langgraph/overview) 基于 LangChain 生态构建有状态 Agent 和图工作流。对于两者,网关通常接入模型客户端,而无需改变应用的其他部分。 LangChain OpenAI 包提供可调用自定义基础 URL、并可选择使用 OpenAI Responses API 的聊天模型客户端 `ChatOpenAI`。当 LangChain 应用需要通过 AISIX 发送 Responses API 请求时,请使用这些设置。 本指南使用带有 `langchain-openai` 的 LangChain Python。你将使用 AISIX 代理 URL、调用方 API Key、模型别名和 `use_responses_api=True` 配置 `ChatOpenAI`。LangGraph 应用可以在图节点或 Agent 工作流中复用同一个 `ChatOpenAI` 客户端。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [LangChain](https://python.langchain.com/docs/how_to/installation/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 LangChain[​](#配置-langchain "配置 LangChain的直接链接") 如果应用尚未包含 LangChain OpenAI 集成,请先安装: ``` pip install langchain-openai langgraph ``` 设置 LangChain 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 使用 AISIX 值创建 `ChatOpenAI` 客户端: ``` import os from langchain_openai import ChatOpenAI llm = ChatOpenAI( model=os.environ["AISIX_MODEL"], api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], use_responses_api=True, ) response = llm.invoke("Write one sentence about why gateways help AI teams.") print(response.content) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 负责模型请求路径:验证调用方 API Key、解析别名、应用策略、记录遥测数据,并将请求分发到别名背后的服务提供方。LangChain 应用仍负责链、提示词、工具、检索和响应处理。 ## 在 LangGraph 中使用客户端[​](#在-langgraph-中使用客户端 "在 LangGraph 中使用客户端的直接链接") 将同一个 `ChatOpenAI` 客户端传递给 LangGraph 节点或图状态转换: ``` import os from langchain_openai import ChatOpenAI from typing_extensions import TypedDict from langgraph.graph import END, START, StateGraph llm = ChatOpenAI( model=os.environ["AISIX_MODEL"], api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], use_responses_api=True, ) class State(TypedDict): prompt: str answer: str def call_model(state: State): response = llm.invoke(state["prompt"]) return {"answer": response.content} graph = StateGraph(State) graph.add_node("call_model", call_model) graph.add_edge(START, "call_model") graph.add_edge("call_model", END) app = graph.compile() result = app.invoke({ "prompt": "Write one sentence about governed agents.", }) print(result["answer"]) ``` LangGraph 负责状态管理、图执行、重试和工具编排。AISIX 只会看到已配置的 `ChatOpenAI` 客户端发出的模型请求。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出聊天响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `base_url` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 LangChain 也可以通过同一个 `ChatOpenAI` 类使用 Chat Completions。只有已有链或依赖项要求 Chat Completions 兼容性时才使用该路径;新的 OpenAI 系列 LangChain 集成优先使用此处的 Responses API 路径。 启用流式响应、工具调用、结构化输出、内置工具或推理选项时,LangChain 可能发送可选的 OpenAI 字段。在依赖该路径的网关策略或遥测数据前,请验证实际使用的链或 Agent 工作流。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的请求行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当已有 LangChain 工作流需要 Chat Completions 时使用该路由。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):启用 LangChain 工具或 Agent 前确认工具调用行为。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):确认网关侧请求指标和日志。 --- # LlamaIndex [LlamaIndex](https://docs.llamaindex.ai/) 是用于构建 LLM 应用的框架,可将 LLM 调用与数据连接器、索引、检索和查询工作流结合。AISIX 位于模型请求边界,而 LlamaIndex 继续负责文档加载、索引、检索和响应组装。 LlamaIndex 的 OpenAI 集成提供 `OpenAIResponses`,这是一个可通过自定义 API 基础 URL 使用 OpenAI Responses API 的 LLM 适配器。当 LlamaIndex 应用需要通过 AISIX 发送 Responses API 请求时,请使用此适配器。 本指南使用带有 `llama-index-llms-openai` 的 LlamaIndex Python。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置 `OpenAIResponses`。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [LlamaIndex](https://docs.llamaindex.ai/en/stable/getting_started/installation/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 LlamaIndex[​](#配置-llamaindex "配置 LlamaIndex的直接链接") 如果应用尚未包含 OpenAI LLM 集成,请先安装: ``` pip install llama-index-llms-openai ``` 设置 LlamaIndex 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" export AISIX_CONTEXT_WINDOW="128000" ``` 使用 AISIX 值创建 `OpenAIResponses` 客户端: ``` import os from llama_index.core.llms import ChatMessage from llama_index.llms.openai import OpenAIResponses llm = OpenAIResponses( model=os.environ["AISIX_MODEL"], api_base=os.environ["AISIX_BASE_URL"], api_key=os.environ["AISIX_API_KEY"], context_window=int(os.environ["AISIX_CONTEXT_WINDOW"]), ) response = llm.chat([ ChatMessage(role="user", content="Write one sentence about retrieval systems."), ]) print(response.message.content) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。将 `AISIX_CONTEXT_WINDOW` 设置为别名背后模型的上下文大小,使 LlamaIndex 不必从别名名称推断该值。AISIX 负责模型请求路径,而 LlamaIndex 应用继续负责数据加载、索引、检索和响应组装。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出聊天响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `api_base` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 LlamaIndex 也提供兼容 OpenAI 的聊天适配器,包括仍需要 Chat Completions 兼容性的应用可以使用的 `OpenAILike`。只有已有工作流或集成依赖 Chat Completions 路由时才使用这些适配器;新的 OpenAI 系列 LlamaIndex 集成优先使用 `OpenAIResponses`。 LlamaIndex 应用常将检索、聊天、工具调用和结构化响应解析组合使用。在依赖相应路径的网关策略或遥测数据前,请验证实际工作流。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的请求行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当已有 LlamaIndex 工作流需要 Chat Completions 时使用该路由。 * [向量嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md):如果 LlamaIndex 工作流通过 AISIX 使用嵌入,请配置嵌入流量。 * [响应缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/caching.md):缓存符合条件的非流式聊天响应。 --- # Microsoft Agent Framework [Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/) 支持 Python、C# 和 Go 工作流,用于构建 Agent、工具、上下文提供方、中间件和 AI 应用。当应用使用带自定义端点的兼容 OpenAI 客户端时,AISIX 位于模型请求边界。 本指南使用采用 Responses API 的 Python `OpenAIChatClient`,该客户端通过 `base_url` 支持兼容 OpenAI 的端点。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置客户端。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Microsoft Agent Framework[​](#配置-microsoft-agent-framework "配置 Microsoft Agent Framework的直接链接") 如果应用尚未包含 OpenAI 服务提供方包,请先安装: ``` pip install agent-framework-openai ``` 设置 Agent 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 使用 AISIX 值创建 `OpenAIChatClient`,并将其转换为 Agent: ``` import asyncio import os from agent_framework.openai import OpenAIChatClient client = OpenAIChatClient( base_url=os.environ["AISIX_BASE_URL"], api_key=os.environ["AISIX_API_KEY"], model=os.environ["AISIX_MODEL"], ) agent = client.as_agent( name="GatewayAgent", instructions="You answer in one concise sentence.", ) async def main(): response = await agent.run("Why do gateways help AI teams?") print(response) asyncio.run(main()) ``` Microsoft 将 `OpenAIChatCompletionClient` 记录为适用于广泛模型兼容性或现有 Chat Completions 集成的 [Chat Completions 回退路径](https://learn.microsoft.com/en-us/agent-framework/agents/providers/openai#chat-completion-client)。 如果应用仍使用 Semantic Kernel,请改为使用 AISIX 端点配置其 OpenAI 聊天补全连接器: ``` #pragma warning disable SKEXP0010 builder.AddOpenAIChatCompletion( modelId: Environment.GetEnvironmentVariable("AISIX_MODEL")!, endpoint: new Uri(Environment.GetEnvironmentVariable("AISIX_BASE_URL")!), apiKey: Environment.GetEnvironmentVariable("AISIX_API_KEY")! ); #pragma warning restore SKEXP0010 ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 管理模型请求路径,而 Microsoft 框架代码继续负责 Agent、工具、上下文提供方、中间件、提示词和工作流行为。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行应用。 请求成功后,请确认以下结果: * 应用输出 Agent 响应。 * AISIX 为 `OpenAIChatClient` 路径记录一条成功的 `POST /v1/responses` 请求,或为 Semantic Kernel 回退路径记录一条成功的 `POST /v1/chat/completions` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `base_url` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 Microsoft Agent Framework 同时支持 [Responses 和 Chat Completions 客户端](https://learn.microsoft.com/en-us/agent-framework/agents/providers/openai)。当需要通过 AISIX 获得广泛的兼容 OpenAI 模型支持时,请使用 Chat Completions。 Responses 托管工具和服务提供方特有功能可能无法映射到所有上游服务提供方。依赖网关对流式传输、工具或 Responses 托管工具行为执行策略或采集遥测前,请先验证 Responses 工作流。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的 Responses 行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当工作流需要广泛的兼容 OpenAI 支持时使用 Chat Completions。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):在启用 Agent 工具前确认工具调用行为。 --- # OpenAI Agents SDK [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) 是用于构建 Agent 应用的 Python 框架,涵盖 Agent、工具、交接、护栏、会话和追踪。它默认使用 Responses API,也可以通过自定义 `AsyncOpenAI` 客户端访问兼容 OpenAI 的端点。 当 Agents SDK 应用需要通过 AISIX 路由模型请求,同时保留 Agent 工作流时,请使用此配置。 本指南使用 OpenAI Agents SDK 的默认 Responses API 模型路径。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置 `AsyncOpenAI`。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 OpenAI Agents SDK[​](#配置-openai-agents-sdk "配置 OpenAI Agents SDK的直接链接") 如果应用尚未包含 OpenAI Agents SDK,请先安装: ``` pip install openai-agents ``` 设置 Agent 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 为 AISIX 创建 `AsyncOpenAI` 客户端,并将其设为 SDK 的默认客户端: ``` import asyncio import os from agents import ( Agent, AsyncOpenAI, Runner, set_default_openai_client, set_tracing_disabled, ) set_tracing_disabled(True) client = AsyncOpenAI( base_url=os.environ["AISIX_BASE_URL"], api_key=os.environ["AISIX_API_KEY"], ) set_default_openai_client(client, use_for_tracing=False) agent = Agent( name="GatewayAgent", instructions="You answer in one concise sentence.", model=os.environ["AISIX_MODEL"], ) async def main(): result = await Runner.run(agent, "Why do gateways help AI teams?") print(result.final_output) asyncio.run(main()) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 管理模型请求路径,而 OpenAI Agents SDK 继续负责 Agent 指令、工具、交接、护栏和运行编排。 本示例禁用了 Agents SDK 默认的追踪导出。如果需要追踪,请单独配置 SDK 追踪导出器,使追踪数据符合组织策略。 OpenAI Agents SDK 还支持用于 [Chat Completions API](https://openai.github.io/openai-agents-python/models/) 的 `OpenAIChatCompletionsModel`。当工作流需要广泛的兼容 OpenAI 服务提供方支持,或已经依赖 Chat Completions 行为时,请使用该模型形式。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出 Agent 响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `base_url` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 OpenAI 托管工具和服务提供方特有的 Responses 功能可能无法映射到所有上游服务提供方。依赖网关对托管工具、流式传输或服务提供方特有响应项执行策略或采集遥测前,请先验证 Responses 工作流。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的 Responses 行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当工作流需要广泛的兼容 OpenAI 支持时使用 Chat Completions。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):在启用 Agent 工具前确认工具调用行为。 --- # Pydantic AI [Pydantic AI](https://ai.pydantic.dev/) 是用于构建类型化 LLM 应用的 Python Agent 框架,涵盖工具、依赖注入、结构化输出和校验。它可以通过 `OpenAIResponsesModel` 和 `OpenAIProvider` 使用 OpenAI Responses API。 当 Pydantic AI 应用需要保留 Agent 和校验工作流,同时通过 AISIX 路由模型请求时,请使用此配置。 本指南使用 OpenAI Responses 模型。你将使用 AISIX 代理 URL、调用方 API Key 和模型别名配置 `OpenAIProvider`。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前,请准备以下内容: * 一个受 [Pydantic AI](https://ai.pydantic.dev/install/) 支持的 Python 环境。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个调用方 API Key 可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Pydantic AI[​](#配置-pydantic-ai "配置 Pydantic AI的直接链接") 如果应用尚未包含 Pydantic AI,请先安装: ``` pip install pydantic-ai ``` 设置 Pydantic AI 应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 使用 AISIX 值创建 OpenAI Responses 模型: ``` import os from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIResponsesModel from pydantic_ai.providers.openai import OpenAIProvider model = OpenAIResponsesModel( os.environ["AISIX_MODEL"], provider=OpenAIProvider( base_url=os.environ["AISIX_BASE_URL"], api_key=os.environ["AISIX_API_KEY"], ), ) agent = Agent(model) response = agent.run_sync("Write one sentence about typed AI applications.") print(response.output) ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 管理模型请求路径,而 Pydantic AI 继续负责 Agent 执行、工具调用、依赖注入、结构化输出和校验。 Pydantic AI 还提供用于 Chat Completions 的 [`OpenAIChatModel`](https://ai.pydantic.dev/api/models/openai/#pydantic_ai.models.openai.OpenAIChatModel)。当工作流需要广泛的兼容 OpenAI 聊天支持时,请使用该模型。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行脚本。 请求成功后,请确认以下结果: * 脚本输出 Agent 响应。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `base_url` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 Pydantic AI 支持多个 OpenAI 模型接口。Responses 工作流使用 `OpenAIResponsesModel`,需要广泛兼容 OpenAI Chat Completions 支持时使用 `OpenAIChatModel`。在依赖网关为该工作流执行策略或采集遥测前,请使用确切的别名验证结构化输出、工具定义和重试。 ## 后续步骤[​](#后续步骤 "后续步骤��的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的 Responses 行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当工作流需要广泛的兼容 OpenAI 支持时使用 Chat Completions。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):在启用 Pydantic AI 工具前确认工具调用行为。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):在 AISIX Cloud 支出控制中考虑重试或校验循环。 --- # Vercel AI SDK [Vercel AI SDK](https://ai-sdk.dev/docs/introduction) 是用于构建 AI 应用流程的 TypeScript 工具包,涵盖文本生成、流式 UI 响应、工具调用和结构化输出。在 AISIX 部署中,应用可以继续使用 AI SDK 的辅助函数,同时将模型服务提供方配置指向网关。 OpenAI 服务提供方包允许 Vercel AI SDK 使用 API Key 调用自定义基础 URL。当 TypeScript 应用需要通过 AISIX 发送 Responses API 请求时,请使用该服务提供方。 本指南使用 AI SDK 核心包和 `@ai-sdk/openai`。你将创建一个指向 AISIX 的 OpenAI 服务提供方,并在应用代码中使用 AISIX 模型别名。 ## 前置条件[​](#前置条件 "前置条件�的直接链接") 开始前,请准备以下内容: * 应用的 TypeScript 项目。 * 一个正在运行且应用可以访问的 AISIX 网关。 * 一个 AISIX 调用方 API Key。 * 一个可通过[Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)访问的模型别名。 如果你的组织已经部署 AISIX,请向管理团队获取网关 URL、模型别名和调用方 API Key。否则,请按照[开源 AISIX 网关快速上手](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速上手](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)完成部署,也可以[联系 API7](https://api7.ai/contact)申请 Hybrid Cloud 访问权限。 ## 配置 Vercel AI SDK[​](#配置-vercel-ai-sdk "配置 Vercel AI SDK的直接链接") 如果应用尚未包含 AI SDK 包,请先安装: ``` npm install ai @ai-sdk/openai ``` 设置应用要使用的值: ``` # AISIX_BASE_URL 以 /v1 结尾,末尾不带斜杠 # 本地快速入门使用 http://127.0.0.1:3000/v1 export AISIX_BASE_URL="YOUR_AISIX_GATEWAY_URL/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="gpt-4o-prod" ``` 为 AISIX 创建 OpenAI 服务提供方: ``` import { createOpenAI } from "@ai-sdk/openai"; import { generateText } from "ai"; const aisix = createOpenAI({ apiKey: process.env.AISIX_API_KEY, baseURL: process.env.AISIX_BASE_URL, }); async function main() { const { text } = await generateText({ model: aisix.responses(process.env.AISIX_MODEL ?? "gpt-4o-prod"), prompt: "Write one sentence about model governance.", }); console.log(text); } main(); ``` 模型值应填写 AISIX 模型别名,而不是上游服务提供方模型 ID。AISIX 负责模型请求路径:验证调用方 API Key、解析别名、应用策略、记录遥测数据,并将请求分发到别名背后的服务提供方。应用仍负责 UI 流式输出、工具编排和响应处理。 OpenAI 服务提供方也可以通过 `aisix.chat(...)` 使用 Chat Completions,而 [`@ai-sdk/openai-compatible`](https://ai-sdk.dev/providers/ai-sdk-providers/openai-compatible) 服务提供方仍适合广泛的兼容 OpenAI 聊天集成。 ## 验证集成[​](#验证集成 "验证集成的直接链接") 在已设置 AISIX 环境变量的 Shell 中运行应用。 请求成功后,请确认以下结果: * 应用输出生成的文本。 * AISIX 为所选模型别名记录一条成功的 `POST /v1/responses` 请求。 请在 AISIX 网关日志中验证请求。也可以使用已配置的指标或上游服务提供方日志。 如果请求失败,请先确认调用方 API Key 可以访问所选模型别名,且 `baseURL` 指向包含 `/v1` 的 AISIX 代理 API 根路径。 本指南使用基于 Responses 的文本生成。使用其他 AI SDK 辅助函数(如流式响应、工具调用或结构化输出)前,请验证对应路径,再依赖其网关策略或遥测数据。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md):查看面向网关的 Responses 行为。 * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):当工作流需要广泛的兼容 OpenAI 支持时使用 Chat Completions。 * [流式响应](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):使用流式 UI 响应前确认流式行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):查看兼容 OpenAI 的工具调用行为。 --- # 语音 Agent 平台 语音应用由多个对延迟敏感的环节组成:音频传输、语音识别、轮次检测、语言模型推理、工具执行和语音合成。语音 Agent 平台负责协调这些环节,使应用能够通过网页、应用程序或电话进行实时对话。 语言模型只是这一运行时的一部分,但它通常也是组织需要集中治理的环节。当语音平台支持兼容 OpenAI 的 LLM 端点时,其文本模型请求可以通过 AISIX 完成调用方身份认证、模型别名解析、路由、策略应用和遥测记录。团队因此可以在 AISIX 中管理模型访问,而无需替换负责提供语音体验的平台。 语音应用或托管平台仍负责媒体会话,并在调用 AISIX 前将语音转换为对话内容。它会把这些内容和所有工具定义发送到网关。AISIX 随后验证调用方身份、解析模型别名、应用已配置的策略、记录遥测数据,并将请求分发给选定的模型服务提供方。 ## 选择平台指南[​](#choose-a-platform-guide "选择平台指南的直接链接") 所有指南都使用相同的 AISIX 值,但各平台提供这些值的方式不同: | 平台 | 集成接口 | 指南 | | ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------- | | ElevenLabs Agents | 托管的 Custom LLM 配置 | [ElevenLabs Agents](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/elevenlabs.md) | | LiveKit Agents | Python OpenAI LLM 插件 | [LiveKit Agents](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/livekit.md) | | Pipecat | Python `OpenAILLMService` | [Pipecat](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/pipecat.md) | | Vapi | 托管的 `custom-llm` 模型配置 | [Vapi](https://docs.apiseven.com/ai-gateway/integrations/voice-agents/vapi.md) | ElevenLabs Agents 和 Vapi 托管语音运行时。LiveKit Agents 和 Pipecat 是应用框架,因此应用还需要配置传输、语音转文本服务、文本转语音服务和轮次检测。 ## 准备 AISIX[​](#prepare-aisix "准备 AISIX的直接链接") 每个平台都需要以下面向网关的值: * 平台或应用能够访问的 AISIX HTTPS 代理 URL。 * 专用于语音应用的 AISIX 调用方 API Key。 * 调用方 Key 可以通过 `POST /v1/chat/completions` 访问的模型别名。 如果组织中已经部署 AISIX,请向管理该部署的团队获取这些值。否则,请完成[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)或 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md),或[联系 API7](https://api7.ai/contact)申请混合云访问权限。 调用方 Key 应仅获准访问语音应用需要的别名。根据预期对话量配置请求和 Token 限制,并为临时评估设置过期时间。 ## 了解边界[​](#understand-the-boundary "了解边界的直接链接") AISIX 在语音平台把语音转换为对话内容后接收模型请求。因此,AISIX 不会取代平台的音频传输、语音识别、语音合成、音色选择、打断处理或电话服务。 网关安全护栏可以检查 Chat Completions 路径上受支持的请求和响应文本,但不能检查仍留在语音平台内的音频。有关端点和内容的准确覆盖范围,请参阅 [安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md),并分别检查各平台的录音、对话文本、保留和区域处理设置。 语音应用通常以流式方式接收模型响应,使语音合成可以在完整答案生成前开始。请确认模型别名支持 Chat Completions 流式传输,并在测量响应延迟时考虑语音运行时、AISIX 网关和模型服务提供方之间的网络距离。 ## 验证集成[​](#verify-an-integration "验证集成的直接链接") 使用一段简短对话确认完整链路: 1. 语音平台接受一条语音或文本测试消息。 2. AISIX 为预期的调用方 Key 和模型别名记录 `POST /v1/chat/completions`。 3. 平台收到流式模型文本,并以音频或文本形式返回给用户。 首次成功后,请测试打断行为以及应用依赖的所有函数工具。工具调用要求选定的上游模型和平台集成都能保留兼容 OpenAI 的工具调用流。 ## 相关指南[​](#related-guides "相关指南的直接链接") 选择上方的平台指南进行配置。以下指南介绍各集成共用的网关行为: * [兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md):查看面向网关的请求格式。 * [流式传输](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):了解流的传输和故障转移边界。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证工具定义和流式工具调用。 * [API Key 和模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):限制语音应用流量。 --- # ElevenLabs Agents [ElevenLabs Agents](https://elevenlabs.io/docs/eleven-agents/overview) 是用于构建和部署对话式语音 Agent 的托管平台。它负责协调语音识别、语音合成、轮次处理、工具和对话传输。Agent 可以监听、决策并作出响应,应用无需自行组装每个媒体组件。 组织可能仍希望 Agent 的语言模型流量使用与其他 AI 应用相同的访问控制、路由策略和遥测。为此,ElevenLabs 支持 Custom LLM。Agent 的语音会话继续在 ElevenLabs 中运行,而兼容 OpenAI 的 Chat Completions 请求通过 AISIX 发送到已配置的模型服务提供方。 在此集成中,ElevenLabs 将专用的 AISIX 调用方 API Key 保存为 Secret,在 `model` 中发送 AISIX 模型别名,并以流式方式向网关的 `/v1/chat/completions` 端点发送请求。AISIX 治理模型请求和响应;ElevenLabs 继续处理音频和对话体验。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下内容: * 可使用 ElevenLabs Agents 的 ElevenLabs 账户。 * 一个可编辑的 ElevenLabs Agent。 * 可从公网访问的 AISIX HTTPS 代理 URL。 * 专用于该 Agent 的 AISIX 调用方 API Key。 * 调用方 Key 可以通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 不要在 ElevenLabs 中存储上游服务提供方 Key。Custom LLM Secret 应只包含 AISIX 调用方 Key。 ## 配置 Custom LLM[​](#configure-the-custom-llm "配置 Custom LLM的直接链接") 在 ElevenLabs Dashboard 中打开 Agent,然后配置模型: 1. 在 **Agent** 页面打开 **LLM**。 2. 打开主要模型选择器,然后选择 **Custom LLM**。 3. 保持 **Chat Completions** 作为 API 格式。 4. 将 **Server URL** 设置为 AISIX 代理 API 根路径并包含 `/v1`,例如 `https://gateway.example.com/v1`。ElevenLabs 会附加 `/chat/completions`。 5. 将 **Model ID** 设置为 AISIX 模型别名,例如 `voice-agent-prod`。 6. 在 **API Key** 下创建或选择一个包含 AISIX 调用方 Key 的 Secret。 7. 选择 **Test Connection**。 连接测试应收到成功的兼容 OpenAI 的响应流。如果失败,请确认该 URL 可从公网访问,并且调用方 Key 有权访问该别名。 连接测试成功后,关闭 LLM 设置并发布 Agent。 ## 验证对话[​](#verify-a-conversation "验证对话的直接链接") 打开 **Preview** 并开始一段简短对话。说出一个简单请求,例如“请用一个短句回答”。 确认以下结果: * Agent 返回语音响应。 * AISIX 记录一条成功的 `POST /v1/chat/completions` 请求。 * 记录的调用方身份和模型与专用的 ElevenLabs Key 和 AISIX 别名一致。 ElevenLabs 负责语音转文本结果、生成的语音、录音设置和对话文本。AISIX 看到的是兼容 OpenAI 的模型请求和响应文本,而不是原始音频流。 ## 谨慎使用工具[​](#use-tools-carefully "谨慎使用工具的直接链接") ElevenLabs 系统工具和自定义工具要求 Custom LLM 生成兼容的函数调用。在生产环境启用工具前,请确认所选模型别名会通过 AISIX 返回工具名称和参数,并且 ElevenLabs 会按预期执行工具。 纯文本连接测试成功并不能证明工具兼容。投入生产前,请测试 Agent 使用的每个系统工具或自定义工具,包括一次轮次中调用多个工具的场景。 ## 排查连接问题[​](#troubleshoot-the-connection "排查连接问题的直接链接") | 现象 | 检查项 | | ---------------------- | ------------------------------------------------------------------------------------------------ | | Server URL 无效 | 输入到 `/v1` 为止的 AISIX HTTPS 基础 URL,不要添加 `/chat/completions`;Dashboard 会附加该后缀。 | | 连接测试返回 `401` | 确认所选 ElevenLabs Secret 包含 AISIX 调用方 Key。 | | 连接测试返回 `403` | 确认调用方 Key 允许访问所选模型别名。 | | 连接测试返回 `404` | 确认 Model ID 是 AISIX 模型别名,并且 AISIX 代理路由可访问。 | | Agent 一直等待而不说话 | 检查 AISIX 响应流和上游延迟,然后验证 ElevenLabs 的语音与轮次设置。 | ## 后续步骤[​](#next-steps "后续步骤的直接链接") * [流式传输](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):查看网关的流式行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证通过 AISIX 的函数调用。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):监控模型延迟和请求结果。 --- # LiveKit Agents [LiveKit Agents](https://docs.livekit.io/agents/) 是用于构建实时语音和媒体 Agent 的框架。它把 Agent 的会话逻辑与音频或视频传输、语音识别、语言模型、语音合成、轮次检测和工具连接起来。这些组件共同使应用能够在实时交互中作出响应。 该框架让这些组件保持模块化。LiveKit 应用可以继续使用现有的房间或传输机制以及语音服务,只把文本语言模型环节通过 AISIX 发送。这样,应用无需把媒体会话移入网关,就能获得 AISIX 模型别名、访问控制、路由和遥测能力。 此集成使用 LiveKit 的 `openai.LLM` 客户端,并配置 AISIX 代理 URL、调用方 API Key 和模型别名。它不使用 OpenAI Realtime 模型插件;LiveKit 继续协调文本 LLM 周围的音频流水线。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下内容: * 使用 LiveKit Agents 的 Python 项目。 * LiveKit Worker 能够访问的运行中 AISIX 网关。 * AISIX 调用方 API Key。 * 调用方 Key 可以通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 Worker 还需要现有的 LiveKit、语音转文本和文本转语音配置。这些凭证与 AISIX 调用方 Key 相互独立。 ## 配置 LLM 插件[​](#configure-the-llm-plugin "配置 LLM 插件的直接链接") 如果项目尚未包含 LiveKit OpenAI 插件,请安装它: ``` pip install "livekit-agents[openai]~=1.5" ``` 在 Worker 环境中设置网关值: ``` # AISIX_BASE_URL 包含 /v1,且末尾不带斜杠。 export AISIX_BASE_URL="https://gateway.example.com/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="voice-agent-prod" ``` 使用这些值创建 LLM 插件: ``` import os from livekit.plugins import openai llm = openai.LLM( api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], model=os.environ["AISIX_MODEL"], ) ``` 把 `llm` 传给应用的 `AgentSession`。保持现有的传输、STT、TTS 和轮次检测组件不变。 ## 测试 LLM 连接[​](#test-the-llm-connection "测试 LLM 连接的直接链接") 加入 LiveKit 房间前,先把同一插件作为独立流式客户端进行测试: ``` import asyncio import os from livekit.agents import ChatContext from livekit.plugins import openai async def main(): context = ChatContext() context.add_message( role="user", content="Reply with one short sentence about voice gateways.", ) llm = openai.LLM( api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], model=os.environ["AISIX_MODEL"], ) stream = llm.chat(chat_ctx=context) async for text in stream.to_str_iterable(): print(text, end="", flush=True) await llm.aclose() asyncio.run(main()) ``` 脚本应打印流式模型响应。AISIX 应为所选调用方 Key 和别名记录 `POST /v1/chat/completions`。 此测试通过后,运行常规 LiveKit Worker 并验证一轮简短语音对话。如果文本生成成功,但参与者没有收到音频,请排查 LiveKit TTS 和房间流水线,而不是更改 AISIX 模型端点。 ## 了解 API 选择[​](#understand-the-api-choice "了解 API 选择的直接链接") LiveKit 建议直接使用 OpenAI 时优先采用 Responses API 插件。本指南使用 `openai.LLM`,因为 LiveKit 将该客户端用于兼容 OpenAI 的 Chat Completions 端点,而这是适用范围更广的 AISIX 集成路径。 除非应用明确使用网关的 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md),并且已经验证完整的音频事件协议,否则不要把 LiveKit OpenAI Realtime 插件指向 AISIX。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") * [流式传输](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):了解流完成和故障转移行为。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证 LiveKit Agent 使用的工具。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):为语音流量配置具有弹性的模型目标。 --- # Pipecat [Pipecat](https://docs.pipecat.ai/) 是用于实时语音和多模态 Agent 的开源 Python 框架。它把对话表示为由帧和服务组成的流水线。应用可以围绕自己的交互逻辑组合传输、语音识别、上下文管理、语言模型推理、语音合成和其他处理器。 得益于模块化服务,现有 Pipecat 流水线无需更改传输或语音组件,就能把文本语言模型请求路由到 AISIX。AISIX 为该环节提供模型别名、访问控制、路由和遥测,而 Pipecat 继续在应用流水线中传输音频、对话文本、模型文本和合成语音。 Pipecat 的 `OpenAILLMService` 支持自定义 OpenAI 基础 URL 和 API Key。请将它们分别设置为 AISIX 代理 API 根路径和调用方 Key,并在服务设置中使用 AISIX 模型别名。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下内容: * 使用 Pipecat 的 Python 项目。 * Pipecat 进程能够访问的运行中 AISIX 网关。 * AISIX 调用方 API Key。 * 调用方 Key 可以通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 流水线还需要正常使用的传输、语音转文本和文本转语音服务。这些服务的凭证不会被 AISIX 调用方 Key 替换。 ## 配置 OpenAILLMService[​](#configure-openaillmservice "配置 OpenAILLMService的直接链接") 如果项目尚未安装 Pipecat 的 OpenAI 集成,请安装: ``` pip install "pipecat-ai[openai]" ``` 设置网关值: ``` # AISIX_BASE_URL 包含 /v1,且末尾不带斜杠。 export AISIX_BASE_URL="https://gateway.example.com/v1" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export AISIX_MODEL="voice-agent-prod" ``` 使用当前基于设置的配置创建 LLM 服务: ``` import os from pipecat.services.openai.llm import OpenAILLMService llm = OpenAILLMService( api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], settings=OpenAILLMService.Settings( model=os.environ["AISIX_MODEL"], ), ) ``` 在现有 Pipecat 流水线中,把 `llm` 放在用户上下文聚合器和 TTS 服务之间。模型设置使用 AISIX 别名,而不是上游服务提供方的模型 ID。 ## 测试 LLM 连接[​](#test-the-llm-connection "测试 LLM 连接的直接链接") 启动完整媒体流水线前,请先测试流式传输: ``` import asyncio import os from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.services.openai.llm import OpenAILLMService async def main(): llm = OpenAILLMService( api_key=os.environ["AISIX_API_KEY"], base_url=os.environ["AISIX_BASE_URL"], settings=OpenAILLMService.Settings( model=os.environ["AISIX_MODEL"], ), ) context = LLMContext( messages=[ { "role": "user", "content": "Reply with one short sentence about voice gateways.", } ] ) stream = await llm.get_chat_completions(context) async for chunk in stream: if chunk.choices and chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="", flush=True) await llm.cleanup() asyncio.run(main()) ``` 脚本应打印流式响应。AISIX 应为已配置的别名记录 `POST /v1/chat/completions`。 最后一行清理代码会在这个独立冒烟测试中调用服务的公开清理钩子。在常规 Pipecat 应用中,流水线生命周期负责服务的启动和清理。 ## 验证语音流水线[​](#verify-the-voice-pipeline "验证语音流水线的直接链接") LLM 测试通过后,启动常规 Pipecat 应用并完成一轮语音对话。使用 Pipecat 指标分别查看语音识别、LLM 和语音合成延迟,并将 LLM 环节与 AISIX 请求指标进行比较。 如果独立 LLM 测试成功,但完整流水线没有发出语音,请检查上下文聚合器、TTS 服务和输出传输。AISIX 返回模型文本和工具调用,不会创建 Pipecat 音频帧。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") * [流式传输](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):查看网关的响应流路径。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):使用 AISIX 模型输出验证 Pipecat 函数处理程序。 * [指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md):比较网关延迟和 Pipecat 服务指标。 --- # Vapi [Vapi](https://docs.vapi.ai/) 是用于构建和运行网页及电话对话语音助手的托管平台。它负责协调通话传输、语音识别、语言模型轮次、语音生成、工具和助手编排,使应用能够通过已配置的助手提供实时语音体验。 Vapi 的 Custom LLM 服务提供方将这种编排与模型端点分离。Vapi 助手可以继续在 Vapi 中使用其语音服务、通话处理和工具,同时把兼容 OpenAI 的语言模型请求通过 AISIX 发送。这样,团队无需把 AISIX 当作语音运行时,就能在 LLM 环节应用 AISIX 模型别名、调用方授权、路由和遥测。 请使用 AISIX 兼容 OpenAI 的 API 根路径、AISIX 模型别名以及包含专用 AISIX 调用方 API Key 的凭证配置 Vapi 模型。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下内容: * Vapi 账户和一个可编辑的助手。 * 可从公网访问的 AISIX HTTPS 代理 URL。 * 专用于该助手的 AISIX 调用方 API Key。 * 调用方 Key 可以通过[兼容 OpenAI 的 API](https://docs.apiseven.com/ai-gateway/endpoints/openai-compatible-chat.md)访问的模型别名。 请把上游服务提供方凭证保存在 AISIX 中。Vapi 只应存储受限的 AISIX 调用方 Key。 ## 配置 Custom LLM[​](#configure-a-custom-llm "配置 Custom LLM的直接链接") 首先,把 AISIX 调用方 Key 存储为组织级 Custom LLM 凭证: 1. 在 Vapi Dashboard 中打开 **Settings → Integrations**。 2. 在 **Model Providers** 下选择 **Configure Custom LLM**。 3. 在 **API Key** 中输入 AISIX 调用方 Key。将可选的 OAuth2 字段留空。 4. 选择 **Save**。 接下来,配置助手以使用 AISIX: 1. 打开 **Assistants**,然后选择要配置的助手。 2. 选择 **Model** 卡片,然后选择 **Custom LLM**。 3. 将 **Model** 设置为 AISIX 模型别名,例如 `voice-agent-prod`。 4. 将 **Custom LLM URL** 设置为 AISIX API 根路径并包含 `/v1`,例如 `https://gateway.example.com/v1`。 5. Vapi 保存草稿后,选择 **Publish** 并检查模型变更。 6. 选择 **Next**,在 **Publish Description** 下输入版本名称,然后再次选择 **Publish**。 Vapi 把该 URL 用作 OpenAI 客户端的基础 URL,并附加 `/chat/completions`。它在调用自定义端点时,会把凭证作为 Bearer Token 放入 `Authorization` 请求头。AISIX 将该值作为调用方 Key 进行身份认证。 AISIX 别名及其上游模型必须支持流式 Chat Completions。Vapi 可以在收到文本增量时开始合成答案。 ## 验证集成[​](#verify-the-integration "验证集成的直接链接") 运行一段简短的网页或电话测试,并要求返回一句话。 确认以下结果: * Vapi 以语音形式返回响应。 * AISIX 记录一条成功的 `POST /v1/chat/completions` 请求。 * 调用方 Key 和模型别名与专用 Vapi 配置一致。 Vapi 负责通话录音设置、对话文本、语音服务和电话事件。AISIX 只治理 Vapi 通过自定义端点发送的 LLM 交互。 ## 单独验证工具[​](#verify-tools-separately "单独验证工具的直接链接") Vapi 可以在 Custom LLM 请求中包含兼容 OpenAI 的工具定义。如果助手使用工具,请先验证通过 AISIX 传输的流式函数名称、参数和工具调用 ID,再在生产环境中依赖该集成。 Vapi 工具执行还可能涉及助手、工具或账户级 Server URL。这些 Webhook 端点与 Custom LLM URL 相互独立,不会被 AISIX 替换。 ## 排查 Vapi 请求问题[​](#troubleshoot-vapi-requests "排查 Vapi 请求问题的直接链接") | 现象 | 检查项 | | ------------------ | --------------------------------------------------------------------- | | 身份认证失败 | 确认 Custom LLM 凭证包含 AISIX 调用方 Key,而不是上游服务提供方 Key。 | | 找不到模型 | 确认 Vapi 模型值是调用方 Key 可见的 AISIX 别名。 | | 响应延迟 | 分别检查 Vapi Transcriber 和语音延迟,以及 AISIX 上游延迟。 | | 文本成功但工具失败 | 验证 Vapi 的工具服务器配置以及模型的流式函数调用格式。 | ## 后续步骤[​](#next-steps "后续步骤的直接链接") * [流式传输](https://docs.apiseven.com/ai-gateway/endpoints/streaming.md):了解流式响应传输。 * [工具调用](https://docs.apiseven.com/ai-gateway/endpoints/tool-calling.md):验证网关工具调用约定。 * [API Key 和模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):限制助手流量。 --- # 使用策略管理 MCP 访问权限 当调用方数量较少时,在每个调用方 API Key 上单独授权 MCP 工具很方便。规模扩大后,每次注册新的 MCP 服务器或工具都可能需要更新数百个 Key。MCP 访问策略把授权中共享的部分提升到环境或团队层级,使其对这些层覆盖的所有 Key 生效。 本指南介绍各层如何组合、如何配置环境和团队授权,以及如何查看 Key 的有效访问权限。 ## 各层如何组合[​](#各层如何组合 "各层如何组合的直接链接") 一个调用方 API Key 最多受三层约束。它们都包含相同的两个字段——`allow` 和 `deny`——且任何一层都不会覆盖其他层: 1. **环境策略**:作用于环境内的每个 Key。 2. **团队策略**:作用于绑定到某个团队的 Key,在组织的所有环境中生效。 3. **Key 的 `mcp_access` 配置块**:Key 自身的那一层。 每次请求都会解析 Key 的有效访问权限: ``` 有效权限 =(所有存在的层的 allow 取交集)−(所有存在的层的 deny 取并集) ``` 以下三条规则让该模型保持可预测: * **allow 取交集。** 只有当所有存在的层都允许某个工具时,它才可用;因此任何一层都只能收窄结果,都不能扩大结果。团队策略无法授予环境策略未开放的工具,Key 同样不能。 * **deny 始终优先。** 任何一层中的拒绝模式都会移除对应工具,无论其他层如何允许。 * **缺失的层不施加约束,但一层都没有则不授予任何权限。** 没有 `mcp_access` 配置块的 Key、没有策略的团队、以及被禁用的策略,都只是退出交集运算。当三者都未配置时,该 Key 没有任何 MCP 工具访问权限——权限总是被显式授予,绝不会因为缺少配置而产生。 由于每一层都必须给出 `allow`,两种边界情况总是被显式写出,而不是靠省略字段隐含: | `allow` | 含义 | | ------- | ---------------------------------------------------------------- | | `[]` | 该层不允许任何工具,因此它覆盖的每个 Key 都会失去 MCP 访问权限。 | | `["*"]` | 该层不收窄任何范围。用于只通过 `deny` 做扣除的层。 | 所有模式都使用[控制工具访问权限](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md)中描述的 `__` 命名方式和单个 `*` 通配符匹配规则。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 本页示例使用 AISIX Cloud Admin API。请准备组织的控制面 URL、环境 ID 和具有写入权限的 Admin Token,并安装 `curl` 和 `jq`。 对于 On-Premises 部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。然后设置: ``` # AISIX_CP 包含 /api,末尾不带斜杠 # 本地 On-Premises 快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` ## 设置环境策略[​](#设置环境策略 "设置环境策略的直接链接") 保存环境层: ``` curl -sS -X PUT "$AISIX_CP/environments/$ENV_ID/mcp_policy" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "allow": ["github__*"], "deny": ["github__delete_repository"] }' ``` ❶ 该环境只允许 `github` 下的所有工具。只有在所有当前和未来服务器上的所有工具都应可达时,才发送 `["*"]`;发送 `[]` 则会关闭整个环境的 MCP 访问权限。 ❷ 拒绝模式适用于环境中的每个 Key,无论团队层和 Key 层如何配置。 控制台在 **Environment → MCP Access** 中提供相同的编辑器。 ## 为 Key 配置自己的层[​](#为-key-配置自己的层 "为 Key 配置自己的层的直接链接") 没有配置自己那一层的 Key,会取得环境层和团队层留下的全部权限: ``` API_KEY_RESPONSE=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "inheriting-caller", "allowed_models": [] }') export API_KEY_ID=$(printf '%s\n' "$API_KEY_RESPONSE" | jq -er '.api_key.id') export AISIX_API_KEY=$(printf '%s\n' "$API_KEY_RESPONSE" | jq -er '.plaintext') printf '%s\n' "$API_KEY_RESPONSE" | jq ``` `API_KEY_ID` 和 `AISIX_API_KEY` 指向同一调用方。AISIX Cloud 只会在此创建响应中返回明文,因此请保留这两个变量,供设置和验证使用。 当 Key 应当比环境层和团队层更受限时,为它添加 `mcp_access` 配置块: ``` "mcp_access": { "allow": ["github__*"], "deny": ["github__delete_repository"] } ``` 该配置块就是这个 Key 完整的允许范围,因此 `"allow": []` 会让它完全没有 MCP 访问权限,而 `"allow": ["*"]` 则不收窄任何范围——适用于只想通过自身 `deny` 做扣除的 Key。更新时发送 `"mcp_access": null` 可移除 Key 自己的层,使它重新取得其他层留下的权限。 ## 验证有效访问权限[​](#验证有效访问权限 "验证有效访问权限的直接链接") 查看该 Key,确认哪些层在约束它,以及每个模式来自哪一层: ``` curl -sS "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID/effective_permissions" \ -H "Authorization: Bearer $AISIX_TOKEN" | jq ``` 上面这个 Key 只受环境层约束: ``` { "effective_permissions": { "mcp": { "layers": [ { "source": "env_policy", "policy_id": "a5065729-3049-407a-90d4-357a6ab214c2" } ], "all_tools": false, "allow": [ { "pattern": "github__*", "source": "env_policy" } ], "deny": [ { "pattern": "github__delete_repository", "source": "env_policy" } ] } } } ``` `layers` 为空数组表示任何一层都没有配置,这正是此类 Key 没有 MCP 工具访问权限的原因。控制台在 **API Keys** 页面的 Key 行中提供相同的视图。 ## 授予团队策略[​](#grant-a-team-policy "授予团队策略的直接链接") 团队策略按团队配置一次,并应用于组织各环境中明确绑定到该团队的调用方 API Key。[SCIM 目录同步](https://docs.apiseven.com/ai-gateway/cloud/scim-directory-sync.md)会在身份提供商组成员变化时更新团队成员名单,但不会绑定或重新绑定调用方 API Key。只有[绑定到团队](https://docs.apiseven.com/ai-gateway/cloud/teams.md#bind-caller-api-keys-to-the-team)后,调用方 Key 才会获得团队策略。 请从[团队](https://docs.apiseven.com/ai-gateway/cloud/teams.md#create-a-team)页面复制 Team ID,然后为请求导出该值: ``` export TEAM_ID="YOUR_TEAM_ID" curl -sS -X PUT "$AISIX_CP/teams/$TEAM_ID/entitlements" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mcp": { "allow": ["postgres__*"] } }' ``` 团队层与环境层取交集,而不是替换环境层:只有环境策略也允许时,团队绑定的 Key 才能访问 `postgres__*`。发送 `"mcp": null` 可移除该层,使这些 Key 继续受环境层和仍然存在的 Key 级 `mcp_access` 配置块约束。 ## 运维说明[​](#运维说明 "运维说明的直接链接") * 策略可以设置 `"enabled": false`。被禁用的策略根本不构成一层:它既不授权也不拒绝,直接退出交集运算。 * 删除环境策略后,既没有团队策略也没有 `mcp_access` 配置块的 Key 将不再受任何层约束,因而没有 MCP 访问权限。解析过程遵循故障关闭原则,绝不会故障开放。 * 未经授权的工具会从 `tools/list` 中过滤,并在发生任何上游路由前拒绝 `tools/call`,同时返回相同的中性错误。 * 每次策略写入和权益变更都会记录在审计日志中。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 如果上游服务器尚未注册,请使用[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md#register-the-server-and-grant-a-tool)中的注册流程。验证 `everything__echo` 前,请确保适用于调用方的每个访问层都允许它。设置流程会更新 Key 级授权;也请更新适用的环境或团队策略。随后为工具调用路径添加[限流和预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md)、[安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md)或[可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md)。 --- # 客户端身份认证 MCP 客户端可以通过两类入口访问 AISIX:聚合入口 `/mcp` 以 `__` 形式提供所有已注册服务器的工具,`/mcp/{server}` 则以工具的原始名称提供单个服务器的工具。本文介绍调用方如何在这些入口上证明自己的身份。 客户端身份认证与[上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md)相互独立:客户端发送给 AISIX 的凭证用于向 AISIX 标识调用方,而 AISIX 发送给上游 MCP 服务器的凭证由网关侧持有,永远不会被转发。 共有三种模式,同一个环境可以组合使用: | 模式 | 客户端发送 | 适用场景 | | ------------ | --------------------------------- | --------------------------------------------------------- | | 网关 API Key | `Authorization: Bearer ` | 默认方式。机器对机器的调用方,以及由你签发 Key 的 Agent。 | | OAuth 登录 | 身份提供商签发的 Access Token | 能够自行发现登录流程的标准 MCP 客户端。 | | 匿名 | 不发送任何凭证 | 可信网络中无法携带凭证的客户端。 | 无论采用哪种模式,调用方都会解析为一个 API Key 主体。它的工具授权决定了可以列出和调用哪些工具;已配置的限流和 Guardrails 可以治理工具调用,而用量仍归属于该主体。在 AISIX Cloud 中,匹配的预算也会生效。因此,匿名调用方与认证调用方受到相同的控制。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下内容: * 完成 AISIX Cloud 或开源 AISIX 网关的[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md),并保留该指南末尾使用的 `AISIX_PROXY` 和 `AISIX_MCP_KEY` 值。 * 对于 AISIX Cloud 配置示例,还需保留 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)中的 `AISIX_CP`、`AISIX_TOKEN` 和 `ENV_ID`。若要申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。 * 用于运行请求示例的 [cURL](https://curl.se/)。 ## 网关 API Key[​](#gateway-api-key "网关 API Key的直接链接") 这是默认方式,无需任何配置。客户端在每个请求上发送自己的 Key: ``` curl -sS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' ``` 该 Key 的授权决定了调用方能看到和调用哪些工具。将 Key 限定到特定工具、整个服务器或全部工具,参见[控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md);在环境或团队级别授权,参见 [MCP 访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)。 也可以使用 `x-api-key: ` 作为替代请求头。 ## OAuth 登录[​](#oauth-sign-in "OAuth 登录的直接链接") 桌面助手等标准 MCP 客户端可以让用户登录,而不必粘贴一个 Key。它们的做法是:读取 `401` 响应上的 `WWW-Authenticate` 请求头,获取其中指向的受保护资源元数据,然后针对元数据中声明的授权服务器执行 OAuth 流程。 当环境同时具备以下两项时,AISIX 会发布该元数据: * 一个规范的 MCP 资源 URL——客户端访问该环境 `/mcp` 入口所使用的公开 URL;以及 * 至少一个已启用的 OIDC 信任提供商,即 Token 必须来自的授权服务器。 两者都配置后,`GET /.well-known/oauth-protected-resource`(以及 `/.well-known/oauth-protected-resource/mcp`)会返回资源标识、Token 可以来自的 issuer,以及 Token 必须携带的 scope。若未配置,这些路由返回 `404`,`401` 响应也不携带 challenge,与该能力不存在时完全一致。 Access Token 的 audience 声明必须包含该资源 URL。这是最常见的配置错误:即使登录成功,audience 不匹配的 Token 仍会在网关侧被拒绝。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 在环境上设置资源 URL: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mcp_resource_url": "https://gateway.example.com/mcp" }' ``` 该 URL 必须是绝对的 `http` 或 `https` URL,路径必须恰好是 `/mcp`,不能带查询参数或片段,也不能内嵌凭证——它会被发布在一个无需认证的端点上。传入 `null` 可清除该值并关闭 OAuth 发现。 在 Dashboard 中,同样的设置位于环境的 **MCP Access** 页面;当已启用的提供商的 audiences 不包含该 URL 时,该页面还会给出提示。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX 网关的直接链接") 在单例 `mcp_auth_settings` 条目上设置 `resource_url`;如果该条目不存在,则创建它,并保持所有 `anonymous` 设置不变。将 `corp-sso` 添加到 `oidc_providers`: resources.yaml(OAuth 发现) ``` mcp_auth_settings: - resource_url: https://gateway.example.com/mcp oidc_providers: - name: corp-sso issuer: https://sso.example.com/realms/agents audiences: - https://gateway.example.com/mcp required_scopes: - mcp:tools ``` `mcp_auth_settings` 最多只能有一条。第二条会在加载时被拒绝;若重复条目以其他方式进入了运行中的网关,发现面会保持关闭,而不是从中挑选一条。 ## 匿名访问[​](#anonymous-access "匿名访问的直接链接") 匿名访问允许不携带任何凭证的客户端访问你为其开放的入口。它面向的场景是:客户端集群原本对接的网关从不要求凭证,如今逐个改造客户端并不现实。 匿名请求仍然会解析为你指定的 API Key 主体。它的工具授权决定了可以列出和调用哪些工具;已配置的限流和 Guardrails 可以治理工具调用,而用量仍归属于该主体。在 AISIX Cloud 中,匹配的预算也会生效。只有凭证检查发生变化。 警告 任何能从允许网段访问该网关的人,都可以在没有凭证的情况下调用被允许的工具,相关用量会计入该环境。请把来源网段白名单当作真正的访问控制来对待,并把主体的工具授权收窄到客户端实际需要的范围。 ### 匿名访问不是什么[​](#what-anonymous-is-not "匿名访问不是什么的直接链接") **它不是降级路径。** 携带凭证的请求会按正常流程认证,凭证无效、过期、被禁用或格式错误时返回 `401`。只有完全不携带凭证的请求才会走匿名路径。认证方案写错或请求头值为空同样算作“携带了凭证”,因此尝试认证却出错的客户端会失败,而不会以另一个身份悄然成功。 **它对不被允许的调用方不可见。** 所有拒绝——来源不在白名单、该服务器未对匿名开放、主体被删除或禁用、匿名访问未开启——返回的都是与“未配置匿名访问”时完全相同的 `401`。调用方无法区分这些情况,也无法区分某个 MCP 服务器是已注册还是根本不存在。运维可以在网关的 `aisix_auth_decisions_total` 指标上看到具体原因。 ### 配置项[​](#configuration "配置项的直接链接") 匿名访问按环境配置: | 字段 | 含义 | | ----------------- | -------------------------------------------------------------- | | `api_key_id` | 匿名流量运行时使用的 API Key。 | | `source_cidrs` | 允许进入的客户端来源网段。必填且不能为空。 | | `servers` | 匿名调用方可以访问的 MCP 服务器。必填且不能为空。 | | `aggregate_entry` | 聚合入口 `/mcp` 是否也对匿名调用方开放。默认关闭。 | | `enabled` | 设为 `false` 可在保留配置的情况下关闭匿名访问。默认为 `true`。 | 其中两项需要展开说明。 #### 服务器列表是能力上界[​](#the-server-list-is-a-ceiling "服务器列表是能力上界的直接链接") `servers` 不仅是要开放的 `/mcp/{server}` 入口列表,它同时限定了该主体在任何入口上能触达的范围,聚合入口也不例外。否则,当主体自身的工具授权比该列表更宽时,匿名调用方就能在聚合入口上直接指定 `__`,从而访问到按服务器入口已经关闭的服务器。 因此匿名调用方的有效授权 = 列表中服务器的工具 **∩** 主体自身的授权。`tools/list` 和 `tools/call` 都遵循这一结果,所以匿名调用方绝不会看到自己无法调用的工具。 新注册的 MCP 服务器默认不对匿名开放。要让匿名调用方访问它,必须把它的名称加入该列表。 #### 主体必须拥有自己的授权[​](#the-principal-needs-its-own-grant "主体必须拥有自己的授权的直接链接") 在 AISIX Cloud 中,主体必须携带自己的 `mcp_access` 配置块。没有该配置块的 Key 会被拒绝:它会取得环境层和团队层留下的全部权限,因此一旦这些策略被放宽,匿名访问就可能在无人重新审视此设置的情况下扩大。带有自己配置块的 Key 则始终受自身 `allow` 列表约束,无论其他层如何变化。 在使用资源文件配置的开源网关中,同一个配置块是该主体唯一的权限层,因为资源文件没有策略集合。`servers` 列表仍然是额外的能力上界。 ### 在 AISIX Cloud 中配置[​](#configure-in-aisix-cloud "在 AISIX Cloud 中配置的直接链接") 导出匿名流量所使用的 API Key ID。该 Key 必须属于当前环境,并携带上述 MCP 授权: ``` export ANON_KEY_ID="YOUR_ANONYMOUS_PRINCIPAL_API_KEY_ID" ``` 在环境上设置该配置块: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mcp_anonymous": { "api_key_id": "'"$ANON_KEY_ID"'", "source_cidrs": ["10.0.0.0/8"], "servers": ["everything"], "aggregate_entry": false } }' ``` ❶ 匿名流量以其身份运行的 API Key 主体。它必须属于该环境,并且携带自己的 `mcp_access` 配置块。 ❷ 与 AISIX 通过 Real-IP 配置解析出的来源地址比对,而不是客户端提交的请求头。单个地址请写成 `10.0.0.1/32`。 ❸ 已批准且对该环境开放的服务器。匿名调用方只能访问 `/mcp/everything`,其他一概不能。 ❹ 聚合入口继续要求网关凭证。开启前请阅读[匿名访问与 OAuth 登录](#anonymous-access-and-oauth-sign-in)。 传入 `"mcp_anonymous": null` 可关闭匿名访问。该变更无需重启即可应用到运行中的网关。 在 Dashboard 中,同样的设置位于环境的 **MCP Access** 页面,开启匿名访问需要显式确认风险提示。 ### 在开源网关中配置[​](#configure-in-an-open-source-gateway "在开源网关中配置的直接链接") 将 `anonymous-mcp` 添加到 `api_keys`。在单例 `mcp_auth_settings` 条目中添加 `anonymous`;如果该条目不存在,则创建它。保持 `resource_url`、`everything` 服务器及其他资源不变。下方 ID 派生自 `anonymous-mcp`: resources.yaml(匿名 MCP 访问) ``` api_keys: - display_name: anonymous-mcp key_env: ANONYMOUS_MCP_KEY allowed_models: [] mcp_access: allow: - everything__* mcp_auth_settings: - anonymous: api_key_id: d6869ae7-741a-598e-8213-16672e922546 source_cidrs: - 10.0.0.0/8 servers: - everything aggregate_entry: false ``` 加载该文件前,请在网关进程环境中设置 `ANONYMOUS_MCP_KEY`。如果使用其他 API Key 显示名称,请把 `api_key_id` 替换为该条目的[确定性派生 ID](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#identity-and-derived-ids)。用于 OAuth 发现的 `resource_url` 字段位于同一条 `mcp_auth_settings` 条目上;两项设置相互独立,可以只配置其中一项。 ### 匿名访问与 OAuth 登录[​](#anonymous-access-and-oauth-sign-in "匿名访问与 OAuth 登录的直接链接") 同一个环境可以同时使用两者。对大多数部署来说,自然的分工是:无法携带凭证的存量客户端匿名使用按服务器的入口,标准 MCP 客户端则通过聚合入口 `/mcp` 登录。 如果在已发布 OAuth 发现的环境中开启 `aggregate_entry`,情况就会改变:不携带凭证的 `/mcp` 请求会直接成功,而不再返回携带发现提示的 `401`,因此支持 OAuth 的客户端永远不会发起登录流程,会一直停留在匿名授权上。按服务器的入口不受影响。 ## 验证[​](#verify "验证的直接链接") 确认你配置的模式行为符合预期。 不携带凭证访问已开放的入口应当成功: ``` curl -sS -X POST "$AISIX_PROXY/mcp/everything" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' ``` 响应会以原始名称列出该服务器上主体被授权的工具。 凭证错误时仍然会被拒绝,而不会以匿名身份放行: ``` curl -sS -o /dev/null -w '%{http_code}\n' -X POST "$AISIX_PROXY/mcp/everything" \ -H "Authorization: Bearer not-a-real-key" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' ``` 网关返回 `401`。 ## 可观测性[​](#observability "可观测性的直接链接") 匿名流量是可归属的。用量事件与其他请求一样携带主体的 API Key id,并额外携带 `auth_type: anonymous`,用于区分“从入口配置继承主体”的流量和“出示了该 Key 自身凭证”的流量。包括拒绝及其原因在内的认证决策,统计在 `aisix_auth_decisions_total` 上。 ## 限制[​](#limitations "限制的直接链接") 匿名访问面向可信网络设计。有两项容量保护尚未提供: * 暂不支持按来源 IP 限流。由于所有匿名流量共用一个主体,单个匿名客户端可能耗尽该主体的全部额度。 * `initialize`、`ping` 和 `tools/list` 方法不计入用量,只有 `tools/call` 会经过限流门禁,并检查适用的 AISIX Cloud 预算。 必填的来源网段白名单是约束这一风险的手段。请不要将匿名入口暴露给不可信网络。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):把某个 Key(包括匿名主体)限定到特定工具或整个服务器。 * [限流与预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md):应用调用方限流,并使用覆盖该调用方 API Key 的 AISIX Cloud 预算。 * [Guardrails](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md):检查 MCP 工具的参数和结果。 * [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md):在日志、指标和用量中查找 MCP 流量。 --- # 将 Cursor 连接到 MCP 网关 Cursor 可以作为远程 Streamable HTTP 客户端连接到 AISIX MCP 端点。它发送 AISIX 调用方 API Key,仅发现该密钥有权使用的工具,并通过网关调用这些工具,无需获取上游服务器凭证。 Cursor 继续负责选择模型、决定何时请求工具、获取所需批准和展示结果。此连接将 MCP 工具流量发送到 AISIX,不会将 Cursor 的模型请求路由到网关。要单独路由受支持的 Ask 模式模型请求,请参阅 [Cursor 模型集成](https://docs.apiseven.com/ai-gateway/integrations/coding-agents/cursor.md)。 本指南将 Cursor 连接到聚合的 `/mcp` 端点。你可以接着[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)继续操作,该指南仅向调用方授予 `everything__echo` 权限;也可以使用现有 AISIX 环境,以及调用方有权访问且可安全调用的工具。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始之前,请准备以下内容: * 完成[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)并保留 `AISIX_PROXY` 和 `AISIX_MCP_KEY`,或向网关运维团队获取 AISIX 代理源地址和调用方 API Key。对于现有环境,请使用这两个变量名导出相应值,并选择一个已获许可且可安全调用的工具进行验证。 * 安装 [Cursor](https://www.cursor.com/),并配置支持 Agent 的模型。 * 确保 Cursor 可访问 AISIX 代理 URL。运行在网关宿主机上的 Cursor 可以使用快速入门中的地址;远程开发环境则需要使用其可访问的地址。 本示例使用工作区配置,以便随项目审查连接设置。不要提交调用方 API Key,Cursor 会从环境中读取它。 ## 配置连接[​](#配置连接 "配置连接的直接链接") 从已导出 `AISIX_MCP_KEY` 的 Shell 启动 Cursor。如果 Cursor 已在运行但未继承该变量,请先关闭它,再从该环境重新启动,然后测试连接。 在工作区中创建 `.cursor/mcp.json`,将示例 URL 替换为 `$AISIX_PROXY/mcp`: .cursor/mcp.json ``` { "mcpServers": { "aisix": { "url": "https://gateway.example.com/mcp", "headers": { "Authorization": "Bearer ${env:AISIX_MCP_KEY}" } } } } ``` 如果需要在所有工作区中使用该连接,请将同一个对象添加到 `~/.cursor/mcp.json`。确保使用此配置的每个 Cursor 进程均可读取该环境变量。 打开 **Customize → MCPs**,选择 `aisix`;如果工作区来源已禁用,请将其启用。确认本地环境已连接,并显示所选的已授权工具。对于 Everything 测试服务,应仅显示 `everything__echo`。 ## 验证工具调用[​](#验证工具调用 "验证工具调用的直接链接") 以下提示词使用设置指南中的 Everything 测试服务。对于现有 MCP 服务器,请替换为已授权的工具名称、有效参数和预期结果。在 Cursor Agent 聊天中明确要求使用指定工具,不要依赖自动工具选择: ``` 使用 MCP 工具 everything__echo,消息为 "hello through AISIX"。原样返回工具结果。 ``` 如果 Cursor 请求确认,请审查并批准此次调用。使用 Everything 测试服务时,结果应为: ``` Echo: hello through AISIX ``` 确认完整路径: * Cursor 显示已授权工具,不显示调用方有效授权范围之外的工具。对于此测试服务,应仅显示 `everything__echo`。 * [AISIX MCP 可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md)记录预期调用方 API Key 和服务器的一次成功 `tools/call`。 * Cursor 显示经由 AISIX 返回的工具结果。 工具发现成功说明连接和调用方授权正常,但不能证明模型会选择工具,也不能证明 Cursor 的批准策略允许执行。因此,仍需保留显式工具调用测试。 ## Cursor 故障排查[​](#cursor-故障排查 "Cursor 故障排查的直接链接") | 现象 | 检查项 | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Cursor 未连接 | 确认 URL 以 `/mcp` 结尾、Cursor 可访问网关,且启动 Cursor 的环境中包含 `AISIX_MCP_KEY`。 | | 工作区来源已禁用 | 打开 **Customize → MCPs**,选择 `aisix`,并启用工作区来源。 | | Cursor 返回 `401` | 确认 `AISIX_MCP_KEY` 包含 AISIX 调用方 API Key,而非上游 MCP 凭证。 | | 连接成功但未显示工具 | 按照[工具访问故障排查](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md#troubleshoot-tool-access)检查服务器和有效授权,然后在 Cursor 中重新加载服务器。 | | 工具已显示,但 Agent 未调用它 | 明确指定所选工具的名称,在 MCP 工具列表中启用它,并检查 Cursor 的工具批准策略。对于测试服务,请选择 `everything__echo`。 | ## 下一步[​](#下一步 "下一步的直接链接") * [客户端身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/client-authentication.md):使用网关 API Key、OAuth 登录,或在适合的可信网络中使用匿名访问。 * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):授权具体工具、符合服务器名称模式的工具,或所有已注册工具。 * [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md):按调用方、服务器、工具和结果检查 MCP 调用。 --- # 安全护栏 AISIX AI 网关可以在调用上游工具之前,以及工具结果返回客户端之前,对 MCP 工具调用执行安全护栏。被阻断的调用会以失败的工具结果返回,并且不会发送到上游 MCP 服务器。 MCP 工具调用使用与模型流量相同的安全护栏链。请在共享的流量控制部分创建安全护栏,然后将其挂载到可以作用于 MCP 流量的作用域。与模型路径共用的作用域和执行模式语义请参见[安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md)。 ## 安全护栏如何作用于 MCP[​](#安全护栏如何作用于-mcp "安全护栏如何作用于 MCP的直接链接") 网关只会对 `tools/call` 请求执行安全护栏。MCP 握手和 `tools/list` 不包含工具内容,因此不会被扫描。 对于每个工具调用,AISIX 会解析一次安全护栏链,并在输入和输出两个方向运行: * 输入:AISIX 会在调用工具之前扫描工具调用参数。如果安全护栏阻断,请求会被拒绝,AISIX 不会联系上游 MCP 服务器。 * 输出:AISIX 会在工具结果返回客户端之前扫描结果。如果安全护栏阻断,AISIX 会拦截结果并改为返回失败的工具结果。 MCP 工具调用没有模型,因此模型作用域的安全护栏不会作用于 MCP。环境、MCP 服务器、调用方 API Key 和团队作用域都可以匹配 MCP 调用。在 AISIX Cloud 和开源 AISIX 网关中,安全护栏的作用域都由挂载关系决定。未挂载的安全护栏不会检查任何流量,包括 MCP 调用。 当没有匹配的安全护栏时,工具调用不会增加安全护栏带来的额外延迟。 ## 会扫描哪些内容[​](#会扫描哪些内容 "会扫描哪些内容的直接链接") * 输入:`tools/call` 请求中的参数对象。AISIX 会把参数交给与模型路径相同的输入检查流程。 * 输出:标准内容块暴露的已解码文本。其中包括每个块的 `text`、资源链接的 `title` 和 `description`,以及嵌入资源的 `resource.text`。资源名称和 URI 属于标识符而非内容,且不会解码 base64 `blob` 值。 * 输出:结果中 `structuredContent` 里的取值。返回结构化输出的工具会把该字段与 `content` 一起发送给客户端,而且它不一定会被同时写入文本块,因此 AISIX 会遍历该字段并扫描其中的字符串值。字段名不会被扫描——它们属于工具的输出结构定义,而不是数据本身。 如果结果使用非标准结构,且上述字段都未提供文本,将内容合并后评估的安全护栏会回退为扫描序列化后的结果;逐字段审核的安全护栏则只检查上述字段。后一类包括 Alibaba Cloud AI Guardrails、Bedrock、Lakera、Presidio 和自定义脚本。 没有 result 数据内容的协议级错误结果没有可扫描的工具输出,会被直接放行。 网关只在传输过程中检查 MCP 工具参数或结果,不会存储它们。内容捕获与安全护栏检查是不同的能力边界。 ## 阻断响应[​](#阻断响应 "阻断响应的直接链接") 当安全护栏阻断某个工具调用或工具结果时,AISIX 返回的是 **HTTP `200` 加标记了 `isError` 的工具结果**,而不是模型路径中的 HTTP `422`: ``` { "jsonrpc": "2.0", "id": 1, "result": { "content": [{ "type": "text", "text": "tool call blocked by content policy (guardrail 'block-secrets')" }], "isError": true } } ``` MCP 区分两类失败:请求本身不合法属于 JSON-RPC 协议错误,而调用没有成功则通过结果中的 `isError` 表达。策略拒绝属于后者——请求格式是合法的,因此拒绝会作为工具输出返回给调用方 Agent,让它能够读取并据此调整,而不是被当作传输层故障。 错误信息会标明触发的安全护栏,以及被阻断的是输入参数还是输出结果,并且不会回显命中的内容。网关会把被阻断的调用记录为[用量事件](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md),并设置安全护栏阻断标记。 如果 AISIX 无法把工具结果解析为预期的 JSON 响应,则由输出失败策略决定是否可以返回。只要有一个读取输出的安全护栏采用失败关闭,就会扣留该结果。仅当链中没有安全护栏读取输出,或所有输出读取器都采用失败开放时,AISIX 才会返回结果;后一种情况会记录 `guardrail_bypassed_reason: unscannable_body`。 完整 MCP 错误格式和其他 MCP 状态行为请参见[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md#mcp-errors)。 ## 将安全护栏限定到单个 MCP 服务器[​](#将安全护栏限定到单个-mcp-服务器 "将安全护栏限定到单个 MCP 服务器的直接链接") 使用 `mcp_server` 作用域挂载安全护栏,即可只检查路由到某个已注册服务器的工具调用。在 AISIX Cloud 中,将 `scope_id` 设为服务器 ID;在 `resources.yaml` 中,则使用服务器名称。AISIX 会同时扫描发送到该服务器的参数及其返回的结果。 `mcp_server` 是唯一按目标服务器筛选流量的作用域。若要按调用方缩小覆盖范围,可以为单个调用方使用 `api_key` 挂载,或为同一团队的调用方使用 `team` 挂载。这些基于调用方的作用域也会作用于同一 API Key 或团队发起的模型流量。模型作用域永远不会作用于 MCP,因为工具调用不会解析出模型。 该服务器必须可供安全护栏所作用的环境使用。AISIX Cloud 会拒绝挂载到未在该环境中开放的服务器;如果资源文件中的挂载指向未定义的服务器,该文件将加载失败。要保护多个服务器,需要为每个服务器分别添加挂载;安全护栏在每次请求中仍只运行一次。 ## 验证安全护栏阻断[​](#验证安全护栏阻断 "验证安全护栏阻断的直接链接") 创建一个关键词安全护栏,并设置一个容易触发的词,例如 `secret`。将其挂载到测试时使用的调用方 API Key。在 AISIX Cloud 中,以调用方 API Key ID 作为挂载的 `scope_id`;在 `resources.yaml` 中,则使用该 Key 的 `display_name`。 配置流程请参见[内置关键词安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/keyword.md)。 然后使用允许访问某个工具的调用方 API Key 连接 MCP 客户端,在工具参数中包含被阻断词并调用该工具。 工具调用应返回 HTTP `200`,且结果中的 `isError` 为 `true`,上游 MCP 服务器不会收到请求。参数和结果都干净的调用会正常返回。把安全护栏切换为监控模式后,同样的调用会被放行,但仍会记录命中信息;详见[使用监控模式](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/keyword.md#use-monitor-mode)。 ## AISIX Cloud 控制面[​](#aisix-cloud-控制面 "AISIX Cloud 控制面的直接链接") 在 AISIX Cloud 中,请通过控制面创建和挂载安全护栏,而不是在资源文件中声明。要检查 MCP 工具调用,请使用可以作用于非模型流量的作用域:整个环境、指定 MCP 服务器、调用方 API Key 或团队。 当安全护栏需要检查 MCP 流量时,不要使用模型专属作用域。MCP 工具调用没有模型,因此模型作用域安全护栏不会运行。 早于 MCP 服务器作用域支持的网关无法识别该作用域,并会丢弃这条挂载,因此保存的作用域不会在该网关上运行。此时的行为取决于网关版本:早于“仅通过挂载确定作用域”机制的版本会让安全护栏作用于整个环境,使规则覆盖的流量多于预期;当前机制下则会让安全护栏不检查任何流量。如果环境中有任一数据面运行此类版本,AISIX 会在保存时发出警告;在依赖更窄的作用域前,请先升级这些网关。 ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经了解安全护栏如何检查 MCP 工具参数和工具结果。使用下面的指南创建安全护栏,或观察被阻断的调用: * [内置关键词安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/keyword.md):创建安全护栏并选择执行模式。 * [安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md):了解作用域匹配、执行模式以及远程安全护栏失败处理。 * [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md):在用量事件和指标中查看被阻断的工具调用。 --- # 可观测性 MCP 工具调用使用与模型流量相同的遥测链路。用量事件字段会标识调用方、上游服务器、工具和结果;Prometheus 标签可帮助你将 MCP 流量与模型流量区分开。 可以使用这些信号衡量工具调用量并监控失败。限流和安全护栏阻断会出现在你已经用于模型流量的同一套可观测性工具中。在 AISIX Cloud 中,预算拒绝也会出现在这里。 ## 用量事件[​](#usage-events "用量事件的直接链接") AISIX 仅在请求进入 `tools/call` 用量核算后才生成一条用量事件。在此之前被拒绝的请求不会产生事件,包括认证失败、指定了未知服务器、请求体无法读取或过大、JSON 无效或 AISIX 无法解析 `params` 的结构,以及协议版本不受支持。 请求进入该核算路径后,即使缺少 `params` 对象或工具名称,AISIX 仍会记录这次调用。之后因访问控制、限流、安全护栏、AISIX Cloud 预算或 MCP 协议处理器而被拒绝的调用也会被记录。如果 AISIX 随后读取或缓冲 MCP 响应体时失败,可能会在事件发出前返回。因此,用量遥测覆盖的是上述可识别结果,而不是每个已识别的工具调用。它也不覆盖 MCP 握手或发现方法,以及在进入工具调用用量核算前被拒绝的请求。 事件会标识调用方、服务器、工具、结果和耗时: | 字段 | 值 | | --------------------------- | --------------------------------------- | | `inbound_protocol` | `mcp` | | `mcp_server_name` | 工具所属的已注册服务器。 | | `mcp_tool_name` | 被调用的上游工具。 | | `api_key_id` | 发起调用的调用方 API Key。 | | `status_code` | 调用结果状态。 | | `upstream_latency_ms` | 上游工具调用所花费的时间。 | | `downstream_latency_ms` | 调用方等待工具调用完成的总时间。 | | `guardrail_blocked` | 当输入或输出被安全护栏阻断时为 `true`。 | | `request_id`、`occurred_at` | 关联 ID 和时间戳。 | MCP 工具调用没有模型 Token,因此 Token 和成本字段为零。需要按工具归因调用量时,请使用 `mcp_server_name` 和 `mcp_tool_name`,而不是依赖 Token 或花费分析。 MCP 目前只执行一次贯穿整个请求的上游尝试,因此 `upstream_latency_ms` 和 `downstream_latency_ms` 会报告相同的时长。保留两个独立字段可使 MCP 记录与其它网关流量保持一致;在其它流量中,重试和网关处理可能使两者不同。 事件会记录服务器名称、工具名称和调用结果,但不会包含工具参数或工具结果。MCP 内容捕获与用量遥测是不同的能力边界。 MCP 用量事件会通过与模型用量事件相同的路径投递。所有已配置的可观测性导出器都会收到这些事件,因此 MCP 流量会与其它网关流量一起出现在导出链路中。在 AISIX Cloud 中,这些事件也会流入控制面的用量接收端。 ## 指标[​](#指标 "指标的直接链接") MCP 请求会出现在网关的 Prometheus 指标中,并携带可用于区分模型流量的标签。使用下列标签筛选相关指标序列: | 目标 | 指标 | 过滤条件 | | ----------------------- | ---------------------------------- | ------------------------------------------- | | 跟踪活跃 MCP 请求。 | `aisix_proxy_in_flight_requests` | `inbound_protocol="mcp"` | | 检查 MCP 用量事件投递。 | `aisix_usage_events_emitted_total` | `handler="mcp"` 和 `inbound_protocol="mcp"` | 指标通过专用指标监听器的 `GET /metrics` 暴露。完整指标目录和标签语义请参见[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 ## 验证指标[​](#验证指标 "验证指标的直接链接") 要验证 MCP 指标是否发出,请先通过网关发送一次 MCP 工具调用,然后抓取专用指标监听器。下面的示例使用默认监听地址和路径。如果你的启动配置设置了其它 `observability.metrics.prometheus.addr`,请使用对应地址。 指标族会在首次观测后注册,因此只有记录过工具调用后才会出现 MCP 序列: ``` curl -sS "http://127.0.0.1:9090/metrics" | grep 'inbound_protocol="mcp"' ``` 输出中应包含带有以下标签的指标样本: | 指标 | 标签 | | ---------------------------------- | ------------------------------------------- | | `aisix_proxy_in_flight_requests` | `inbound_protocol="mcp"` | | `aisix_usage_events_emitted_total` | `handler="mcp"` 和 `inbound_protocol="mcp"` | ## 下一步[​](#下一步 "下一步的直接链接") 你现在已经了解 MCP 工具调用会出现在用量事件和指标中的哪些位置。使用下面的指南查看完整指标目录,或调整产生这些信号的流量: * [指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md):查看完整指标目录和标签语义。 * [限流与预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md):对 MCP 工具调用应用请求限制和并发限制,并配置 AISIX Cloud 预算。 * [安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md):检查 MCP 工具参数和工具结果。 --- # 把 REST API 公开为 MCP 工具 MCP 服务器注册表条目可以由普通 REST API 提供支持,而不必连接上游 MCP 服务器。注册该 API 的 OpenAPI 3.x 文档,并把 `type` 设为 `openapi`,AISIX 就会为每个操作生成一个 MCP 工具。`tools/call` 会针对 API 的基础 URL 执行 HTTP 请求,并在已配置时附加网关持有的凭证。MCP 调用方永远不会获得该凭证,API 本身也不需要提供 MCP 服务器。 这样可以把 ERP、库存系统或薪资 API 等现有内部服务转换为 Agent 可调用的工具。两种管理路径都适用[工具访问控制](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md)、[流量控制](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md)、[安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md)和[可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md)。AISIX Cloud 还提供[服务器审查](https://docs.apiseven.com/ai-gateway/mcp-gateway/server-review.md)和共享的[访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下环境: * 对于 AISIX Cloud,请完成 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md),然后保持其 Shell 和已附加网关继续运行。本流程会复用其中的环境、管理员 Token、调用方 API Key 和网关 URL。若要申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,完成[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md),然后停留在其 Shell 和工作目录中,并且不要清理临时 Docker 网络。 * AISIX Cloud 示例需要 [cURL](https://curl.se/) 和 [jq](https://jqlang.org/)。 ## 工具的生成方式[​](#how-tools-are-generated "工具的生成方式的直接链接") AISIX 遍历文档中的 `paths`,并为 `get`、`post`、`put`、`delete` 和 `patch` 方法的每个操作生成一个工具: * 工具名称:把操作的 `operationId` 转换为小写,将 `a-z`、`0-9`、`_` 和 `-` 之外的字符替换为 `_`,并限制为最多 128 个字符。没有 `operationId` 的操作按相同规则命名为 `_`。与所有 MCP 工具一样,工具以 `__` 的形式公开给调用方。 * 输入 Schema:每个 `path` 和 `query` 参数都会成为一个属性,并保留其类型、说明、`enum` 值和 `required` 标志。JSON 请求正文会成为单个 `body` 对象属性,并在规范要求时标记为必填。AISIX 会解析本地 `$ref`,包括正文中引用的组件 Schema,因此 Agent 能看到实际结构。请求头和 Cookie 参数不会公开,因为上游请求头由网关而不是调用方管理。 * 跳过的操作:如果某个操作的请求正文没有 `application/json` 变体(例如 `multipart/form-data` 文件上传),AISIX 会跳过它,而不会生成一个无法成功调用的工具。 两种管理路径的验证时机不同。AISIX Cloud 在注册时验证文档。无法解析的文档、Swagger 2.0 文档、不含可生成工具操作的文档,以及规范化后 `operationId` 发生冲突的文档都会被拒绝。创建响应会在 `tool_names` 中返回生成的名称。 使用 `resources.yaml` 时,`aisix validate` 会检查资源结构,包括 `spec` 必须是映射且不能是 Swagger 文档。客户端列出或调用工具时,网关才会生成工具。如果文档没有可用的 `paths` 对象,该服务器不会向聚合列表贡献任何工具,网关也会记录错误。规范化后的名称发生冲突时会依次添加 `_2`、`_3` 等后缀,确保每个操作都可访问。加载文件后,请列出工具以验证生成的工具面。 ## 注册 REST API[​](#register-a-rest-api "注册 REST API的直接链接") AISIX Cloud 与开源 AISIX 网关的注册结构不同。两种情况下,`url` 都是 REST API 的基础 URL,生成的调用都会请求 ``。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 可以通过以下两种方式提供文档: * `spec_content`:直接提供 JSON 或 YAML 文本形式的文档。控制面无法访问 API 所在网络时使用此方式。 * `spec_url`:控制面在注册期间获取一次的 URL。获取的文档会经过验证、规范化并存储;数据面不会再次获取,因此只有更新注册表条目时工具集才会变化。默认情况下,解析到非公网地址的 URL 会被拒绝。本地部署可以在控制面设置 `AISIX_CLOUD_MCP_SPEC_ALLOW_PRIVATE_URLS=true` 以允许此类地址;否则,请直接粘贴文档。 AISIX Cloud 把 OpenAPI 文档大小限制为 1 MiB。 导出控制面地址、管理员 Token 和环境 ID: ``` # AISIX_CP 包含 /api,末尾不带斜杠 # 本地 On-Premises 快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 注册 HTTPBin 端点及其 OpenAPI 文档。这个公共端点让生成的工具调用无需内部 API 或上游凭证即可复现: ``` MCP_SERVER_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "httpbin", "type": "openapi", "url": "https://httpbin.org", "spec_content": "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"HTTPBin\",\"version\":\"1.0.0\"},\"paths\":{\"/anything\":{\"get\":{\"operationId\":\"inspectRequest\",\"responses\":{\"200\":{\"description\":\"OK\"}}}}}}", "auth_type": "none", "allowed_environments": ["'$ENV_ID'"] }') echo "$MCP_SERVER_RESPONSE" | jq export MCP_SERVER_ID=$(echo "$MCP_SERVER_RESPONSE" | jq -er '.mcp_server.id') ``` 响应包含生成的 `tool_names`: ``` { "mcp_server": { "id": "6f64f080-17d7-44d9-b995-6a353e71f6bc", "name": "httpbin", "type": "openapi", "url": "https://httpbin.org", "tool_names": ["inspectrequest"], "approval_status": "approved" } } ``` 将生成的工具授予快速入门创建的调用方 API Key: ``` curl -fsS -X PATCH \ "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"mcp_access":{"allow":["httpbin__inspectrequest"]}}' | jq export AISIX_MCP_KEY="$AISIX_API_KEY" ``` 该部分更新会保留 Key 的模型访问权限。如果环境或团队 MCP 访问策略也作用于该 Key,这些层也必须允许 `httpbin__inspectrequest`。 按照[使用 HTTP 验证 MCP 工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md#verify-mcp-tool-access-with-http)发送 `initialize` 请求和 `notifications/initialized` 通知,然后轮询,直到投射的工具出现: ``` for attempt in $(seq 1 45); do TOOLS_RESPONSE=$(curl -fsS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "MCP-Protocol-Version: 2025-11-25" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }') || true if echo "$TOOLS_RESPONSE" | jq -e \ '.result.tools | any(.name == "httpbin__inspectrequest")' >/dev/null 2>&1; then break fi sleep 2 done echo "$TOOLS_RESPONSE" | jq -e \ '.result.tools | any(.name == "httpbin__inspectrequest")' ``` 最后一条命令会输出 `true`。调用生成的工具,并验证 HTTPBin 收到的 URL: ``` curl -fsS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "MCP-Protocol-Version: 2025-11-25" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "httpbin__inspectrequest", "arguments": {} } }' | jq -e \ '.result.content[] | select(.text | fromjson | .url == "https://httpbin.org/anything")' ``` 该命令会输出匹配的工具结果内容块。 在控制台中注册 MCP 服务器时,选择 **REST API (OpenAPI)**。可以粘贴文档、提供文档 URL,或通过 **Choose file…** 选择本地 `.json` 或 `.yaml` 文件。所选文件会被读入编辑器,因此保存前可以检查和调整内容。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX 网关的直接链接") 在 `mcp_servers` 条目上设置 `type: openapi`,并在 `spec` 下以嵌套映射的形式提供文档。资源文件不接受 AISIX Cloud 的写入字段 `spec_content` 或 `spec_url`。 在[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)创建的临时 Docker 网络中启动 HTTP 测试服务。该服务器通过 HTTP 公开一个空目录,主机上无需安装任何软件包: ``` docker run -d --name aisix-openapi-fixture \ --network aisix-mcp \ python:3.13-alpine \ python3 -m http.server 8081 --bind 0.0.0.0 --directory /tmp ``` 在[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)中的完整文件内,替换 `quickstart-caller`,并将 `fixture` 添加到 `mcp_servers`。保持其他资源不变: resources.yaml(API Key 与 MCP 服务器) ``` api_keys: - display_name: quickstart-caller key_env: CALLER_API_KEY allowed_models: - gpt-4o-mini mcp_access: { allow: ["fixture__list_directory"] } mcp_servers: - name: fixture type: openapi url: http://aisix-openapi-fixture:8081 auth_type: none spec: openapi: 3.0.0 info: title: Local directory API version: 1.0.0 paths: /: get: operationId: list_directory summary: List the fixture directory responses: "200": description: Directory listing returned successfully ``` 此示例复用 `CALLER_API_KEY`,该变量已由开源快速入门设置在正在运行的网关中。验证并重新加载完整资源文件。使用[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md#verify-mcp-tool-access-with-http)中的初始化请求,然后调用生成的工具: ``` curl -sS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "MCP-Protocol-Version: 2025-11-25" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "fixture__list_directory", "arguments": {} } }' | jq -e \ '.result.content[] | select(.text | contains("Directory listing for /"))' ``` 该命令会打印匹配的工具结果内容块。完成后移除测试容器: ``` docker rm -f aisix-openapi-fixture ``` ## 在 AISIX Cloud 中查看生成的工具[​](#review-the-generated-tools-in-aisix-cloud "在 AISIX Cloud 中查看生成的工具的直接链接") 每个已注册服务器的卡片会列出前几个生成的工具名称,并链接到该服务器的**工具页面**。该页面列出每个工具的: * `__` 名称,可将这种形式复制到 API Key 的 [`mcp_access` 配置块](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md)或[访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)模式中; * 调用的 HTTP 操作,例如 `GET /items/{id}`; * 说明。 API 也提供相同的列表: ``` curl -sS "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/tools" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` ``` { "data": [ { "name": "inspectrequest", "namespaced_name": "httpbin__inspectrequest", "method": "GET", "path": "/anything", "description": "GET /anything" } ] } ``` 该列表由存储的文档生成,因此始终与网关提供的工具一致。它仅适用于 `type: openapi` 的服务器。上游 MCP 服务器的工具位于上游,因此对这类服务器调用该端点会返回 `400`。 ## 对 REST API 执行身份认证[​](#authenticate-to-the-rest-api "对 REST API 执行身份认证的直接链接") [上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md)模式会原样应用,凭证附加到每个生成的工具调用: * `bearer`:`Authorization: Bearer `。 * `api_key`:默认把 `secret` 中的 Key 作为 `x-api-key` 请求头发送。REST API 经常要求自定义请求头;设置 `api_key_header`(例如 `X-ERP-Key`)可以覆盖请求头名称。该字段仅适用于 `auth_type: api_key` 的 `openapi` 服务器。 * `oauth2`:AISIX 使用已配置的客户端凭证签发访问 Token,并以 Bearer 形式发送;Token 缓存行为与 MCP 上游相同。 生成的工具调用永远不会跟随重定向,因此凭证不会被再次发送到未配置的主机。 ## 调用结果和错误[​](#call-results-and-errors "调用结果和错误的直接链接") 成功响应的正文会作为工具结果文本返回。非 2xx 响应会返回工具级错误结果(`isError: true`),其中包含 `HTTP ` 和响应正文,因此 Agent 可以看到失败并作出反应。缺少必填路径参数时,也会以同样可读的方式报告。为了让请求保持在已配置路径上,AISIX 还会拒绝包含 `/` 或 `\`,或者等于 `.` 或 `..` 的路径值。 ## 更新文档[​](#update-the-document "更新文档的直接链接") 替换文档会重新生成工具列表。 对于开源 AISIX 网关,请替换嵌套的 `spec`,验证完整资源文件并重新加载网关。被拒绝的重新加载会保留先前的工具面。成功重新加载后,请列出工具,验证更新后的文档生成了预期工具面。 在 AISIX Cloud 中,请在更新调用中提供 `spec_content` 或 `spec_url`,也可以使用控制台中的 **Replace OpenAPI document** 编辑器。调用返回后,控制面开始投射新的工具面。调用方拥有批准服务器的权限,因此该替换会视为调用方完成审查,并更新审查时间戳。用户会话操作还会记录审查用户,而管理员 Token 操作不包含用户 ID。仅对 `mcp_server_submissions` 拥有 `write` 权限的角色会暂存替换内容;在审查者批准前,当前工具会继续提供服务。更改 `api_key_header` 的行为相同。重新上传规范化后与已存储版本相同的文档不会被视为变更。 在 AISIX Cloud 中,服务器的 `type` 在创建后固定:若要在 MCP 上游与 OpenAPI 支持之间切换,请删除条目并重新注册。在 `resources.yaml` 中,修改条目并重新加载文件;新验证的配置会替换先前的运行时条目。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 现在可以通过任一管理路径把 REST API 公开为 MCP 工具。使用以下指南保护和治理生成的工具: * [上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md):配置 AISIX 发送给 REST API 的凭证。 * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):选择每把调用方 API Key 可以列出和调用的生成工具。 * [审查并批准 MCP 服务器](https://docs.apiseven.com/ai-gateway/mcp-gateway/server-review.md):在通过 AISIX Cloud 发布前审查 OpenAPI 支持的服务器和文档变更。 --- # MCP 网关概览 AISIX 网关通过聚合的 `/mcp` 端点代理已注册的模型上下文协议(MCP)工具源。工具源可以是使用 Streamable HTTP 的上游 MCP 服务器,也可以是通过 OpenAPI 文档描述的 REST API。有关 REST API 路径,请参阅[把 REST API 公开为 MCP 工具](https://docs.apiseven.com/ai-gateway/mcp-gateway/openapi-servers.md)。 MCP 客户端和 Agent 使用 AISIX 调用方 API Key 连接 `/mcp`,发现该 Key 可以使用的工具并调用它们,而不会获得上游 MCP 服务器的凭证。 这样,工具流量就与模型和 A2A 流量共享相同的身份认证、访问控制和遥测边界。一把调用方 API Key 可以同时治理调用方可使用的模型、可调用的 MCP 工具,以及可访问的 A2A Agent。 AISIX 对每个 MCP 请求执行身份认证,并根据调用方的有效工具授权过滤工具发现。对于 `tools/call`,AISIX 还会应用限流和安全护栏、检查适用的 AISIX Cloud 预算、使用已配置的上游凭证路由调用,并记录用量遥测。 ## MCP 网关的工作原理[​](#how-the-mcp-gateway-works "MCP 网关的工作原理的直接链接") 每个 MCP 服务器都有一个 `name`。在 AISIX Cloud 中,服务器注册在组织级别,并公开给选定环境。在开源 AISIX 网关中,服务器通常在 `resources.yaml` 中声明。AISIX 聚合已启用服务器的工具,并以带前缀的名称公开每个工具。 AISIX 使用两个下划线分隔已注册的服务器名称和上游工具名称。例如,`github__create_issue` 会路由到名为 `github` 的已注册 MCP 服务器,并调用其名为 `create_issue` 的上游工具。对于两种管理路径,服务器名称都不能包含保留分隔符 `__`,也不能以下划线结尾。名称内部可以使用单个下划线,例如 `internal_tools`。AISIX Cloud 还把名称限制为 56 个字母、数字、下划线、点或连字符,并要求首尾为字母或数字。 ## 开始使用[​](#get-started "开始使用的直接链接") 按照[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)中的步骤,通过 AISIX Cloud 或 `resources.yaml` 注册上游服务器,并向调用方 API Key 授予一个工具的访问权限。该指南通过允许和拒绝的 HTTP 检查单独验证网关路径。随后,连接 [Cursor](https://docs.apiseven.com/ai-gateway/mcp-gateway/cursor.md) 或 [VS Code](https://docs.apiseven.com/ai-gateway/mcp-gateway/vscode.md),在真实 MCP 客户端中验证工具发现、所需批准和工具执行。两种管理路径配置的是同一个网关运行时和 MCP 端点。 ## 客户端连接[​](#client-connection "客户端连接的直接链接") MCP 客户端通过 Streamable HTTP 连接 AISIX 代理监听器。使用 `/mcp` 访问聚合工具面: | 设置 | 值 | | ---------- | ---------------------------------------- | | 服务器 URL | `/mcp` | | 传输方式 | Streamable HTTP | | 请求头 | `Authorization: Bearer ` | 调用方 API Key 控制客户端可以发现和调用哪些工具。客户端只连接 AISIX,不会获得上游服务器 URL 或凭证。 ## 协议版本支持[​](#protocol-version-support "协议版本支持的直接链接") AISIX 网关通过 `/mcp` 和 `/mcp/{server}` 提供当前两代 MCP 协议,并自动与每个客户端协商,因此客户端无需进行 AISIX 专用配置: | MCP 协议修订版 | 客户端支持情况 | 说明 | | -------------- | -------------- | ------------------------------------------------------------------------------------- | | `2026-07-28` | 支持 | 无状态修订版本:通过 `server/discover` 启动,无需握手,并在每个请求中携带协议元数据。 | | `2025-11-25` | 支持 | 使用 `initialize` 握手。 | | `2025-06-18` | 支持 | 使用 `initialize` 握手。 | | `2025-03-26` | 支持 | 使用 `initialize` 握手。 | | `2024-11-05` | 不支持 | HTTP+SSE 传输代际;MCP 端点仅提供 Streamable HTTP。 | 协议涉及两种版本信号,网关会分别处理。对于 `initialize` 握手,网关会回显请求中受支持的 `protocolVersion`;如果请求的版本不受支持,则响应 `2025-11-25`。在握手之外的请求中,`MCP-Protocol-Version` HTTP 请求头是可选的:缺少该请求头时仍会接受请求,并按照规范的兼容规则将其视为 `2025-03-26`;如果请求头指定了不受支持的修订版,则返回 HTTP `400`,并在 JSON-RPC 错误信封中列出受支持的修订版。采用 `2026-07-28` 生命周期的客户端可以从 `server/discover` 开始,无需握手。所有协议代际都以无状态方式提供服务:网关不会发出 `Mcp-Session-Id`,因此 MCP 请求在多个网关副本之间无需会话亲和性。 ### 上游协议选择[​](#upstream-protocol-selection "上游协议选择的直接链接") 面向客户端的协议与上游会话相互独立:网关在 MCP 端点终止客户端协议,并为每个 `type: mcp` 的已注册服务器建立自己的会话。(`openapi` 工具源没有上游 MCP 会话,因此此设置不适用于该类型。)上游会话的修订版通过每个服务器的 `protocol_version` 设置选择: | `protocol_version` | 上游会话行为 | | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | 未设置(默认) | 网关使用 `initialize` 握手建立会话,并协商一个受支持的 2025 Streamable HTTP 修订版本。对于仍会响应 `initialize` 的 `2026-07-28` 服务器,此方式同样有效。 | | `"2026-07-28"` | 网关通过无需握手的 `server/discover` 建立会话。对于不再响应 `initialize` 的服务器,必须使用此设置。 | 在 `resources.yaml` 中,省略 `protocol_version` 即可保留默认生命周期。在 AISIX Cloud 中,把 `protocol_version` 设置为 `null` 可移除现有固定设置;在更新时省略该字段则会保留固定设置。有关两种管理路径的配置步骤,请参阅[固定 MCP 协议修订版](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md#pin-the-mcp-protocol-revision)。 版本选择是显式的:网关只使用已配置的生命周期,绝不会在不同协议代际之间探测或静默降级。当已配置的生命周期与服务器不兼容时,`tools/list` 会记录失败并从聚合列表中省略该服务器的工具,而对该服务器执行 `tools/call` 会返回上游失败。下游和上游的选择始终相互独立。 网关不会把调用方的 `MCP-Protocol-Version` 或 `Mcp-Session-Id` 请求头转发给上游服务器;只有当该服务器的 `forward_client_headers` 精确点名时,才会转发调用方的 `Authorization`。它使用服务器已注册的身份认证和协议设置建立独立的上游会话;有状态上游可以为该会话生成自己的会话标识符,而工具名称、参数和结果会按调用需要跨越该边界。 一致性 网关的持续集成会针对网关及桥接链提供的工具面运行官方 MCP 一致性测试套件中的适用场景,并将其作为阻止合并的检查。 ## 治理 MCP 工具调用[​](#govern-mcp-tool-calls "治理 MCP 工具调用的直接链接") MCP 工具调用与模型请求共享相同的调用方 API Key 身份和遥测管道。它们与模型流量共享该 Key 的请求限制和并发限制;适用的安全护栏,以及 AISIX Cloud 中覆盖该调用方的预算也会生效。MCP 专用控制包括按服务器限流和工具授权:每把 Key 都可以携带自己的授权,AISIX Cloud 还可以叠加环境层和团队层。 使用以下指南进一步配置 MCP 路径: * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):限制每把调用方 API Key 可以列出和调用的工具。 * [限流和预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md):应用调用方 API Key 请求和并发限制,并对 `tools/call` 请求使用 AISIX Cloud 预算。 * [安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md):检查 MCP 工具参数和结果。 * [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md):查看 MCP 工具调用发出的用量事件和指标。 AISIX Cloud 还提供共享的 [MCP 访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)以及[服务器审查和批准工作流](https://docs.apiseven.com/ai-gateway/mcp-gateway/server-review.md)。 ## 按服务器划分的端点[​](#per-server-endpoints "按服务器划分的端点的直接链接") 当客户端要求每个已注册 MCP 服务器使用单独 URL 时,请使用 `/mcp/{server}`。该端点只呈现指定服务器。`initialize` 报告其注册名称,`tools/list` 通常以原始上游名称返回调用方有权使用的工具。`tools/call` 同时接受 `create_issue` 之类的原始名称和 `github__create_issue` 之类的聚合名称。 身份认证、工具访问、限流、安全护栏、用量遥测和 AISIX Cloud 预算的行为与 `/mcp` 相同。访问授权和按服务器限流在两种端点上都保留其 `{server}__{tool}` 身份,因此同时使用两种 URL 形式不会产生第二份限额。调用方身份认证通过后,未知或已禁用的服务器返回 404。 有关工具名称冲突行为和端点错误,请参阅[代理 API 参考](https://docs.apiseven.com/ai-gateway/reference/proxy-api.md#mcp-gateway)。如果现有客户端使用其他 URL 形式(例如 `/mcp-servers/{server}/mcp`),请通过 [URL 重写](https://docs.apiseven.com/ai-gateway/deployment/url-rewriting.md#example-serve-per-server-mcp-urls)将其映射到 `/mcp/{server}`。 ## 排查工具访问问题[​](#troubleshoot-tool-access "排查工具访问问题的直接链接") 如果客户端无法看到或调用某个工具,请检查以下项目: * MCP 服务器资源的 `enabled` 为 true。 * 在 AISIX Cloud 中,服务器状态为 `approved`,且其 `allowed_environments` 包含调用方 API Key 所在的环境。 * AISIX 网关可以访问上游 MCP 服务器,且已配置的上游身份认证有效。请参阅[上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md)。 * 调用方 API Key 的有效工具授权覆盖带前缀的工具名称。该授权是所有适用层的交集:Key 自身的 `mcp_access` 配置块,以及在 AISIX Cloud 中环境和团队的 [MCP 访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)。 * MCP 客户端把调用方 API Key 发送给 AISIX,而不是发送上游 MCP 凭证。 有关 MCP 错误响应行为,请参阅[请求头和错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md#mcp-errors)。有关端点级行为,请参阅[代理 API 参考](https://docs.apiseven.com/ai-gateway/reference/proxy-api.md#mcp-gateway)。 --- # 审查并批准 MCP 服务器 MCP 服务器注册表条目为 Agent 提供由网关管理的工具面,其后端可以是上游 MCP 服务器或 REST API。发布条目后,Agent 可以使用调用方提供的参数调用远程操作。因此,AISIX Cloud 将注册与发布分离:每个 MCP 服务器都有一个 `approval_status`,只有已批准的服务器才会发送到网关。 等待审查或已被拒绝的服务器完全不会出现在网关上。即使调用方 API Key 明确把其工具加入白名单,该服务器也不会出现在 `tools/list` 中,工具也无法调用。服务器必须先获批准才能发布;获批后,`enabled` 标志控制服务器能否提供工具。 这种分离允许成员提议 MCP 服务器,但不能自行发布。它还可以防止不同配置沿用既有批准:变更要么来自拥有批准权限的人,要么等待审查。提议的变更等待审查时,已上线服务器仍会提供其已批准配置,因此审查不会造成停机。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下环境: * AISIX Cloud 组织和环境。 * 用于审查和批准示例的写入作用域管理员 Token。 * [cURL](https://curl.se/) 和 [jq](https://jqlang.github.io/jq/)。 对于本地部署,[AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)会创建组织、环境和写入作用域管理员 Token。如需申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。导出示例使用的值: ``` # AISIX_CP 包含 /api,末尾不带斜杠。 # 本地部署快速入门使用 http://localhost:8080/api。 export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` ## 审查工作流的工作原理[​](#how-the-review-workflow-works "审查工作流的工作原理的直接链接") | `approval_status` | 网关上的状态 | 进入该状态的操作 | | ----------------- | ----------------------------- | --------------------------------------------------- | | `pending_review` | 不投射 | 提交服务器或修改提案。 | | `approved` | 投射到 `allowed_environments` | 批准服务器,或通过 `POST /mcp_servers` 注册服务器。 | | `rejected` | 不投射 | 拒绝服务器。 | 对已上线服务器提出变更时,其状态不会离开 `approved`。变更会在单独的 `pending_change` 字段中等待审查,其他字段仍描述网关当前提供的配置。请参阅[对已上线服务器提交变更](#submit-a-change-to-a-live-server)。 此功能推出前注册的服务器会被视为已批准,因此升级不会中断工具流量。 ## 配置审查者权限[​](#configure-reviewer-permissions "配置审查者权限的直接链接") 批准和注册使用相同权限:对 `mcp_servers` 的 `write` 权限。Owner 和 Admin 拥有该权限。拥有此权限的用户本来就能直接发布服务器,因此额外的审查不会增加控制。这也允许只有一名管理员的组织批准自己的提交。 可以分离的是另一项权限:对 `mcp_server_submissions` 的 `write` 权限。拥有该权限、但没有 `mcp_servers` `write` 权限的[自定义角色](https://docs.apiseven.com/ai-gateway/cloud/custom-roles.md),可以提交服务器、修改提案,以及对已上线服务器提出变更,但不能发布任何内容。应将此角色授予负责集成自身工具的团队。 ## 提交服务器以供审查[​](#submit-a-server-for-review "提交服务器以供审查的直接链接") 通过 `POST /mcp_server_submissions` 提交服务器。请求体与 `POST /mcp_servers` 相同: ``` curl -sS -X POST "$AISIX_CP/mcp_server_submissions" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "runbooks", "url": "https://mcp.example.com/runbooks", "auth_type": "none", "allowed_environments": ["'"$ENV_ID"'"] }' ``` 服务器已经注册,但尚未发布: ``` { "mcp_server": { "id": "6f64f080-17d7-44d9-b995-6a353e71f6bc", "name": "runbooks", "url": "https://mcp.example.com/runbooks", "enabled": true, "allowed_environments": ["YOUR_ENVIRONMENT_ID"], "approval_status": "pending_review", "submitted_at": "2026-07-29T09:30:00Z" } } ``` ❶ `enabled` 和 `allowed_environments` 描述获批后将生效的配置。 ❷ `pending_review` 使服务器保持未发布状态,因此任何网关都无法访问它。 在控制台中,MCP 服务器页面会在对应行显示 **Pending review** 徽标,页面顶部还会显示等待审查的服务器数量。 ## 审查待处理服务器[​](#review-a-pending-server "审查待处理服务器的直接链接") 通过读取 `GET /mcp_servers` 返回的 `approval_status` 列出等待审查的服务器: ``` curl -sS "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ | jq '.data[] | select(.approval_status == "pending_review") | {id, name, url}' ``` 批准前请审查服务器: * 确认名称不是现有服务器名称的近似仿冒,且 URL 指向预期上游。 * 检查 `allowed_environments` 和 `enabled`,确认获批后服务器会在哪里可用。 * 检查身份认证模式,并通过你的提交流程验证凭证来源。存储的凭证只写不可读,无法从 API 或控制台查看;如果无法确定来源,请通过批准者路由替换凭证。 * 对于 OpenAPI 后端服务器,请审查生成的工具名称和存储的文档。请参阅[在 AISIX Cloud 中查看生成的工具](https://docs.apiseven.com/ai-gateway/mcp-gateway/openapi-servers.md#review-the-generated-tools-in-aisix-cloud)。 批准服务器后,它会发布到 `allowed_environments` 指定的环境: ``` export MCP_SERVER_ID="YOUR_MCP_SERVER_ID" curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/approve" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 也可以附带原因拒绝服务器。备注会随服务器返回,提交者可以据此修改: ``` curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/reject" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"review_notes": "Not on the trusted registry. Use the internal mirror."}' ``` 批准已经批准的服务器或拒绝已经拒绝的服务器会返回 `400`。带有暂存变更的服务器属于例外,请参阅[对已上线服务器提交变更](#submit-a-change-to-a-live-server)。 ## 修改待处理提交[​](#revise-a-pending-submission "修改待处理提交的直接链接") `PATCH /mcp_server_submissions/{id}` 会修正提交内容并将其重新放回审查队列: ``` curl -sS -X PATCH "$AISIX_CP/mcp_server_submissions/$MCP_SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url": "https://mcp.internal.example.com/runbooks"}' ``` 对于尚未发布的服务器,变更会应用到记录上,服务器继续留在队列中。对于已上线服务器,相同调用会暂存变更,而不会立即应用。 ## 对已上线服务器提交变更[​](#submit-a-change-to-a-live-server "对已上线服务器提交变更的直接链接") 只拥有 `mcp_server_submissions` `write` 权限的角色不能发布,因此它对已上线服务器的修改不能自行生效;但变更等待审查期间也不能让服务器下线,所以 `PATCH /mcp_server_submissions/{id}` 会暂存该变更: ``` curl -sS -X PATCH "$AISIX_CP/mcp_server_submissions/$MCP_SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url": "https://mcp.internal.example.com/runbooks"}' ``` 响应会返回服务器当前状态,并在旁边显示提案: ``` { "mcp_server": { "id": "6f64f080-17d7-44d9-b995-6a353e71f6bc", "name": "runbooks", "url": "https://mcp.example.com/runbooks", "approval_status": "approved", "pending_change": { "changes": { "url": "https://mcp.internal.example.com/runbooks" }, "submitted_by": "YOUR_USER_ID", "submitted_at": "2026-07-30T09:30:00Z" } } } ``` ❶ `pending_change` 以外的字段描述网关当前提供的配置。整个审查窗口内,Agent 仍可列出并调用服务器的现有工具。 ❷ `pending_change` 包含提议的替换值和提交元数据。 提案会在提交时验证,无效变更会立即被拒绝,而不会等到批准阶段。提议的凭证与正式凭证一样会加密存储且不会返回;`pending_change.secret_set` 表示提案设置了凭证。同一时间只保留一个提案,再次修改会替换它。 ## 审查已上线服务器的变更[​](#review-a-change-to-a-live-server "审查已上线服务器的变更的直接链接") 批准操作会在一个步骤中应用并发布暂存变更: ``` curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/approve" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 批准时会再次检查提案指定的环境。如果某个环境在等待期间被删除,变更会被拒绝,而不会只应用一部分。 拒绝操作会丢弃提案。服务器保持 `approved` 并继续提供原有配置,网关不会发生任何变化: ``` curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/reject" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"review_notes": "Point it at the internal mirror instead."}' ``` 在控制台中,带有暂存变更的记录会显示变更涉及哪些字段。状态筛选器的 **Awaiting review** 选项会同时列出未发布的提交和等待变更审查的已上线服务器。 ## 以批准者身份更新已上线服务器[​](#update-a-live-server-as-an-approver "以批准者身份更新已上线服务器的直接链接") `PATCH /mcp_servers/{id}` 需要 `mcp_servers` `write` 权限,与批准服务器的权限相同。通过该端点进行的编辑本身就是一次发布。服务器保持已批准状态,控制面会投射新配置,无需让现有配置下线等待另一次审查。批准者因此可以轮换上游凭证,而无需先撤回服务器。 是否视为新审查取决于变更的字段。修改以下任一字段都会更新 `reviewed_at`。通过用户会话发出的请求还会把 `reviewed_by` 设置为该用户;管理员 Token 操作则不包含此字段。 * `name`:Agent 用来寻址工具的命名空间 * `url`:上游本身 * `transport` * `auth_type`、`secret`、`client_id`、`token_url`、`scopes`:凭证及其提交位置 * `allowed_environments`:服务器公开到哪些环境 * [OpenAPI 后端服务器](https://docs.apiseven.com/ai-gateway/mcp-gateway/openapi-servers.md)上的 `spec_content` / `spec_url` 和 `api_key_header`:工具面 `enabled` 和 `timeout_ms` 是已审查配置中的运维参数。修改它们不构成新审查,因此不会改变 `reviewed_by` 和 `reviewed_at`。 缩小 `allowed_environments` 后,异步投射到达各网关时,服务器会从不再列出的每个环境中撤回。 仅拥有 `mcp_server_submissions` `write` 权限的角色不能使用该端点;其变更会进入审查队列。请参阅[对已上线服务器提交变更](#submit-a-change-to-a-live-server)。如需让已上线服务器退出网关,请拒绝该服务器。 ## 撤销批准[​](#revoke-an-approval "撤销批准的直接链接") 拒绝没有暂存变更的已批准服务器,会撤销服务器本身的批准:服务器从所有正在提供服务的环境中撤回,调用方将失去其工具。当上游不再可信时使用此操作。 ``` curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/reject" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"review_notes": "Upstream credential compromised."}' ``` 撤销会异步投射到网关,无需重启网关。如需彻底移除注册项,请删除服务器。 拒绝带有暂存变更的服务器时,会先丢弃该变更。要撤销此类服务器,需要调用两次:第一次丢弃提案,第二次撤回服务器。 ## 审计记录[​](#audit-trail "审计记录的直接链接") 此工作流中的每次变更都会记录在组织审计日志中,包括时间以及适用时的服务器变更前后状态。用户会话操作包含执行用户;管理员 Token 操作不包含用户 ID。 | 操作 | 记录时机 | | --------- | ---------------------------------------------- | | `submit` | 提交服务器进行审查,或对已上线服务器提出变更。 | | `create` | 直接注册并发布服务器。 | | `approve` | 批准服务器,或应用暂存变更。 | | `reject` | 拒绝服务器、撤销批准或丢弃暂存变更。 | | `update` | 修改服务器配置。 | | `delete` | 删除服务器。 | 可以在控制台的审计日志中查看这些记录,也可以调用 `GET /audit_events?resource_type=mcp_server`。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你现在已经了解 AISIX Cloud 如何把 MCP 服务器提交与发布分开。使用以下指南直接注册服务器或治理调用方访问: * [设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md):直接注册服务器并验证 MCP 工具访问。 * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):选择调用方 API Key 可以调用的工具。 * [使用策略管理 MCP 访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md):配置环境级和团队级工具授权。 --- # 设置 MCP 网关 AISIX MCP 网关把已注册的 MCP 服务器置于统一的 `/mcp` 端点后,并控制每个调用方可以使用的工具。这样,应用无需直接连接各个上游服务器,即可通过 AISIX 访问获准使用的工具。 本指南将注册一个上游 MCP 服务器,把其中一个工具授予一把调用方 API Key,并验证该调用方只能使用这个工具。AISIX Cloud 与开源 AISIX 网关通过不同的管理路径配置相同的运行时行为。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下环境: * 对于 AISIX Cloud,完成 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md),并保持其 Shell 和 `aisix-dp` 网关运行。 * 对于开源 AISIX 网关,完成[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md),并停留在其 Shell 和工作目录中,同时保持 `aisix-quickstart` 网关运行。 * [Docker](https://docs.docker.com/get-docker/)、[cURL](https://curl.se/) 和 [jq](https://jqlang.github.io/jq/)。 ## 启动 MCP 测试服务器[​](#start-an-mcp-test-server "启动 MCP 测试服务器的直接链接") 此示例在 Docker 中运行 MCP 官方的 [Everything 测试服务器](https://github.com/modelcontextprotocol/servers/tree/main/src/everything)。该服务器与你现有的网关会加入一个临时 Docker 网络,因此网关无需重启即可访问服务器。Everything 服务器只能用于本地测试:它没有身份认证,并包含一个可返回其进程环境的诊断工具。此处使用的容器不会接收任何机密信息。完成本指南后,请停止并移除该容器。 根据你的配置路径设置网关容器名称。 对于 AISIX Cloud: ``` export AISIX_GATEWAY_CONTAINER="aisix-dp" ``` 对于开源 AISIX 网关: ``` export AISIX_GATEWAY_CONTAINER="aisix-quickstart" ``` 创建临时网络,并把正在运行的网关连接到该网络: ``` docker network create aisix-mcp docker network connect aisix-mcp "$AISIX_GATEWAY_CONTAINER" ``` 在同一网络上启动 Everything 服务器: ``` docker run -d --name aisix-mcp-everything \ --network aisix-mcp \ node:22-alpine \ sh -c 'npx -y @modelcontextprotocol/server-everything@2026.7.4 streamableHttp' ``` 等待服务器就绪: ``` for attempt in $(seq 1 120); do docker logs aisix-mcp-everything 2>&1 | grep -q "listening on port 3001" && break sleep 1 done docker logs aisix-mcp-everything 2>&1 | grep "listening on port 3001" ``` 最后一条命令会打印一行日志,确认端口 `3001` 已就绪。从网关容器中可通过 `http://aisix-mcp-everything:3001/mcp` 访问 MCP 端点。 ## 注册服务器并授权工具[​](#register-the-server-and-grant-a-tool "注册服务器并授权工具的直接链接") 通过与你的部署对应的管理路径注册服务器。两种路径都把服务器命名为 `everything`,并且只把它的 `echo` 工具授予现有的快速入门调用方。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 注册测试服务器,并允许快速入门环境使用它: ``` MCP_SERVER_RESPONSE=$(curl -fsS -X POST "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- </dev/null 2>&1; then break fi sleep 2 done echo "$TOOLS_RESPONSE" | jq -e \ '.result.tools | map(.name) == ["everything__echo"]' ``` 最后一条命令会打印 `true`。调用允许的工具: ``` curl -fsS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "MCP-Protocol-Version: 2025-11-25" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "everything__echo", "arguments": {"message": "hello through AISIX"} } }' | jq -e \ '.result.content[] | select(.text == "Echo: hello through AISIX")' ``` 该命令会打印匹配的工具结果内容块。为了验证工具授权列表已执行,尝试调用同一上游服务器中的另一个工具: ``` curl -fsS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "MCP-Protocol-Version: 2025-11-25" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "everything__get-sum", "arguments": {"a": 1, "b": 2} } }' | jq -e \ '.error.message == "tool '\''everything__get-sum'\'' is not available"' ``` 该命令会打印 `true`。AISIX 会拒绝此调用,而不会把它发送到上游。 ## 为你的 MCP 服务器调整配置[​](#adapt-the-setup-for-your-mcp-server "为你的 MCP 服务器调整配置的直接链接") 把测试服务器 URL 替换为网关可访问的 Streamable HTTP 端点。保留 `type: mcp`,并通过 `auth_type` 及其相关字段配置上游凭证。请参阅[上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md)。 对于开源 AISIX 网关,请验证完整的资源文件;当正在运行的网关已具有所有被引用的环境变量时,发送 `SIGHUP`。如果添加或更改了环境变量,请使用新值重新创建容器。请参阅[重新加载资源文件](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md#reload-a-resources-file)。 AISIX Cloud 把上游凭证存储在控制面中,并把已批准的配置投射到已连接的网关。若要允许成员提交服务器而不直接发布,请使用[审查并批准 MCP 服务器](https://docs.apiseven.com/ai-gateway/mcp-gateway/server-review.md)。 ### 固定 MCP 协议修订版[​](#pin-the-mcp-protocol-revision "固定 MCP 协议修订版的直接链接") 网关默认使用 MCP `initialize` 握手打开上游会话,并在握手中与服务器协商协议修订版。对绝大多数服务器都应保持该默认值,包括那些实现了无状态 `2026-07-28` 修订版但仍保持向后兼容的服务器。 只有当服务器要求 `2026-07-28` 修订版时,才把 `protocol_version` 设置为 `2026-07-28`——该修订版以按需的 `server/discover` 调用取代握手。被固定的服务器不会回退:如果上游不支持所固定的修订版,连接会直接失败,而不会悄悄协商到更旧的修订版。该设置仅适用于 `type: mcp` 的服务器,因为 `openapi` 服务器没有上游 MCP 会话。 对于 AISIX Cloud,为已注册的服务器固定修订版: ``` curl -fsS -X PATCH "$AISIX_CP/mcp_servers/$MCP_SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"protocol_version":"2026-07-28"}' | jq ``` 发送 `"protocol_version": null` 可移除该设置,让服务器回到握手方式。 对于开源 AISIX 网关,在服务器条目中添加该字段并重新加载: resources.yaml(MCP 协议版本) ``` mcp_servers: - name: everything type: mcp url: http://aisix-mcp-everything:3001/mcp auth_type: none protocol_version: "2026-07-28" ``` ## 清理[​](#clean-up "清理的直接链接") 如果计划继续学习其他 MCP 网关指南,请保留服务器和调用方授权;否则,请通过对应的管理路径移除所添加的资源。 对于 AISIX Cloud,清空调用方的工具授权并删除服务器: ``` curl -fsS -X PATCH \ "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"mcp_access":{"allow":[]}}' | jq curl -fsS -X DELETE "$AISIX_CP/mcp_servers/$MCP_SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 对于开源 AISIX 网关,从 `resources.yaml` 中移除新增的 `mcp_access` 和 `mcp_servers`,验证文件并再次发送 `SIGHUP`。 移除测试服务器和临时网络: ``` docker rm -f aisix-mcp-everything docker network disconnect aisix-mcp "$AISIX_GATEWAY_CONTAINER" docker network rm aisix-mcp ``` ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你现在已注册 MCP 服务器、授权一个工具,并验证了允许和拒绝的工具调用。使用以下指南继续扩展配置: * [将 Cursor 连接到 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/cursor.md):配置 Cursor 并验证一次完整工具调用。 * [将 VS Code 连接到 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/vscode.md):配置 VS Code 并验证一次完整工具调用。 * [把 REST API 公开为 MCP 工具](https://docs.apiseven.com/ai-gateway/mcp-gateway/openapi-servers.md):从 OpenAPI 文档生成工具。 * [配置上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md):使用 Bearer Token、API Key 或 OAuth 客户端凭证。 * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):授权确切工具名称、某个服务器的所有工具或全部已注册工具。 * [应用限流和预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md):使用调用方和服务器限额治理 MCP 工具调用。 * [配置安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md):检查工具参数和结果。 --- # 控制 MCP 工具访问 对于 MCP 流量,调用方 API Key 是工具访问边界。只有显式授予访问权限后,某把 Key 才能列出或调用 MCP 工具。 当不同客户端需要通过同一个网关访问不同上游工具时,请配置工具访问。本指南说明 AISIX 如何命名聚合工具、如何创建或更新带工具访问权限的 Key,以及调用方列出或调用工具时如何执行权限检查。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下环境: * 对于 AISIX Cloud,准备一个环境、已注册的 MCP 服务器和写入作用域管理员 Token。对于本地部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。若要申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,在 `resources.yaml` 中准备一把调用方 API Key 和已注册的 MCP 服务器。[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)提供了可运行的配置以及验证和重新加载工作流。 * AISIX Cloud 示例需要 [cURL](https://curl.se/) 和 [jq](https://jqlang.org/)。 ## 工具访问的工作原理[​](#how-tool-access-works "工具访问的工作原理的直接链接") 工具访问存储在调用方 API Key 的 `mcp_access` 字段中,它是一个包含 `allow` 列表和可选 `deny` 列表的对象。该配置块是这把 Key 在工具 ACL 中自己的那一层:在 AISIX Cloud 中,它会与环境和团队的 [MCP 访问策略](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)取交集,因此 Key 只能收窄这些层允许的范围,不能扩大。 省略该配置块时,这把 Key 不施加自己的约束,也就是取得各策略层留下的全部权限——而当任何一层都没有配置时,它没有任何 MCP 工具访问权限。权限总是被显式授予。 AISIX 采用 `__` 形式命名每个公开的工具。`` 是已注册 MCP 服务器的 `name`,`` 是上游工具名称。例如,`github__create_issue` 会调用已注册 `github` 服务器上的上游 `create_issue` 工具。 每个 `allow` 条目都会与带前缀的工具名称匹配: | 条目 | 授权范围 | 示例 | | ------------- | ------------------------------ | ------------------------------------------------------------------------------------------ | | 精确名称 | 一个指定工具。 | `github__create_issue` 只允许该工具。 | | `__*` | 一个已注册服务器上的全部工具。 | `github__*` 允许 `github__create_issue`、`github__list_repos` 以及任何其他 `github` 工具。 | | `*` | 所有已注册服务器上的全部工具。 | `*` 允许当前和未来的所有工具。 | 精确名称提供最窄访问权限。当调用方可以使用某个服务器的所有工具时,使用按服务器通配符;只有当这把 Key 不需要收窄任何范围时才使用 `*`——它通常与 `deny` 搭配,用于只做扣除的场景。`allow` 为空列表则表示该 Key 完全没有 MCP 访问权限。 条目是单星号 glob,因此通配符可以出现在末尾按服务器形式之外。例如,`*__search` 会授权每个已注册服务器上名为 `search` 的工具。除非确实需要跨服务器模式,否则应优先使用按服务器或精确授权。 `deny` 使用相同的模式,且始终优先:被它匹配到的工具不可用,无论这把 Key 或任何策略层如何允许。 需要管理大量 Key? Key 自身的配置块提供最细粒度的控制。在 AISIX Cloud 中,使用[通过策略管理 MCP 访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/access-policies.md)可在环境或团队级别授予访问权限。没有配置自己那一层的 Key 会跟随共享层,包括后来注册、被匹配通配符覆盖到的工具。 ## 配置工具访问[​](#configure-tool-access "配置工具访问的直接链接") 请通过与你的部署对应的管理路径配置工具访问。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 使用 Admin API 创建带工具访问权限的调用方 API Key,或更新现有 Key 的工具授权。 #### 创建 Key[​](#create-a-key "创建 Key的直接链接") 导出控制面 URL、管理员 Token 和环境 ID: ``` # AISIX_CP 包含 /api,末尾不带斜杠 # 本地 On-Premises 快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 创建 MCP 客户端使用的调用方 API Key。下面示例授权一个服务器上的所有工具,以及另一个服务器上的单个工具: ``` curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "mcp-caller", "allowed_models": [], "mcp_access": { "allow": ["github__*", "runbooks__search"] } }' > api_key.json export API_KEY_ID=$(jq -r '.api_key.id' api_key.json) export CALLER_KEY=$(jq -r '.plaintext' api_key.json) ``` ❶ 当该 Key 仅用于 MCP 流量时,使用空的模型白名单。 ❷ 该层允许调用 `github` 服务器上的全部工具,外加单个 `runbooks__search` 工具,不允许调用其他工具。在 AISIX Cloud 中,这把 Key 实际可达的范围还要受环境层和团队层的限制。 响应会在 `plaintext` 中返回且只返回一次明文 Bearer Key。请立即将其安全存储在客户端;后续读取只返回 Key 元数据。MCP 客户端在网关请求中以 `Authorization: Bearer ` 发送该值。 #### 更新工具访问[​](#update-tool-access "更新工具访问的直接链接") 当工具授权发生变化时,请更新调用方 API Key。更新是部分更新:只有发送的字段会发生变化,而 `mcp_access` 会作为一个完整配置块被替换: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mcp_access": { "allow": ["github__create_issue"] } }' ``` 这次更新会把之前的配置块替换为仅允许 `github__create_issue`。由于请求没有包含模型访问权限和其他设置,这些配置保持不变。 要撤销该 Key 的全部 MCP 工具访问权限,请发送 `"mcp_access": {"allow": []}`。该 Key 会保留模型访问权限和其他配置,但无论各策略层如何允许,它都不能再列出或调用任何 MCP 工具。发送 `"mcp_access": null` 的含义则不同:它会移除这把 Key 自己的层,使它重新跟随环境层和团队层。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX 网关的直接链接") 在 `resources.yaml` 的调用方条目上设置 `mcp_access`: resources.yaml(MCP 访问权限) ``` api_keys: - display_name: mcp-caller key_env: MCP_CALLER_KEY allowed_models: [] mcp_access: allow: - github__* - runbooks__search ``` 在网关进程环境中设置 `MCP_CALLER_KEY`。该调用方可以使用 `github` 下注册的每个工具,以及 `runbooks` 下注册的 `search` 工具。包括模型和 A2A 访问在内的其他调用方设置仍位于同一条目上。 资源文件没有策略层,因此 Key 自己的配置块就是唯一的一层——没有 `mcp_access` 的调用方条目因而无法访问任何 MCP 工具。 若要更改授权,请编辑完整配置块、验证 `resources.yaml` 并重新加载网关。设置 `allow: []` 可以撤销所有 MCP 工具访问,同时保留该 Key 的其他权限。有关验证和重新加载命令,请参阅[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md#open-source-aisix-gateway)。 ## 权限执行的工作原理[​](#how-enforcement-works "权限执行的工作原理的直接链接") 当 MCP 客户端列出工具时,AISIX 会聚合每个已启用服务器的工具,然后按照调用方的有效授权过滤列表——也就是适用于这把 Key 的所有层的交集。客户端只会看到允许访问的工具。 当客户端调用工具时,AISIX 会在联系上游服务器之前再次检查有效授权。调用方无权访问的工具会以中性 MCP 错误被拒绝,且不会路由到上游。该拒绝不会透露该工具或服务器是否存在。 同一授权也适用于[按服务器划分的端点](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md#per-server-endpoints)。AISIX 以带命名空间的 `<server>__<tool>` 形式评估每个工具,然后通常以原始名称呈现允许访问的工具。例如,对 `github__create_issue` 的授权会在 `/mcp/github` 上呈现 `create_issue`,但不会授权访问其他服务器端点上的任何工具。 ## AISIX Cloud 控制面[​](#aisix-cloud-control-plane "AISIX Cloud 控制面的直接链接") 你也可以通过控制面用户界面配置工具访问权限,而不是使用上面的 API 调用。相同的授权模型仍然适用:调用方 API Key 可以限定到单个工具、某个服务器上的全部工具,或该环境中可用的全部 MCP 工具。该工作流适用于 AISIX Cloud 的两种控制面部署方式:[本地部署](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md)和[混合云](https://docs.apiseven.com/ai-gateway/cloud/overview.md)。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你现在已限定每把调用方 API Key 可以列出和调用的 MCP 工具。使用以下指南添加运行时控制,或查看共享的调用方 Key 设置: * [限流和预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md):应用请求和并发限制,并为 MCP 工具调用配置 AISIX Cloud 预算。 * [安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md):检查 MCP 工具参数和结果。 * [调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md):查看同样治理模型和 A2A 流量的共享 Key 设置。 --- # 限流和预算 对于 MCP 流量,调用方 API Key 仍是流量控制边界。MCP 工具调用与模型流量共享该 Key 的请求和并发限制,但不消耗模型 Token。在 AISIX Cloud 中,它们还受覆盖同一调用方 API Key 的预算约束。 调用方 API Key 还可以为其访问的每个 MCP 服务器单独设置限额。这样,Agent 在一个服务器上循环调用时,不会耗尽同一 Key 访问其他服务器所需的限额。请在 `resources.yaml` 或 AISIX Cloud 中配置这些限额,然后在 MCP 路径上验证行为。预算仅在 AISIX Cloud 中可用,始终作用于整个 Key,且没有按服务器设置。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下环境: * 对于 AISIX Cloud,准备一个环境、一把调用方 API Key 和写入作用域管理员 Token。对于本地部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。若要申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,在 `resources.yaml` 中准备一把调用方 API Key 和已注册的 MCP 服务器。[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)提供了可运行的配置以及验证和重新加载工作流。 * AISIX Cloud 示例需要 [cURL](https://curl.se/)。 ## 控制的应用范围[​](#where-controls-apply "控制的应用范围的直接链接") 网关仅对 `tools/call` 请求应用限流和预算检查。MCP 握手(包括 `initialize`)以及通过 `tools/list` 进行的工具发现不会被限流。被限流的调用方仍可连接并列出其 Key 允许的工具,但必须等到窗口重置后才能再次调用工具。 限流或预算拒绝工具调用时,AISIX 会在联系上游 MCP 服务器前返回,并且仍会把被拒绝的调用记录为[用量事件](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md)。 ## 适用的限流[​](#applicable-rate-limits "适用的限流的直接链接") 调用方 API Key 的 `rate_limit` 对象可以定义请求速率、Token 速率和并发限制。在 MCP 路径上,只有请求速率和并发限制直接计量工具调用: | 限制 | 是否应用于 MCP 工具调用 | 说明 | | -------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `rps`、`rpm`、`rph`、`rpd` | 是 | 每个 `tools/call` 在对应窗口内计为一个请求。 | | `concurrency` | 是 | 每个进行中的工具调用会占用一个并发许可,直到返回。 | | `tpm`、`tpd` | 间接应用 | MCP 工具调用不携带模型 Token,因此不会增加 Token 窗口计数。如果调用方 Key 的模型流量已耗尽某个 Token 窗口,该 Key 的工具调用仍会以 HTTP `429` 被拒绝,直到窗口重置。 | 每个字段都是可选的。省略字段时,AISIX 不执行对应限制。 请使用请求速率限制或 `concurrency` 限制 MCP 调用量。仅设置 Token 限制无法约束 MCP 工具调用。若要分别限制每个 MCP 服务器,而不是限制整个调用方,请使用 `mcp_rate_limits`。 完整的限流字段参考和计数器存储选项,请参阅 [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md)。 ## 配置限流[​](#configure-rate-limits "配置限�流的直接链接") 请通过与你的部署对应的管理路径配置限流。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 使用 Admin API 配置调用方整体限额,以及可选的单个 MCP 服务器限额。 #### 设置调用方限流[​](#set-a-caller-rate-limit "设置调用方限流的直接链接") 设置 AISIX Cloud 组织的控制面 URL、管理员 Token 和环境 ID: ``` # AISIX_CP 包含 /api,末尾不带斜杠 # 本地 On-Premises 快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 使用 `rate_limit` 更新调用方 API Key。下面的示例让 Key 保持仅用于 MCP,并把它限制为每分钟一次工具调用。`PATCH` 请求只更改发送的字段,其他 Key 字段保留当前值。请把 `YOUR_API_KEY_ID` 替换为创建响应中的调用方 API Key ID。 ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/api_keys/YOUR_API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "allowed_models": [], "mcp_access": { "allow": ["github__*"] }, "rate_limit": { "rpm": 1 } }' ``` ❶ 当该 Key 仅用于 MCP 流量时,使用空的模型白名单。如果同一 Key 还需要调用模型,请保留现有模型访问权限。 ❷ `rpm: 1` 把此调用方 API Key 限制为每分钟一个请求。 更新后的限额会自动投射到已连接的网关。若要验证限额,请使用此调用方 API Key 连接 MCP 客户端,并在同一分钟内调用允许的工具两次。第一次 `tools/call` 成功。第二次会在 AISIX 联系上游 MCP 服务器前以 HTTP `429` 被拒绝。调用方被限流时,握手和 `tools/list` 仍可正常工作。 #### 按 MCP 服务器限制调用方[​](#limit-a-caller-per-mcp-server "按 MCP 服务器限制调用方的直接链接") 上面的 `rate_limit` 是对该 Key 所有行为的统一上限。若要为每个 MCP 服务器设置独立上限,请在调用方 API Key 上添加 `mcp_rate_limits`。它把 MCP 服务器名称映射到该 Key 对应的服务器限额: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/api_keys/YOUR_API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "mcp_rate_limits": { "github": { "rpm": 100, "concurrency": 5 }, "payments": { "rpm": 10 } } }' ``` ❶ 使用 MCP 服务器的注册名称作为限额键;该名称也会为工具添加前缀,例如 `github__create_issue`。 ❷ 不同服务器可以设置不同上限。未在映射中命名的服务器只受 Key 自身 `rate_limit` 的约束。 每个命名服务器独立计数,因此调用方耗尽 `payments` 的限额后仍保留完整的 `github` 限额,其他调用方访问 `payments` 的流量也不受影响。工具调用必须通过所有匹配的限制:调用 `github` 同时计入 `github` 条目和 Key 的 `rate_limit`。 `mcp_rate_limits` 接受与 `rate_limit` 相同的请求速率和并发字段:`rps`、`rpm`、`rph`、`rpd` 和 `concurrency`。它没有 Token 字段,因为 MCP 工具调用不携带可计量的 Token。 `PATCH` 会替换整个映射,因此一个请求中必须包含要限制的所有服务器。发送 `{}` 或 `null` 可移除全部按服务器限制。尚未匹配已注册 MCP 服务器的名称也可接受,并会在同名服务器注册后生效。 重命名 MCP 服务器时,其限额会随之迁移。所有限制该服务器的调用方 API Key 都会继续以新名称限制它。删除服务器时这些条目会保留:在没有服务器使用该名称期间它们不绑定任何东西,一旦以该名称注册服务器就会重新生效。工具授权的行为与此相同,因此以原名重建的服务器会连同其权限和限额一起回来。 工具授权会以相同方式跟随重命名。命名旧服务器的模式会在每把调用方 Key 的 `mcp_access` 配置块中,以及环境级和团队级访问策略中重写。只匹配形状而非某个服务器的模式(例如单独的 `*`)保持不变。 删除服务器不会移除其授权。允许授权命名一个不存在的服务器,因此可以在服务器注册前预配 Key。 未命中已注册服务器的条目会继续等待,这正是可以在服务器存在前限制 Key 的原因。控制台会标记此类条目,并提供 **Remove** 控件。 若要验证,请在窗口内调用该受限服务器上允许的工具,直到超过限额。这些调用会以 HTTP `429` 被拒绝,而对其他 MCP 服务器的工具调用仍会成功。 在控制台中打开 **API keys**,创建或编辑 Key,然后展开 **Per-MCP-server limits**,即可为已注册服务器设置相同的值。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX 网关的直接链接") 在 `resources.yaml` 的调用方条目上设置整体和按服务器限额: resources.yaml(MCP 限流) ``` api_keys: - display_name: mcp-caller key_env: MCP_CALLER_KEY allowed_models: [] mcp_access: { allow: ["github__*", "payments__*"] } rate_limit: rpm: 120 concurrency: 10 mcp_rate_limits: github: rpm: 100 concurrency: 5 payments: rpm: 10 ``` 每次工具调用必须同时通过调用方整体限额和匹配的服务器限额。在此示例中,对 `github` 的调用同时计入 `rate_limit` 和 `mcp_rate_limits.github`。未在 `mcp_rate_limits` 中列出的服务器只受调用方整体限额约束。 若要更改这些限额,请编辑完整映射、验证资源文件并重新加载网关。有关命令,请参阅[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md#open-source-aisix-gateway)。 ## 应用 AISIX Cloud 预算[​](#apply-aisix-cloud-budgets "应用 AISIX Cloud 预算的直接链接") 预算在 AISIX Cloud 控制面中配置,并由 AISIX 网关执行。当覆盖调用方 API Key 的预算耗尽时,网关会在联系上游 MCP 服务器前,以 `budget_exceeded` 错误拒绝该 Key 的 `tools/call` 请求。模型路径会执行相同检查。 MCP 工具调用没有 Token 成本,因此本身不会增加基于 Token 的支出。当同一预算同时覆盖模型和工具流量时,如果调用方的模型流量耗尽预算,该调用方的 MCP 工具调用仍会被阻止。有关预算目标、拒绝响应和缓存行为,请参阅[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)。 对于开源 AISIX 网关,请使用调用方 API Key 限流治理 MCP 工具调用量。AISIX Cloud 预算配置详情请参阅[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你现在已将调用方 API Key 控制应用到 MCP 流量。使用以下指南观察结果,或进一步调整共享的限额和预算设置: * [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md):查看 MCP 工具调用发出的用量事件和指标。 * [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):查看完整限流字段参考和计数器存储选项。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):配置预算目标、拒绝行为和缓存设置。 --- # 上游身份认证 每个已注册的 MCP 服务器都可以定义 AISIX 如何向上游服务器执行身份认证。AISIX 在网关侧持有所有上游凭证,并在列出工具或转发工具调用时提供该凭证。MCP 客户端发送给 AISIX 的调用方 API Key 用于向 AISIX 认证调用方;默认情况下,没有任何调用方请求头会到达上游服务器。确实需要看到某个请求头(包括调用方自己的凭证)的服务器,通过 [`forward_client_headers`](#forward-caller-headers-to-an-upstream-server) 显式开启。 使用 `auth_type` 字段和对应身份认证模式要求的字段设置凭证。AISIX Cloud 与开源 AISIX 网关通过不同的管理路径支持相同的模式。 ## 前置条件[​](#prerequisites "前置条件的直接链接") 开始前,请准备以下环境: * 对于 AISIX Cloud,准备一个环境和写入作用域管理员 Token。对于本地部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。若要申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。 * 请完成 AISIX Cloud 或开源 AISIX 网关的[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)。如需执行可选的端到端验证,请保持同一个 Shell、网关、Everything 测试服务器和临时 Docker 网络运行。 * AISIX Cloud 示例需要 [cURL](https://curl.se/)。 ## 身份认证模式[​](#authentication-modes "身份认证模式的直接链接") 选择与上游 MCP 服务器期望 AISIX 使用的身份认证方式相匹配的模式: | `auth_type` | 上游凭证 | AISIX 的提供方式 | | ----------- | ------------------------------------ | ----------------------------------------------------------------------- | | `none` | 无 | 不发送凭证。 | | `bearer` | `secret` 中的 Bearer Token | `Authorization: Bearer <secret>` | | `api_key` | `secret` 中的 API Key | `x-api-key: <secret>` | | `oauth2` | `client_id` + `token_url` + `secret` | AISIX 获取访问 Token,然后发送 `Authorization: Bearer <access_token>`。 | `secret` 保存 AISIX 提供给上游的明文凭证。该值仅在网关侧使用,永远不会发送给调用客户端。若要轮换凭证,请使用新的 `secret` 更新资源。 使用凭证的上游应采用 HTTPS。如果为 `http://` URL 配置了 Bearer Token、API Key 或 OAuth 凭证,网关会记录警告,因为凭证将以明文通过网络传输。对于 OAuth,当 `token_url` 使用 `http://` 时,网关也会发出警告,因为客户端密钥会发送到该端点。 ## 配置上游身份认证[​](#configure-upstream-authentication "配置上游身份认证的直接链接") 请通过与你的部署对应的管理路径配置上游身份认证。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") AISIX Cloud Admin API 会同时创建服务器及其上游凭证。`allowed_environments` 列出接收该服务器的环境。列表为空或缺失时,服务器不会公开给任何环境,因此以下每个示例都包含目标环境。 导出控制面连接值: ``` # AISIX_CP 包含 /api,末尾不带斜杠 # 本地 On-Premises 快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` #### 无身份认证[​](#no-authentication "无身份认证的直接链接") 上游 MCP 服务器不要求凭证时使用 `none`,例如只能通过受信任内部网络访问的服务器。 以下示例创建不带上游凭证的服务器资源: ``` curl -sS -X POST "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "runbooks", "url": "https://runbooks.internal/mcp", "auth_type": "none", "allowed_environments": ["'"$ENV_ID"'"] }' ``` `auth_type` 默认为 `none`,因此也可以省略。对于 `none` 服务器,不要设置 `secret`、`client_id`、`token_url` 和 `scopes`。 #### Bearer Token[​](#bearer-token "Bearer Token的直接链接") 上游服务器要求在 `Authorization` 请求头中提供静态 Token 时使用 `bearer`。 以下示例创建服务器资源,并配置 AISIX 应发送给上游的 Bearer Token: ``` curl -sS -X POST "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "github", "url": "https://mcp.example.com/mcp", "auth_type": "bearer", "secret": "YOUR_UPSTREAM_MCP_TOKEN", "allowed_environments": ["'"$ENV_ID"'"] }' ``` ❶ `bearer` 会在发送给此上游的每个请求上添加 `Authorization: Bearer <secret>`。 ❷ `secret` 为必填字段,且不能为空。 #### API Key[​](#api-key "API Key的直接链接") 上游服务器要求在 `x-api-key` 请求头中提供 Key 时使用 `api_key`。 以下示例创建服务器资源,并配置 AISIX 应发送给上游的 API Key: ``` curl -sS -X POST "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "catalog", "url": "https://catalog.example.com/mcp", "auth_type": "api_key", "secret": "YOUR_UPSTREAM_API_KEY", "allowed_environments": ["'"$ENV_ID"'"] }' ``` ❶ `api_key` 会在发送给此上游的每个请求上添加 `x-api-key: <secret>`。 ❷ `secret` 为必填字段,且不能为空。 #### OAuth 2.0 客户端凭证[​](#oauth-20-client-credentials "OAuth 2.0 客户端凭证的直接链接") 上游服务器接受 OAuth 2.0 访问 Token,且你拥有其机器到机器客户端凭证时使用 `oauth2`。 AISIX 在 Token 端点交换客户端凭证,把访问 Token 发送给上游,并在临近过期前复用该 Token。如果上游服务器因未授权而拒绝 Token,AISIX 会丢弃缓存的 Token,并在下次调用时获取新 Token。 以下示例创建服务器资源,并配置 AISIX 应对此上游使用的 OAuth 客户端凭证: ``` curl -sS -X POST "$AISIX_CP/mcp_servers" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "orders", "url": "https://orders.example.com/mcp", "auth_type": "oauth2", "client_id": "aisix-gateway", "token_url": "https://auth.example.com/oauth/token", "secret": "YOUR_OAUTH_CLIENT_SECRET", "scopes": ["mcp.read", "mcp.write"], "allowed_environments": ["'"$ENV_ID"'"] }' ``` ❶ `oauth2` 对此上游使用 OAuth 2.0 客户端凭证授权。 ❷ `oauth2` 服务器必须配置 `client_id`、`token_url` 和 `secret`。 ❸ `scopes` 可选。AISIX 使用空格连接这些值,作为 Token 请求的 `scope` 参数。 AISIX 把访问 Token 保留在网关侧,永远不会返回给调用方。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX ��网关的直接链接") 将以下经过身份认证的 `github` 条目添加到 `mcp_servers`;如果已存在同名条目,则替换它。保持其他资源不变,并通过环境变量插值提供机密信息: resources.yaml(MCP 服务器身份认证) ``` mcp_servers: - name: github type: mcp url: https://mcp.example.com/mcp auth_type: bearer secret: ${GITHUB_MCP_TOKEN} ``` 在网关进程环境中设置 `GITHUB_MCP_TOKEN`。对于 `none`,省略 `secret`。对于 `api_key`,同一个 `secret` 字段会作为 `x-api-key` 发送。对于 `oauth2`,添加 `client_id`、`token_url` 和 `secret`,并可选择添加 `scopes`。 环境变量属于网关进程。正在运行的进程无法接收后来在主机 Shell 中新增或更改的变量。添加或轮换通过环境变量提供的凭证后,请使用新值验证资源文件并重启进程。对于容器,请使用新的环境值重新创建容器。只有当资源文件发生变化,且正在运行的进程已经拥有所有被引用的变量及其预期值时,才使用重新加载。 如果验证或重新加载失败,网关不会应用无效条目;重新加载时会继续提供最后一次有效配置。请参阅 [CLI 参考](https://docs.apiseven.com/ai-gateway/reference/cli.md#validate-a-resources-file)和[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)。 ## 凭证处理[​](#credential-handling "凭证处理的直接链接") 创建或更新服务器时,AISIX 会根据 `auth_type` 验证凭证字段。凭证字段无效的服务器会在写入时被拒绝。 如果凭证之后失效(例如机密信息已轮换或撤销),只有该服务器的工具不可用。`tools/list` 会省略该服务器的工具,而直接且已获许可的调用会返回通用 JSON-RPC 内部错误。其他已注册 MCP 服务器会继续工作。AISIX 会记录详细失败信息,但不会向调用方 Agent 公开凭证详情。 ## 向上游服务器转发调用方请求头[​](#forward-caller-headers-to-an-upstream-server "向上游服务器转发调用方请求头的直接链接") 上面配置的凭证属于网关。而按最终用户授权的内网 MCP 服务器需要的是调用方自己的请求头,`forward_client_headers` 就是它获得该请求头的方式。它是一个请求头名称模式数组,默认为空,两种管理路径都支持,并且对 `type: mcp` 和 `type: openapi` 都适用——因此[以工具形式暴露的 REST API](https://docs.apiseven.com/ai-gateway/mcp-gateway/openapi-servers.md) 在每次工具调用时都会收到这些请求头。 通过 AISIX Cloud Admin API,可以在创建服务器时设置,也可以之后 PATCH。PATCH 会整体替换已存储的列表;发送空数组即可清空: ``` curl -sS -X PATCH "$AISIX_CP/mcp_servers/$MCP_SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "forward_client_headers": ["authorization", "x-trace-*"] }' ``` 在控制台中,同一设置是服务器表单里 **Advanced** 下的 **Forward client headers** 输入框,每行填一个请求头名称或通配符。 在开源 AISIX 网关加载的资源文件中: resources.yaml(把调用方凭证转发给内网服务器) ``` mcp_servers: - name: runbooks type: mcp url: https://runbooks.internal/mcp auth_type: none forward_client_headers: - authorization - x-trace-* ``` 每个条目是精确的请求头名称,或含一个 `*` 通配符的名称,匹配不区分大小写。被转发的请求头会到达服务器,无论 AISIX 本会如何处理它。 指定一个凭证槽位后,AISIX 会用调用方凭证**取代**网关凭证交给服务器,两者不会并存。`authorization` 是 `bearer` 和 `oauth2` 填入的槽位;`api_key` 填入的则是 `api_key_header` 指定的请求头——除非 `type: openapi` 的服务器另行覆盖,否则为 `x-api-key`。因此在同时配置了 `auth_type` 的服务器上点名该槽位,就意味着对于发送了该请求头的调用方,调用方的取值会胜出。校验 `aud` 声明的服务器会拒绝签发给网关的 Token。 [凭证槽位](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#headers-that-must-be-named-exactly)以及链路上下文请求头 `traceparent` 和 `tracestate`,只有在模式精确点名时才会转发。凭证槽位里也包括 AWS SigV4 请求头 `x-amz-security-token`、`x-amz-date` 和 `x-amz-content-sha256`。`*`、`x-*` 或 `x-amz-*` 这类通配符永远不会匹配到它们中的任何一个。转发凭证或链路上下文是一个明确的动作,不应由宽泛的模式顺带带走。 在这个面上,上面链接指向的那张表就是全部。改名后的 `api_key_header` 不在其中:槽位为 `x-mcp-token` 的 `type: openapi` 服务器,其名称会被 `["x-*"]` 匹配到,因此发送该请求头的调用方提供的就是自己的上游凭证,取代网关的那份。 MCP 会话槽位 `mcp-session-id`、`mcp-protocol-version` 和 `last-event-id` 绝不会被转发。它们标识的是调用方与 AISIX 之间的会话,而不是 AISIX 向上游打开的会话;上游服务器会拒绝一个并非自己签发的会话 ID。其余任何模式都无法触及的请求头——`host`、逐跳请求头、`x-aisix-*` 命名空间,以及描述 AISIX 会重新序列化的请求体的那些请求头——列在 [AISIX 绝不转发的调用方请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#caller-headers-aisix-never-forwards)中。 ## 可选:使用本地测试代理验证[​](#optional-verify-with-a-local-test-proxy "可选:使用本地测试代理验证的直接链接") 以上配置定义了 AISIX 应发送的凭证,但配置指南中的 Everything 服务器不进行身份认证也会接受请求,因此无法证明网关提供了预期的 Token。如需进行本地端到端检查,请在服务器前放置一个使用 Bearer 身份认证的小型反向代理,并分别验证请求被接受和拒绝的情况。 该代理仅用于本地测试:它使用明文 HTTP,并会在转发已接受的请求到 Everything 服务器前移除 Bearer Token。 以下辅助函数包含本地代理配置。请原样复制;后续步骤会配置和测试 AISIX。 启动本地 Bearer Token 验证代理 导出独立的上游 Token,然后在现有 Docker 网络上定义并启动测试代理: ``` export MCP_UPSTREAM_TOKEN="mcp-upstream-test-token" start_mcp_auth_proxy() { docker rm -f aisix-mcp-auth >/dev/null 2>&1 || true docker run -d --name aisix-mcp-auth \ --network aisix-mcp \ -e UPSTREAM_TOKEN="$1" \ caddy:2.11.4-alpine \ sh -c 'caddy run --config /dev/stdin --adapter caddyfile <<EOF :3002 { @authorized header Authorization "Bearer $UPSTREAM_TOKEN" handle @authorized { reverse_proxy aisix-mcp-everything:3001 { header_up -Authorization header_up Host {upstream_hostport} } } handle { respond "upstream authentication failed" 401 } } EOF' for attempt in $(seq 1 30); do docker logs aisix-mcp-auth 2>&1 | grep -q "serving initial configuration" && return sleep 1 done docker logs aisix-mcp-auth >&2 return 1 } start_mcp_auth_proxy "$MCP_UPSTREAM_TOKEN" ``` ### 配置 AISIX 使用代理[​](#configure-aisix-to-use-the-proxy "配置 AISIX 使用代理的直接链接") 更新现有 `everything` 服务器,使其使用 `http://aisix-mcp-auth:3002/mcp`、`auth_type: bearer`,并将 `MCP_UPSTREAM_TOKEN` 作为密钥。 对于 AISIX Cloud,请更新配置指南中创建的服务器: ``` curl -fsS -X PATCH "$AISIX_CP/mcp_servers/$MCP_SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- <<EOF | jq { "url": "http://aisix-mcp-auth:3002/mcp", "auth_type": "bearer", "secret": "${MCP_UPSTREAM_TOKEN}" } EOF ``` 对于开源 AISIX 网关,请替换现有 `everything` 条目,并保留其他资源: resources.yaml(已认证的 Everything 服务器) ``` mcp_servers: - name: everything type: mcp url: http://aisix-mcp-auth:3002/mcp auth_type: bearer secret: ${MCP_UPSTREAM_TOKEN} ``` 将 `MCP_UPSTREAM_TOKEN` 添加到网关容器环境中。由于配置指南启动容器时没有提供该变量,请在设置了该变量的环境中验证完整文件,并使用同一个值重新创建容器。保留快速入门中的挂载、端口和其他环境变量。请参阅[重新加载资源文件](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md#reload-a-resources-file)。 对于开源路径,重新创建网关容器会将其与临时 MCP 网络断开。发送测试请求前,请连接替换后的容器: ``` docker network connect aisix-mcp "$AISIX_GATEWAY_CONTAINER" ``` ### 验证有效凭证[​](#verify-a-valid-credential "验证有效凭证的直接链接") AISIX Cloud 投射更新或开源网关重启后,调用已获许可的工具: ``` MCP_RESPONSE=$(curl -fsS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 10, "method": "tools/call", "params": { "name": "everything__echo", "arguments": {"message": "authenticated through AISIX"} } }') echo "$MCP_RESPONSE" | jq -e \ '.result.content[] | select(.text == "Echo: authenticated through AISIX")' ``` 该命令会打印匹配的结果。代理只接受携带网关所持 Token 的请求,因此该响应确认 AISIX 已将调用方的 `Authorization` 请求头替换为上游凭证。代理会在转发到 Everything 服务器前移除该凭证。 ### 验证被拒绝的凭证[​](#verify-a-rejected-credential "验证被拒绝的凭证的直接链接") 让代理期待另一个 Token,但不更改 AISIX 中的凭证: ``` start_mcp_auth_proxy "deliberately-wrong-token" MCP_FAILURE=$(curl -fsS -X POST "$AISIX_PROXY/mcp" \ -H "Authorization: Bearer $AISIX_MCP_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 11, "method": "tools/call", "params": { "name": "everything__echo", "arguments": {"message": "this call should fail"} } }') echo "$MCP_FAILURE" | jq -e \ '.error.code == -32603 and .error.message == "upstream MCP server '\''everything'\'' failed to call tool"' if echo "$MCP_FAILURE" | grep -qF "$MCP_UPSTREAM_TOKEN" || \ echo "$MCP_FAILURE" | grep -qF "$AISIX_MCP_KEY"; then echo "credential found in client response" >&2 exit 1 fi ``` `jq` 命令会打印 `true`,凭证检查不会产生输出。此上游身份认证失败使用 HTTP `200`,因此应检查 JSON-RPC `error` 对象,而不是 HTTP 状态。失败的上游也不会向 `tools/list` 提供任何工具;其他可访问服务器仍会提供它们的工具。 继续操作前,请恢复预期 Token: ``` start_mcp_auth_proxy "$MCP_UPSTREAM_TOKEN" ``` 使用该本地身份认证配置时,请保持 `aisix-mcp-auth` 运行。在执行配置指南中的清理命令前移除它: ``` docker rm -f aisix-mcp-auth ``` ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你现在已经了解 AISIX 如何向上游 MCP 服务器执行身份认证。使用以下指南控制哪些调用方可以访问这些工具,以及如何治理其流量: * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):把调用方 API Key 限定到特定工具、整个服务器或所有工具。 * [限流和预算](https://docs.apiseven.com/ai-gateway/mcp-gateway/traffic-controls.md):应用请求和并发限制,并为 MCP 工具调用配置 AISIX Cloud 预算。 * [安全护栏](https://docs.apiseven.com/ai-gateway/mcp-gateway/guardrails.md):检查 MCP 工具参数和结果。 * [上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md):同一个 `forward_client_headers` 字段在 AISIX 其他代理面上的用法,以及任何模式都无法触及的完整请求头清单。 --- # 将 VS Code 连接到 MCP 网关 Visual Studio Code 可以作为远程 Streamable HTTP 客户端连接到 AISIX MCP 端点。它发送 AISIX 调用方 API Key,仅发现该密钥有权使用的工具,并通过网关调用这些工具,无需获取上游服务器凭证。 VS Code 继续负责选择模型、决定何时请求工具、获取所需批准和展示结果。此连接将 MCP 工具流量发送到 AISIX,不会将模型请求路由到网关。如果 VS Code 支持兼容的模型覆盖配置,且模型流量也需要使用 AISIX,请单独配置该路径。 本指南将 VS Code 连接到聚合的 `/mcp` 端点。你可以接着[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)继续操作,该指南仅向调用方授予 `everything__echo` 权限;也可以使用现有 AISIX 环境,以及调用方有权访问且可安全调用的工具。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始之前,请准备以下内容: * 完成[设置 MCP 网关](https://docs.apiseven.com/ai-gateway/mcp-gateway/setup.md)并保留 `AISIX_PROXY` 和 `AISIX_MCP_KEY`,或向网关运维团队获取 AISIX 代理源地址和调用方 API Key。对于现有环境,请使用这两个变量名导出相应值,并选择一个已获许可且可安全调用的工具进行验证。 * 安装 [Visual Studio Code](https://code.visualstudio.com/),并配置支持 Agent 的聊天服务提供方。 * 确保 VS Code 可访问 AISIX 代理 URL。运行在网关宿主机上的 VS Code 可以使用快速入门中的地址;远程开发环境则需要使用其可访问的地址。 本示例使用工作区配置和受保护的输入,既可随项目审查连接设置,又无需提交调用方 API Key。 ## 配置连接[​](#配置连接 "配置连接的直接链接") 在工作区中创建 `.vscode/mcp.json`,将示例 URL 替换为 `$AISIX_PROXY/mcp`: .vscode/mcp.json ``` { "inputs": [ { "type": "promptString", "id": "aisix-mcp-key", "description": "AISIX caller API key", "password": true } ], "servers": { "aisix": { "type": "http", "url": "https://gateway.example.com/mcp", "headers": { "Authorization": "Bearer ${input:aisix-mcp-key}" } } } } ``` 此配置适用于在本地 VS Code 扩展宿主中运行的聊天。VS Code 不会将需要 `${input:aisix-mcp-key}` 等交互式输入的服务器转发给 Agent Host 会话。对于 Agent Host 会话,请使用其可移植的工作区配置 `.mcp.json` 或用户级路径 `~/.copilot/mcp-config.json`,并采用受支持的非交互式密钥来源。 打开命令面板,运行 **MCP: List Servers**。选择 `aisix`,再选择 **Start Server**。如果 VS Code 询问是否信任工作区或服务器配置,请先检查文件再批准。出现提示时,输入 `AISIX_MCP_KEY` 中保存的调用方 API Key 值,而非变量名。VS Code 将受保护的输入与工作区文件分开存储。 通过 **Configure Tools** 打开聊天工具选择器,确认所选的已授权工具显示在 AISIX 服务器下。对于 Everything 测试服务,应仅显示 `everything__echo`,且 MCP 输出日志应报告发现了一个工具。 ## 验证工具调用[​](#验证工具调用 "验证工具调用的直接链接") 以下提示词使用设置指南中的 Everything 测试服务。对于现有 MCP 服务器,请替换为已授权的工具名称、有效参数和预期结果。在 VS Code Agent 聊天中明确要求使用指定工具,不要依赖自动工具选择: ``` 使用 MCP 工具 everything__echo,消息为 "hello through AISIX"。原样返回工具结果。 ``` 如果 VS Code 请求确认,请审查并批准此次调用。使用 Everything 测试服务时,结果应为: ``` Echo: hello through AISIX ``` 确认完整路径: * VS Code 显示已授权工具,不显示调用方有效授权范围之外的工具。对于此测试服务,应仅显示 `everything__echo`。 * [AISIX MCP 可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md)记录预期调用方 API Key 和服务器的一次成功 `tools/call`。 * VS Code 显示经由 AISIX 返回的工具结果。 工具发现成功说明连接和调用方授权正常,但不能证明模型会选择工具,也不能证明 VS Code 的批准策略允许执行。因此,仍需保留显式工具调用测试。 ## VS Code 故障排查[​](#vs-code-故障排查 "VS Code 故障排查的直接链接") | 现象 | 检查项 | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | VS Code 未启动服务器 | 信任预期工作区,运行 **MCP: List Servers**,并启动 `aisix`。使用 **Show Output** 检查 MCP 连接日志。 | | VS Code 返回 `401` | 确认受保护的输入包含 AISIX 调用方 API Key,而非上游 MCP 凭证。 | | 连接成功但未显示工具 | 按照[工具访问故障排查](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md#troubleshoot-tool-access)检查服务器和有效授权。更改授权后,运行 **MCP: Reset Cached Tools**。 | | 工具已显示,但 Agent 未调用它 | 明确指定所选工具的名称,通过 **Configure Tools** 启用它,并检查工具批准策略。对于测试服务,请选择 `everything__echo`。 | | Agent Host 无法使用服务器 | 交互式 `${input:...}` 值不会转发给 Agent Host。请使用其可移植 MCP 配置和非交互式密钥来源。 | ## 下一步[​](#下一步 "下一步的直接链接") * [客户端身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/client-authentication.md):使用网关 API Key、OAuth 登录,或在适合的可信网络中使用匿名访问。 * [控制工具访问](https://docs.apiseven.com/ai-gateway/mcp-gateway/tool-access-control.md):授权具体工具、符合服务器名称模式的工具,或所有已注册工具。 * [可观测性](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md):按调用方、服务器、工具和结果检查 MCP 调用。 --- # 模型别名 模型别名为调用方提供稳定的名称,同时由 AISIX 控制请求如何到达上游模型。 每个 AISIX 模型资源都通过 `display_name` 定义面向调用方的别名,并定义该别名背后的分发路径。直接模型通过一个服务提供方密钥将别名映射到一个上游模型。路由模型、语义模型和合议模型则是虚拟模型别名,会在请求时解析为一个或多个直接模型。 请先为 AISIX 可以调用的上游创建直接模型。仅当面向调用方的别名需要选择目标或合成响应时,才添加虚拟模型。 ## 选择模型形态[​](#choose-a-model-shape "选择模型形态的直接链接") AISIX 支持以下分发形态。选择一种形态即可打开相应的配置说明。向量嵌入模型与直接模型采用相同的分发方式,只是额外包含向量元数据;它不属于虚拟分发形态。 | 模型形态 | AISIX 如何处理请求 | 适用场景 | | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------- | | [直接模型](#create-a-direct-model) | 通过一个服务提供方密钥调用一个上游模型。 | 别名仅有一个上游目标。 | | [向量嵌入模型](https://docs.apiseven.com/ai-gateway/routing/semantic-routing.md#configure-a-semantic-router) | 调用支持向量嵌入的上游,并记录用于语义比较的向量元数据。 | 语义路由器需要向量嵌入模型。 | | [路由模型](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md) | 通过故障转移、轮询、权重、成本、延迟或负载选择一个直接模型目标。 | 一个稳定别名需要分发流量,或在目标故障时继续服务。 | | [语义模型](https://docs.apiseven.com/ai-gateway/routing/semantic-routing.md) | 对最新的用户消息进行向量嵌入,并根据语义选择一个直接模型目标。 | 不同主题需要到达不同模型,且调用方不应自行路由。 | | [合议模型](https://docs.apiseven.com/ai-gateway/routing/ensemble-models.md) | 调用多个直接模型作为合议成员,再由一个直接评审模型合成单一响应。 | 一个回答需要综合多个模型的响应。 | 一个模型资源只能包含一种分发形态:直接上游字段、`routing` 块、`semantic` 块或 `ensemble` 块。AISIX Cloud 通过资源 ID 引用服务提供方密钥和其他模型;开源 AISIX 网关则通过 `display_name` 在 `resources.yaml` 中引用这些资源。两种管理方式都会拒绝混用多种形态的资源。 直接模型将上游模型记录在 `model_name` 中。即使没有向量嵌入元数据,它也可以处理 `/v1/embeddings`。只有当模型用于支持语义路由时,才添加 `embedding` 块;相关配置流程请参阅[语义路由](https://docs.apiseven.com/ai-gateway/routing/semantic-routing.md)。有关受支持的服务提供方和调用方请求格式,请参阅[向量嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 开始前,请准备以下资源: * 为模型将使用的每个上游凭据创建一个[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md)。 * 对于 AISIX Cloud,需要有权访问一个环境、一台已接入的网关,以及具有写权限范围的 Admin Token。服务提供方密钥必须允许目标环境,并且你需要取得其资源 ID。对于本地部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请混合云访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,需要一台加载了声明式资源文件的网关,且该文件中已包含服务提供方密钥。模型通过该密钥的 `display_name` 引用它。 ## 创建直接模型[​](#create-a-direct-model "创建直接模型的直接链接") 直接模型将一个面向调用方的别名映射到一个上游模型。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 导出 AISIX Cloud 连接信息和服务提供方密钥 ID: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且末尾不要带斜杠。 # 本地部署快速入门使用 http://localhost:8080/api。 export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" export PROVIDER_KEY_ID="YOUR_PROVIDER_KEY_ID" ``` 使用准备好的服务提供方密钥 ID 创建直接模型: ``` curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gpt-4o-prod", "model_name": "gpt-4o", "provider_key_id": "'"$PROVIDER_KEY_ID"'" }' ``` 每个成功的模型创建请求都会在同一个响应信封中返回已创建的资源。以下示例展示直接模型的响应: ``` { "model": { "id": "677c847f-d92d-4f0e-b445-8b449764f06a", "env_id": "YOUR_ENVIRONMENT_ID", "kind": "direct", "display_name": "gpt-4o-prod", "model_name": "gpt-4o", "provider_key_id": "YOUR_PROVIDER_KEY_ID", "created_at": "2026-06-24T12:18:39Z", "updated_at": "2026-06-24T12:18:39Z" } } ``` 复制高亮显示的 `id`。路由模型、语义模型和合议模型会通过这个 ID 引用其他模型;之后更新、查看或删除模型时也需要使用它。其他模型形态的示例会省略这个通用响应。 `display_name` 是调用方在 `model` 中发送的名称。`model_name` 是 AISIX 发送给服务提供方的上游模型 ID 或部署名称。两者可以相同,也可以不同。上游服务提供方由被引用的服务提供方密钥决定。 在控制台中,**上游模型 ID** 字段会根据所选服务提供方密钥,建议目录中发布的模型。点击字段中的箭头打开建议列表,或输入内容进行筛选。该字段仍可接受任意值。对于预览模型、私有部署或其他未在目录中列出的模型,请原样输入 ID。[自定义模型服务](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)的服务提供方密钥没有目录条目,因此该字段会保持为纯文本输入框。 ### 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 将模型添加到 [`models` 集合](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#models),并按名称引用服务提供方密钥: resources.yaml(模型别名) ``` models: - display_name: gpt-4o-prod provider: openai model_name: gpt-4o provider_key: openai-prod ``` `display_name` 仍是调用方在 `model` 中发送的别名,`model_name` 则是上游模型 ID。模型条目需要显式声明 `provider`,并按名称引用服务提供方密钥。验证并重新加载完整资源文件以应用该模型。 ## 使用通配符匹配模型名称[​](#match-model-names-with-a-wildcard "使用通配符匹配模型名称的直接链接") 如果模型别名的 `display_name` 包含一个 `*`,它就会匹配所有符合该模式的请求模型名称。因此,一个别名便可代理多个上游模型,无需为每个名称分别创建资源。 通配符别名属于直接模型。将 `model_name` 设置为 `*` 可把匹配部分转发给上游;也可以使用固定值,将所有匹配请求发送到同一个上游模型。 对于 AISIX Cloud,使用先前准备的服务提供方密钥创建通配符模型: ``` curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openai/*", "provider_key_id": "'"$PROVIDER_KEY_ID"'", "model_name": "*" }' ``` 使用此别名时,请求 `openai/gpt-4o` 会使用上游模型 `gpt-4o`,请求 `openai/o3-mini` 则使用 `o3-mini`。精确别名始终优先于通配符别名;如果有多个通配符匹配,则最具体的通配符优先。 把返回的模型 ID 添加到调用方 API Key 的 `allowed_models` 列表。通配符别名是模式而不是具体模型名称,因此不会出现在 `GET /v1/models` 中。 对于开源网关,选择一个独立的调用方 API Key 值,并使网关进程能够访问它: ``` export WILDCARD_CALLER_KEY="YOUR_CALLER_API_KEY" ``` 将 `openai/*` 添加到现有的 `models` 集合,并将 `wildcard-caller` 添加到 `api_keys`。保留无关条目和集合: resources.yaml(通配符模型访问) ``` models: - display_name: openai/* provider: openai provider_key: openai-prod model_name: "*" api_keys: - display_name: wildcard-caller key_env: WILDCARD_CALLER_KEY allowed_models: - openai/* ``` 加载前请验证组装后的完整文件。如果正在运行的网关进程尚未获得 `WILDCARD_CALLER_KEY`,请使用新变量重启或重新创建网关,而不是就地重新加载。 ## 配置可选模型行为[​](#configure-optional-model-behavior "配置可选模型行为的直接链接") 大多数直接模型只需要面向调用方的别名、上游模型名称和服务提供方密钥引用。只有当某项行为属于流量方案的一部分时,才添加相应的可选字段。 常用可选字段包括: * `timeout`:服务提供方请求需要更严格的单次请求超时时使用。 * `stream_timeout`:流式请求需要单独的分块读取超时时使用。 * `retries`:模型在遇到可重试的上游失败后需要重试特定次数时使用。请参阅[重试预算](#retry-budget)。 * `allowed_cidrs`:只有来自特定客户端 IP 范围的调用方可以使用模型别名时使用。 * `background_model_check`:AISIX 需要在请求路径之外探测直接模型,并在探测失败后将其标记为不健康时使用。 * `cooldown`:实际请求失败后需要暂时将直接模型排除在路由之外时使用。 * [`effort_mapping`](https://docs.apiseven.com/ai-gateway/models/reasoning-effort-mapping.md):调用方与上游模型使用不同的推理力度值时使用。 * `rate_limit`:限流需要应用于单个模型别名时使用。详情请参阅 [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md)。 路由模型使用所选目标的服务提供方设置、超时、健康状态和冷却行为。语义路由器使用所选目标及其向量嵌入模型上的设置,并在选路时同样执行目标自身的门禁:调用方 IP 无法访问的路由目标会回落到默认目标,同时清除 `x-aisix-route` 响应头;路由目标与默认目标都被排除时,返回与直接调用模型相同的 `403`;处于冷却中或被后台健康检查标记为不健康的目标,会被可用的默认目标顶替。向量嵌入子调用的截止时间依次取路由器的 `embedding_timeout_ms`、向量嵌入模型自身的 `timeout`、部署级默认值。语义路由器自身的 `retries` 也是重试链中的组级槽位,请参阅[重试预算](#retry-budget)。合议模型使用合议成员模型和评审模型上的设置。请在被引用的直接模型上配置服务提供方设置、健康状态和冷却行为,而不要在虚拟模型别名上配置。 无论模型以何种方式被使用,`allowed_cidrs` 都会生效,包括它作为[路由模型](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md)目标时。范围之外的调用方既不能直接访问该模型,也不能通过路由模型访问。除非通过 `proxy.real_ip` 配置信任负载均衡器或 Ingress 转发的请求头,否则 AISIX 会从直接对端解析客户端 IP。 ## 重试预算[​](#retry-budget "重试预算的直接链接") `retries` 表示 AISIX 在遇到可重试的上游失败(例如 `5xx` 响应或传输错误)后,对一个模型发起的额外尝试次数。AISIX 会将此预算用于 Chat Completions、Text Completions、Messages、Count Tokens 和 Responses。它还适用于向量嵌入、Rerank、音频、图片生成、视频提交和状态轮询,以及合议模型发起的直接模型调用。无论模型单独使用还是作为路由目标使用,该设置都会生效。 重试预算不适用于 Realtime、[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),也不适用于文件、批处理和微调 API。透传路由把每个请求作为单次上游尝试中继。它可能会将上游失败返回给调用方,但该失败不会将已配置模型标记为进入冷却状态,也不会根据此模型设置重复请求。 AISIX 按以下优先级为每次尝试确定预算: | 来源 | 适用条件 | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | 模型上的 `retries` | 模型设置了该字段。即使该模型作为路由模型的目标,且路由模型也设置了 `retries`,此处仍优先。 | | 路由模型上的 `routing.retries` | 目标没有设置 `retries`。它作为组级默认值应用于每个目标。 | | 语义路由器上的 `retries` | 分发的路由目标没有设置 `retries`,且请求经由语义路由器。路由器顶层的值填充的组级槽位与模型组上的 `routing.retries` 相同。 | | 网关配置文件中的 `upstream.retries` | 以上均未设置。默认值为 `2`。请参阅[启动配置参考](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md)。 | 将 `retries: 0` 设为模型的值可关闭重试。无论在哪一层,`0` 都是显式设置,绝不表示该字段未设置。 以下两条规则仅适用于部署级默认值。无论在模型层还是路由层显式配置的预算,都会始终按所写值应用。 * **存在其他目标。** 当路由模型仍有其他目标可尝试且未配置 `retries` 时,AISIX 会转到下一个目标,而不会重复尝试当前目标。重复请求一个失败的目标只会延迟故障转移,无法改善结果。列表中的最后一个目标无处可转,因此会应用默认值。 * **请求超时。** 未显式配置的预算不会消耗在 `timeout` 上。`timeout` 是对等待模型时间的主动限制,重复尝试会成倍增加等待时间,通常仍得到相同结果。如果需要在超时后重试,请在模型上配置 `retries`。无论是否配置重试,超时都会触发到另一个目标的故障转移。 每次重试都会重新发送完整请求体,且 AISIX 的重试发生在服务提供方边缘自身可能进行的重试之外。在高流量模型上提高预算前,请计算合计的上游尝试次数。 在视频提交调用中,如果服务提供方已经返回响应状态,则非幂等请求绝不会重试。此时响应体丢失或无效意味着操作已在上游提交,重放会造成重复写入。连接或发送阶段的失败仍可在所有端点重试。 ## 成本元数据[​](#cost-metadata "成本元数据的直接链接") 成本会影响用量报告、预算检查和 `least_cost` 路由;不会影响服务提供方路由或访问控制。 在 AISIX Cloud 部署中,控制面会从定价目录和组织级覆盖项中解析单次请求成本。如需为目录尚未覆盖的模型设置价格,请参阅[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)。 对于开源 AISIX 网关,请通过模型上的 `cost` 字段在 `resources.yaml` 中记录成本元数据。该字段以每 1,000 个 Token 的美元价格记录输入和输出成本: ``` models: - display_name: gpt-4o-prod provider: openai model_name: gpt-4o provider_key: openai-prod cost: input_per_1k: 0.0025 output_per_1k: 0.01 ``` 有关从 `resources.yaml` 文件运行网关的方法,请参阅[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)。 ## 下一步[​](#下一步 "下一步的直接链接") 至此,你已经配置了面向调用方的模型别名。接下来,请参阅[调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md),允许应用使用该别名并通过代理进行验证。 --- # 服务提供方密钥轮换 轮换服务提供方密钥会替换 AISIX 访问上游服务提供方时使用的凭证。调用方无需修改调用方 API Key 或模型别名。 如果所有依赖模型都可以同时切换到新凭证,请原地轮换服务提供方密钥。如果希望逐步迁移模型,并保留旧凭证用于回滚,请创建替代服务提供方密钥。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前请准备: * 替代上游凭证。 * 使用该服务提供方密钥的全部模型清单。服务提供方密钥是共享依赖,原地修改会影响所有依赖模型。 * 对于 AISIX Cloud,需要管理服务提供方密钥和模型的权限。 * 对于开源 AISIX 网关,需要访问网关进程环境和声明式资源文件。 * 如果替换凭证的同时还会更改上游端点或协议,请查看[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 选择轮换策略[​](#选择轮换策略 "选择轮换策略的直接链接") | 策略 | 影响 | 适用场景 | | ------------------ | ------------------------------------------------ | ---------------------------------------------- | | 原地轮换 | 保留服务提供方密钥引用,并同时切换所有依赖模型。 | 可以快速验证替代凭证,并接受一次协调切换。 | | 替代服务提供方密钥 | 在模型迁移到新密钥期间保留两套凭证。 | 需要渐进发布、逐模型验证或简单直接的回滚路径。 | ## 在 AISIX Cloud 中轮换服务提供方密钥[​](#在-aisix-cloud-中轮换服务提供方密钥 "在 AISIX Cloud 中轮换服务提供方密钥的直接链接") AISIX Cloud 将服务提供方凭证作为只写密钥存储。读取操作绝不会返回已存储凭证。更新现有服务提供方密钥的密钥会保留其 ID,因此依赖模型无需更改。 只要模型别名保持不变,调用方无需获得新的调用方 API Key,应用也无需修改模型别名。 ### 原地轮换[​](#原地轮换 "原地轮换的直接链接") 在控制台中: 1. 打开 **Provider keys**,并在目标密钥上选择 **Edit**。 2. 在 **Upstream API key** 中输入替代值。该字段为空,因为控制面不会返回已存储密钥;留空会保留当前值。对于包含多个凭证字段的服务提供方,请提供所有必填字段,并在存在替代方案时选择一种凭证方式。凭证会整体替换,而不是逐字段替换。 3. 选择 **Save**。控制面会加密替代凭证,并将其下发到允许使用该密钥的每个环境。关于保存的配置如何成为有效网关配置,参见[资源下发](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md)。 4. 通过每个受影响模型发送请求,确认上游接受新凭证。 要自动执行相同操作,请使用具有写入权限的 [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md)。完整请求和响应 Schema 参见 [AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)。 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;请包含 /api,且不要以斜杠结尾。 # 本地 On-Premises 快速入门使用 http://localhost:8080/api。 export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export PROVIDER_KEY_ID="YOUR_PROVIDER_KEY_ID" ``` 通过 `api_key` 发送替代明文密钥: ``` curl -sS -X PATCH "$AISIX_CP/provider_keys/$PROVIDER_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "api_key": "YOUR_NEW_UPSTREAM_API_KEY" }' ``` 省略 `api_key` 会保留已存储密钥,空值会被拒绝。 对于包含多个凭证字段的服务提供方,请在 `config` 中发送完整替代凭证。以下示例轮换 Amazon Bedrock 凭证: ``` curl -sS -X PATCH "$AISIX_CP/provider_keys/$PROVIDER_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "config": { "access_key_id": "YOUR_NEW_ACCESS_KEY_ID", "secret_access_key": "YOUR_NEW_SECRET_ACCESS_KEY", "region": "us-west-2" } }' ``` 结构化凭证会整体替换,因此请包含服务提供方要求的每个字段。例如,Google Vertex AI 要求提供 `project`、`region`,并且必须在 `access_token` 和 `service_account_json` 中二选一。 警告 原地轮换会让所有依赖模型切换到替代凭证。如果凭证无效,这些模型会持续失败,直到提供可用凭证。需要在验证期间保留旧凭证时,请使用替代服务提供方密钥。 ### 使用替代服务提供方密钥轮换[​](#使用替代服务提供方密钥轮换 "使用替代服务提供方密钥轮换的直接链接") 在控制台中: 1. 使用与旧密钥相同的服务提供方和端点设置创建新的服务提供方密钥,但提供替代凭证。对于自定义上游,请选择相同的适配器。 2. 允许替代密钥在所有受影响环境中使用。 3. 编辑每个受影响模型并选择替代服务提供方密钥。下拉列表只显示目标环境允许使用的服务提供方密钥。如果没有显示替代密钥,请先更新其允许环境。 4. 配置下发到网关后,通过迁移后的模型发送实际请求。如果保存的变更尚未到达网关,请参见[资源下发](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md)。 5. 只有在所有依赖模型完成迁移并验证替代凭证后,才删除旧服务提供方密钥。 以下 API 示例迁移一个环境中的模型。如果旧服务提供方密钥跨环境共享,请在所有受影响环境中允许替代密钥,并在删除旧密钥前迁移所有依赖模型。除直接模型外,还要包含语义路由使用的 Embedding 模型。 导出 AISIX Cloud 连接信息和受影响资源 ID: ``` # AISIX_CP 是 Admin API 基础 URL;请包含 /api,且不要以斜杠结尾。 # 本地 On-Premises 快速入门使用 http://localhost:8080/api。 export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" export MODEL_IDS="YOUR_MODEL_ID_1 YOUR_MODEL_ID_2" export OLD_PROVIDER_KEY_ID="YOUR_OLD_PROVIDER_KEY_ID" ``` 创建替代服务提供方密钥,并复制返回的 ID: ``` curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- <<EOF { "provider": "openai", "display_name": "OpenAI replacement", "api_key": "YOUR_NEW_UPSTREAM_API_KEY", "allowed_environments": ["${ENV_ID}"] } EOF ``` 对于自定义上游,请包含该服务提供方密钥类型所需的端点和适配器。 导出替代 ID,然后更新每个受影响模型: ``` export REPLACEMENT_PROVIDER_KEY_ID="YOUR_REPLACEMENT_PROVIDER_KEY_ID" for MODEL_ID in $MODEL_IDS; do curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/models/$MODEL_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- <<EOF { "provider_key_id": "${REPLACEMENT_PROVIDER_KEY_ID}" } EOF done ``` 所有受影响模型都使用替代凭证成功后,删除旧服务提供方密钥: ``` curl -sS -X DELETE "$AISIX_CP/provider_keys/$OLD_PROVIDER_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 如果仍有模型引用该服务提供方密钥,删除它会导致这些模型无法成功分发请求。删除前请重新绑定每个依赖模型。 ## 在开源 AISIX 网关中轮换服务提供方密钥[​](#在开源-aisix-网关中轮换服务提供方密钥 "在开源 AISIX 网关中轮换服务提供方密钥的直接链接") 资源文件通过 `display_name` 引用服务提供方密钥。网关加载文件时解析环境变量,因此只修改 Shell 中的变量不会更新已运行的网关进程。 ### 原地轮换[​](#原地轮换-1 "原地轮换的直接链接") 检查现有模型服务提供方 Key 条目并保持其不变。轮换通过替换该条目引用的环境变量值完成: resources.yaml(模型服务提供方 Key) ``` provider_keys: - display_name: openai-prod provider: openai adapter: openai api_key: ${OPENAI_API_KEY} api_base: https://api.openai.com/v1 ``` 在启动网关使用的环境中替换 `OPENAI_API_KEY`,然后重启或重新创建网关,使进程获得新值。由于服务提供方密钥名称仍是 `openai-prod`,模型引用无需更改。 ### 使用替代服务提供方密钥轮换[​](#使用替代服务提供方密钥轮换-1 "使用替代服务提供方密钥轮换的直接链接") 让网关进程可以访问两套凭证。将 `openai-replacement` 添加到 `provider_keys`,然后替换 `gpt-4o-prod` 模型条目。保持 `openai-prod` 和其他资源不变: resources.yaml(替代模型服务提供方 Key 与模型) ``` provider_keys: - display_name: openai-replacement provider: openai adapter: openai api_key: ${OPENAI_API_KEY_NEW} api_base: https://api.openai.com/v1 models: - display_name: gpt-4o-prod provider: openai model_name: gpt-4o provider_key: openai-replacement ``` 替代项是独立的服务提供方密钥。复制旧条目中所有适用的非密钥字段,包括 `provider`、`adapter`、`api_base`、`strip_headers`、`telemetry_tags`、`request` 和 `response`。除非有意修改其他设置,否则只更改 `display_name` 和凭证引用。 如果替代环境变量此前对网关进程不可用,请重启或重新创建网关。要分阶段迁移模型,请在文件中同时保留两个服务提供方密钥,将选定模型的引用改为 `openai-replacement`,并在每批迁移后验证和重新加载文件。只有在没有模型引用 `openai-prod`,且所有迁移模型的实际请求均成功后,才删除它。 ## 验证轮换[​](#验证轮换 "验证轮换的直接链接") 用于验证模型的网关请求与其管理方式无关。对每个受影响模型: 1. 使用已授权的调用方 API Key,通过面向调用方的别名发送代表性实际请求。 2. 使用模型正常提供服务的端点和请求格式。例如,应通过 `/v1/embeddings` 验证 Embedding 模型,而不是使用 Chat Completions 端点。 3. 确认上游接受替代凭证并返回预期响应。 使用替代服务提供方密钥时,请在删除旧密钥前确认每个受影响模型都已引用新密钥。在 AISIX Cloud 中,可以通过[请求日志](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md#request-logs)检查验证请求;如果保存的变更尚未到达网关,请查看[资源下发](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md)。对于开源网关,重新加载资源文件后请检查[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已经在不改变调用方访问方式的情况下轮换了服务提供方凭证。将模型迁移到其他上游前,请继续阅读[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md),比较支持的请求路径和适配器行为。 --- # 服务提供方密钥 创建服务提供方密钥,用于保存 AISIX 解析模型别名后访问上游所需的凭证和端点设置。在 AISIX Cloud 中,模型通过 ID 引用服务提供方密钥;在开源 AISIX 网关中,`resources.yaml` 里的模型通过 `display_name` 引用。两种方式都能避免在应用代码中保存上游凭证,并允许多个别名复用同一个凭证。 创建示例涵盖两种管理方式。字段和行为章节会说明 AISIX Cloud Admin API 与声明式资源文件之间的重要差异。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前请准备: * 上游服务提供方凭证。 * 对于 AISIX Cloud,需要环境访问权限和具有写入权限的 Admin Token。对于 On-Premises 部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,需要一个加载声明式资源文件的网关。[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)提供了可运行的配置和重新加载流程。 ## 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 根据部署使用的管理方式配置凭证。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 创建服务提供方密钥,并保存返回的 ID 供模型配置使用。 服务提供方密钥的作用域是组织。`allowed_environments` 列出创建模型时可以引用该密钥的环境,因此请包含模型所在环境。 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;请包含 /api,且不要以斜杠结尾。 # 本地 On-Premises 快速入门使用 http://localhost:8080/api。 export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 以下示例创建一个 OpenAI 服务提供方密钥: ``` # 请替换为实际值 export OPENAI_API_KEY="YOUR_OPENAI_API_KEY" curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openai-prod", "provider": "openai", "api_key": "'"${OPENAI_API_KEY}"'", "api_base": "https://api.openai.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' ``` 你应该会看到类似以下的响应: ``` { "provider_key": { "id": "db8613ea-2ecd-40e4-91aa-08197119f766", "org_id": "3f1c2b6a-9d4e-4c1f-8a2b-5e6d7c8f9a0b", "provider": "openai", "display_name": "openai-prod", "allowed_environments": ["9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d"], "strip_headers": null, "telemetry_label": "openai-prod", "created_at": "YYYY-MM-DDTHH:MM:SSZ", "updated_at": "YYYY-MM-DDTHH:MM:SSZ" } } ``` 创建响应不包含 `api_base`;使用 `GET $AISIX_CP/provider_keys/{id}` 获取该密钥,即可查看端点覆盖值。 复制高亮的 `id` 并将其导出。创建[模型](https://docs.apiseven.com/ai-gateway/models/model-aliases.md)时会将其用作 `provider_key_id`: ``` export PROVIDER_KEY_ID="YOUR_PROVIDER_KEY_ID" ``` 该操作只创建上游凭证资源。要通过 AISIX 发送流量,还需把服务提供方密钥关联到模型、在调用方 API Key 上允许该模型,并使用调用方 API Key 发送代理请求。 ### 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 在资源文件的 [`provider_keys` 集合](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#provider-keys)中添加服务提供方密钥。请通过环境变量提供凭证,不要把明文密钥写入 YAML: ``` export OPENAI_API_KEY="YOUR_OPENAI_API_KEY" ``` 将以下条目添加到完整资源文件的 `provider_keys` 中: resources.yaml(模型服务提供方 Key) ``` provider_keys: - display_name: openai-prod provider: openai adapter: openai api_key: ${OPENAI_API_KEY} api_base: https://api.openai.com/v1 ``` 模型通过该密钥的 `display_name`(即 `openai-prod`)进行引用。应用前请验证完整的资源文件。如果运行中的网关进程已经能够访问 `OPENAI_API_KEY`,请按照[重新加载资源文件](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md#reload-a-resources-file)操作。如果刚刚新增该变量,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md#start-aisix-ai-gateway)中的启动命令,使用 `-e` 传入该变量,再重新创建网关,使进程能够解析它。 ## 设置服务提供方和适配器[​](#设置服务提供方和适配器 "设置服务提供方和适配器的直接链接") 服务提供方密钥将上游身份与上游 API 格式分开。 在 AISIX Cloud 中,服务提供方用于标识上游厂商或端点。它不是任意字符串:`provider` 必须是 AISIX 服务提供方目录 ID(例如 `openai`、`anthropic` 或 `deepseek`),或表示自定义端点的保留值 `byo`。该目录包含 AISIX 原生集成和来自 [models.dev](https://models.dev) 的社区条目。对于开源 AISIX 网关,`resources.yaml` 中的 `provider` 是开放标签,`adapter` 用来选择已经实现的协议族。 适配器标识 AISIX 应使用的上游 API 格式。它是封闭取值,因为 AISIX 只能编码已经实现的协议族,例如 `openai`、`anthropic`、`bedrock`、`vertex` 和 `azure-openai`。 对于 AISIX Cloud 目录中的服务提供方,控制面会根据目录条目推导适配器;发送 `adapter` 字段会返回 400 错误。上面的 OpenAI 示例只设置 `provider: "openai"`,控制面会推导 OpenAI 适配器。DeepSeek 等提供 OpenAI 兼容 API 的目录服务提供方也采用相同方式:设置 `provider`,并在需要时设置 `api_base`: ``` { "provider": "deepseek", "api_base": "https://api.deepseek.com" } ``` 对于不在 AISIX Cloud 目录中的私有或 OpenAI 兼容端点,将 `provider` 设置为 `byo`,显式选择 `adapter`,并配置 BYO 密钥必需的 `api_base`: ``` { "provider": "byo", "adapter": "openai", "api_base": "https://api.example.com/v1" } ``` AISIX Cloud Admin API 不允许修改现有 BYO 服务提供方密钥的适配器。请使用所需适配器创建新的服务提供方密钥,并更新依赖模型。对于开源 AISIX 网关,修改 `resources.yaml` 中服务提供方密钥条目的适配器并重新加载配置即可。 适配器选择详情参见[适配器协议族](https://docs.apiseven.com/ai-gateway/providers/adapters.md)。 ## 配置基础 URL[​](#配置基础-url "配置基础 URL的直接链接") `api_base` 控制 AISIX 默认发送上游请求的位置。请按所选适配器预期的格式配置。如果上游在另一条路径上还提供了第二种协议,可以单独声明该路径,见[声明 API 协议面](#declare-the-api-surfaces)。AISIX Cloud 可在目录存在默认值时自动提供;开源网关只会为设置指南中明确说明的服务提供方推导端点。 常见示例如下: | 上游 API | 适配器 | 基础 URL | | ---------------------- | -------------- | --------------------------------------------------------- | | OpenAI | `openai` | `https://api.openai.com/v1` | | DeepSeek | `openai` | `https://api.deepseek.com` | | Gemini OpenAI 兼容 API | `openai` | `https://generativelanguage.googleapis.com/v1beta/openai` | | Anthropic | `anthropic` | `https://api.anthropic.com` | | Azure OpenAI | `azure-openai` | `https://<resource>.openai.azure.com` | | AWS Bedrock | `bedrock` | `https://bedrock-runtime.<region>.amazonaws.com` | | Google Vertex AI | `vertex` | `https://<region>-aiplatform.googleapis.com` | 对于 Bedrock,AISIX Cloud Admin API 要求把区域运行时端点作为 `api_base`。开源 AISIX 网关在标准 AWS 环境中可以省略该值,让 AWS SDK 根据 `region` 推导端点。 AISIX 会规范化常见的复制错误,例如末尾斜杠和完整端点路径,但不会猜测任意服务提供方的 URL 布局。对于私有模型服务、企业代理或自定义端点,请显式配置 `api_base`。 ## 声明 API 协议面[​](#declare-the-api-surfaces "声明 API 协议面的直接链接") `api_base` 只能指向一个端点,适配器也只表示一种协议。有两类常见上游不符合这个形状: * **一份凭证、两种协议。** 部分服务提供方(包括 DeepSeek)会在同一个主机上以同一份凭证提供 OpenAI 兼容路径和 Anthropic 兼容路径。只能到达 `api_base` 指向的那条路径,就意味着另一种协议的请求全部要经过转换,而转换会丢掉该协议独有、聊天格式没有的东西——Anthropic 的提示词缓存断点和思考块都在其中。 * **没有 Responses API 的 OpenAI 兼容端点。** 很多自建端点和中转端点只实现了 `/v1/chat/completions`。Responses API 是 chat completions 的超集而不是改名,因此适配器无法说明该路由是否存在。把 Codex 的请求转发到端点没有实现的路由,只会得到上游返回的 404。 用 `apis` 声明该端点原生提供哪些协议面、分别在哪个地址。每一项都可以带自己的 `base`,格式要求与 `api_base` 相同;该协议面就在 `api_base` 上时省略 `base` 即可。 ``` { "provider": "deepseek", "api_base": "https://api.deepseek.com", "apis": { "responses": {}, "messages": { "base": "https://api.deepseek.com/anthropic" } } } ``` 这里列出 `responses` 是因为该端点就在 `api_base` 上提供它。不写它并不表示「保持原样」——那是在声明该端点没有这个接口,Responses 请求会改为被转换。 配置成这样之后,走 `/v1/chat/completions` 的调用方到达 `https://api.deepseek.com/chat/completions`,走 `/v1/messages` 的调用方原样到达 `https://api.deepseek.com/anthropic/v1/messages`,走 `/v1/responses` 的调用方到达 `https://api.deepseek.com/v1/responses`,三者用的是同一个模型名。 可以声明两个协议面: | 协议面 | 路由 | 解析规则 | | ----------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `responses` | `/v1/responses` | 只认声明。一旦存在 `apis`,只有列出该协议面时 AISIX 才会原生转发 Responses 请求。不列出它,就是在告诉 AISIX 该端点没有这个路由,请求会改为转换成 chat completions。 | | `messages` | `/v1/messages`、`/v1/messages/count_tokens` | 增量声明。适配器为 `anthropic` 的密钥无论 `apis` 是否列出都提供该协议面;列出它是为了给适配器是别的协议的密钥补上这两条路由。AISIX 会在两条路由上使用 `x-api-key` 发送服务提供方凭证,并添加 `anthropic-version`。 | 由于 `responses` 由声明决定,一个已有的 OpenAI 密钥如果因为别的原因新增了 `apis`,必须同时列出 `responses`,才能继续原生转发 Responses 请求。AISIX Cloud 控制台在你开启该分节时会按该密钥当前提供的协议面预填,因此默认是在现状基础上编辑。 只有当上游接受 Anthropic 身份认证请求头,并在同一个 API Base 上实现这两条路由时,才声明 `messages`。如果其原生 Messages API 需要 Bearer 身份认证,或不提供 `/v1/messages/count_tokens`,请改用经过身份认证的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)访问该 API。 部分目录服务提供方自带一份经过厂商线上端点验证的声明——DeepSeek 就是其中之一——指向该服务提供方自有 base 的密钥无需任何配置即可获得。该声明和其他字段一样存在密钥上:控制台打开该区块时已经填好,服务提供方密钥的详情响应会同时返回 `apis` 和 `apis_source: catalog`,因此 AISIX 替你声明了什么是可见的,而不是隐含的。自行设置 `apis` 会覆盖它,并报告 `apis_source: operator`——正是这一点让 AISIX 后续修正内置条目时不会动你自己选择的声明。用 `null` 清除该字段会回到内置声明,而不是变成没有任何声明。把 `api_base` 改指到你自己的端点则会使声明失效,因为它描述的是厂商的路径而不是你的。 对于不自带声明的服务提供方,完全不写 `apis`,所有协议面就继续按服务提供方和适配器解析,这也是所有没有该字段的密钥的行为。该字段不控制 Chat Completions、嵌入、音频、图片、视频、文件、批处理、微调或重排序;这些协议面一律使用 `api_base`。 `bedrock`、`vertex` 和 `azure-openai` 适配器不接受 `apis`。这些平台提供的是自己的路由而不是上述路由,所有请求都要经过转换才能到达。 ## 凭证处理[​](#credential-handling "凭证处理的直接链接") 服务提供方密钥保存敏感的上游凭证。在跨多个模型复用一个密钥前,请明确该上游凭证的负责人。 在 AISIX Cloud 中,`api_key` 只写。明文值在存储前加密,读取端点绝不会返回它。Bedrock 和 Vertex AI 的凭证包含多个字段,因此使用结构化 `config` 对象。创建这些服务提供方密钥时,将必需的 `api_key` 字段设置为空字符串,并通过 `config` 提供凭证。更新 `config` 时省略 `api_key`;更新请求会拒绝空的 `api_key`。 对于开源 AISIX 网关,请在 `resources.yaml` 中通过环境变量引用凭证,而不要保存明文密钥。结构化凭证需要序列化为 JSON 字符串,并通过服务提供方密钥的 `api_key` 字段提供。 服务提供方密钥是共享依赖。原地轮换会影响引用它的所有模型。无论使用哪种管理方式,都可以通过[服务提供方密钥轮换](https://docs.apiseven.com/ai-gateway/models/provider-key-rotation.md)在原地更新和渐进替换之间选择。 ## 配置服务提供方专用覆盖[​](#configure-provider-specific-overrides "配置服务提供方专用覆盖的直接链接") 服务提供方密钥覆盖用于适配与所选适配器略有差异的上游 API。引用该密钥的每个模型都会继承这些覆盖,因此只在需要时配置。 以下 AISIX Cloud Admin API 示例为自定义 OpenAI 兼容上游配置请求和响应兼容性: ``` export COMPAT_API_KEY="YOUR_UPSTREAM_API_KEY" curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "custom-openai-prod", "provider": "byo", "adapter": "openai", "api_key": "'"${COMPAT_API_KEY}"'", "api_base": "https://api.example.com/v1", "allowed_environments": ["'"${ENV_ID}"'"], "request": { "param_renames": { "max_completion_tokens": "max_tokens" } }, "response": { "reasoning_field": "delta.thinking" } }' ``` ❶ 当上游期望不同名称时,`request.param_renames` 会重命名顶层参数。如果请求同时包含两个名称,AISIX 使用原始调用方字段中的值。 ❷ `response.reasoning_field` 将非标准流式 `delta` 路径中的推理内容映射到 `delta.reasoning_content`。该覆盖适用于 `openai` 和 `azure-openai` 适配器。 对于开源 AISIX 网关,在资源文件的服务提供方密钥条目中添加相同的 `request` 和 `response` 配置块。 支持情况因适配器、请求路径和管理方式而异。[AISIX Cloud Admin API 参考](https://docs.apiseven.com/ai-gateway/reference/cloud-admin-api.md)定义控制面接受的覆盖。[资源文件参考](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#provider-keys)定义完整的开源字段目录。 `request` 对象还可以控制 AISIX 发送到上游的请求头。两种管理方式都支持 `request.default_headers` 生成调用团队等值,也支持 `request.forward_client_headers` 转发指定的调用方请求头。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md)。 ## 验证服务提供方密钥[​](#验证服务提供方密钥 "验证服务提供方密钥的直接链接") 通过使用该密钥的模型发送代表性请求,并确认上游接受该请求。如果配置了自定义 `reasoning_field`,请发送流式 Chat Completions 请求,并确认推理内容出现在 `delta.reasoning_content` 中。 在跨多个模型复用服务提供方密钥前,先使用非生产别名测试覆盖配置。错误覆盖会影响引用该密钥的所有模型。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 继续阅读[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md),将新的服务提供方密钥关联到面向调用方的别名。要替换现有模型使用的凭证,请按照[服务提供方密钥轮换](https://docs.apiseven.com/ai-gateway/models/provider-key-rotation.md)操作。 --- # 推理力度映射 支持推理的模型并不总是使用相同的力度取值。客户端可能发送 `medium`,而所选上游模型只接受 `high` 或 `max`。在直接模型上配置 `effort_mapping`,即可由网关改写这些值。 该映射默认关闭。仅当请求包含推理力度字符串,且该字符串与配置的键完全匹配时,AISIX 才会修改请求。 ## 映射的工作方式[​](#how-mapping-works "映射的工作方式的直接链接") AISIX 根据调用方使用的规范化端点,从以下位置读取推理力度: | 端点 | 请求字段 | | -------------------------------- | ---------------------- | | `POST /v1/chat/completions` | `reasoning_effort` | | `POST /v1/responses` | `reasoning.effort` | | `POST /v1/messages` | `output_config.effort` | | `POST /v1/messages/count_tokens` | `output_config.effort` | AISIX 选出最终的直接模型后、序列化服务提供方请求前,会执行一次区分大小写的精确查找。流式与非流式请求的行为相同;AISIX 在 OpenAI 与 Anthropic 请求格式之间转换时也会应用该映射。 对于以下映射: ``` { "medium": "high", "high": "max" } ``` * `medium` 会变为 `high`。AISIX 不会再次查找结果中的 `high`,因此不会继续变为 `max`。 * `high` 会变为 `max`。 * `low` 等未配置的值仍保持为 `low`。 * 未携带推理力度字段的请求保持不变;映射不会主动添加该字段。 映射属于最终的直接模型,而不是调用方请求的别名。当路由模型或语义路由器选择某个直接模型时,会应用该目标自身的映射。每个合议成员使用各自的映射,直接评审模型也会对合成请求应用自己的映射。不要在路由、语义、合议或向量嵌入模型资源上配置该字段;AISIX 会拒绝这些配置。 改写后仍受服务提供方和具体模型的能力限制。目标值只能使用所选上游模型接受的取值。对于不支持的值,服务提供方适配器可能根据其规范化端点行为进行转换、省略或拒绝。[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)不使用模型资源,因此不会应用推理力度映射。 ## 配置 AISIX Cloud[​](#configure-aisix-cloud "配置 AISIX Cloud的直接链接") 在控制台中创建或编辑直接模型,展开**推理力度映射**,然后逐项添加请求力度与上游力度。删除所有映射项并保存即可关闭映射。 也可以通过 Admin API 设置映射。以下请求创建一个直接模型,将 `medium` 改为 `high`,并将 `high` 改为 `max`: ``` curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "kind": "direct", "display_name": "reasoning-prod", "model_name": "YOUR_UPSTREAM_MODEL", "provider_key_id": "'"$PROVIDER_KEY_ID"'", "effort_mapping": { "medium": "high", "high": "max" } }' ``` 更新模型时,省略 `effort_mapping` 表示保持不变;发送 `null` 或空对象可将其清除: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/models/$MODEL_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"effort_mapping": null}' ``` ## 配置开源网关[​](#configure-the-open-source-gateway "配置开源网关的直接链接") 在完整的 [`resources.yaml`](https://docs.apiseven.com/ai-gateway/reference/resources-file.md) 快照中,为直接模型添加 `effort_mapping`: resources.yaml(直接模型) ``` models: - display_name: reasoning-prod provider: openai model_name: YOUR_UPSTREAM_MODEL provider_key: openai-prod effort_mapping: medium: high high: max ``` 省略 `effort_mapping` 或将其设为空对象即可关闭改写。 ## 发送请求[​](#send-a-request "发送请求的直接链接") 像往常一样调用模型,应用无需使用服务提供方专属的力度设置: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" curl -sS "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "reasoning-prod", "messages": [{"role": "user", "content": "Solve this problem."}], "reasoning_effort": "medium" }' ``` 对于此请求,AISIX 会向所选直接模型发送 `high`。 --- # 资源模型 AISIX 网关通过一组精简资源,将调用方请求转换为已完成上游认证的服务提供方请求。 核心资源包括调用方 API Key、模型和服务提供方密钥。当你需要目标选择、响应合成、限流、安全护栏、缓存、可观测性或 AISIX Cloud 预算检查时,可以在这条链路上继续叠加虚拟模型形态和策略资源。 ## 核心流量资源[​](#核心流量资源 "核心流量资源的直接链接") 大多数 AISIX 流量都从三个资源开始:调用方 API Key、模型和服务提供方密钥。它们共同决定谁可以调用网关、调用方可以使用哪个模型别名,以及 AISIX 会调用哪个上游服务提供方。对于单目标模型,AISIX Cloud 与开源 AISIX 网关都遵循相同的关系: 不同产品管理和引用这些资源的方式不同: | 产品 | 管理关系 | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | AISIX Cloud | 调用方 API Key 和模型属于某个环境,并通过 ID 引用相关资源。服务提供方密钥属于组织,且必须允许目标环境使用。控制面会将生成的配置投射到已挂载的网关。 | | 开源 AISIX 网关 | 所有资源在 `resources.yaml` 中声明。调用方 API Key 引用模型的 `display_name`,模型引用服务提供方密钥的 `display_name`。 | 在 AISIX Cloud 中,通过控制台或 Admin API 创建或更新每个资源,然后使用[资源投射](https://docs.apiseven.com/ai-gateway/cloud/resource-projection.md)确认更改已到达网关。在开源网关中,请校验完整资源文件,并将其作为一个配置快照重新加载。如果重新加载失败,网关会继续使用上一个有效快照。 在[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中,调用方 API Key 是 `YOUR_CALLER_API_KEY`,模型别名是 `gpt-4o-mini`,模型服务提供方密钥保存 OpenAI 凭证,上游模型同样是 `gpt-4o-mini`。 在生产环境中,别名和上游模型不必相同。例如,应用可以持续发送 `prod-chat`,而网关在该别名背后切换上游模型、服务提供方密钥或路由策略。 ### 调用方 API Key[​](#调用方-api-key "调用方 API Key的直接链接") 调用方 API Key 是 AISIX 用于应用请求的授权身份。应用可以直接提供该 Key 的明文值,也可以提供 OIDC 签发的 JWT;该 JWT 的外部身份需绑定到此 Key。 解析出的 Key 决定调用方可以使用哪些模型别名,以及应用哪些 Key 范围的流量控制。关于 Key 哈希、轮换和模型允许列表,请参见[调用方 API Key](https://docs.apiseven.com/ai-gateway/traffic-controls/caller-api-keys.md)。关于将外部身份绑定到 Key,请参阅 [JWT 身份认证](https://docs.apiseven.com/ai-gateway/traffic-controls/jwt-authentication.md)。 ### 模型[​](#模型 "模型的直接链接") 模型是调用方在请求体中发送的、面向网关的模型别名。 对于直接模型,面向调用方的别名可以不同于上游服务提供方的模型 ID。模型还会指向 AISIX 调用上游时应使用的服务提供方密钥。虚拟模型会先通过路由、语义或合议决策解析别名,再到达直接模型。 有关各模型形态及其配置,请参阅[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md)。 ### 服务提供方密钥[​](#服务提供方密钥 "服务提供方密钥的直接链接") 服务提供方密钥保存 AISIX 解析模型后用于访问上游的凭证和连接设置。 服务提供方密钥可以让上游凭证不进入应用代码,并允许多个模型复用同一个上游账号、base URL 和适配器族。关于凭证字段、base URL 行为、服务提供方标签和适配器,请参见[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md)。如需更换共享上游凭证,请参见[轮换服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-key-rotation.md)。 在开源网关中,每个服务提供方密钥都显式声明适配器。AISIX Cloud 会为目录中的服务提供方推导适配器,并允许自带服务提供方显式指定适配器。 ## 模型分发形态[​](#模型分发形态 "模型分发形态的直接链接") 每个模型都有 `display_name`,它是调用方使用的别名。在 AISIX Cloud 中,模型资源之间通过资源 ID 引用;在开源 AISIX 网关的 `resources.yaml` 中,则通过 `display_name` 引用。其余字段定义一种分发形态: | 形态 | 资源关系 | | -------- | ------------------------------------------------------------------------------ | | 直接模型 | 存储上游 `model_name`,并引用一个服务提供方密钥。 | | 路由模型 | 引用多个直接目标,并按路由策略选择一个目标。 | | 语义模型 | 引用一个支持向量嵌入的直接模型、一个默认直接模型,以及语义路由对应的直接目标。 | | 合议模型 | 引用直接合议成员模型和一个直接评审模型。 | 四种形态互斥。资源不能将直接上游字段与 `routing`、`semantic` 或 `ensemble` 块组合使用。 向量嵌入模型仍是直接模型。其 `embedding` 块记录向量维度和归一化行为,使该模型能够提供向量嵌入并支持语义路由。 调用方可以继续使用一个稳定别名,运维人员则可以更改别名背后的直接上游、路由目标、语义路由或合议成员。调用方 API Key 必须允许请求中指定的别名;AISIX 会在内部选择或调用被引用的模型。 有关详细行为,请参阅[路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md)、[语义路由](https://docs.apiseven.com/ai-gateway/routing/semantic-routing.md)和[合议模型](https://docs.apiseven.com/ai-gateway/routing/ensemble-models.md)。 ## 策略资源[​](#策略资源 "策略资源的直接链接") 策略资源会围绕调用方 API Key、模型和服务提供方密钥组成的链路添加网关行为。 限流用于控制请求速率和并发。安全护栏用于检查请求或响应内容。缓存可以复用 Chat Completions 响应。可观测性导出器会将网关请求遥测发送到 OTLP/HTTP、对象存储、阿里云 SLS 或 Datadog 目的地。 预算检查通过 AISIX Cloud 控制面策略执行。开源 AISIX 网关不会暴露本地预算资源。 --- # 上游请求头 `forward_client_headers` 用于点名调用方发来、需要由 AISIX 中继给上游的入站请求头。它在 AISIX 代理的四个面上是同一个字段、同一套语义,取值是一个请求头名称模式数组,默认为空。 需要配置它的场景,是上游需要某些只有调用方才能提供的信息:服务提供方的 Beta 功能标记、应用路由提示、链路关联请求头;或者当上游是按最终用户(而不是按网关)授权的内网服务时,调用方自己的凭证。 字段所在的位置取决于由哪个面访问上游: | 字段 | 适用范围 | | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `provider_key.request.forward_client_headers` | 使用该服务提供方密钥的标准协议端点(`/v1/chat/completions`、`/v1/completions`、`/v1/messages`、`/v1/responses`、`/v1/realtime`,以及 embeddings、rerank、音频、图像、视频和 files/batches/fine-tuning 接口)。`/v1/realtime` 上该字段生效,但 `default_headers` 不生效,详见[下文](#forward-client-headers)。 | | `passthrough_route.forward_client_headers` | 由该[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)处理的请求。 | | `mcp_server.forward_client_headers` | 对该 [MCP 服务器](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md#forward-caller-headers-to-an-upstream-server)的工具调用,`type: mcp` 和 `type: openapi` 均适用。 | | `a2a_agent.forward_client_headers` | 对该 [A2A Agent](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md#forward-caller-headers-to-an-upstream-agent)的调用——`/a2a/<name>` 上的每个 JSON-RPC 方法,以及 agent card 拉取,均适用。 | 两种管理路径都可以在这四个资源上配置该字段。加载声明式资源文件的网关支持本文的全部内容,AISIX Cloud Admin API 和控制台同样如此——包括精确点名凭证槽位的条目,而这正是按最终用户授权的内网上游所依赖的写法。 该字段在各处的行为一致——被模式点名的请求头就会到达上游——但各个面的默认行为并不相同,因此设置它的实际含义也不同: * 在标准端点、MCP 和 A2A 上,AISIX 从头构建上游请求,不中继任何调用方请求头。此时该列表是**白名单**:它是调用方请求头到达上游的唯一途径。 * 在透传路由上,AISIX 默认中继调用方的请求头,只剥离一小部分。此时该列表是**对剥离集合的覆盖**:它只对路由本会删除的那些请求头有意义,其中包括网关刚刚用来认证调用方的那个凭证槽位。 服务提供方密钥上还有另一个与之无关的请求头设置:`request.default_headers` 添加由 AISIX 生成的请求头,其值可以引用当前请求。两者都位于服务提供方密钥上,因此引用该密钥的每个模型都会继承它们。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 开始前请准备: * 上游服务提供方凭证和端点。示例会在服务提供方密钥上配置这些设置;该资源的其他字段参见[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md)。 * 对于 AISIX Cloud,需要环境、已关联网关和具有写入权限的 Admin Token。对于 On-Premises 部署,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,需要一个加载声明式资源文件的网关。 ## 配置上游请求头[​](#配置上游请求头 "配置上游请求头的直接链接") 请使用与你的部署方式对应的管理路径配置服务提供方密钥。两种路径下,这些设置的运行时行为相同。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 导出 AISIX Cloud 连接信息和上游凭证: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" export UPSTREAM_API_KEY="YOUR_UPSTREAM_API_KEY" ``` 创建一个注入网关上下文并转发获准客户端请求头的服务提供方密钥。这两项设置可以独立配置;下例展示它们如何共存于同一密钥: ``` curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "internal-vllm", "provider": "byo", "adapter": "openai", "api_key": "'"${UPSTREAM_API_KEY}"'", "api_base": "https://models.internal.example.com/v1", "allowed_environments": ["'"${ENV_ID}"'"], "request": { "default_headers": { "x-tenant-id": "${request.api_key.team_id}", "x-audit-context": "key=${request.api_key.id};model=${model.name}", "x-correlation-id": "${request.id}", "x-upstream-tier": "premium" }, "forward_client_headers": [ "anthropic-beta", "x-routing-hint", "x-trace-*" ] } }' ``` ❶ 调用方 API Key 所属团队,可用于标识租户,以便上游进行配额或路由决策。 ❷ 由字面文本、调用方 API Key 标识符和面向调用方的模型名称组合而成的值。 ❸ 当前请求的关联 ID,与 AISIX 在 `x-aisix-request-id` 中发送并写入自身日志的值相同。 ❹ 字面值,每个请求都会原样发送。 ❺ 入站请求头名称和模式的允许列表。AISIX 在向上游发送请求前,仍会移除[绝不转发的请求头](#caller-headers-aisix-never-forwards)。凭证或链路上下文请求头需要[精确点名](#headers-that-must-be-named-exactly);这里的 `x-trace-*` 模式并不会匹配 `traceparent`。 响应中会包含服务提供方密钥 ID。如需稍后更改请求头设置,请保存该 ID: ``` export PK_ID="YOUR_PROVIDER_KEY_ID" ``` #### 后续修改配置[​](#后续修改配置 "后续修改配置的直接链接") `PATCH /provider_keys/{id}` 会整体替换 `request` 配置块,变更会影响引用该密钥的每个模型。请先读取当前配置块,然后在编辑后的请求中发送要保留的所有字段: ``` curl -sS "$AISIX_CP/provider_keys/$PK_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ | jq '.provider_key.request' curl -sS -X PATCH "$AISIX_CP/provider_keys/$PK_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "request": { "default_headers": { "x-tenant-id": "${request.api_key.team_id}" }, "forward_client_headers": ["anthropic-beta", "x-trace-*"] } }' ``` 空的 `"request": {}` 会清除已存储的覆盖设置。目录服务提供方密钥会恢复为服务提供方的内置默认值;BYO 密钥清除后没有请求覆盖设置。省略 `request` 则会保留已存储的配置块。 在控制台中,相同配置块位于服务提供方密钥编辑表单的 **Advanced wire-shape overrides** 下,并会预填已存储值。 ### 开源 AISIX 网关[​](#open-source-aisix-gateway "开源 AISIX 网关的直接链接") 将 `request` 配置块添加到 `resources.yaml` 中的服务提供方密钥条目。保留该条目已有的凭证字段,以及其他无关条目和集合。下例使用 `UPSTREAM_API_KEY`,该变量必须可供网关进程使用: resources.yaml(服务提供方密钥请求头) ``` provider_keys: - display_name: internal-vllm provider: byo adapter: openai api_key: ${UPSTREAM_API_KEY} api_base: https://models.internal.example.com/v1 request: default_headers: x-tenant-id: $${request.api_key.team_id} x-audit-context: key=$${request.api_key.id};model=$${model.name} x-correlation-id: $${request.id} forward_client_headers: - anthropic-beta - x-trace-* ``` 在资源文件中,未转义的每个 `${NAME}` 都会在文件加载时从环境中替换。请将请求上下文引用中的美元符号转义为 `$${...}`。加载器会将 `$$` 转换为字面 `$`,因此 `$${request.id}` 到达网关运行时会变成 `${request.id}`。转义后的名称如果不在[可用变量](#available-variables)中,运行时不会解析,AISIX 会丢弃该请求头。 添加或更改该配置块后,请验证并重新加载完整资源文件。完整工作流参见[重新加载资源文件](https://docs.apiseven.com/ai-gateway/deployment/configuration-propagation.md#reload-a-resources-file),完整字段目录参见[资源文件参考](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#provider-keys)。 ## 请求上下文请求头值[​](#request-context-header-values "请求上下文请求头值的直接链接") 当上游需要知道调用者身份时,使用 `request.default_headers`。内部模型服务可以据此应用租户配额、把成本归属到团队,或将自身访问日志与 AISIX 请求 ID 关联。这些请求头可以避免为每个租户准备单独的上游凭证。 请求头值可以是字面字符串、`${...}` 引用,也可以是字面文本与多个引用的组合。AISIX 会在认证调用方并选择模型后解析每个引用。 ### 可用变量[​](#available-variables "可用变量的直接链接") | 变量 | 值 | | ------------------------- | ------------------------------------------------ | | `request.id` | 当前请求的关联 ID。 | | `request.api_key.id` | 调用方 API Key 的标识符。 | | `request.api_key.name` | 调用方 API Key 的名称。 | | `request.api_key.team_id` | 调用方 API Key 所属团队。 | | `request.api_key.user_id` | 拥有调用方 API Key 的组织成员。 | | `model.id` | 解析后模型的标识符。 | | `model.name` | 解析后模型面向调用方的名称,而不是上游模型名称。 | | `provider_key.id` | 当前服务提供方密钥的标识符。 | | `provider_key.name` | 当前服务提供方密钥的名称。 | 只有这些变量会在请求时解析。保存服务提供方密钥时,如果值引用了其他名称,AISIX Cloud Admin API 会拒绝该值,使拼写错误立即失败,而不是变成一个永远无法到达上游的请求头。资源文件另有一个加载时插值步骤,因此请求上下文引用需要按[开源 AISIX 网关](#open-source-aisix-gateway)一节所述进行转义。 所有变量都不会暴露密钥。调用方 API Key、上游凭证和签名材料都不属于请求头值可以读取的请求上下文。 如果请求头引用的变量在某次请求中并非都有值,AISIX 会从该请求中删除整个请求头,而不是发送空值。如果调用方 API Key 不属于任何团队,上述示例的请求会包含 `x-audit-context` 和 `x-correlation-id`,但不会包含 `x-tenant-id`。空的 `x-tenant-id` 会让上游误以为租户是空字符串。 ### 受保护的请求头名称[​](#受保护的请求头名称 "受保护的请求头名称的直接链接") `request.default_headers` 不能设置那些任何配置都无法放到上游请求上的名称:`host`、逐跳请求头集合,以及网关自己的 `x-aisix-*` 命名空间。两种管理路径在这条边界上是一致的——保存服务提供方密钥时 AISIX Cloud 会拒绝这些名称,读取资源文件的网关则在分发时丢弃它们。它们就是 [AISIX 绝不转发的调用方请求头](#caller-headers-aisix-never-forwards)中的**第一组**,无论请求头来自哪里,这一组都会约束 `default_headers`。那里的**第二组**只针对从调用方收到的请求头,因此对 `default_headers` 不构成任何限制。 凭证名称不在其中。在 `default_headers` 中点名 `authorization`、`x-api-key` 或其他凭证槽位,正是让“读取第二份静态凭证”的上游拿到该凭证的方式——前提是该服务提供方自身的凭证走的是另一个槽位。 这类条目做不到的,是顶替 AISIX 已经设置的请求头。默认请求头只会填充所选服务提供方桥接留空的槽位,绝不会替换上游凭证或 `content-type`。 ## 转发客户端请求头[​](#forward-client-headers "转发客户端请求头的直接链接") 每个条目可以是精确的请求头名称,也可以是包含一个 `*` 通配符的名称。匹配不区分大小写,因此 `X-Trace-*` 和 `x-trace-*` 是同一个模式,都能匹配 `x-trace-id`。列表为空或不存在时(默认值),既不转发任何请求头,也不覆盖任何剥离行为。 调用方不能自行获得转发资格。该列表属于上游侧资源上的运维方配置;没有被任何条目点名的调用方请求头,其处理方式与未配置该字段时完全一致。 在标准端点、MCP 和 A2A 上,如果调用方多次发送同一个请求头,只有第一个值会被转发、其余丢弃,让上游收到一个格式良好的请求头,而不是一个网关从未解读过的列表。透传路由则按调用方发来的原样中继,包括重复项。 有一个请求头会让调用方为这条规则付出代价,而重复发送它并不是调用方自己的选择:`cookie`。AISIX 会终结入站的 HTTP/2,并且不做 cookie 重组(RFC 9113 第 8.2.3 节),因此如果 HTTP/2 调用方的客户端把 `cookie` 拆成多个请求头字段(这是 HPACK 的一种压缩手段,并非每个客户端都会这么做),只有第一个字段会被转发。同样的例外依然成立:透传路由会中继它收到的每一个 `cookie` 字段。 有些请求背后根本没有调用方——例如异步任务的后台轮询,或语义路由发起的向量检索。无论如何配置,这些请求都不转发任何内容,因为并不存在可供取值的入站请求。 `/v1/realtime` WebSocket 会像其他标准端点一样,转发其服务提供方密钥列表点名的请求头。有三点是这个面独有的: * 除了[任何面上都无法触及的名称](#caller-headers-aisix-never-forwards)之外,它还会拒绝自己拥有的五个握手槽位——`sec-websocket-accept`、`sec-websocket-extensions`、`sec-websocket-key`、`sec-websocket-protocol` 和 `sec-websocket-version`。它们描述的是调用方向 AISIX 打开的那次握手,而不是 AISIX 向上游打开的那次。 * 任何模式都触及不到这五个,包括完整写出名称的模式:这个面会先检查自己的拒绝清单,再去查列表。其中最要紧的是 `sec-websocket-protocol`——浏览器流程会把调用方自己的 AISIX Key 作为一项放进那个列表里。 * `request.default_headers` 在这里**不生效**。服务提供方密钥 `request` 块的一半在这个面上生效,另一半不生效。 转发值如果不是 ASCII,会从握手中被丢弃,而不是让整个会话失败——因为这个面是以文本形式写出它到上游的握手的。其他每个面都会按字节原样转发同一个取值。 ### 在路由、MCP 服务器或 A2A Agent 上配置[​](#configure-it-on-a-route-or-an-mcp-server "在路由、MCP 服务器或 A2A Agent 上配置的直接链接") 在透传路由、MCP 服务器和 A2A Agent 上,该字段位于顶层而不是 `request` 块内,模式写法完全相同。 通过 AISIX Cloud Admin API,把你希望它最终具备的完整列表 PATCH 上去。`ROUTE_ID`、`SERVER_ID` 和 `AGENT_ID` 是创建该路由、该服务器和该 Agent 时返回的 ID: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/passthrough_routes/$ROUTE_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"forward_client_headers": ["authorization", "x-trace-*"]}' curl -sS -X PATCH "$AISIX_CP/mcp_servers/$SERVER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"forward_client_headers": ["authorization"]}' curl -sS -X PATCH "$AISIX_CP/a2a_agents/$AGENT_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"forward_client_headers": ["authorization"]}' ``` PATCH 是整体替换已存储的列表,而不是追加。三个资源都可以用空数组清空;透传路由还额外接受 `null`,而 MCP 服务器和 A2A Agent 不接受。省略该字段时,已存储的列表保持不变。 在控制台中,同一设置是透传路由、MCP 服务器和 A2A Agent 表单里 **Advanced** 下的 **Forward client headers** 输入框,每行填一个请求头名称或通配符。 在开源 AISIX 网关加载的资源文件中这样配置: resources.yaml(另外三个面上的同一个字段) ``` passthrough_routes: - name: internal-copilot path_prefix: /internal target_url: https://models.internal.example.com auth_mode: gateway_key # 默认值 `inject` 需要配一个服务提供方密钥来注入。 credential_mode: forward_client forward_client_headers: - authorization - x-trace-* mcp_servers: - name: runbooks type: mcp url: https://runbooks.internal/mcp # 不配网关凭证:该服务器读取的就是调用方自己的凭证。 auth_type: none forward_client_headers: - authorization a2a_agents: - name: invoice-processor url: https://agents.internal.example.com/a2a # 该 Agent 按最终用户授权,读取的就是调用方自己的 Token。 auth_type: none forward_client_headers: - authorization - x-trace-* ``` ### 必须精确点名的请求头[​](#headers-that-must-be-named-exactly "必须精确点名的请求头的直接链接") 通配符不会匹配到 AISIX 自己当作凭证消费的请求头,也不会匹配到 W3C 链路上下文请求头。转发这类请求头是一个明确的动作,完整写出名称才会转发它。 在所有面上都需要单独点名的是: | 请求头 | 类别 | | ------------------------------------------------------------------------------------------ | -------------------------- | | `authorization`、`proxy-authorization`、`x-api-key`、`api-key`、`x-goog-api-key`、`cookie` | 凭证槽位 | | `x-amz-security-token`、`x-amz-date`、`x-amz-content-sha256` | 凭证槽位(AWS SigV4 材料) | | `traceparent`、`tracestate` | W3C 链路上下文 | 这三个 `x-amz-*` 名称作为同一份调用方身份一起传递。`x-amz-security-token` 是一份有效的 AWS 会话凭证,另外两个则是签名所覆盖的时间戳与请求体哈希。任何通配符都触及不到它们,`x-amz-*` 也不例外。因此要把调用方的 AWS 凭证中继出去,必须把三个名称逐个完整写出来,并连同 `authorization` 一起点名——签名本身由该请求头承载,它同样需要单独写出名称。Bedrock 服务提供方密钥对同样这几个名称适用的是另一条规则——它会把它们[丢弃](#caller-headers-aisix-never-forwards),好让自己的签名器独占这些请求头。本页其余规则都把这三个名称当作凭证槽位对待,包括顶替行为在内。 透传路由还会加上它自己点名的两个槽位。AISIX 会消费掉这两个请求头,而共享清单无从知道某条路由为它们取了什么名字: | 请求头 | 类别 | | ------------------------- | -------------------------------------- | | 路由的 `auth_header_name` | `auth_mode: header_key` 下承载网关凭证 | | 路由的 `identity_header` | 路由负责记录并剥离的最终用户身份 | 完整写出其中任意一个才会转发它,通配符触及不到。否则,配置为 `["x-*"]` 的路由就会把 AISIX 刚刚用来认证调用方的那个请求头中继出去,或者把路由承诺要剥离的那个身份取值中继出去。 写下 `*` 或 `x-*`,表达的是关于你自己那些请求头的意图。它不构成“把调用方凭证交给第三方服务提供方”的同意,也不构成“把调用方的链路嫁接到该服务提供方遥测中”的同意——若无上述限制,只要调用方碰巧发送了这些请求头,宽泛的通配符就会造成上述后果。完整写出请求头名称就是这份同意,而且只需要这一步:`"forward_client_headers": ["authorization"]` 会在每个面上转发调用方的 `Authorization`。 这条规则也让已有的宽泛模式保持其编写时的含义。配置为 `["x-*"]` 的服务提供方密钥不会因为网关升级,就开始中继调用方的 `x-api-key`——在 `/v1/*` 上,那个请求头装的是调用方自己的 AISIX 网关 Key。 ### 转发调用方凭证[​](#forwarding-the-callers-credential "转发调用方凭证的直接链接") 点名一个凭证槽位,是让本就按最终用户授权的内网上游在 AISIX 接入之后继续这样工作的方式。调用方的值会**占用**该槽位,取代 AISIX 本会注入到那里的凭证: * 在服务提供方密钥上,取代该密钥自身的凭证。 * 在 MCP 服务器上,取代 `auth_type` 本会填入的凭证——`bearer` 和 `oauth2` 填 `authorization`;`api_key` 填的是 `api_key_header` 指定的请求头,除非 `type: openapi` 的服务器另行覆盖,否则为 `x-api-key`。 * 在 A2A Agent 上,取代 `auth_type` 本会填入的凭证——`bearer` 填 `authorization`,`api_key` 填 `x-api-key`。 * 在透传路由上,取代注入的服务提供方凭证;同时也取代 `gateway_key` 身份认证本会对 `authorization` 和 `x-api-key` 执行的剥离。 MCP 服务器的 `api_key_header` 只要不恰好是上述必须精确点名的请求头之一,通配符就能匹配到它。它的默认值 `x-api-key` 属于凭证槽位,因此需要单独点名;而 `type: openapi` 的服务器如果把该槽位改名——比如改成 `x-mcp-token`——它就有了一个会被 `["x-*"]` 匹配到的名称,此时发送该请求头的调用方提供的就是自己的上游凭证。 无论哪种情况,该槽位都是单值的:AISIX 会替换而不是追加,因此上游只会收到一份凭证,永远不需要在两份之间做选择。AISIX 仍会照常先认证调用方——该设置只改变上游看到的内容,绝不改变 AISIX 认定的调用者身份。 转发出去的是调用方放在该槽位里的任何内容——不一定是最终用户的身份 Token。在 `/v1/*`、`/a2a/*`、`gateway_key` 模式的透传路由,以及所有 MCP 客户端上,调用方的 `Authorization` 装的就是 AISIX 调用方 API Key 本身,因此点名 `authorization` 会把一份有效的网关凭证发往上游。只在你愿意把该取值托付给它的上游上点名该槽位。 上游也必须是能接受它的一方:校验 `aud` 声明的上游会拒绝签发给网关的 Token。不要在公共模型服务提供方上点名凭证槽位。 只有凭证槽位才会顶替 AISIX 已经设置的内容。AISIX 放在请求上的其他请求头,都是为了让这次交互能够成立——例如服务提供方的异步模式标记或 API 版本选择器——因此同名的转发请求头会被丢弃,而不是被允许破坏这次调用。 ### W3C 链路上下文[​](#w3c-trace-context "W3C 链路上下文的直接链接") AISIX 将调用方的 `traceparent` 和 `tracestate` 读作遥测输入。一个有效的入站 `traceparent` 会让网关的 HTTP SERVER 跨度成为调用方跨度的子级。取值格式错误或存在多个 `traceparent` 时,AISIX 会启动新的本地链路,而不会拒绝请求。只有 `traceparent` 有效时,AISIX 才会保留 `tracestate`。AISIX 导出的跨度参见 [OTLP 链路结构](https://docs.apiseven.com/ai-gateway/observability/exporters.md#understand-otlp-trace-structure)。 读取链路上下文与中继它是两回事。默认情况下,AISIX 不会在任何面上把调用方的链路请求头发往上游。在 `forward_client_headers` 中精确点名 `traceparent` 或 `tracestate`,才会连同它们一起中继——这适用于向同一套链路后端上报的内网上游,而不适用于第三方服务提供方。 ## AISIX 绝不转发的调用方请求头[​](#caller-headers-aisix-never-forwards "AISIX 绝不转发的调用方请求头的直接链接") 有些请求头是任何模式都无法触及的。这类限制存在的原因是:转发它们会破坏这次交互本身,而不是改变请求来自谁,因此无论如何配置都会生效。 这些限制也仅适用于调用方提供的值。AISIX 仍会为其中一些名称发送自己的值:它为构建的请求体设置 `content-type`,并添加 `x-aisix-request-id`。 第一组在每个面上都适用: | 请求头组 | 请求头 | 原因 | | -------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Host | `host` | 它决定请求最终到达哪台服务器。 | | 逐跳 | `connection`、`keep-alive`、`te`、`trailer`、`transfer-encoding`、`upgrade`、`proxy-authenticate` | 这些字段描述的是调用方与 AISIX 之间的连接,而不是 AISIX 与上游之间的连接。 | | 网关所有 | `x-aisix-*` | 这些是 AISIX 就自己处理过的请求做出的断言。转发调用方副本会让调用方得以在上游伪造它们,同时也会丢失断言本身。在 `proxy.request_id.accept_headers` 中列出的请求头(默认是 `x-aisix-request-id`)只在一点上例外:AISIX 会从中[读取请求 ID](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#reuse-your-own-request-id),随后把读到的取值以自己的请求头发出,因此上游收到的该名称只有一个值。 | 标准端点、MCP 和 A2A 会重建出站消息,因此还会额外排除第二组: | 请求头组 | 请求头 | 原因 | | ------------------ | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | 请求体与内容协商 | `content-type`、`content-length`、`content-encoding`、`accept`、`accept-encoding`、`expect` | 它们描述的是 AISIX 会重新序列化的请求体和它会解析的响应形态,因此调用方的副本描述的是另一条消息。 | | 仅响应 | `set-cookie` | 这是一个响应头,出现在请求中没有意义。 | | 服务提供方传输格式 | `anthropic-version` | 它选择 Anthropic 形态的上游以何种传输格式作答,而 AISIX 随后要解析该格式。调用方的取值会破坏解析。 | | 客户端 SDK | `x-stainless-*` | 调用方 SDK 描述自身的版本请求头。如果转发给同样使用这些请求头标识其 SDK 的服务提供方,会破坏调用。 | 各个面自己还会多排除一些: * **MCP** 还绝不转发 `mcp-session-id`、`mcp-protocol-version` 和 `last-event-id`。它们标识的是调用方与 AISIX 之间的会话,而不是 AISIX 向上游打开的会话;上游 MCP 服务器会拒绝一个并非自己签发的会话 ID。 * **A2A** 还绝不转发 `a2a-version`。它是 AISIX 自己就该 Agent 的 `protocol_version` 所固定的线格式版本做出的声明;调用方的副本会覆盖这个固定值——Agent 会以运维方并未配置的信封形态作答,或者干脆拒绝这次调用。 * **透传路由**原样中继请求体,因此上面第二组对它不适用——`content-type` 会保留下来。它在第一组之外额外排除 `content-length`,因为出站客户端会根据拿到的请求体自行推导长度,中继过去的取值是一个请求分帧缺陷。 * **`/v1/realtime`** 还绝不转发 `sec-websocket-accept`、`sec-websocket-extensions`、`sec-websocket-key`、`sec-websocket-protocol` 和 `sec-websocket-version`。它们描述的是调用方向 AISIX 打开的那次握手,而不是 AISIX 向上游打开的那次;即使模式完整写出名称也触及不到它们。 还有一个服务提供方特有的例外:在 AWS Bedrock 服务提供方密钥上,AWS SigV4 会根据所签名的请求推导出 `authorization`、`x-amz-date`、`x-amz-content-sha256`、`x-amz-security-token`、`x-amz-target` 和 `x-amzn-bedrock-accept`,这些名称无论来自 `forward_client_headers` 还是 `default_headers` 都会被丢弃。在那里提供取值只会破坏签名,而不会认证任何人。 这种丢弃属于 Bedrock 自己的签名器,与[必须精确点名](#headers-that-must-be-named-exactly)是两条不同的规则。在其他任何上游上,这三个 `x-amz-*` 名称都可以送达,但前提是模式把它们逐个完整写出来。 ## 优先级[​](#优先级 "优先级的直接链接") 同名请求头来自多个位置时,AISIX 按以下方式确定: 1. `request.default_headers` 优先于由 `request.forward_client_headers` 转发的请求头——两者都是运维方配置,而静态的那个是更明确的意图表达——但[凭证槽位](#headers-that-must-be-named-exactly)除外。转发值从 `default_headers` 条目手里拿走凭证槽位,和从网关自己手里拿走一样。 2. `default_headers` 条目绝不会替换 AISIX 自行设置的请求头,包括上游凭证、`content-type` 和 `x-aisix-request-id`。 3. 转发的调用方请求头**只有**在名称属于[凭证槽位](#headers-that-must-be-named-exactly)时,才会替换 AISIX 自行设置的请求头。对于其他任何名称,AISIX 设置的取值保持不变。 4. 在透传路由上,`forward_client_headers` 的优先级高于服务提供方密钥的 `strip_headers`。被剥离的名称并不是从此禁行:在 `credential_mode: inject` 下,列表为 `["x-*"]` 的路由会把被剥离的 `x-` 请求头重新放回上游请求上——对普通请求头名称来说,一个通配符就够了。精确点名规则对凭证或链路上下文请求头、以及路由自己那两个槽位仍然成立;而 [AISIX 绝不转发的调用方请求头](#caller-headers-aisix-never-forwards)无论写什么模式都进不来。 请求头在传输时始终是单值的:AISIX 会替换而不是追加,因此上游不会同时收到同名的运维方值和调用方值。 ## 验证[​](#验证 "验证的直接链接") 导出调用方 API Key 和模型别名,确保其可以使用引用该服务提供方密钥的模型。然后发送请求,并包含允许列表中指定的请求头: ``` # AISIX_PROXY 是网关源站;请勿包含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000。 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export MODEL_ALIAS="YOUR_MODEL_ALIAS" curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -H "x-trace-id: trace-0001" \ -d '{ "model": "'"${MODEL_ALIAS}"'", "messages": [{"role": "user", "content": "ping"}] }' ``` 在上游服务的访问日志或同类请求遥测数据中确认预期请求头。 如果将 `api_base` 指向请求检查服务,请记住 AISIX 会把服务提供方密钥凭证和请求体发送到该 `api_base` 指向的地址。请使用自己控制的端点、测试服务提供方密钥上的一次性凭证,以及不包含真实数据的提示词。 如果缺少预期请求头,请检查: * 请求头名称已列在 `forward_client_headers` 中,或与其中一个通配符条目匹配。 * 请求头不属于 [AISIX 绝不转发的调用方请求头](#caller-headers-aisix-never-forwards)。 * 凭证或链路上下文请求头是[精确点名](#headers-that-must-be-named-exactly)的,而不是靠通配符条目匹配的。在透传路由上,路由自己的 `auth_header_name` 和 `identity_header` 同理。 * 在 `/v1/realtime` 上,该请求头不属于这个面拒绝的握手槽位,也不是 `default_headers` 条目——`request` 块的那一半在这里并不生效。 * 对于含变量的 `default_headers` 值,调用方 API Key 确实具有该属性。没有所属团队的 Key 会删除引用 `request.api_key.team_id` 的请求头。 * 在资源文件中,每个请求上下文引用都已转义为 `$${...}`,以避开加载时的环境变量插值。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") * [服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md):了解服务提供方密钥的其他配置,包括兼容性覆盖。 * [资源文件参考](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#provider-keys):查看声明式字段目录。 * [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)、[MCP 上游身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/upstream-authentication.md)和 [A2A 上游身份认证](https://docs.apiseven.com/ai-gateway/agent-gateway/upstream-authentication.md#forward-caller-headers-to-an-upstream-agent):该字段出现的另外三个面。 --- # 可观测性导出器 可观测性导出器会将网关用量事件发送到用于链路追踪、日志记录、存储或记账的目标。本指南将介绍如何通过 AISIX Cloud 或开源 AISIX 网关配置 OTLP/HTTP 导出器,并说明目标选择、内容采集和投递行为。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 以下任一配置路径: <!-- --> * AISIX Cloud,其中包含一个环境、已关联的网关和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 加载声明式 [`resources.yaml`](https://docs.apiseven.com/ai-gateway/reference/resources-file.md) 文件的开源 AISIX 网关。 * 计划使用的导出器对应的遥测目标。 * 用于验证投递的可用模型别名和调用方 API Key。 导出验证所用的网关和请求参数: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export MODEL_ALIAS="YOUR_MODEL_ALIAS" ``` 对于 AISIX Cloud 示例,请导出 Admin API 基础 URL、Admin Token 和环境 ID: ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 其他部署方式请使用可访问的 AISIX Cloud Admin API URL。 ## 选择导出器类型[​](#选择导出器类型 "选择导出器类型的直接链接") 两种配置路径都支持所有导出器类型。AISIX Cloud API 请求和资源文件条目通过 `kind` 值选择类型,控制台则显示同一底层类型对应的标签: | `kind` 值 | 控制台标签 | 适用场景 | | -------------- | ----------------- | ------------------------------------------------------------------------------------------- | | `otlp_http` | OTLP/HTTP | 已经通过 OTLP/HTTP 收集器或厂商端点收集链路。 | | `object_store` | Object storage | 希望将批量 NDJSON 请求事件写入 Amazon S3、S3 兼容存储、Google Cloud Storage 或 Azure Blob。 | | `datadog` | Datadog | 使用 Datadog Logs HTTP 接收端。 | | `aliyun_sls` | Alibaba Cloud SLS | 使用阿里云日志服务作为日志目标。 | 网关会将遥测直接发送到所选目标。 ## 配置 OTLP 导出器[​](#配置-otlp-导出器 "配置 OTLP 导出器的直接链接") 设置示例使用的收集器端点和授权请求头: ``` # 请替换为实际值 export OTLP_ENDPOINT="https://collector.example.com/v1/traces" export OTLP_AUTH_HEADER="Bearer YOUR_COLLECTOR_TOKEN" ``` 网关进程必须能够访问该端点。如果接收端与网关进程位于同一主机,可以使用 `http://localhost:4318/v1/traces`;容器化网关则需要使用接收端在容器网络或宿主机上的地址。如果接收端不要求认证,请从导出器中移除 `headers` 块。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 创建导出器并获取其 ID: ``` EXPORTER_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/observability_exporters" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "prod-otlp", "kind": "otlp_http", "endpoint": "'"${OTLP_ENDPOINT}"'", "headers": { "Authorization": "'"${OTLP_AUTH_HEADER}"'" }, "sample_rate": 1 }' | jq -r '.observability_exporter.id') ``` ❶ 只有当 OTLP 目标要求时才设置静态请求头。请求头值会加密存储,并且读取操作绝不会返回这些值。 ❷ `sample_rate: 1` 可以让投递检查得到确定的结果。它等同于省略该字段,即导出每个请求链路。验证完成后,如需减少跨度数量,可以降低该值。 获取导出器,确认存储的配置: ``` curl -sS "$AISIX_CP/environments/$ENV_ID/observability_exporters/$EXPORTER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 你应该会看到类似下面的响应。读取操作通过 `header_keys` 暴露已配置的请求头名称,并通过 `headers_set` 确认已存储请求头值;但绝不会返回请求头值本身。 ``` { "observability_exporter": { "id": "b46a9f5d-6a4d-4bb1-ae2c-4ab1b22f5e80", "env_id": "0f2f6a1e-9d33-4a8f-9a6e-2a7b6a9c1d2e", "name": "prod-otlp", "enabled": true, "kind": "otlp_http", "endpoint": "https://collector.example.com/v1/traces", "header_keys": ["Authorization"], "headers_set": true, "sample_rate": 1, "created_at": "2026-07-22T08:30:00Z", "updated_at": "2026-07-22T08:30:00Z" } } ``` 保存 `$EXPORTER_ID`,以便后续更新或删除导出器。导出器默认启用。设置 `enabled: false` 可在不发送遥测的情况下保存资源。 ### 开源 AISIX 网关[​](#开源-aisix-网关 "开源 AISIX 网关的直接链接") 将以下导出器添加到完整资源文件的 `observability_exporters` 中。使用环境变量插值可以避免将收集器 Token 写入文件: resources.yaml(OTLP 导出器) ``` observability_exporters: - name: prod-otlp kind: otlp_http endpoint: ${OTLP_ENDPOINT} headers: Authorization: ${OTLP_AUTH_HEADER} sample_rate: 1 ``` 验证组装后的完整文件: ``` aisix validate --resources resources.yaml ``` 在进程环境中设置 `OTLP_ENDPOINT` 和 `OTLP_AUTH_HEADER`,然后启动或重启网关。只有当这些变量已经可用于运行中的进程时,才重新加载网关。导出器默认启用;添加 `enabled: false` 可保留条目但不发送遥测。 ## 验证 OTLP 投递[​](#verify-otlp-delivery "验证 OTLP 投递的直接链接") 保存导出器只能确认 AISIX 接受了配置。要验证上面配置的 OTLP 导出器,请获取 AISIX 返回的请求 ID,在目标端查找该 ID,并检查网关的投递信号。如果正在检查的现有 OTLP 导出器的 `sample_rate` 小于 `1`,请暂时将采样率设为 `1`,避免该请求被采样丢弃。 通过一个可用的模型别名发送成功请求,并获取 AISIX 返回的 ID。无论 AISIX 接受调用方提供的 ID,还是自行生成 ID,这种方式都能取得准确结果: ``` export EXPORTER_NAME="prod-otlp" if TEST_REQUEST_ID=$( set -o pipefail curl -fsS -D - -o /dev/null \ -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${MODEL_ALIAS}"'", "messages": [{"role": "user", "content": "Reply with: exporter check"}] }' \ | awk 'tolower($1) == "x-aisix-request-id:" { id = $2; sub(/\r$/, "", id) } END { print id }' ) && test -n "$TEST_REQUEST_ID"; then export TEST_REQUEST_ID printf 'request ID: %s\n' "$TEST_REQUEST_ID" else unset TEST_REQUEST_ID printf 'verification request failed or returned no request ID\n' >&2 false fi ``` 等待导出器发送该批次,然后在 OTLP 后端查找 `aisix.request_id` 属性等于 `$TEST_REQUEST_ID` 的跨度。找到该跨度即可确认端到端投递:网关已加载导出器,在需要时完成目标端认证,且目标端已接受该批次。 在 AISIX Cloud 中,环境的 **Observability** 视图通过导出器行显示投递是否健康,以及在线网关已发送的批次数。也可以通过 Admin API 查看相同的逐网关心跳数据: ``` curl -sS "$AISIX_CP/environments/$ENV_ID/dp_nodes" \ -H "Authorization: Bearer $AISIX_TOKEN" \ | jq --arg exporter "$EXPORTER_NAME" \ '[.data[] | select(.status != "offline") | .exporter_health[]? | select(.name == $exporter)]' ``` 下次心跳后,至少一个在线网关应报告大于零的 `delivered_batches` 和 `last_error: null`。网关重启或导出器配置变更时,计数器会重置。非空的 `last_error` 表示当前投递失败。后续成功投递会清除 `last_error`,但历史字段 `failed_batches` 和 `last_failure_unix` 仍会保留数值。 使用开源 AISIX 网关时,请在目标端确认成功。如果记录未到达,请在网关日志中检查 `sink delivery failed; retrying` 或 `sink delivery dropped after retries`。 ## 了解 OTLP 链路结构[​](#understand-otlp-trace-structure "了解 OTLP 链路结构的直接链接") 对于每个产生 OTLP 遥测数据的请求,AISIX 会导出一个链路层级,而不是为每个用量事件导出彼此无关的跨度。模型请求到达上游时,层级如下: | 跨度 | OTLP 类型 | 范围 | | -------- | --------- | --------------------------------------------------------------------------------------------------- | | 入站请求 | SERVER | 覆盖请求从到达开始,直到响应完成或调用方断开连接。有效的入站 `traceparent` 会成为此跨度的远程父级。 | | 逻辑操作 | CLIENT | 覆盖网关执行的上游操作,包括所有重试和故障转移尝试。它是 SERVER 跨度的子级。 | | 上游尝试 | CLIENT | 表示一次服务提供方分发。每次尝试都是逻辑操作的子级,并携带 `aisix.attempt_index`。 | 因此,重试和故障转移会显示为同一逻辑操作下的同级尝试跨度。对于每个用量事件,AISIX 会把完整属性和捕获内容放在当前最具体的跨度上:优先放在尝试跨度,其次放在逻辑操作跨度,最后放在 SERVER 跨度。其他跨度仅携带关联该层级所需的字段,不会重复整个事件。 并非每个请求都包含所有三个层级: * 缓存命中、输入安全护栏阻断或其他分发前结果只有 SERVER 跨度,因为 AISIX 没有调用上游。 * 不采用逐次尝试追踪的 MCP、A2A、Realtime、任务和透传调用包含 SERVER 跨度,以及一个表示上游操作的 CLIENT 跨度。 统计导出链路时,请根据跨度类型和父子关系,而不要只根据跨度名称。筛选 SERVER 跨度可以统计已采样的请求链路。`sample_rate` 小于 `1` 时,未被选中的请求不会出现。部分身份认证和格式错误输入路径会在用量事件或 OTLP 跨度产生前拒绝请求,因此 SERVER 跨度不能完整表示入站请求数。网关请求量请使用[请求指标](https://docs.apiseven.com/ai-gateway/reference/metrics.md#request-metrics)。分析单次模型尝试时,请使用携带 `aisix.attempt_index` 的 CLIENT 跨度。 ### 延续入站 W3C 链路[​](#continue-an-inbound-w3c-trace "延续入站 W3C 链路的直接链接") 请求中恰好包含一个有效的 `traceparent` 时,AISIX 会延续该链路,并让自己的 SERVER 跨度成为调用方跨度的子级。取值格式错误或存在多个 `traceparent` 时,AISIX 会忽略它们并启动本地链路,而不会拒绝请求。通过网关字符和长度检查的配套 `tracestate` 会记录在 SERVER 跨度上。 除非 `forward_client_headers` 精确点名,否则 AISIX 不会把调用方的 `traceparent` 或 `tracestate` 转发给模型服务提供方、透传目标、MCP 服务器或 A2A Agent;通配符模式永远不会匹配到它们。默认情况下,该上下文只用于建立调用方到网关的关系。转发边界参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#w3c-trace-context)。 ## 配置其他导出器[​](#配置其他导出器 "配置其他导出器的直接链接") 当遥测需要发送到对象存储或日志服务,而不是 OTLP 链路后端时,请使用其他导出器类型。使用 AISIX Cloud 时,将以下对象之一作为 `POST $AISIX_CP/environments/$ENV_ID/observability_exporters` 的请求体。 ### 对象存储[​](#对象存储 "对象存储的直接链接") 对于对象存储,请选择存储服务提供方、存储桶和对象键前缀。默认认证模式使用由网关解析的凭证引用: ``` { "name": "request-events-s3", "kind": "object_store", "provider": "s3", "bucket": "acme-aisix-events", "prefix": "ai-gateway", "region": "us-east-1", "credential_ref": "acme_s3" } ``` 对象存储支持 Amazon S3、Google Cloud Storage、Azure Blob 和 S3 兼容目标。只有当网关运行时带有可写入存储桶的附加身份时,才对 S3 或 GCS 使用云身份。对于 Azure Blob,以及要求静态凭证的 S3 兼容目标,请使用 `credential_ref`。 对于 MinIO、Cloudflare R2 或阿里云 OSS 等 S3 兼容目标,请显式设置目标端点。未设置端点时,S3 导出器会使用原生 AWS S3 端点。 ### 阿里云 SLS[​](#阿里云-sls "阿里云 SLS的直接链接") 配置端点主机、项目、日志库和凭证引用: ``` { "name": "request-events-sls", "kind": "aliyun_sls", "endpoint": "ap-southeast-3.log.aliyuncs.com", "project": "acme-observability", "logstore": "ai-gateway", "credential_ref": "acme_sls" } ``` ### Datadog[​](#datadog "Datadog的直接链接") 配置 Datadog 站点、服务名称、标签和凭证引用: ``` { "name": "request-events-datadog", "kind": "datadog", "site": "datadoghq.com", "service": "ai-gateway", "tags": ["team:platform", "tier:prod"], "credential_ref": "acme_datadog" } ``` 对于资源文件路径,请将以下条目添加到 `observability_exporters`: resources.yaml(请求导出器) ``` observability_exporters: - name: request-events-s3 kind: object_store provider: s3 bucket: acme-aisix-events prefix: ai-gateway region: us-east-1 credential_ref: acme_s3 - name: request-events-sls kind: aliyun_sls endpoint: ap-southeast-3.log.aliyuncs.com project: acme-observability logstore: ai-gateway credential_ref: acme_sls - name: request-events-datadog kind: datadog site: datadoghq.com service: ai-gateway tags: ["team:platform", "tier:prod"] credential_ref: acme_datadog ``` 只保留实际使用的目标,然后按照 OTLP 示例所述验证资源文件并启动或重新加载网关。使用与 OTLP 相同的请求 ID 方法验证这些导出器:在对象存储和 SLS 记录中按 `request_id` 查找,在 Datadog 日志中按 `aisix.request_id` 查找。[Snowflake 指南](https://docs.apiseven.com/ai-gateway/observability/load-logs-into-snowflake.md)介绍了如何直接检查对象存储输出。 SLS、Datadog 和对象存储导出器通过凭证引用或云身份,让目标凭证不进入导出器资源。网关发送遥测时会在本地解析这些凭证。 ## 配置内容采集[​](#配置内容采集 "配置内容采集的直接链接") 导出器默认包含请求状态、Token 计数、模型和服务提供方标识、请求 ID、结束原因和时间信息,但不包含提示词和响应正文。OTLP/HTTP、SLS 和 Datadog 导出器可以选择启用完整内容采集。 ### 启用完整内容采集[​](#启用完整内容采集 "启用完整内容采集的直接链接") 创建导出器时添加 `content_mode` 和 `content_max_bytes`。在 AISIX Cloud 中,可以使用相同字段修补现有导出器: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/observability_exporters/$EXPORTER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "content_mode": "full", "content_max_bytes": 131072 }' ``` 在控制台中,将导出器表单的 **Content mode** 设置为 **Full**,然后调整 **Max content bytes**。 对于资源文件路径,请将这些字段添加到导出器条目中,然后验证并重新加载文件: ``` observability_exporters: - name: prod-otlp kind: otlp_http endpoint: ${OTLP_ENDPOINT} headers: Authorization: ${OTLP_AUTH_HEADER} content_mode: full content_max_bytes: 131072 ``` 只有当目标已获准接收最终用户提示词和响应文本时,才使用完整内容采集。AISIX 会根据配置的字节上限分别截断采集到的提示词和响应字段。 ### 了解截断记录[​](#了解截断记录 "了解截断记录的直接链接") 有效 JSON 超过 `content_max_bytes` 时,AISIX 会先按结构缩减,使导出字段仍为有效 JSON。如果缩减后仍超过上限,则回退到 UTF-8 安全的字节截断。采集的提示词是序列化后的请求体,遵循同样规则。 | 内容 | 截断行为 | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 长字符串 | 保留前缀,并追加 `...[aisix: truncated, N bytes total]` 行内标记。 | | Base64 数据 URI | 用包含原始大小的占位符替换编码数据。 | | 长数组 | 保留首尾样本,并插入 `{"_aisix_truncated": true, "omitted_items": N}` 元素,其中 `N` 统计全部省略项。 | | 非 JSON 内容,或结构缩减后仍放不下的 JSON | 在 UTF-8 字符边界处截断。 | 发生截断时,OTLP 记录包含 `aisix.content_truncated: true`,Datadog 和 SLS 记录包含 `content_truncated: true`。 ### 采集透传内容[​](#capture-passthrough-content "采集透传内容的直接链接") 对于成功中继的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)流量,完整内容采集会将请求体记录为字符串,并遵循导出器的内容上限和 JSON 结构感知截断规则。对于缓冲响应,响应符合受支持的提取结构时会记录提取出的文本,否则将响应体记录为文本。对于流式响应,会记录累积的提取文本;不透明数据负载则保留为文本。 ### 采集失败请求[​](#采集失败请求 "采集失败请求的直接链接") 完整内容采集适用于下表汇总的受支持 AI 代理端点类型。A2A 采集记录的是消息内容,而不是 JSON-RPC 信封。完整内容采集不适用于 MCP、Realtime、任务或批处理遥测。透传请求如果在身份认证、授权、输入安全护栏或限流期间被拒绝,则不包含采集内容。 在 `/v1/chat/completions`、`/v1/messages` 和 `/v1/responses` 上,请求解析后产生用量事件的失败会把请求体记录到 `prompt` 字段,但 `401` 和 `403` 响应除外。这包括输入安全护栏阻断(`422`)、除 `401` 和 `403` 之外的上游失败,以及解析后的校验失败(例如 `messages` 数组为空)。执行数据脱敏时,AISIX 采集脱敏后的请求体;格式错误的 JSON 会在创建用量事件前被拒绝,因此不会采集。 还应注意以下边界: * 调用方认证失败会在创建用量事件前被拒绝。 * 所有路由目标都失败时,最后一次尝试的记录携带提示词。 * 响应侧安全护栏阻断不会采集被阻断的输出。 这些边界既避免导出被拒绝的凭证和阻断输出,也保留调查其它失败所需的请求上下文。 ### 查看各端点采集的内容[​](#查看各端点采集的内容 "查看各端点采集的内容的直接链接") | 端点类型 | 采集的内容 | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | 文本生成 | 响应文本。 | | A2A | `message/send` 和 `message/stream` 上,请求消息与回复消息里文本部分的内容。文件部分、数据部分和 JSON-RPC 信封不会被采集。 | | Embeddings、Rerank 和图片生成 | 完整响应 JSON。 | | 音频转录 | 返回的转录文本。上传音频不会被采集;其 SHA-256 校验和会与请求文本字段一起记录。 | | 文本转语音 | 不采集二进制语音响应。 | ## 导出遥测中的模型字段[​](#导出遥测中的模型字段 "导出遥测中的模型字段的直接链接") 当调用方请求的模型别名与处理某次尝试的模型不同时,用量遥测会同时记录两者。这对路由和合议流量很重要,因为一个面向调用方的别名可能解析为多个目标模型调用。 不同目标会以各自的遥测格式呈现这些值。OTLP 链路使用以下字段: * `gen_ai.request.model` 包含调用方请求的别名。 * `gen_ai.response.model` 包含服务提供方上报的具体响应模型版本。 * `aisix.model_id` 标识解析后的模型资源。 ### 网关协议跨度[​](#gateway-protocol-spans "网关协议跨度的直接链接") A2A 或 MCP 调用不是模型推理,因此不会被编码成模型推理。A2A 导出为 `invoke_agent <agent>`,MCP 导出为 `execute_tool <tool>`,遵循 OpenTelemetry 生成式 AI 语义约定,并携带各自协议的细节: * A2A:`gen_ai.agent.name`、`gen_ai.conversation.id`(即 A2A 的上下文),以及 `aisix.a2a.operation`、`aisix.a2a.method`、`aisix.a2a.protocol_version`、`aisix.a2a.task_id`、`aisix.a2a.task_state`、`aisix.a2a.stream_event_count`。 * MCP:`gen_ai.tool.name` 和 `aisix.mcp.server_name`。 * 透传路由:跨度导出为 `passthrough <route>`,携带 `aisix.passthrough.route_name`;当路由的 `identity_header` 提取到最终用户身份时,`aisix.client_identity` 一并携带。 模型流量仍然使用 `chat.completions` 这一跨度名称和 `gen_ai.operation.name: chat`。在此变更之前按这两个值编写的链路查询也会匹配到 Agent 和工具调用,现在只会匹配模型流量——而这本来就是它想表达的含义。 Datadog 日志使用 `aisix.requested_model` 表示调用方请求的别名,使用 `gen_ai.response.model` 表示具体响应模型版本,并使用 `aisix.model_id` 表示解析后的模型资源。 对象存储和阿里云 SLS 会保留底层用量事件字段名称,例如 `requested_model`、`model_id` 和 `provider_model_version`。 ## 导出遥测中的请求类型[​](#request-kind-in-exported-telemetry "导出遥测中的请求类型的直接链接") 每条记录还携带该请求要求网关做的事情——对话补全、图片生成、视频提交、工具调用。取值及其含义参见[区分请求类型](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#tell-request-kinds-apart)。 各目的地对它的命名不同: * 对象存储和阿里云 SLS 保留用量事件字段名 `operation`。 * Datadog 映射为 `aisix.operation`。 * OTLP 以 `aisix.operation` 跨度属性携带,并出现在该请求整个跨度层级的每一层上,因此可以在链路的根节点按类型筛选。 OTLP 跨度上同时还有 OpenTelemetry 的 `gen_ai.operation.name` 属性,两者回答的是不同的问题。后者使用 OpenTelemetry 自己的词汇表,能区分模型推理与 Agent、工具调用,但所有 OpenAI 兼容端点只对应一个取值——因此无法区分对话、图片和视频。端点本身重要时,请按 `aisix.operation` 过滤。 ## AISIX Cloud 控制面[​](#aisix-cloud-控制面 "AISIX Cloud 控制面的直接链接") 控制台在目标环境的 **Observability** 视图中管理相同的导出器资源。导出器表单会收集目标字段、内容模式和各类型专属选项。 无论导出器通过 API 还是控制台保存,控制面都会把配置投射到关联到该环境的 AISIX 网关。 以下行为适用于投射到 AISIX 网关的导出器: * AISIX 网关会直接将请求遥测发送到你的目标。控制面不会代理导出的遥测。 * 除非在导出器上启用完整内容采集,否则提示词和响应内容会留在网关上。 * 凭证引用由 AISIX 网关解析。当目标需要运行时凭证时,控制台会展示需要在网关上配置的环境变量。 * 投递健康状态来自网关心跳数据,会显示批次是否正在发送,或网关是否报告了投递错误。 对于 OTLP/HTTP 导出器,控制台提供 Langfuse、Honeycomb 和 Grafana Cloud Tempo 的预设,也接受自定义 OTLP 端点。 Trace UI URL 模板是可选的。当 **Request Logs** 视图需要将请求记录链接到外部 Trace UI 时使用它。模板必须包含 `{request_id}`,以便控制面用日志记录中的请求 ID 替换它。 ## 下一步[​](#下一步 "下一步的直接链接") 如需在 Snowflake 中查询对象存储遥测,请继续阅读[将请求遥测加载到 Snowflake](https://docs.apiseven.com/ai-gateway/observability/load-logs-into-snowflake.md)。使用[指标和日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md)将导出记录与网关指标、访问日志和响应头关联。 --- # 将请求遥测加载到 Snowflake AISIX 可以通过可观测性导出器将请求遥测写入对象存储。完成[导出器配置](https://docs.apiseven.com/ai-gateway/observability/exporters.md)后,如果财务、商业智能或审计团队需要在 Snowflake 中查询网关用量、成本、延迟、缓存结果和安全护栏结果,可以使用本指南。 网关会将批量 NDJSON 对象写入你拥有的存储桶。Snowpipe 会将这些对象导入 Snowflake 表,SQL 视图再把每条请求尝试记录转换为可查询的列。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 请先准备以下内容: * 以下任一配置路径: <!-- --> * AISIX Cloud,其中包含一个环境、已关联的网关和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 加载声明式 [`resources.yaml`](https://docs.apiseven.com/ai-gateway/reference/resources-file.md) 文件的开源 AISIX 网关。 * 一个可发送 Chat Completions 请求的模型别名和调用方 API Key。 * 一个用于暂存请求遥测的 Amazon S3 存储桶或 Azure Blob 容器。 * 一个 Snowflake 账户,以及可创建存储集成、通知集成、Stage、Pipe、表和视图的角色。 导出用于生成测试遥测的网关 URL 和请求值: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" export AISIX_API_KEY="YOUR_CALLER_API_KEY" export MODEL_ALIAS="YOUR_MODEL_ALIAS" ``` 对于 AISIX Cloud 示例,还需导出 Admin API 基础 URL、Admin Token 和环境 ID: ``` # AISIX_CP 包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 其他部署方式请使用可访问的 AISIX Cloud Admin API URL。 本指南使用 `acme-aisix-events` 作为 S3 存储桶名称,使用 `ai-gateway` 作为对象前缀。请替换为你自己环境中的值。 ## 遥测导入流程[​](#遥测导入流程 "遥测导入流程的直接链接") `object_store` 导出器是对象存储暂存路径。AISIX 不会在请求链路上直接把请求遥测推送到 Snowflake。 AISIX 会为每次请求尝试发出用量遥测。发生重试或故障转移的请求会生成多条具有相同请求 ID 的记录。导出器会将 gzip 压缩的 NDJSON 对象写入 Amazon S3 或 Azure Blob Storage。Snowpipe 将每条记录加载到 Snowflake 落地表,SQL 视图则暴露请求、尝试、成本、延迟、缓存和安全护栏列用于分析。 导出器投递默认以元数据为主,包括请求 ID、请求的模型别名、解析后的模型 ID、状态、Token 计数、成本、延迟、缓存状态和安全护栏结果等字段。除非受支持的导出器显式配置内容采集,否则不会包含提示词或响应文本。 请为每个网关部署使用独立的存储桶前缀。AISIX 会在已配置前缀下按日期和小时分区对象,但对象路径不会自动添加部署段。 ## 配置对象存储导出[​](#配置对象存储导出 "配置对象存储导出的直接链接") 请先创建导出器,并确认文件能够落到对象存储,再连接 Snowflake。这样可以把网关侧问题和数据仓库导入问题拆开排查。 ### Amazon S3[​](#amazon-s3 "Amazon S3的直接链接") 使用 AISIX Cloud 时,通过 Admin API 创建导出器: ``` EXPORTER_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/observability_exporters" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "snowflake-staging", "kind": "object_store", "provider": "s3", "bucket": "acme-aisix-events", "prefix": "ai-gateway", "region": "us-east-1", "credential_ref": "acme_s3_prod" }' | jq -r '.observability_exporter.id') ``` ❶ Amazon S3 及兼容 S3 的存储目标使用 `s3`。 ❷ `bucket` 和 `prefix` 定义 AISIX 写入 Snowflake 暂存文件的位置。请为每个网关部署使用不同的前缀。 ❸ `credential_ref` 将该导出器映射到网关环境变量。后缀来自该引用的值并转换为大写。 对于开源 AISIX 网关,请将以下条目添加到完整资源文件的 `observability_exporters` 中: resources.yaml(S3 导出器) ``` observability_exporters: - name: snowflake-staging kind: object_store provider: s3 bucket: acme-aisix-events prefix: ai-gateway region: us-east-1 credential_ref: acme_s3_prod ``` 在发送遥测的每个网关实例的环境中配置匹配的凭证。对于从 shell 启动的网关,请在启动前导出这些值: ``` # 请替换为实际值 export OBJSTORE_CRED_ACME_S3_PROD_AWS_ACCESS_KEY_ID="YOUR_AWS_ACCESS_KEY_ID" export OBJSTORE_CRED_ACME_S3_PROD_AWS_SECRET_ACCESS_KEY="YOUR_AWS_SECRET_ACCESS_KEY" ``` 对于资源文件路径,请验证组装后的完整文件: ``` aisix validate --resources resources.yaml ``` 验证后,在进程环境中设置凭证变量,然后启动或重启网关。只有当这些变量已经可用于运行中的进程时,才重新加载网关。 生成几次请求,让导出器有遥测数据可以发送: ``` for i in 1 2 3; do curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${MODEL_ALIAS}"'", "messages": [{"role": "user", "content": "ping"}] }' > /dev/null done sleep 8 ``` 列出暂存对象: ``` aws s3 ls "s3://acme-aisix-events/ai-gateway/" --recursive ``` 存储桶中应该会在配置的前缀、日期分区和小时分区下出现一个或多个 `.ndjson.gz` 对象: ``` 2026-06-09 14:03:11 742 ai-gateway/dt=2026-06-09/hh=14/9f86d081884c7d659a2feaa0c55ad015.ndjson.gz ``` 配置 Snowpipe 前,先检查一个对象: ``` aws s3 cp "s3://acme-aisix-events/ai-gateway/dt=2026-06-09/hh=14/OBJECT.ndjson.gz" - | gunzip ``` 输出中每一行都是一条请求尝试记录。下面是格式化后的一条示例记录: ``` { "schema_version": "1.0", "request_id": "742c6f5e-7b97-4bb1-9f5f-8cb42b4c93e1", "occurred_at": "2026-06-09T14:03:10Z", "requested_model": "gpt-4o-prod", "model_id": "b7c8e4f2-2e4d-4776-a8d7-09b4eb0cb2b1", "attempt_index": 0, "attempt_kind": "initial", "prompt_tokens": 8, "completion_tokens": 12, "upstream_latency_ms": 548, "downstream_latency_ms": 612, "status_code": 200, "cost_usd": 0.00021, "cache_status": "miss", "guardrail_blocked": false } ``` ### Azure Blob[​](#azure-blob "Azure Blob的直接链接") 使用 AISIX Cloud 时,通过 Admin API 创建导出器: ``` EXPORTER_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/observability_exporters" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "snowflake-staging", "kind": "object_store", "provider": "azure_blob", "bucket": "ai-gateway", "prefix": "ai-gateway", "credential_ref": "acme_az_prod" }' | jq -r '.observability_exporter.id') ``` ❶ 当暂存目标是 Azure Blob 容器时,使用 `azure_blob`。 ❷ 对于 Azure Blob,`bucket` 即容器名称。`prefix` 控制该容器下类似文件夹的路径。 ❸ `credential_ref` 将该导出器映射到网关环境变量。后缀来自该引用值并转换为大写。 对于开源 AISIX 网关,请将以下条目添加到完整资源文件的 `observability_exporters` 中: resources.yaml(Azure Blob 导出器) ``` observability_exporters: - name: snowflake-staging kind: object_store provider: azure_blob bucket: ai-gateway prefix: ai-gateway credential_ref: acme_az_prod ``` 在发送遥测的每个网关实例的环境中配置匹配的凭证。对于从 shell 启动的网关,请在启动前导出这些值: ``` # 请替换为实际值 export OBJSTORE_CRED_ACME_AZ_PROD_AZURE_ACCOUNT="YOUR_STORAGE_ACCOUNT" export OBJSTORE_CRED_ACME_AZ_PROD_AZURE_ACCESS_KEY="YOUR_STORAGE_ACCESS_KEY" ``` 对于资源文件路径,请验证组装后的完整文件: ``` aisix validate --resources resources.yaml ``` 验证后,在进程环境中设置凭证变量,然后启动或重启网关。只有当这些变量已经可用于运行中的进程时,才重新加载网关。 生成流量并列出暂存的 Blob 对象: ``` for i in 1 2 3; do curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${MODEL_ALIAS}"'", "messages": [{"role": "user", "content": "ping"}] }' > /dev/null done sleep 8 az storage blob list \ --account-name "YOUR_STORAGE_ACCOUNT" \ --account-key "YOUR_STORAGE_ACCESS_KEY" \ --container-name "ai-gateway" \ --prefix "ai-gateway/" \ --query "[].name" \ -o tsv ``` 容器中应该会在相同的前缀、日期分区和小时分区布局下出现 gzip 压缩的 NDJSON 对象。 ## 创建 Snowflake 落地表[​](#创建-snowflake-落地表 "创建 Snowflake 落地表的直接链接") 创建一个包含 `VARIANT` 列的落地表,让 Snowflake 可以导入每条 NDJSON 记录且不丢失字段: ``` CREATE DATABASE IF NOT EXISTS aisix; CREATE SCHEMA IF NOT EXISTS aisix.gateway; USE SCHEMA aisix.gateway; CREATE TABLE IF NOT EXISTS gateway_events ( record VARIANT, source_file STRING, loaded_at TIMESTAMP_LTZ DEFAULT CURRENT_TIMESTAMP() ); ``` 当 Pipe 的文件格式使用 `COMPRESSION = AUTO` 时,Snowflake 会自动识别 gzip。 ## 将 Snowflake 连接到 S3[​](#将-snowflake-连接到-s3 "将 Snowflake 连接到 S3的直接链接") 对于 S3,Snowflake 通过存储集成读取存储桶,并通过与 Pipe 关联的 SQS 队列接收对象创建事件。 创建存储集成: ``` CREATE STORAGE INTEGRATION aisix_s3_int TYPE = EXTERNAL_STAGE STORAGE_PROVIDER = 'S3' ENABLED = TRUE STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::123456789012:role/aisix-snowflake-read' STORAGE_ALLOWED_LOCATIONS = ('s3://acme-aisix-events/ai-gateway/'); DESC INTEGRATION aisix_s3_int; ``` 使用 `DESC INTEGRATION` 返回的 `STORAGE_AWS_IAM_USER_ARN` 和 `STORAGE_AWS_EXTERNAL_ID` 配置 IAM 角色信任策略。为该角色授予列出存储桶和读取配置前缀下对象的权限。 创建 Stage 和 Pipe: ``` CREATE STAGE aisix_stage URL = 's3://acme-aisix-events/ai-gateway/' STORAGE_INTEGRATION = aisix_s3_int; CREATE PIPE aisix_events_pipe AUTO_INGEST = TRUE AS COPY INTO gateway_events (record, source_file) FROM (SELECT $1, METADATA$FILENAME FROM @aisix_stage) FILE_FORMAT = (TYPE = JSON COMPRESSION = AUTO); SHOW PIPES; ``` 使用 `SHOW PIPES` 返回的 `notification_channel` 值,为对象创建事件添加 S3 事件通知: ``` aws s3api put-bucket-notification-configuration \ --bucket "acme-aisix-events" \ --notification-configuration '{ "QueueConfigurations": [{ "QueueArn": "arn:aws:sqs:us-east-1:NNNN:sf-snowpipe-example", "Events": ["s3:ObjectCreated:*"], "Filter": {"Key": {"FilterRules": [{"Name": "prefix", "Value": "ai-gateway/"}]}} }] }' ``` ## 将 Snowflake 连接到 Azure Blob[​](#将-snowflake-连接到-azure-blob "将 Snowflake 连接到 Azure Blob的直接链接") 对于 Azure Blob,Snowflake 通过存储集成读取容器,并通过存储队列接收对象创建事件。 创建存储队列和 Event Grid 订阅: ``` az storage queue create \ --name "aisix-snowpipe" \ --account-name "YOUR_STORAGE_ACCOUNT" az eventgrid event-subscription create \ --source-resource-id "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE_ACCOUNT" \ --name "aisix-snowpipe-sub" \ --endpoint-type storagequeue \ --endpoint "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/YOUR_STORAGE_ACCOUNT/queueServices/default/queues/aisix-snowpipe" \ --advanced-filter data.api stringin CopyBlob PutBlob PutBlockList FlushWithClose ``` 创建通知集成: ``` CREATE NOTIFICATION INTEGRATION aisix_az_notif ENABLED = TRUE TYPE = QUEUE NOTIFICATION_PROVIDER = AZURE_STORAGE_QUEUE AZURE_STORAGE_QUEUE_PRIMARY_URI = 'https://YOUR_STORAGE_ACCOUNT.queue.core.windows.net/aisix-snowpipe' AZURE_TENANT_ID = 'YOUR_TENANT_ID'; DESC NOTIFICATION INTEGRATION aisix_az_notif; ``` 为 `DESC NOTIFICATION INTEGRATION` 返回的 Snowflake 服务主体授予访问存储队列的权限。 创建存储集成、Stage 和 Pipe: ``` CREATE STORAGE INTEGRATION aisix_az_int TYPE = EXTERNAL_STAGE STORAGE_PROVIDER = 'AZURE' ENABLED = TRUE AZURE_TENANT_ID = 'YOUR_TENANT_ID' STORAGE_ALLOWED_LOCATIONS = ('azure://YOUR_STORAGE_ACCOUNT.blob.core.windows.net/ai-gateway/ai-gateway/'); DESC INTEGRATION aisix_az_int; CREATE STAGE aisix_stage URL = 'azure://YOUR_STORAGE_ACCOUNT.blob.core.windows.net/ai-gateway/ai-gateway/' STORAGE_INTEGRATION = aisix_az_int; CREATE PIPE aisix_events_pipe AUTO_INGEST = TRUE INTEGRATION = 'AISIX_AZ_NOTIF' AS COPY INTO gateway_events (record, source_file) FROM (SELECT $1, METADATA$FILENAME FROM @aisix_stage) FILE_FORMAT = (TYPE = JSON COMPRESSION = AUTO); ``` 为 `DESC INTEGRATION` 返回的 Snowflake 服务主体授予读取 Blob 容器的权限。 ## 查询请求遥测[​](#查询请求遥测 "查询请求遥测的直接链接") 继续通过 AISIX 发送流量后,检查 Snowpipe 是否正在接收文件: ``` SELECT SYSTEM$PIPE_STATUS('aisix_events_pipe'); ``` 确认数据已写入,并为原始记录创建视图: ``` SELECT COUNT(*) FROM gateway_events; CREATE OR REPLACE VIEW gateway_attempts AS SELECT record:request_id::string AS request_id, record:occurred_at::timestamp_tz AS occurred_at, record:requested_model::string AS requested_model, record:model_id::string AS model_id, record:attempt_index::number AS attempt_index, record:attempt_kind::string AS attempt_kind, record:status_code::number AS status_code, record:prompt_tokens::number AS prompt_tokens, record:completion_tokens::number AS completion_tokens, record:cost_usd::float AS cost_usd, record:upstream_latency_ms::number AS upstream_latency_ms, record:upstream_ttft_ms::number AS upstream_ttft_ms, record:downstream_latency_ms::number AS downstream_latency_ms, record:cache_status::string AS cache_status, record:guardrail_blocked::boolean AS guardrail_blocked, record:finish_reason::string AS finish_reason, source_file FROM gateway_events; ``` 使用 `downstream_latency_ms` 查看调用方经历的时间;该字段只出现在最后一次尝试中。使用 `upstream_latency_ms` 分析每次服务提供方尝试,使用 `upstream_ttft_ms` 查看该次尝试流式输出首个帧所需的时间。对于非流式请求、错误和缓存命中,首帧耗时字段会被省略或为零。 查询最近的尝试: ``` SELECT requested_model, status_code, prompt_tokens, completion_tokens, cost_usd, cache_status FROM gateway_attempts ORDER BY occurred_at DESC LIMIT 10; ``` 运行一个简单的成本和 Token 汇总: ``` SELECT requested_model, COUNT(DISTINCT request_id) AS requests, COUNT(*) AS attempts, SUM(prompt_tokens + completion_tokens) AS total_tokens, ROUND(SUM(cost_usd), 5) AS total_cost_usd FROM gateway_attempts GROUP BY requested_model ORDER BY total_cost_usd DESC; ``` ## 清理[​](#清理 "清理的直接链接") 测试结束后删除 Snowflake 对象: ``` DROP PIPE IF EXISTS aisix_events_pipe; DROP STAGE IF EXISTS aisix_stage; DROP VIEW IF EXISTS gateway_attempts; DROP TABLE IF EXISTS gateway_events; DROP STORAGE INTEGRATION IF EXISTS aisix_s3_int; DROP STORAGE INTEGRATION IF EXISTS aisix_az_int; DROP NOTIFICATION INTEGRATION IF EXISTS aisix_az_notif; ``` 移除创建的存储桶通知或 Event Grid 订阅。使用 AISIX Cloud 时,通过 Admin API 删除导出器: ``` curl -sS -X DELETE "$AISIX_CP/environments/$ENV_ID/observability_exporters/$EXPORTER_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" ``` 对于开源 AISIX 网关,请从 `resources.yaml` 中移除导出器条目,然后验证并重新加载文件。 ## 下一步[​](#下一步 "下一步的直接链接") 你已经将 AISIX 请求遥测加载到 Snowflake。当你需要把导出的用量事件与运行时指标、访问日志和响应头关联起来时,请继续阅读[指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md)。 --- # 指标与日志 AISIX AI 网关会公开聚合指标、逐请求日志、响应头和可导出的用量事件。这些信号共同反映服务健康状况,并将调用方可见的响应关联到产生该响应的模型、路由和策略结果。 ## 选择遥测来源[​](#选择遥测来源 "选择遥测来源的直接链接") 请先选择与运维问题匹配的来源;需要深入调查问题时,再按请求、模型或服务提供方关联各类信号。 | 运维问题 | 首选来源 | 提供的信息 | | -------------------------------------------- | --------------- | ------------------------------------------------------------------------------------ | | 各网关实例的流量是否健康? | Prometheus 指标 | 请求速率、延迟分布、Token 和成本计数、策略结果、路由健康、缓存行为和导出器投递健康。 | | 单个请求发生了什么? | 访问日志 | 结构化请求字段,包括状态、延迟、模型、服务提供方、请求 ID,以及可用时的路由结果。 | | 调用应用可以观察到什么? | 响应头 | 受支持路由上的请求关联、缓存结果、重试时机和选中目标提示。 | | 请求记录可以存储到哪里、如何分析或用于核算? | 用量事件 | 通过可观测性导出器投递的逐次尝试结果和消耗记录。 | ## 抓取 Prometheus 指标[​](#抓取-prometheus-指标 "抓取 Prometheus 指标的直接链接") Prometheus 指标是观察流量趋势、延迟、Token 计数、成本计数、限流结果、缓存行为和导出器投递健康状态的最佳起点。 AISIX 默认通过专用指标监听器在 `/metrics` 提供 Prometheus 指标。你可以通过启动期可观测性设置修改路径或禁用该端点。 该端点设计上不做认证。请保持专用指标监听器私有。 在启动配置中配置 Prometheus 暴露: config.yaml ``` observability: metrics: prometheus: enabled: true path: "/metrics" ``` 专用监听器默认绑定到 `0.0.0.0:9090`。如果 Prometheus 应从其他接口或端口抓取指标,请设置不同的监听地址。 抓取默认指标端点: ``` curl -sS "http://127.0.0.1:9090/metrics" ``` 产生流量后才会出现流量指标 AISIX 会在每次抓取时发布配置状态。其他指标族会在首次观测时注册,因此流量指标可能不会在启动后立即出现。请先发送一次模型请求,再检查 `aisix_requests_total` 和 `aisix_tokens_consumed_total` 等序列。 AISIX 使用 `aisix_` 前缀输出原生指标名称。使用直方图序列计算跨网关实例的延迟百分位数,并使用请求计数器分析成功率和路由情况。精确指标名称、标签范围和 PromQL 示例请参见[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 通过 `observability.metrics.labels` 可以选择各指标族输出的标签。配置示例、默认值和完整变量列表参见[指标标签与变量](https://docs.apiseven.com/ai-gateway/reference/metric-labels.md)。 ### 导入 Grafana 概览仪表板[​](#import-the-grafana-overview-dashboard "导入 Grafana 概览仪表板的直接链接") 预构建的 [AISIX AI Gateway 仪表板](https://grafana.com/grafana/dashboards/25746-aisix-ai-gateway/)提供网关流量、延迟、Token 吞吐量、支出、治理(限流、安全护栏和入站身份认证)及上游健康状况的概览。修订版 1 查询此版本提供的指标族,并且仅使用 Grafana 内置面板类型。它的 JSON 声明使用 Grafana 11.0.0;如果使用较早的 Grafana 版本,请在使用前验证该仪表板。 下载修订版 1: ``` curl -sS "https://grafana.com/api/dashboards/25746/revisions/1/download" -o aisix-dashboard.json ``` 在 Grafana 中依次选择 **Dashboards**、**New**、**Import**,然后上传 JSON 文件。选择抓取网关指标的 Prometheus 数据源。如果改为导入仪表板 ID `25746`,Grafana 会选择其最新修订版,而该版本可能会在此文档版本发布后发生变化。 该仪表板提供运维概览,并不是完整的指标目录。它没有用于缓存、预算、导出器、MCP、A2A 或配置状态指标的专用面板。完整列表和针对具体任务的 PromQL 请参见[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 服务提供方和模型变量只能筛选其指标携带相应标签的面板。该仪表板要求 `aisix_requests_total` 以及其筛选面板所用的指标族包含默认的 `provider` 和 `model` 标签。如果通过 `observability.metrics.labels` 删除了任一标签,请更新仪表板变量和受影响的查询。参见[指标标签与变量](https://docs.apiseven.com/ai-gateway/reference/metric-labels.md)。 可选功能的面板在这些功能产生数据之前会保持空白。支出面板反映网关在本地计算的支出,目前仅包括 Realtime 会话。对于开源 AISIX 网关,Realtime 支出要求模型配置 [`cost` 元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。AISIX Cloud 会在控制面计算其他请求成本,包括普通的 Chat Completions、Messages 和 Responses 请求;这些值不会填充此网关指标,请通过[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)和[请求日志](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md#request-logs)查看这些支出。 安全护栏面板要求已附加安全护栏。只有调用方在响应头发送前断开连接时,才会出现客户端取消数据。 ## 区分请求计数与尝试计数[​](#count-requests-and-attempts-separately "区分请求计数与尝试计数的直接链接") 请求和上游尝试是两种不同的计量单位,把两者混为一谈是数字看起来自相矛盾的最常见原因。一次客户端请求可能发起多次上游调用:对同一目标的重试,或在模型组内故障转移到下一个目标。AISIX 会分别统计这两种单位,且统计位置不同。 | 单位 | 统计位置 | 一个样本或一行代表什么 | | -------- | -------------------------------------------------------- | --------------------------------------------------------------------------------- | | 请求 | `aisix_proxy_requests_total`、`aisix_llm_requests_total` | 一次客户端请求,状态是调用方实际收到的状态码。 | | 尝试 | `aisix_deployment_requests_total` 及部署指标族 | 对某一个目标模型的一次上游调用。 | | 发出尝试 | `aisix_usage_events_emitted_total` | 一次用量事件的发出尝试,在投递队列接受或拒绝它之前计数。 | | 尝试 | 用量事件记录,以及基于其构建的用量日志 | 一次尝试,通过 `request_id` 与同一请求的其他尝试关联,并按 `attempt_index` 排序。 | 需要牢记的推论是:**被故障转移救回的失败尝试在请求计数器中是不可见的。** 调用方收到的是 200,因此请求计数器记录 `status="200"`,仅此而已。第一个目标返回的 502 存在于部署计数器和用量日志中,作为它自己的一次尝试。 因此,当一个模型组中只有一个目标损坏、其余健康时,网关的用量日志完全可能显示数万条 `5xx` 记录,而 `sum(increase(aisix_proxy_requests_total{status=~"5.."}[24h]))` 只返回几百。日志统计的是失败的尝试,指标统计的是看到失败的调用方。两者都没有错,也不应该趋于一致。 请按各查询真正回答的问题选用: ``` # 最终以服务端错误结束的请求——调用方实际经历的情况。 sum(increase(aisix_proxy_requests_total{status=~"5.."}[24h])) # 发生过故障转移、但最终仍以服务端错误结束的请求。 sum(increase(aisix_proxy_requests_total{status=~"5..", is_fallback="true"}[24h])) # 失败的上游尝试,按目标聚合——包含后续被故障转移救回的那些。 # 这是 5xx 用量日志行数在尝试层面的对应视图,范围限于通过模型组下发的端点。 sum(increase(aisix_deployment_failure_responses_total[24h])) by (model) # 成功救回请求的故障转移,按模型组和实际到达的目标聚合。 sum(increase(aisix_routing_successful_fallbacks_total[24h])) by (model, fallback_model) # 用量事件的发出尝试,以及被交接队列拒绝的事件。 sum(increase(aisix_usage_events_emitted_total{status_code="5xx"}[24h])) sum(increase(aisix_usage_event_drops_total[24h])) # 某个成员被限流拒绝的次数。`status` 携带原始 HTTP 状态码, # 因此无需扫描整个状态族即可定位单一故障模式。 sum(increase(aisix_usage_events_emitted_total{user_id="<member-id>", status="429"}[24h])) # 哪些队列交接被拒绝了。两个计数器携带相同的模型与 Provider Key 标签, # 因此该差值在按模型的粒度上同样成立,而不只是总量。 sum(increase(aisix_usage_event_drops_total[24h])) by (model, provider_key_name) ``` 在断定两个来源互相矛盾之前,请先确认它们覆盖的是同一批数据: * **抓取覆盖范围。** 请求计数器不带环境标签,因此除非服务该环境的每个网关实例都被抓取,否则来自用量记录的单环境数字无法与全网关范围的 PromQL 结果相比较。用 `sum by (job, instance) (...)` 可以看出哪些实例贡献了数据,再与实际在运行的实例对照。 * **时间窗口覆盖范围。** `increase(...[24h])` 只统计该区间内实际存在的样本。如果实例在窗口中途重启过,或 Prometheus 的保留期短于该窗口,结果覆盖的时间就短于用量日志筛选的时间。把原始计数器按同一区间画成曲线,就能同时看出这两类缺口。 * **投递。** `aisix_usage_event_drops_total` 统计的是在生产者向 worker 交接的队列处被拒绝的事件。队列接受事件之后,投递仍可能失败,而这个计数器并不会随之增加,因此它并不界定发出尝试数与最终进入存储的记录数之间的差额。队列丢弃可以按 `model` 分组查看。至于后续环节的失败,请监控控制面投递的 `telemetry batch failed (events dropped)`,以及导出器投递的 `sink delivery dropped after retries`。 * **从未离开网关的尝试。** deployment 系列统计的是上游调用,因此没有产生上游调用的尝试会被有意排除在外:被目标自身限流拒绝的尝试,以及在请求仍在组装阶段就被拒绝的尝试——例如凭证不可用、缺少 `model_name`、`api_base` 缺失或格式非法。这些尝试仍会出现在用量日志和 `aisix_usage_events_emitted_total` 中。因此这只是 deployment 尝试数低于用量日志尝试数的**原因之一**,而不是全部:上文提到的统计范围是另一个原因(deployment 系列只覆盖经模型组下发的端点,而用量事件还包含直连模型的尝试),本清单中的抓取、窗口和投递缺口同样会影响差额。请逐项隔离验证,不要把整个差额都当作网关内拒绝。不过这类排除有一个明确特征:配置错误的目标只会表现为失败的**请求**,而完全不产生 deployment 失败——服务提供方从未被请求过,因此没有任何数据归因到它。 ## 收集访问日志[​](#collect-access-logs "收集访问日志的直接链接") 访问日志描述单个代理请求。AISIX 会通过进程 logger 将其写入标准错误流,因此它们会出现在运行时收集的容器或进程日志中。 在启动配置中配置进程日志: config.yaml ``` observability: log_level: "info" ``` 进程环境可以通过 `RUST_LOG` 环境变量覆盖已配置的日志级别。 每个代理请求会写出一条访问日志条目,无论请求成功、失败或提前终止。条目会包含 method、path、status、latency、provider、model、API Key ID、request ID、Token 计数和路由结果等字段(如果相关值可用)。 条目的写出时机因响应类型而异,这也决定了它能携带哪些字段。非流式请求在请求结束时写出,因此条目包含网关已解析出的全部内容。流式请求在响应打开时写出,此时流还没有被消费——因此条目既没有 Token 计数,也没有服务提供方响应 ID,因为这两者都还不存在。流式请求的这些数值由下文的用量事件承载。 如果网关在写出条目时已经拿到该值,条目还会带上 `provider_request_id`:服务提供方自己返回的响应对象 ID,例如 OpenAI 的 `chat.completion.id`、Anthropic 的消息 `id` 或 Responses API 的 `resp_…`。服务提供方的控制台和技术支持渠道正是按这个 ID 检索一次调用的。只要没有可记录的 ID,该字段就会被省略而不是留空,因此可以按字段是否存在进行过滤。除上面的流式情况外,还包括:请求在下发之前就被拒绝(例如护栏拦截)、响应由缓存命中返回,以及服务提供方响应本身就不带 ID 的端点(如 Embedding、音频和图像生成)。 对于 ID 无法进入访问日志条目的调用,网关会单独输出一条 `provider call completed` 日志,其中包含 `request_id`、`attempt_index`、`attempt_kind` 和 `provider_request_id`。每一次返回了 ID 的服务提供方调用写一条——因此流式响应会产生一条,而在流中途发生故障转移的请求会按其发起的服务提供方调用各产生一条。可通过 `request_id` 将它们与访问日志条目关联,并通过 `attempt_index` 区分重试或故障转移请求中的不同调用。 另有两个字段描述的是请求所到达的连接,而不是请求本身。它们附着在整个请求上,因此会同时出现在访问日志条目、`provider call completed` 条目,以及这次请求在两者之间输出的每一条诊断日志上: | 字段 | 记录内容 | | ----------------------- | ------------------------------------------------------------------------------------------------------------- | | `peer` | 已接受的下游连接的对端地址,格式为 `<ip>:<port>`。 | | `downstream_request_id` | 随 `x-request-id` 请求头到达的关联 ID——反向代理、Ingress 控制器和服务网格会为它们转发的每个请求打上该请求头。 | 两者都是按实际情况记录而非固定声明:两者都没有携带的请求既不会输出这两个字段,也不会输出空值,因此可以按字段是否存在进行过滤。 `peer` 不是调用方的 IP 地址,把二者互相替代会同时失去各自的意义。网关会另行解析调用方地址——位于受信任代理之后时遵循 `proxy.real_ip`——并将其用于访问控制和用量记录,该取值不带端口。`peer` 则是这次请求实际到达时所用 TCP 连接的对端,端口正是它的全部价值所在:当网关位于四层负载均衡器之后并使用宿主机网络时,`peer` 是唯一能把一条网关日志与前置代理关于同一条连接的记录对应起来的字段。 流式响应是这种附着关系唯一可能悄悄失效的场景:它的响应体是在一次请求的日志上下文通常已经结束之后才写出的。流式路径会显式地把该上下文延续下去,因此流结束时写出的日志——包括 `provider call completed`——仍然携带与请求其余部分相同的 `request_id`、`peer` 和 `downstream_request_id`。 如果调用方在网关发送响应头之前断开连接,也会生成一条日志,状态码为 `499`、`error_kind="client_disconnected"`。该条目会携带请求当时已解析出的模型和服务提供方,但没有 Token 字段——请求根本没有走到可以统计 Token 的响应阶段。若请求在模型解析之前就被放弃,则两者都不会有。此类请求也会计入 [`aisix_proxy_client_cancelled_requests_total`](https://docs.apiseven.com/ai-gateway/reference/metrics.md#request-metrics)。如果调用方在响应传输中途断开,则不会以这种方式记录,因为该请求已经有正常状态码和用量事件。 因超过 `proxy.request_body_limit_bytes` 而被拒绝的请求会以 `aisix::body_limit` 为日志目标生成第二条日志,包含 `declared_content_length`、`configured_limit_bytes`、`drained_bytes` 和 `drain_outcome`。可通过 `request_id` 将其与访问日志条目关联。 `drain_outcome` 表示网关如何结束对被拒绝请求体的读取,并决定调用方最终看到什么。`completed` 表示调用方发送了声明的全部内容,因此可以读取 `413` 响应。`cap_reached`、`timeout` 和 `client_read_error` 表示读取提前停止,因此调用方通常会看到连接关闭。`completed` 以 `info` 级别记录;另外三种结果以 `warn` 级别记录,并按每种结果每秒最多一条进行限流。因此,请使用 [`aisix_proxy_request_body_limit_rejections_total`](https://docs.apiseven.com/ai-gateway/reference/metrics.md#request-metrics) 查看总量。 `access_log` 字段目前为保留字段,不会产生任何作用。代理处理器仍会输出结构化访问日志,但没有单独的访问日志格式或 sink 设置。当日志需要离开网关主机时,请使用运行时日志流水线收集标准错误流。 ## 将响应与遥测关联[​](#将响应与遥测关联 "将响应与遥测关联的直接链接") 响应头提供调用方可见的关联和路由提示。在受支持路径上,它们可以标识请求、缓存结果、重试时机或选中的目标。 使用请求 ID 和其它受支持的响应头,将调用方可见的响应关联到访问日志或导出的记录。每条代理路由适用的响应头范围请参见[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md#proxy-response-headers)。 一次调用最多会带着三个 ID,它们之间不能相互替代: | ID | 由谁分配 | 用途 | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `request_id` | 由网关分配,每个请求一个;调用方自带 ID 且被 AISIX 采用时则由调用方决定(见下文)。通过 `x-aisix-request-id` 响应头返回。 | 将响应与该请求产生的任何网关访问日志和用量事件关联起来,包括已导出的记录或控制台日志页面中的条目。它对服务提供方没有意义。 | | `downstream_request_id` | 由网关前面的组件在 `x-request-id` 请求头中给出。收到时记录在这次请求的日志行上,绝不会返回给调用方。 | 在你的 Ingress 控制器、反向代理、服务网格或 CDN 的日志中定位同一个请求。 | | `provider_request_id` | 由服务提供方在响应体中给出(前提是它会返回)。按 attempt 记录在该次尝试的用量事件上,以及上文所述的日志条目中。 | 在服务提供方自己的控制台中定位同一次调用,或提供给服务提供方技术支持。 | 调用方报障时通常手上只有 `request_id`——网关在每个响应上都会返回它。先用它查到该请求,再从实际提供响应的那次尝试中读取 `provider_request_id`,然后拿这个 ID 去找服务提供方。如果调用方保留了完整响应体,也可能直接从中读到服务提供方的 ID,但仅限于会返回该 ID 的端点。 `downstream_request_id` **只记录,绝不采用。** 调用方提供的 ID 是否成为网关自己的 `request_id` 是另一个独立的决定,由 [`proxy.request_id.accept_headers`](#choose-the-accepted-headers) 控制——它默认只接受 `x-aisix-request-id`。因此位于 Ingress 之后的网关通常会记录两个含义不同的 ID,二者不会被混淆。该字段按与被采用的 ID 相同的规则筛查(参见[可接受的取值](#accepted-values)),请求头缺失或取值不可用时会被省略。 ### 复用自己的请求 ID[​](#reuse-your-own-request-id "复用自己的请求 ID的直接链接") 如果你的服务已经为该业务调用生成了请求 ID,直接把它发给 AISIX,AISIX 就会采用这个 ID,而不再自行生成。该 ID 随即成为这次请求在各处的身份标识:`x-aisix-request-id` 响应头、访问日志和这次请求产生的每一条用量事件上的 `request_id`,以及服务提供方收到的 `x-aisix-request-id`。 这样一来,你排查一次请求所用的各条线索,都以自己应用日志里已有的 ID 为键——网关访问日志、导出的用量事件,以及 AISIX Cloud 的[请求日志](https://docs.apiseven.com/ai-gateway/cloud/logging-and-auditing.md#request-logs)都是如此,无需再维护第二套映射关系。 通过 `x-aisix-request-id` 发送: ``` # AISIX_PROXY 是网关源站;请勿包含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" curl "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -H "x-aisix-request-id: req_abc123-orders-svc" \ -d '{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}]}' -i ``` 响应会回显同一个值: ``` HTTP/1.1 200 OK x-aisix-request-id: req_abc123-orders-svc ``` 发生重试或故障转移的请求会为每次尝试各产生一条用量事件,它们全部携带你的 ID,因此按该 ID 过滤得到的是完整的调用链,而不只是最终成功的那次尝试。 #### 可接受的取值[​](#accepted-values "可接受的取值的直接链接") ID 长度为 1–256 字节且仅包含可见 ASCII 字符(`!` 到 `~`)时按原值使用:不能含空格、控制字符或非 ASCII 字符。UUID、ULID、`req_abc123` 这类带前缀的 ID,以及 nginx `$request_id` 中的十六进制 ID 都符合要求。 超出该范围的取值会被忽略,AISIX 转而生成一个 UUID,与完全不发送 ID 时的行为一致。请求本身绝不会因为关联 ID 而被拒绝。 AISIX 不要求 ID 唯一。为两次不同的请求发送相同的 ID,会让它们在所有以该 ID 为键的线索中无法区分,因此请为每次请求生成新的 ID。 #### 选择接受的请求头[​](#choose-the-accepted-headers "选择接受的请求头的直接链接") 默认情况下 AISIX 只读取自己的 `x-aisix-request-id`。通过 `proxy.request_id.accept_headers` 修改: config.yaml ``` proxy: request_id: accept_headers: ["x-aisix-request-id", "x-request-id"] ``` 请求头按列出的顺序依次查找,第一个可接受的取值胜出,因此该列表同时也是优先级顺序。仅使用环境变量的部署通过 `AISIX_PROXY__REQUEST_ID__ACCEPT_HEADERS` 以逗号分隔设置该列表。 默认不接受 `x-request-id` 是有意为之。反向代理、Ingress 控制器和负载均衡器会为它们转发的每个请求都打上该请求头,因此在 AISIX 位于它们之后的部署中启用它,意味着关联 ID 来自你的基础设施而非发起调用的服务。当 AISIX 是第一跳,或者你确实希望按代理分配的 ID 来追踪时,再把它加进来。 不过,把它加进这个列表并不是它可见的前提。只要 `x-request-id` 的取值可接受,它都会作为 `downstream_request_id` 记录在这次请求的日志行上,因此不改这项设置也能按基础设施自己的 ID 检索。把它列进来还会多做一件事:让该取值成为这次请求在各处的身份标识——响应头、访问日志中的 `request_id` 以及每一条用量事件——此时 `request_id` 和 `downstream_request_id` 会持有相同的值,这如实反映了实际发生的情况。 设置 `accept_headers: []` 可完全忽略调用方提供的 ID,始终自行生成。 如果某个名称不是合法的 HTTP 请求头名称,网关会启动失败,而不是静默跳过。 ## 导出用量事件[​](#导出用量事件 "导出用量事件的直接链接") 用量事件是受支持代理路径输出的逐次尝试记录。发生重试或故障转移的请求会生成多条具有相同 `request_id` 的事件,并按 `attempt_index` 排序。因此统计这些记录得到的是尝试数而非请求数——在拿记录条数与请求指标作比较之前,请先阅读[区分请求计数与尝试计数](#count-requests-and-attempts-separately)。每条事件都会包含请求结果、消耗详情、调用方请求的模型别名,以及网关能够观测到时处理该次尝试的解析模型。由响应缓存返回的响应会把命中层记录在 `cache_hit_layer`(`exact` 或 `semantic`),语义命中还会把匹配相似度记录在 `cache_similarity`。 延迟字段会区分服务提供方耗时和调用方可见耗时: | 字段 | 范围 | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `upstream_latency_ms` | 一次上游尝试所花费的时间,不包括请求解析、安全护栏、路由、重试延迟和先前尝试。 | | `upstream_ttft_ms` | 从一次上游尝试开始到首个流式帧的时间,无论帧类型为何——包括 `response.created`、仅含角色的 chat 增量等元数据起始帧,与调用方侧代理的统计口径一致。非流式请求、错误和缓存命中时省略或为零。 | | `downstream_latency_ms` | 调用方等待请求的总时间,包括网关处理、重试及重试延迟和所有输出暂存;仅出现在最后一次尝试中。 | 如果调用方在流式响应传输中途断开,仍会生成用量事件,因为上游已经执行工作并可能计费。该事件的状态码为 `499` 而不是 `200`,Token 计数仅覆盖断开前已到达的内容。统计流式成功请求时请使用 `status_code = 200`,以排除被放弃的响应。 ### 区分请求类型[​](#tell-request-kinds-apart "区分请求类型的直接链接") 每条事件都携带 `operation`,即该请求要求网关做的事情。没有这个字段时,一个字段说明由哪种协议访问网关、另一个说明由哪个模型作答,却没有任何字段说明这次调用是对话、图片还是视频:所有 OpenAI 兼容端点上报的 `inbound_protocol` 都相同,因此对话补全、图片生成和视频提交会汇成同一条无法区分的流量。 取值来自请求匹配到的端点,因此是一个可安全用于索引、分组和绘图的固定小集合: | 取值 | 端点 | | --------------------------------- | -------------------------------------------------------------------- | | `chat` | `/v1/chat/completions` | | `messages` | `/v1/messages` | | `count_tokens` | `/v1/messages/count_tokens` | | `responses` | `/v1/responses` | | `completions` | `/v1/completions` | | `embeddings` | `/v1/embeddings` | | `rerank` | `/v1/rerank` | | `image_generation` | `/v1/images/generations` | | `image_edit` | `/v1/images/edits` | | `transcription` | `/v1/audio/transcriptions` | | `translation` | `/v1/audio/translations` | | `speech` | `/v1/audio/speech` | | `video_generation` | `POST /v1/videos` | | `realtime` | `/v1/realtime` | | `files`、`batches`、`fine_tuning` | 文件、批处理和微调管理端点 | | `batch_completion` | 网关自己对已完成批处理作业的计量,在作业完成时记录,而非在提交时记录 | | `mcp`、`a2a` | MCP 网关和 A2A 网关 | | `passthrough` | 透传路由 | 在按该字段编写查询之前,有三点需要了解: * **它描述的是请求,不是结果。** 失败的请求、被护栏拒绝的请求,携带的取值与成功请求相同。它是这类记录上唯一能说明端点的字段。 * **它以请求为作用域。** 发生重试或故障转移的请求会为每次尝试生成一条事件,且每次尝试携带相同取值,因此按 operation 统计事件数得到的是尝试数。参见[区分请求计数与尝试计数](#count-requests-and-attempts-separately)。 * **轮询视频作业不是视频生成。** 只有提交(`POST /v1/videos`)会产生用量事件,查询作业状态或下载结果都不会。因此 `video_generation` 的计数是被请求生成的视频数量,而不是围绕这些视频发出的请求数量。 该字段属于记录的元数据,因此两种内容模式下都存在。配置为 `metadata_only` 的导出器从不接收提示词,但依然可以按类型拆分流量——在那里靠检查内容是完全做不到的。 在阿里云 SLS 中,该字段作为独立列到达,无需解析。先在 logstore 索引中为它开启分析——SQL 分析读取的是已建索引的字段: ``` * | SELECT operation, COUNT(*) AS calls, SUM(prompt_tokens + completion_tokens) AS tokens GROUP BY operation ORDER BY calls DESC ``` 要筛选某一类流量,直接按它过滤即可——`operation: video_generation`——而不必匹配模型名称或搜索提示词。模型名称在这里并不是好的替代品:同一个模型可以服务多个端点,而且调用方是通过别名和模型组来寻址模型的,因此 `requested_model` 回答的是"命中了哪个配置条目",而不是"这是哪一类调用"。 ### 将事件归因到成员[​](#attribute-events-to-a-member "将事件归因到成员的直接链接") 每条事件都携带 `user_id`:发起该请求所用 API 密钥所属的组织成员,该归属在密钥本身上设置。密钥未绑定成员时该字段不存在——归属是在创建或编辑密钥时显式指定的,不会根据创建者自动推断。 一个成员通常持有多个凭证,而该字段正是把它们统一为同一身份的依据。JWT 认证的请求以其身份解析到的 API 密钥的身份运行,因此同时通过 API 密钥和 OIDC Token 调用的成员会产生 `api_key_id` 不同、`user_id` 相同的事件。按成员筛选可以拿到完整视图,按单个密钥筛选只能拿到其中一部分。 该值是请求发生时拍下的快照,而不是读取事件时再做的查询。把密钥改绑到另一个成员,只会改变后续请求的归属,此前的事件仍归属于原先的成员——这正是历史查询可回答的前提。删除密钥也不会抹掉它此前产生的那些事件的归属。 由不记录该字段的旧版本数据面写入的事件不携带成员,因此成员筛选覆盖的是从数据面升级之后的流量。 在控制台中,**日志**页面以 **成员** 筛选器提供该能力,并配有 **状态** 筛选器,后者接受状态族(`4xx`)、具体状态码(`429`)或区间(`500-599`)。二者组合即可用一次查询回答「该成员最近 24 小时内哪些请求被限流了」这类问题。CSV 导出同时包含 `user_id` 和成员名称。 用量事件通过 sink 消费,而不是从本地端点读取。配置可观测性导出器,将它们发送到 OTLP/HTTP、对象存储、阿里云 SLS 或 Datadog。 ## OpenAI 缓存写入 Token[​](#openai-cache-write-tokens "OpenAI 缓存写入 Token的直接链接") OpenAI 可以在 Chat Completions 的 `usage.prompt_tokens_details` 或 Responses 的 `usage.input_tokens_details` 中返回 `cache_write_tokens`。AISIX 将这个原始值保留为用量事件的可选字段 `cache_write_tokens`,包括通过 `/v1/messages` 或 `/v1/responses` 桥接的请求,以及支持协议识别的透传路由。此能力需要使用 1.1.0 之后的网关版本。 用量事件字段 ``` { "prompt_tokens": 101, "completion_tokens": 11, "cached_prompt_tokens": 19, "cache_write_tokens": 37 } ``` 上游未提供时省略此字段;明确返回 `0` 时保留零值。AISIX Cloud 的日志详情、用量事件 API 和 JSON/CSV 导出均保留这一区别,CSV 用空单元格表示缺失值。对于使用字段前缀的日志后端,沿用其原有前缀,例如 Datadog 中为 `aisix.cache_write_tokens`。 此字段与 Anthropic 的可累加字段 `cache_creation_tokens` 相互独立,不增加输入/输出 Token 总量,也不改变现有计费计算。上例的输入加输出仍为 112。现有缓存计数器不会因此重命名或合并。 ## 下一步[​](#下一步 "下一步的直接链接") 配置[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md),把用量事件发送到外部收集器、日志目标、对象存储或数据仓库工作流。构建 Prometheus 控制面板或告警时,请使用[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 --- # 私有化安装 使用 Docker Compose、Helm 或离线包,在你运营的基础设施中安装 AISIX Cloud 控制面。本指南可帮助你选择安装方式、配置控制面端点,并验证持久化环境。 该安装方式提供与混合云相同的 [AISIX Cloud 控制面工作流](https://docs.apiseven.com/ai-gateway/cloud/overview.md),包括资源管理、网关证书签发、用量上报和预算执行。控制面服务及数据均保留在你的基础设施中,也支持完全隔离的内网环境。 如需在本地评估环境中继续创建网关资源并发送第一个 AI 请求,请改用 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)。 许可证 在生产环境中使用 AISIX Cloud 控制面和控制台需要商业许可证。在生产环境中部署控制面前,请[联系 API7](https://api7.ai/contact),或发送邮件至 <support@api7.ai>。 ## 规划安装[​](#规划安装 "规划安装的直接链接") 根据目标基础设施和网络访问条件选择安装方式: | 安装方式 | 目标环境 | 要求 | | -------------- | ------------------------------ | --------------------------------------------------------------------------------------- | | Docker Compose | 可访问互联网的主机 | Docker 与 Docker Compose V2、cURL、`tar`、OpenSSL,以及 Docker Hub 访问权限 | | Helm | 可访问互联网的 Kubernetes 集群 | 可用的集群、Helm、`kubectl`、OpenSSL,以及 Docker Hub 访问权限 | | 离线部署包 | 隔离网络主机 | Docker 与 Docker Compose V2、`tar`、OpenSSL,以及一台可以使用 cURL 下载部署包的独立机器 | 使用 Helm 安装前,请决定使用随包提供的 PostgreSQL 数据库,还是使用[外部数据库](https://docs.apiseven.com/ai-gateway/on-premises/external-database.md)。Docker Compose 和离线部署包只能使用随包数据库。还需确定公开控制台源站,以及网关要连接的数据面管理器端点。可以先使用本地端点,但在公开控制台或连接其他主机上的网关前,必须配置外部可访问的端点。 Docker Compose 安装默认使用主机端口 `5432`、`8080` 和 `7944`。请确保这些端口可用,或配置其他主机端口映射。有关各组件、流量方向和建议暴露方式,请参阅[端口参考](https://docs.apiseven.com/ai-gateway/reference/ports.md#on-premises-control-plane-ports)。 ## 控制面组件[​](#控制面组件 "控制面组件的直接链接") 每种安装方式都包含以下组件: | 服务 | 作用 | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `cp-api` | 管理组织、环境、资源和计费 | | `dp-manager` | 签发 mTLS 证书,并向数据面下发配置 | | `dashboard` | 浏览器界面 | | PostgreSQL 数据库 | 共享数据存储。Docker Compose 部署包包含该数据库;Helm 可以部署随包数据库,也可以连接[外部数据库](https://docs.apiseven.com/ai-gateway/on-premises/external-database.md)。 | 在线和离线 Docker Compose 部署包必须使用随包提供的 PostgreSQL 16 服务。Helm Chart 可以部署随包 PostgreSQL 实例,也可以连接外部数据库。 AISIX 网关会作为数据面单独运行。数据面通过 mTLS 主动连接到 `dp-manager`,因此控制面不需要能够入站访问网关主机。 ## 生产资源建议基线[​](#生产资源建议基线 "生产资源建议基线的直接链接") 以下规格是部署容量规划的起点,不是 Helm Chart 的默认值、基准测试得出的容量保证,也不是适用于所有工作负载的固定下限。请根据请求速率、请求大小、已启用的流量控制策略、网关数量以及数据保留期进行压测和调整。 ### 在主机上使用 Docker Compose 或离线部署包[​](#在主机上使用-docker-compose-或离线部署包 "在主机上使用 Docker Compose 或离线部署包的直接链接") 在线和离线 Docker Compose 部署包提供单主机拓扑,为每个控制面服务启动一个实例,并启动随包提供的 PostgreSQL 数据库。它们不支持外部数据库,也不提供控制面高可用所需的多主机服务配置。 生产高可用拓扑请使用 Helm,并参考下表中的实例数量。使用部署包进行评估或非高可用部署时,可以根据 CPU、内存和存储列评估主机容量。 CPU、内存和主机存储均按单个组件实例计算。主机存储是为操作系统、容器镜像、平台管理的日志以及组件本地状态预留的主机容量,不等同于 Kubernetes 中应用持久卷的容量要求。 | 组件 | CPU | 内存 | 主机存储 | 起始实例数 | 规划说明 | | ------------------ | ------ | ------- | ---------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | AISIX 网关 | 4 核 | 8–16 GB | ≥100 GB | 每个网关部署至少 3 个,建议 4 个 | 随业务流量横向扩容。高并发或启用安全护栏时从 16 GB 起步;需要保留更长时间的本地日志时,请增加主机存储。 | | `cp-api` | 2 核 | 4 GB | ≥32 GB | 2 | 无状态服务;将实例分布到不同故障域。 | | `dp-manager` | 2–4 核 | 4–8 GB | ≥32 GB | 2 | 处理配置下发、网关心跳和用量遥测;将实例分布到不同故障域。 | | `dashboard` | 1–2 核 | 2 GB | ≥20 GB | 2 | 无状态服务;将实例分布到不同故障域。 | | PostgreSQL | 4–8 核 | 16 GB | ≥500 GB NVMe SSD | 3 | 关键有状态组件。生产高可用部署请使用 Helm 并连接外部 PostgreSQL,例如主节点、同步备用节点和异步备用节点;根据用量事件保留期调整存储。 | | Prometheus(可选) | 4 核 | 8–16 GB | ≥200 GB | 1–2 | 用于存储监控指标。如果已有 Prometheus,可以复用现有部署;根据指标基数和保留期调整存储。 | 对于较小的部署,`cp-api`、`dp-manager`、`dashboard` 和 Prometheus 可以共用服务器,但必须为各组件预留 CPU 和内存,并为容器镜像和日志提供充足的共享主机容量。请将冗余实例分布到不同故障域。 ### 使用 Helm 部署到 Kubernetes[​](#helm-on-kubernetes "使用 Helm 部署到 Kubernetes的直接链接") 在 Kubernetes 中,应按副本规划计算资源,并根据[性能与容量规划](https://docs.apiseven.com/ai-gateway/deployment/performance-and-sizing.md)单独扩缩 AISIX 网关。下列规格是容量规划建议,而不是 Chart 的默认值: | 组件 | 单个副本 CPU | 单个副本内存 | 起始副本数 | 规划说明 | | ------------------ | ------------ | ------------ | -------------------------------- | --------------------------------------------------------- | | AISIX 网关 | 4 核 | 8–16 GB | 每个网关部署至少 3 个,建议 4 个 | 随业务流量横向扩容。高并发或启用安全护栏时从 16 GB 起步。 | | `cp-api` | 2 核 | 4 GB | 2 | 无状态服务;将副本分布到不同故障域。 | | `dp-manager` | 2–4 核 | 4–8 GB | 2 | 将副本分布到不同故障域。 | | `dashboard` | 1–2 核 | 2 GB | 2 | 无状态服务;将副本分布到不同故障域。 | | PostgreSQL | 4–8 核 | 16 GB | 生产高可用部署使用 3 个 | 使用外部高可用部署,而不是随包提供的单实例数据库。 | | Prometheus(可选) | 4 核 | 8–16 GB | 1–2 | 如果已有 Prometheus,可以复用现有部署。 | 默认控制面 Helm Chart 不会为 `cp-api`、`dp-manager` 或 `dashboard` 分配应用持久卷。容器镜像和平台管理的日志应计入 Kubernetes Node 容量,而不是作为每个 Pod 的存储要求。如果在集群中自行运行 PostgreSQL 或 Prometheus,请单独配置持久存储,并根据用量事件或指标的保留期调整容量。建议起始容量为每个 PostgreSQL 实例至少 500 GB NVMe SSD、每个 Prometheus 实例至少 200 GB。 不要将 PostgreSQL 副本放在同一故障域或共享存储上。随附的 PostgreSQL Chart 默认不提供复制数据库,请参阅[高可用](https://docs.apiseven.com/ai-gateway/cloud/high-availability.md)和[外部数据库](https://docs.apiseven.com/ai-gateway/on-premises/external-database.md)。 这些规格只覆盖 AISIX 组件,不包含上游模型推理所需的计算资源。AISIX 本身不要求 GPU。 ## 在线部署[​](#在线部署 "在线部署的直接链接") 当主机或 Kubernetes 集群可以从 Docker Hub 拉取容器镜像时,请使用在线部署。 ### Docker Compose[​](#docker-compose "Docker Compose的直接链接") 对于已安装 Docker 和 Docker Compose 的主机,可以使用 Docker Compose。快速开始 URL 会解析到当前版本。 ``` curl -sL "https://run.api7.ai/aisix-self-hosted/quickstart" | bash ``` 该脚本会将部署包下载到 `./aisix-self-hosted`,生成包含新密钥的 `.env` 文件,从 Docker Hub 拉取镜像,并启动整个服务栈。 该部署包使用随包提供的 PostgreSQL 服务,不支持外部数据库。如需使用外部 PostgreSQL 数据库,请使用 [Helm 安装](#helm-on-kubernetes)。 启动完成后,脚本会打印控制台 URL。默认 URL 为 `http://localhost:8080`。打开控制台后,创建第一个管理员账号。 在 `./aisix-self-hosted` 中管理服务栈: ``` ./aisix-self-hosted/run.sh logs # 查看日志 ./aisix-self-hosted/run.sh stop # 停止容器 ./aisix-self-hosted/run.sh down # 删除容器(保留数据卷) ``` ### 使用 Helm 部署到 Kubernetes[​](#使用-helm-部署到-kubernetes "使用 Helm 部署到 Kubernetes的直接链接") 在 Kubernetes 中,可以从 API7 Helm 仓库安装 chart: ``` helm repo add api7 https://charts.api7.ai helm repo update helm install aisix-cp api7/aisix-cp --version 1.2.0 \ --set secrets.masterKey="$(openssl rand -base64 32)" \ --set secrets.betterAuthSecret="$(openssl rand -base64 48)" \ --set postgresql.auth.password="$(openssl rand -hex 24)" \ --set postgresql.auth.postgresPassword="$(openssl rand -hex 24)" ``` 默认情况下,该 chart 会部署核心 API、数据面管理器、控制台和随包 PostgreSQL 实例。 配置外部访问前,可以通过端口转发访问 `cp-api` 服务: ``` kubectl port-forward svc/aisix-cp-api 8080:8080 ``` 端口转发运行期间,打开 `http://localhost:8080`。 如果需要使用已有数据库,请先[准备外部数据库和角色](https://docs.apiseven.com/ai-gateway/on-premises/external-database.md)。然后将 `postgresql.builtin=false` 禁用随包 PostgreSQL chart,并配置顶层 `externalDatabase.*` 值。 如需在本地查看默认 chart values,请运行: ``` helm show values api7/aisix-cp --version 1.2.0 ``` Chart 源码和软件包发布在 [`aisix-cp-1.2.0` Helm Chart Release](https://github.com/api7/api7-helm-chart/releases/tag/aisix-cp-1.2.0) 中。 注意 请使用 URL 安全的数据库密码,例如通过 `openssl rand -hex 24` 生成的值。数据库密码会嵌入 `postgres://` 连接 URL 中,`openssl rand -base64` 生成的 `+`、`/`、`=` 等字符可能破坏 URL。 ## 离线内网部署[​](#离线内网部署 "离线内网部署的直接链接") 对于无法访问镜像仓库的主机,请使用离线部署包。离线包包含所有必要的容器镜像。 离线包 URL 固定为 AISIX 1.2.0。 在可以访问互联网的机器上下载部署包: ``` curl -fSL "https://run.api7.ai/aisix-self-hosted/aisix-self-hosted-offline-1.2.0.tar.gz" \ -o aisix-self-hosted-offline-1.2.0.tar.gz ``` 将部署包传输到离线主机,然后启动服务栈: ``` tar -xzf aisix-self-hosted-offline-1.2.0.tar.gz cd aisix-self-hosted ./run.sh ``` 启动脚本会执行以下操作: * 加载内置容器镜像 * 生成包含新密钥的 `.env` 文件 * 在无互联网访问的情况下启动服务栈 * 启动完成后打印控制台 URL 默认控制台 URL 为 `http://localhost:8080`。 随包提供的 `cp-api` 镜像包含模型价格快照,因此用量和预算计算可以在不访问 `models.dev` 的情况下初始化。启动时,控制面会从该快照加载模型价格目录。如需改用在线价格,请在 `.env` 中设置 `AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH=`,并重新创建 `api` 服务。价格目录相关设置请参见[私有化部署配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md#pricing-catalog)。 ## 配置外部访问[​](#配置外部访问 "配置外部访问的直接链接") 在将控制面暴露到本地主机或集群之外之前,请配置公开控制台源站和数据面管理器端点。 对于 Docker Compose,请编辑 `.env`。对于 Kubernetes,请更新 Helm values: | Docker Compose 设置 | Helm value | 作用 | | ----------------------------- | ------------------- | ----------------------------------------------------------------------------------------- | | `AISIX_CLOUD_PUBLIC_BASE_URL` | `api.publicBaseURL` | 面向浏览器的源站,例如 `https://aisix.example.com`。登录时会根据该值校验 session issuer。 | | `AISIX_CLOUD_DPMGR_BASE_URL` | `api.dpmgrBaseURL` | 数据面主机连接的 `dp-manager` mTLS 端点,可以是 DNS 名称或 IP 地址。 | Helm Chart 默认将 `cp-api`、`dp-manager` 和控制台服务公开为 `ClusterIP`。请通过适合你集群的网络端点公开 `cp-api` 和 `dp-manager` 服务,再将上述两个公开访问参数设置为相应端点。 `dp-manager` 同样会接收数据面管理器端点,并为该主机签发 TLS 服务器证书。数据面会根据实际连接的地址验证证书,因此该值必须与生成的网关安装命令中的端点一致,无论该端点是 DNS 名称还是 IP 地址。 更新这些设置后,请使用 `docker compose up -d` 重新创建相关服务,或使用 `helm upgrade` 应用变更。 ### 可信登录源站[​](#可信登录源站 "可信登录源站的直接链接") 登录请求只接受来自可信浏览器源站的请求。公开 base URL 的源站会自动受信任,同时还会信任它的 loopback 对应源站。这个对应源站会在 `localhost` 与 `127.0.0.1` 之间替换主机名,并保持与 base URL 相同的 scheme 和端口。例如,base URL 为 `http://localhost:8080` 时,也会信任 `http://127.0.0.1:8080`,但不会信任不同端口或不同 scheme。这样,本地安装可以从两个地址访问。无需在其它位置再次列出 base URL。 只有当控制台会通过多个主机名访问时,才需要设置额外源站,例如第二个域名或反向代理地址。请以逗号分隔: | Docker Compose 设置 | Helm value | 作用 | | ----------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------- | | `AISIX_TRUSTED_ORIGINS` | `ui.extraEnvVars`(添加 `AISIX_TRUSTED_ORIGINS`) | 额外登录源站,逗号分隔,例如 `https://console.example.com,https://admin.example.com`。 | 来自不可信源站的登录尝试会失败,并提示该地址不允许访问。将该源站添加到这里即可解决。 更多 Docker Compose 环境变量和 Helm values 请参见[私有化部署配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md)。 ## 验证安装[​](#验证安装 "验证安装的直接链接") 通过配置的公开 base URL 打开控制台。对于新安装,请创建第一个管理员账号,然后登录。当前运行的控制面版本显示在控制台左侧导航底部,格式可能是以下两种之一: * `v1.0.0`:正式发布版本。查看[发布说明](https://docs.apiseven.com/ai-gateway/release-notes.md)或报告问题时,请提供该版本号。 * `dev · 2f9c1ab`:基于开发提交而非正式版本构建,并以缩写的提交 SHA 标识。 无需登录也可以获取相同的版本标识,便于在脚本和支持信息包中使用。如果控制面不是通过默认本地地址访问,请将下面的 base URL 替换为实际公开 base URL: ``` AISIX_CP_URL="http://localhost:8080" curl -sS "${AISIX_CP_URL}/api/config/public" | jq '{cp_version, cp_commit}' ``` ``` { "cp_version": "1.0.0", "cp_commit": "a22f131" } ``` API 返回的正式版本号不包含控制台所显示的 `v` 前缀。如果构建并非来自正式版本,`cp_version` 为空;无论哪种情况,`cp_commit` 都会标识对应提交。 各网关实例的版本会单独显示在环境的 **Data planes** 视图中,因为控制面和网关分别升级。 ## 下一步[​](#下一步 "下一步的直接链接") 创建或选择目标[组织和环境](https://docs.apiseven.com/ai-gateway/cloud/organizations-and-environments.md),然后[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md),签发网关证书并接入提供流量服务的运行时。 使用[私有化部署配置参考](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md)查看 Docker Compose 环境变量和 Helm values。 --- # 外部数据库 使用 Helm 安装的 [AISIX Cloud 控制面](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md)可以使用 Chart 随附的 PostgreSQL 实例,也可以使用由 DBA 团队管理的外部 PostgreSQL 数据库。外部数据库连接角色需要特定数据库权限,但不需要 `SUPERUSER`。不支持其它数据库引擎。 Docker Compose 必须使用随包 PostgreSQL 在线和离线 Docker Compose 部署包不支持外部数据库。其 Compose 文件会将控制面服务的数据库 URL 指向随包提供的 `postgres` 服务,且不会在 `.env` 中提供覆盖项。控制面必须连接外部 PostgreSQL 数据库时,请使用 Helm。 控制面服务会共享同一个数据库: * `cp-api`:控制面 API Server,启动时会执行 schema migration。 * `dp-manager`:数据面管理器,连接同一个数据库,但不会执行控制面应用的 migration。其内嵌 Kine 后端会管理自己的存储 schema。在全新数据库中,如果应用 schema 尚未就绪,`dp-manager` 会重试最多约两分钟,等待 `cp-api` 完成 migration。 * 控制台:控制面用户界面,将身份认证数据存储在同一个数据库中。 ## PostgreSQL 要求[​](#postgresql-要求 "PostgreSQL 要求的直接链接") * PostgreSQL 14 或更高版本。 * 一个由控制面连接角色拥有的空数据库。 * 一个带 `CREATEROLE` 和 `BYPASSRLS` 权限、但不是 `SUPERUSER` 的登录角色。 * 不需要 PostgreSQL 扩展。UUID 使用内置的 `gen_random_uuid()`。 ## 为什么控制面需要这些权限[​](#为什么控制面需要这些权限 "为什么控制面需要这些权限的直接链接") 首次启动时,`cp-api` 会准备数据库 schema,并创建一个内部低权限角色。连接角色需要足够权限来完成该引导过程,以及执行共享控制面操作。 每项权限都有明确用途: * **数据库所有权**允许 `cp-api` 创建 `public` 和 `auth` schema、表、索引、函数和行级安全策略。在 PostgreSQL 默认权限下,数据库 owner 可以在 `public` 中创建对象,因此标准集群不需要额外 schema grant。 * \*\*`CREATEROLE`\*\*允许 `cp-api` 创建和配置内部角色 `cp_api_app`。该角色用于带行级安全的租户范围查询。你不需要手动创建这个角色。 * **`BYPASSRLS`** 允许共享控制面操作在必要时跨组织读取数据,包括调用方 Token 认证、计费 webhook、后台预算聚合器和 `dp-manager` 操作。 租户范围请求仍会切换到 `cp_api_app`,该角色既不是 `SUPERUSER`,也没有 `BYPASSRLS`。因此,控制面连接角色需要特定 PostgreSQL 能力,但不需要超级用户权限。 ## 创建数据库和角色[​](#创建数据库和角色 "创建数据库和角色的直接链接") 以数据库管理员身份执行一次。请使用能够创建角色、创建数据库并授予 `BYPASSRLS` 的账号。控制面连接角色本身不需要是超级用户。 ``` -- 1) 控制面使用的专用登录角色,不授予超级用户权限。 CREATE ROLE aisix LOGIN PASSWORD 'change-me-to-a-strong-password' NOSUPERUSER CREATEROLE BYPASSRLS; -- 2) 由该角色拥有的专用数据库。 CREATE DATABASE aisix_cloud OWNER aisix; ``` 你可以自行选择角色名、密码和数据库名。数据库所有权让 `aisix` 可以在首次启动时创建 `public` 对象并添加 `auth` schema。 请使用 URL 安全的密码,因为密码会嵌入 PostgreSQL 连接 URL 中。`+`、`/`、`=` 等字符如果没有百分号编码,可能破坏 DSN。请生成 URL 安全值,例如使用 `openssl rand -hex 24`。参见 [On-Premises 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md#helm-on-kubernetes)。 如果 DBA 加固了 `public` schema,例如撤销了默认 `CREATE` 权限,请连接到新数据库后显式授予 schema 访问权限: ``` \c aisix_cloud GRANT USAGE, CREATE ON SCHEMA public TO aisix; ``` 不要预先创建 `cp_api_app` 角色。控制面会在 migration 期间创建并配置该角色,同时校验它的属性。提前创建该角色,尤其是属性不一致时,可能导致 migration 安全检查失败。 ## 连接控制面到数据库[​](#连接控制面到数据库 "连接控制面到数据库的直接链接") 使用 Helm 时,请按照[私有化部署配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md#postgresql)中的说明设置 `externalDatabase.*` values,并设置 `postgresql.builtin=false`。Chart 会根据这些值为控制面服务构造连接 URL。 当数据库通过不完全受控的网络访问时,请设置 `sslmode=require`,或使用更严格的模式,例如 `verify-full`。 ## 控制面会创建什么[​](#控制面会创建什么 "控制面会创建什么的直接链接") 首次成功启动时,`cp-api` 会在你准备的数据库中构建完整 schema。之后启动时,它会应用尚未执行的 migration,并跳过已经完成的一次性 migration: * 用于控制面表的 `public` schema,例如 organizations、environments、models、调用方 API Key 和预算,由你的角色拥有; * 用于认证表的 `auth` schema,例如 users 和 sessions; * `cp_api_app` 角色,属性为 `NOSUPERUSER NOBYPASSRLS NOINHERIT NOLOGIN`,只被授予控制面表的 CRUD 权限,以及少数非敏感身份列的读写权限; * 将每个租户表限定到单个组织的行级安全策略。 连接角色会自动成为 `cp_api_app` 的成员,因此可以在每个请求中切换到该角色。你不需要手动授予该成员关系。 ## 数据库权限检查清单[​](#数据库权限检查清单 "数据库权限检查清单的直接链接") 与 DBA 团队评审数据库角色时,可以使用以下清单: | 要求 | 作用 | | ---------------- | -------------------------------------------------------------- | | `LOGIN` | 允许控制面服务以该角色连接数据库。 | | 数据库所有权 | 允许 `cp-api` 创建和修改 schema、表、索引、函数和 RLS 策略。 | | `CREATEROLE` | 允许 `cp-api` 创建并管理内部 `cp_api_app` 角色。 | | `BYPASSRLS` | 允许跨组织控制面路径和 `dp-manager` 在共享连接上读取所需数据。 | | 不是 `SUPERUSER` | 将角色权限控制在 PostgreSQL 超级用户以下。 | ## 验证数据库设置[​](#验证数据库设置 "验证数据库设置的直接链接") 控制面启动后,以管理员身份连接数据库并确认引导结果。 内部角色存在且权限正确受限: ``` SELECT rolname, rolsuper, rolbypassrls, rolcanlogin FROM pg_roles WHERE rolname = 'cp_api_app'; -- 预期结果:cp_api_app | f | f | f ``` 两个 schema 已创建: ``` SELECT nspname FROM pg_namespace WHERE nspname IN ('public', 'auth'); -- 预期结果:两行 ``` ## 排查启动错误[​](#排查启动错误 "排查启动错误的直接链接") 可以根据启动错误信息定位缺失的数据库能力。 **`cp-api database role must be SUPERUSER or have BYPASSRLS ...`** 连接角色缺少 `BYPASSRLS`。请以数据库管理员身份授予: ``` ALTER ROLE aisix BYPASSRLS; ``` **`permission denied for schema public`** 该角色无法在 `public` schema 中创建对象。请确认数据库所有权。如果 schema 被锁定,请显式授予 schema 访问权限: ``` \c aisix_cloud GRANT USAGE, CREATE ON SCHEMA public TO aisix; ``` **`permission denied to create role`** 连接角色缺少 `CREATEROLE`。请以数据库管理员身份授予: ``` ALTER ROLE aisix CREATEROLE; ``` **`permission denied to set role "cp_api_app"`** 授予 `cp_api_app` 成员关系的 migration 可能没有完成。请检查 `cp-api` 启动日志中是否有更早的 migration 错误。 ## 下一步[​](#下一步 "下一步的直接链接") 数据库和角色准备完成后,请返回 [On-Premises 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md),配置控制面使用外部数据库。 完整的 Helm values 请参见[私有化部署配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md#helm-values)。 --- # 升级 AISIX AISIX 部署分两部分升级:AISIX Cloud 控制面,以及承载流量的 AISIX 网关。两者独立升级,顺序固定;在你逐台升级网关的过程中,它们运行的版本可以不同。 本页说明哪些升级路径受支持、应遵循的顺序,以及各安装方式的升级步骤。各版本的具体变更请参见[发布说明](https://docs.apiseven.com/ai-gateway/release-notes.md)。 ## 支持的升级路径[​](#supported-upgrade-paths "支持的升级路径的直接链接") **支持的升级下限是 0.12.0**。运行 0.12.0 或更高版本的部署可以直接升级到任意更新的版本,包括当前版本。 版本可以跳过。从 0.12.0 直接升级到当前版本是受支持的,不需要逐个经过中间版本。决定升级是否受支持的是下限,而不是跨度:只要来源版本不低于 0.12.0,就可以一步升级到任意更新的目标版本。 升级下限只有在某个版本明确宣布上调时才会变化,不会随着新版本发布而静默抬高,因此今天受支持的部署会一直受支持,直到有版本公告说明为止。从较旧的部署规划跨版本升级前,请先查看目标版本的发布说明。 低于 0.12.0 的部署需要分两步升级:先升级到 0.12.0 与目标版本之间的某个版本,让它启动并完成数据库迁移,然后再升级到目标版本。 兼容性例外是按功能划分的,而不是按版本划分:升级过程中可能出现差异的,始终是某一项具体配置,而不是版本组合本身。这里有两种不同的差异。一种是网关版本**无法加载**的配置,它会让该网关丢掉整个资源——在 0.12.0 与当前版本之间不存在这样的配置,因此控制面能够保存的每一份配置,都能作为完整资源在下限以上的每个网关版本上加载。另一种是网关版本**不认识**的配置,这是升级期间的常见情况:资源照常加载并生效,只是这一项配置在该网关上不起作用,直到它被升级。 ## 升级顺序与混合版本窗口[​](#upgrade-order-and-the-mixed-version-window "升级顺序与混合版本窗口的直接链接") **先升级控制面,再升级网关。** 控制面能够理解下限以上的每个网关版本,而网关不一定能理解比自己更新的控制面。 在这两步之间,部署处于混合版本状态:控制面已是新版本,网关仍是旧版本。这个窗口由升级下限限定,而不是由时间限定。只要每台网关都不低于 0.12.0,这个窗口可以持续到你需要的任何时长——分批推进的机群升级、刻意滞后一周的灰度环境、按自己维护窗口升级的网关,都可以。整个期间网关照常承载流量。 各网关实例的版本单独显示在环境的 **Data planes** 视图中,因此可以看出哪些实例尚未升级。控制面版本显示在控制台左侧导航底部,也可以通过 `GET /api/config/public` 获取,参见 [On-Premises 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md)中的「验证安装」一节。 保存作用域内某些网关不认识的配置项是允许的,保存响应会明确告知:它会给出字段名、最早实现该字段的网关版本,以及有多少台网关会忽略它。控制台也会在表单上显示同一条警告。在依赖该配置项之前请先读它——被忽略的限制类配置在这些网关上并不生效,而这正是需要关注的方向。 在网关侧,`aisix_config_partially_compatible_resources` 统计的是携带了本网关版本不认识的字段的资源数量。在窗口期内它不为零属于预期,网关升级完成后应回落到零。配置健康类指标参见[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 ## 跳过的每个版本,其升级说明依然适用[​](#read-the-upgrade-notes-for-every-release-you-skip "跳过的每个版本,其升级说明依然适用的直接链接") 跳过一个版本,跳过的是它的发布说明,而不是它带来的行为变化。一次跨越多个版本的升级,其间每个版本的**升级说明**都对你适用,并且要按顺序阅读——从你当前版本的下一个版本开始,一直读到目标版本,由旧到新。 升级说明记录的是升级前需要做的事:含义发生变化的配置项、开始生效的 Helm 取值、需要复核的告警表达式。被跳过版本中的说明,不会因为后续版本的说明而失效。 从更早的版本升级到 1.0.0 之前,还要完成[升级到 1.0.0 时复核已有安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/semantic-screening-calibration.md#review-existing-guardrails-when-upgrading-to-100)。它不是一条升级说明,而是一份升级前检查清单:它要求你在控制面以新版本启动**之前**,先找出并停用受影响的语义安全护栏。 ## 升级部署包安装[​](#upgrade-a-package-installation "升级部署包安装的直接链接") Docker Compose 部署包——在线快速安装包和离线包——升级方式相同:把新版本部署包解压覆盖到现有安装目录上,然后重新运行 `run.sh`。 请先备份数据库。`cp-api` 会在新版本下首次启动时迁移数据库结构,而回滚依赖的正是这份备份。 在线安装的升级方式是在包含安装目录的上级目录中重新运行一键脚本——它会拉取当前版本的部署包,解压覆盖到 `aisix-self-hosted`,然后执行 `run.sh`: ``` curl -sL "https://run.api7.ai/aisix-self-hosted/quickstart" | bash ``` 内网隔离环境需要把离线包带进去。请在能联网的机器上下载——下面的 URL 指向当前版本,同时还发布有 `aisix-self-hosted-offline-<version>.tar.gz` 形式的指定版本 URL: ``` curl -fSL "https://run.api7.ai/aisix-self-hosted/aisix-self-hosted-offline-latest.tar.gz" \ -o aisix-self-hosted-offline-latest.tar.gz ``` 在**包含**安装目录的上级目录中解压覆盖,而不是在安装目录内部: ``` cd /path/that/contains/aisix-self-hosted tar -xzf aisix-self-hosted-offline-latest.tar.gz cd aisix-self-hosted ./run.sh ``` 在 `aisix-self-hosted` 内部执行 `tar` 会解压出一个嵌套副本,原安装目录不会有任何变化。 部署包中不含 `.env`,因此这一步只替换 Compose 文件、脚本和随包镜像,你的密钥和数据卷保持原样。`.env` 中唯一属于部署包的取值是 `AISIX_VERSION`,它固定了所有镜像版本——包括控制台在生成网关安装命令时使用的网关镜像。`run.sh` 会把它调整为与部署包一致,并打印所做的操作: ``` ==> Upgrading AISIX 1.0.0 -> 1.1.0. AISIX_VERSION in .env now matches this package; your secrets are untouched. ``` `run.sh` 在这里会打印两种行之一。上面这种是常规情况;如果 `.env` 中原本完全没有 `AISIX_VERSION`,打印的会是 `==> Added AISIX_VERSION=<version> to .env (it had none).`,这种情况同样完成了升级。两种行都没有出现,才说明没有发生升级。确认实际运行的版本: ``` COMPOSE_PROJECT_NAME=aisix-self-hosted docker compose images ``` 单个镜像覆盖项——`AISIX_API_IMAGE`、`AISIX_DPM_IMAGE`、`AISIX_UI_IMAGE` 和 `AISIX_CLOUD_DP_IMAGE`——`run.sh` 从不改写,并且它们的优先级高于 `AISIX_VERSION`。如果希望某个组件跟随部署包,请在升级前移除对应的覆盖项。参见 [On-Premises 配置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md)中的「镜像和发布版本」。 唯一需要避免的做法,是把新部署包解压到**另一个目录**。Compose 项目名属于部署包,因此新目录会接管同一个数据卷,而它旁边的 `.env` 却是全新生成的。此时 `run.sh` 会停下来而不是启动:只要发现这套栈的容器正运行在另一个目录下,它就会拒绝,与新目录的 `.env` 内容无关。请回到原目录升级;如果确实要迁移安装位置,请先在原目录执行 `./run.sh down`,再把它的 `.env` 复制过去,然后运行新目录中的脚本。 ## 使用 Helm 升级[​](#upgrade-with-helm "使用 Helm 升级的直接链接") 控制面 Chart 与网关 Chart 每个版本都使用相同的 `version` 和 `appVersion`,因此两者升级到同一个版本号。先升级控制面 Chart。 升级控制面 Chart 前请备份数据库,无论使用的是随 Chart 部署的数据库还是[外部数据库](https://docs.apiseven.com/ai-gateway/on-premises/external-database.md)。 ``` helm repo update helm upgrade aisix-cp api7/aisix-cp -f your-cp-values.yaml ``` 请用你自己的 values 文件升级,不要用 `--reuse-values`。`--reuse-values` 会重放上一个 release 完全解析后的取值,其中包含 Chart 默认值,因此新 Chart 改动过的默认值不会被采用。Chart 中的探针预算就属于会随版本变化的默认值,而使用新镜像、却沿用上一版 Chart 预算启动的工作负载,可能被自己的探针重启。如果你此前没有维护 values 文件,可以用 `helm get values aisix-cp` 打印安装时使用的覆盖项,保存下来再用 `-f` 传入。 等待 `cp-api` Pod 就绪——数据库迁移在新版本下首次启动时执行——之后再继续。 然后升级网关,可以逐批升级,也可以一次全部升级,取决于你的机群推进方式: ``` helm upgrade aisix api7/aisix -f your-gateway-values.yaml ``` 网关由 Deployment 的滚动更新替换。除非你在 Chart 上设置 `updateStrategy`,否则用的是 Kubernetes 的默认策略,因此在规模较大的部署中会同时替换多个 Pod。新 Pod 在能够提供服务之前不会接到流量:在网关从控制面拿到并应用配置之前,Kubernetes 不会把它加入 Service 端点。滚动过程涉及的探针预算和排空设置参见[在 Kubernetes 上部署网关](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md)。 开始之前有一项取值值得检查:控制面 Chart 的 `api.dpImage` 固定了控制台在生成安装命令时使用的网关镜像,作用与部署包安装中的 `AISIX_CLOUD_DP_IMAGE` 完全相同。如果你显式设置过它,它会在历次升级中一直保留,升级之后新加的网关仍会以旧镜像启动。留空即可跟随 Chart 的 `appVersion`。 部署中的每一批网关都要重复这一步。在此之前,这些网关处于上文所述的混合版本窗口中,这是受支持的状态。 ## 窗口期内控制面会做哪些检查[​](#what-the-control-plane-checks-during-the-window "窗口期内控制面会做哪些检查的直接链接") 在网关尚未升级期间,控制面会针对这些网关实际能够加载的内容,检查你保存的每一份配置。 如果保存的配置是某台已注册网关无法加载的,请求会以 HTTP `422` 失败,错误码为 `DP_INCOMPATIBLE`。响应中会指出无法加载它的网关版本、受影响的网关、字段路径以及 schema 给出的原因。此时不会写入任何内容:资源保持原有配置。这项检查是按功能触发的——触发它的是你正在保存的那项具体配置,而不是版本差异本身——因此只有当你配置了旧版本网关无法承载的内容时才会出现。请升级这些网关,或者在它们升级完成前先不要使用该配置项。 网关刚升级完成时,重启后的网关此前的注册记录最长还会被计入 5 分钟。如果在这段时间内保存被拒绝,而它指出的版本你已经升级过了,通常就是这条过期注册记录导致的;稍等片刻重试即可。 低于升级下限的网关完全不做检查。没有受支持的契约可供比对,因此保存会成功,响应中携带一条 `below_floor` 警告,给出受影响的网关数量、它们上报的版本,以及升级下限。请如实理解这条警告:这些网关已不在支持范围内,控制面无法告诉你它们能否加载你刚刚保存的内容。请把它们升级到 0.12.0 或更高版本。 ## 升级下限闸门[​](#the-upgrade-floor-gate "升级下限闸门的直接链接") 从低于下限的版本升级,会被直接拒绝而不是尝试执行,因为一个迁移到一半的数据库,比多做一步升级难恢复得多。 当数据库上一次由低于下限的版本运行时,`cp-api` 拒绝启动。错误信息会给出数据库中记录的版本、本版本能够升级的最低来源版本,以及覆盖开关。这项检查在任何迁移动作之前执行,因此被拒绝的启动不会改动数据库,它保持上一个版本留下的样子。正确做法是先升级到一个受支持的版本。 这项检查读取的是控制面从本版本起才写入的版本记录,因此它只能判断已经被带有该记录的版本运行过的数据库。被更早版本运行过的数据库没有这条记录,无从判断,因此不会被拒绝——在这一次升级中,只有部署包安装的 `.env` 检查能拦住你,而 Helm 安装完全没有闸门。请自行确认你是从哪个版本升上来的。 离线包和在线包在 `run.sh` 中拒绝同样的升级,并且发生在任何容器启动之前,同时给出两步做法:取一个介于 0.12.0 与目标版本之间的部署包,解压覆盖到安装目录并运行,等它完成迁移,然后再解压目标部署包并再次运行。 如果确实要继续,请设置 `AISIX_ALLOW_UNSUPPORTED_UPGRADE=1`,取值必须正好是 `1`。**请先备份数据库**——这会执行从那么早的版本起从未被验证过的迁移路径,而这份备份是唯一的退路。 部署包安装在命令上设置: ``` AISIX_ALLOW_UNSUPPORTED_UPGRADE=1 ./run.sh ``` Helm 安装通过 `api.extraEnvVars` 传给 `cp-api`: values.yaml ``` api: extraEnvVars: - name: AISIX_ALLOW_UNSUPPORTED_UPGRADE value: "1" ``` 把它加进你升级时使用的 values 文件,这样它才会真正生效: ``` helm upgrade aisix-cp api7/aisix-cp -f your-cp-values.yaml ``` `cp-api` 和部署包的 `run.sh` 都读取这个开关,因此两条升级路径使用同一个名字。升级完成后请把它移除,以免后续某次不受支持的升级被静默放行。 ## 回滚[​](#roll-back "回滚的直接链接") 回滚按相反顺序进行:先网关,后控制面。 控制面回滚是一次数据库恢复,而不只是换个镜像。新版本已经迁移过数据库结构,把旧版本直接跑在上面,等于让旧代码运行在它不认识的数据库上。请先恢复升级前的备份,再用旧版本对接恢复后的数据库启动。 对于部署包安装,当目录中的部署包版本低于 `.env` 中记录的版本时,`run.sh` 会拒绝启动,因为这几乎总是意外——重新下载了旧的 tarball,或者把 `latest` 的 URL 取到了更新的安装上。有意为之的回滚,在恢复数据库备份之后,需要显式确认: ``` AISIX_ALLOW_DOWNGRADE=1 ./run.sh ``` `run.sh` 结束时会打印部署的版本号。请核对这一行是否是你要回滚到的版本。 对于 Helm 安装,`helm rollback` 可以把工作负载恢复到上一个 revision;数据库恢复仍然需要你先自行完成。 ## 不受支持的情况[​](#situations-that-are-not-supported "不受支持的情况的直接链接") * **从低于升级下限的版本一步升级。** 请先升级到 0.12.0 与目标版本之间的某个版本,让它完成迁移,然后再升级一次。 * **接入的网关版本,低于环境现有配置已经要求的版本。** 混合版本窗口覆盖的是**向前**升级中的网关。把一台较旧版本的网关接入一个现有配置已经依赖更新版本的环境,是不受支持的——这台网关无法加载分发给它的配置。 * **让低于 0.12.0 的网关对接当前版本的控制面。** 这类网关不在支持范围内,控制面无法判断它会加载到什么。 * **先升级网关再升级控制面。** 在所有部署方式中,顺序都是控制面优先。 --- # 适配器协议族 适配器是模型别名解析到服务提供方密钥后,AISIX 用来访问上游的协议族。它决定上游认证方式、请求编码方式,以及服务提供方相关的请求处理逻辑。 路由级服务提供方支持情况请参见[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 选择适配器[​](#选择适配器 "选择适配器的直接链接") 适配器的选择方式取决于网关的管理方式: * 对于 AISIX Cloud 目录中的服务提供方,请选择服务提供方。控制面会推导适配器,AISIX Cloud Admin API 会拒绝显式的 `adapter` 字段。 * 对于 AISIX Cloud 中的自定义端点,请将 `provider` 设置为 `byo`,并显式选择适配器。 * 对于开源 AISIX 网关,请在 `resources.yaml` 中同时设置 `provider` 和 `adapter`。服务提供方值是开放字符串,可以使用目录 ID,也可以为私有端点使用描述性名称。 在所有情况下,服务提供方值用于标识上游厂商或端点,适配器用于标识 AISIX 与其通信所使用的协议族。适配器值是闭集,因为 AISIX 只能编码已经实现的协议。 例如,以下 AISIX Cloud 服务提供方密钥通过 OpenAI 适配器连接私有 OpenAI 兼容端点: ``` { "provider": "byo", "adapter": "openai", "api_base": "https://llm.private.example/v1" } ``` 随后,AISIX 会使用 OpenAI 兼容协议向配置的 `api_base` 发送上游请求。 ## 适配器取值[​](#适配器取值 "适配器取值的直接链接") | 上游 API 格式 | `adapter` | 示例 | | --------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------- | | OpenAI 兼容 API | `openai` | OpenAI、DeepSeek、Groq、Mistral、Together.ai、Fireworks、Perplexity、vLLM、SGLang、Ollama、私有 OpenAI 兼容端点 | | Anthropic Messages | `anthropic` | Anthropic 原生 Messages API | | AWS Bedrock Runtime | `bedrock` | Bedrock 上的 Anthropic Claude、Bedrock Converse 发布方 | | Google Vertex AI 发布方路由 | `vertex` | Gemini 以及受支持的 Vertex AI 发布方路由 | | Azure OpenAI Service | `azure-openai` | 使用 API Key 或 Entra ID 认证的 Azure OpenAI 部署 | ## 适配器行为[​](#适配器行为 "适配器行为的直接链接") | `adapter` | 行为 | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | `openai` | 使用 OpenAI 兼容请求和响应格式。该适配器覆盖 OpenAI、公开的 OpenAI 兼容厂商,以及私有 OpenAI 兼容端点。 | | `anthropic` | 使用 Anthropic Messages API 请求。上游认证使用 `x-api-key` 和 `anthropic-version`。 | | `bedrock` | 使用 AWS Bedrock Runtime。AISIX 会使用 AWS SigV4 对出站请求签名。Anthropic Claude 模型使用 Bedrock invoke 请求,其它受支持发布方使用 Bedrock Converse。 | | `vertex` | 使用 Google Vertex AI 发布方路由。AISIX 通过 GCP OAuth2 Bearer Token 认证,并调用发布方对应的 Vertex 端点。 | | `azure-openai` | 使用 Azure OpenAI Service 部署路由。AISIX 会根据服务提供方密钥中的资源主机和模型的上游部署名称构造 Azure URL。 | ## 请求处理[​](#请求处理 "请求处理的直接链接") 直接[模型](https://docs.apiseven.com/ai-gateway/models/model-aliases.md)会引用[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md)。AISIX Cloud 在 `provider_key_id` 中保存该引用;对于开源 AISIX 网关,`resources.yaml` 使用 `provider_key` 引用服务提供方密钥的 `display_name`。服务提供方密钥提供服务提供方值和适配器,AISIX 会结合这些字段与模型的上游模型 ID 构造服务提供方请求。 AISIX 分两步选择上游请求处理方式: 1. 检查服务提供方值是否有服务提供方专属请求处理逻辑。 2. 如果没有,则使用适配器协议族。 如果两条路径都不可用,请求会在到达上游服务提供方之前失败。 模型的 `display_name` 是面向调用方的模型别名;`model_name` 是上游模型 ID。在 Chat Completions、Responses API、Text Completions、Embeddings、Anthropic Messages、视频任务对象、顶层携带 `model` 字段的重排序响应,以及 Realtime 的 `session.created` 和 `session.updated` 事件中,model 字段都会回显面向调用方的别名。透传路由(Passthrough Routes)是例外,它会原样转发服务提供方的响应。 适配器描述的是上游协议族,并不保证每个代理端点都支持每个服务提供方。 ## 目录与自定义服务提供方[​](#目录与自定义服务提供方 "目录与自定义服务提供方的直接链接") 在 AISIX Cloud 中,用户通过控制台或 AISIX Cloud Admin API 选择目录服务提供方。控制面会将其映射到适配器协议族,在目录定义了默认 Base URL 时填充该值,并将服务提供方密钥配置下发到 AISIX 网关。 对于开源 AISIX 网关,请在声明式资源文件的每个服务提供方密钥中直接设置 `provider`、`adapter`、`api_base` 和上游凭证(`api_key` 或其别名 `secret`)。 运行时行为取决于模型别名、服务提供方密钥、服务提供方值、适配器和连接设置。 --- # Amazon Nova API [Amazon Nova](https://nova.amazon.com/dev/documentation) 是 Amazon 的基础模型系列,可通过直连 API 或 Amazon Bedrock 使用。本指南将直连 API 接入 AISIX,使应用可以通过网关的 OpenAI 兼容 API 调用 Nova。 此配置适用于 `api.nova.amazon.com` 上基于 API Key 的端点。它不同于使用 AWS 凭证、区域和 SigV4 请求签名的 Amazon Bedrock。若要通过 Bedrock 调用 Nova,请改用 [Amazon Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md)。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * 为 Amazon Nova 直连 API 签发的 API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 导出 Nova API Key: ``` export NOVA_API_KEY="YOUR_NOVA_API_KEY" ``` 创建服务提供方密钥: ``` PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nova-prod", "provider": "nova", "api_key": "'"${NOVA_API_KEY}"'", "api_base": "https://api.nova.amazon.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` AISIX 通过社区目录接受 `nova`,并派生使用 Bearer 身份认证的 `openai` 适配器。不要在该目录服务提供方密钥上发送 `adapter`。 AISIX 会在配置的 API 基础 URL 后追加 `/chat/completions`。请保留值中的 `/v1`;仅使用 `https://api.nova.amazon.com` 主机将指向错误路由。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 为 Nova 2 Lite 创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nova-lite-prod", "model_name": "nova-2-lite-v1", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` 请使用 [Amazon Nova 开发者文档](https://nova.amazon.com/dev/documentation)发布的精确模型 ID。Nova 直连 API 和 Bedrock 访问同一模型系列时可能使用不同的标识符,因此不要把 Bedrock 模型或推理配置文件 ARN 复制到此字段。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建一个只能访问 Nova 别名的调用方密钥: ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nova-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export NOVA_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "nova-prod" provider: "nova" adapter: "openai" api_key: ${NOVA_API_KEY} api_base: "https://api.nova.amazon.com/v1" models: - display_name: "nova-lite-prod" provider: "nova" model_name: "nova-2-lite-v1" provider_key: "nova-prod" api_keys: - display_name: "nova-caller" key_env: CALLER_API_KEY allowed_models: - "nova-lite-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "nova-lite-prod", "messages": [ { "role": "user", "content": "Say hello from Amazon Nova." } ] }' ``` AISIX 会把 `nova-2-lite-v1` 发送到 `https://api.nova.amazon.com/v1/chat/completions`,并在 Bearer 请求头中携带 Nova API Key。 ## 在 Nova API 与 Bedrock 之间选择[​](#在-nova-api-与-bedrock-之间选择 "在 Nova API 与 Bedrock 之间选择的直接链接") | 账户路径 | AISIX 服务提供方 | 凭证和适配器 | | -------------- | ---------------- | ------------------------------------ | | Nova 直连 API | `nova` | 使用 `openai` 适配器的 Nova API Key | | Amazon Bedrock | `amazon-bedrock` | 使用 `bedrock` 适配器的 AWS 访问凭证 | 请为两条路径使用不同的服务提供方密钥。即使两个别名都代表 Nova 模型,这也能明确区分凭证轮换、账户归因和故障转移行为。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Nova 直连 API 使用 `/v1/chat/completions`。AISIX 可以通过聊天适配器桥接兼容的 Responses 和 Anthropic Messages 请求。只有当 Nova 直连 API 实现了对应的 OpenAI 形态端点,并且 AISIX 在该路由上接受 `nova` 服务提供方时,其他标准化路由才能工作。 图像生成、视频生成和 rerank 不接受 `nova` 服务提供方值。请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 故障排除[​](#故障排除 "故障排除的直接链接") | 现象 | 检查项 | | ---------------------------- | -------------------------------------------------------- | | 上游身份认证错误 | 确认凭证是 Nova 直连 API Key,而不是 AWS Access Key。 | | 上游 `404` | 在 `api_base` 中保留 `/v1`,并使用 Nova 直连模型 ID。 | | 要求 SigV4 或 AWS 区域 | 当前使用的是 Bedrock 端点;请改为按照 Bedrock 配置操作。 | | 创建服务提供方密钥返回 `400` | 使用 `provider: "nova"` 并省略 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 接入 Amazon Nova 直连 API,并验证了模型别名。接下来可以阅读: * [AWS Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md):改为使用 AWS 凭证配置 Bedrock 托管的 Nova 模型。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Nova 直连 API 和 Bedrock 之间进行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Anthropic [Anthropic](https://docs.anthropic.com/) 开发 Claude 系列模型,并提供用于访问这些模型的原生 Messages API。AISIX 允许应用使用原生 Messages 格式或网关的 OpenAI 兼容 API,同时管理 Anthropic 凭证、调用方访问权限、限流和用量核算。 本指南介绍如何将 AISIX 直接连接到 Anthropic。如需改为通过 AWS 访问 Claude,请使用 [AWS Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md)。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Anthropic 控制台](https://console.anthropic.com/settings/keys)获取的 Anthropic API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由 Anthropic 支持的路由创建服务提供方密钥、模型别名和调用方 API Key。 AISIX 通过原生 `anthropic` 适配器连接到 Anthropic,并使用 Anthropic 的 `x-api-key` 请求头对上游请求进行身份验证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Anthropic 凭证的服务提供方密钥,并允许其在该环境中使用: ``` # 请替换为实际值 export ANTHROPIC_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "anthropic-prod", "provider": "anthropic", "api_key": "'"${ANTHROPIC_API_KEY}"'", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') ``` ❶ `provider` 为 `anthropic`。AISIX Cloud Admin API 会从目录服务提供方派生适配器;适配器字段仅在 BYO 服务提供方密钥上被接受。AISIX 会将凭证作为 `x-api-key` 请求头发送,并在出站调用中添加 `anthropic-version: 2023-06-01`。 ❷ `api_key` 存储 Anthropic API Key。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 Anthropic 的 `api_base` 可以省略;此时会回退到 Anthropic 默认端点。响应会返回服务提供方密钥 ID,上文已将其保存为 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Claude 4.6 及后续代际的模型 ID 是固定快照,而不是持续更新的指针。当前 ID 请参阅 [Anthropic 模型参考](https://docs.anthropic.com/en/docs/about-claude/models)。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "claude-sonnet-prod", "model_name": "claude-sonnet-5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Claude 模型 ID,例如 `claude-sonnet-5`、`claude-opus-4-8` 或 `claude-haiku-4-5`。 ❸ `provider_key_id` 将别名关联到 Anthropic 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且只在创建响应中返回一次: ``` export AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "claude-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') ``` `allowed_models` 值通过上文保存为 `MODEL_ID` 的 ID 引用模型。请安全存储明文密钥,此后无法再次获取。 调用方通过 `Authorization: Bearer` 请求头中的调用方 API Key 向 AISIX 进行身份验证。AISIX 会向上游提供 Anthropic 的 `x-api-key` 和 `anthropic-version` 请求头,客户端无需发送这些请求头。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export ANTHROPIC_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "anthropic-prod" provider: "anthropic" adapter: "anthropic" api_key: ${ANTHROPIC_API_KEY} api_base: "https://api.anthropic.com" models: - display_name: "claude-sonnet-prod" provider: "anthropic" model_name: "claude-sonnet-5" provider_key: "anthropic-prod" api_keys: - display_name: "claude-caller" key_env: CALLER_API_KEY allowed_models: - "claude-sonnet-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送原生 Messages 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/messages" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-prod", "max_tokens": 64, "messages": [ { "role": "user", "content": "Say hello from Claude." } ] }' ``` 网关会返回 Anthropic Messages 响应,其中回显面向调用方的别名 `claude-sonnet-prod`。如果请求因上游身份验证错误而失败,请检查服务提供方密钥的 `api_key`。 对于使用 OpenAI 格式的客户端,同一个别名也适用于 `/v1/chat/completions`。此转换会丢弃非文本内容块,因此图像或文档输入应直接调用 `/v1/messages`。 ## 清理资源[​](#清理资源 "清理资源的直接链接") 不再需要示例资源时,请在 Dashboard 中依次删除 `claude-caller` 调用方 API Key、`claude-sonnet-prod` 模型和 `anthropic-prod` 服务提供方密钥。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Anthropic,并验证了模型别名。接下来可阅读以下指南: * [Anthropic SDK](https://docs.apiseven.com/ai-gateway/getting-started/anthropic-sdk.md):通过 Anthropic SDK 在 `/v1/messages` 上调用此别名。 * [AWS Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md):改为配置由 Bedrock 托管的 Claude 模型。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # AWS Bedrock [Amazon Bedrock](https://docs.aws.amazon.com/bedrock/) 是一项 AWS 服务,可通过托管 API 访问 Amazon 及其他服务提供方的基础模型。AISIX 为应用提供统一的 OpenAI 兼容接口,用于访问由 Bedrock 托管的 Claude、Llama、Mistral、Amazon Nova、Cohere 等模型。 此配置适用于需要使用 AISIX 身份验证、模型允许列表、限流和用量核算的 Bedrock 托管模型。AISIX 使用 AWS SigV4 对出站 Bedrock 调用进行签名。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 对目标模型具有 `bedrock:InvokeModel` 权限的 AWS Access Key ID 和 Secret Access Key。使用临时凭证时还需准备 STS Session Token。 * 对于跨区域推理,需要对推理配置文件 ARN、源区域以及每个目标区域中的基础模型 ARN 拥有 `bedrock:InvokeModel` 权限。具体要求参见 AWS 的[地理区域](https://docs.aws.amazon.com/bedrock/latest/userguide/geographic-cross-region-inference.html)和[全球](https://docs.aws.amazon.com/bedrock/latest/userguide/global-cross-region-inference.html)推理配置文件说明。 * 对所选区域中目标 Bedrock 模型的访问权限,以及该模型的模型 ID 或推理配置文件 ID。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 使用 Bedrock 目录服务提供方和结构化 `config` 凭证创建服务提供方密钥: ``` PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "bedrock-prod", "provider": "amazon-bedrock", "api_key": "", "api_base": "https://bedrock-runtime.us-west-2.amazonaws.com", "config": { "access_key_id": "YOUR_AWS_ACCESS_KEY_ID", "secret_access_key": "YOUR_AWS_SECRET_ACCESS_KEY", "region": "us-west-2" }, "allowed_environments": ["'"$ENV_ID"'"] }' | jq -r '.provider_key.id') ``` `api_key` 留空是有意为之。即使 `config` 提供了结构化 Bedrock 凭证,创建请求仍要求包含此字段。更新 `config` 时应省略 `api_key`,不要再次发送空字符串。 开源网关可以推导标准 AWS 端点,但 AISIX Cloud 当前要求为 Bedrock 显式设置 `api_base`。主机名和 `config` 中的区域必须设置为相同值。Dashboard 会显示 Access Key ID、Secret Access Key 和区域字段。如果通过 AISIX Cloud Admin API 使用临时 STS 凭证,还需在 `config` 中添加 `session_token`。 为 [Claude Sonnet 5](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-sonnet-5.html) 创建别名。该模型无法在 `us-west-2` 中进行区域内推理,因此示例使用其美国地理区域推理配置文件: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "claude-bedrock", "model_name": "us.anthropic.claude-sonnet-5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') ``` 创建可访问该模型的调用方 API Key: ``` BEDROCK_CALLER_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "bedrock-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出 AWS 凭证,并选择应用将发送给 AISIX 的调用方 API Key: ``` # 请替换为实际值 export BEDROCK_CREDENTIALS='{"access_key_id":"YOUR_AWS_ACCESS_KEY_ID","secret_access_key":"YOUR_AWS_SECRET_ACCESS_KEY","region":"us-west-2"}' export BEDROCK_CALLER_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源。 resources.yaml ``` _format_version: "1" provider_keys: - display_name: bedrock-prod provider: amazon-bedrock adapter: bedrock api_key: ${BEDROCK_CREDENTIALS} models: - display_name: claude-bedrock provider: amazon-bedrock model_name: us.anthropic.claude-sonnet-5 provider_key: bedrock-prod api_keys: - display_name: bedrock-caller key_env: BEDROCK_CALLER_KEY allowed_models: ["claude-bedrock"] ``` ❶ `provider` 用于标记上游。 ❷ `adapter` 选择 Bedrock。 ❸ `api_key` 是包含 `access_key_id`、`secret_access_key` 和 `region` 的 JSON 字符串。Bedrock 端点按区域确定,例如 `bedrock-runtime.us-west-2.amazonaws.com`,因此区域为必填项。对于标准 AWS,应不设置 `api_base`;如果使用私有 Bedrock 端点,则将其设置为该端点。 ❹ `model_name` 是 Bedrock 模型 ID 或完整的推理配置文件 ID。示例中的 `us.` 配置文件可从 `us-west-2` 使用,并将推理限制在美国和加拿大境内。 ❺ `provider_key` 通过服务提供方密钥的 `display_name` 将模型关联到凭证。模型的 `provider` 使用与服务提供方密钥相同的上游标签。 要在示例文件中使用 Meta Llama,请替换 `claude-bedrock` 模型条目,并更新 `bedrock-caller` 以允许新别名。保留 `bedrock-prod` 和其他资源不变: resources.yaml(Meta Llama 模型访问) ``` models: - display_name: llama-bedrock provider: amazon-bedrock model_name: us.meta.llama3-3-70b-instruct-v1:0 provider_key: bedrock-prod api_keys: - display_name: bedrock-caller key_env: BEDROCK_CALLER_KEY allowed_models: ["llama-bedrock"] ``` 对于 Amazon Nova,请使用 Bedrock 模型或推理配置文件 ID,例如可从 `us-west-2` 使用的 Nova 2 Lite 配置文件 `us.amazon.nova-2-lite-v1:0`。与 Claude 和 Llama 示例相同,`us.` 前缀选择美国地理区域推理配置文件。网关会从 `BEDROCK_CALLER_KEY` 读取明文调用方 Key,并且只存储其哈希。 下面的验证使用 `claude-bedrock`。如果应用了 Meta Llama 配置块,请改为发送 `llama-bedrock`,并预期响应中出现该别名。 使用临时 STS 凭证时,请在凭证 JSON 中包含 `session_token`;使用长期静态密钥时则省略该字段。服务提供方密钥 Secret 遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中说明的凭证处理方式。 ### 验证并加载配置[​](#验证并加载配置 "验证并加载配置的直接链接") 如果 AISIX 安装在本地,请在加载前验证完整文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。 ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${BEDROCK_CALLER_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-bedrock", "messages": [ { "role": "user", "content": "Say hello from Bedrock." } ] }' ``` 网关会返回 OpenAI 兼容响应,其中包含面向调用方的别名: ``` { "id": "msg_01example", "object": "chat.completion", "model": "claude-bedrock", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello from Bedrock!" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 9, "completion_tokens": 5, "total_tokens": 14 } } ``` 在 Bedrock 调用指标、CloudTrail 或服务提供方侧日志中检查测试请求。如果 AISIX 返回上游身份验证或授权错误,请检查 AWS 凭证、区域、IAM 权限和 Bedrock 模型访问权限。 ## 准备生产环境[​](#准备生产环境 "准备生产环境的直接链接") 如果应用使用流式传输,请在 AWS 权限中添加 `bedrock:InvokeModelWithResponseStream`,并确认目标模型的流式传输行为。 对于非 Claude Bedrock 模型,请至少发送一条用户或助手消息。Bedrock Converse 不接受仅包含系统消息的请求,因此 AISIX 会在调用服务提供方之前拒绝此类请求。 面向调用方的错误会隐去 AWS 返回的上游错误详情,避免泄露 ARN、区域和账户 ID 等 AWS 标识符。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 AWS Bedrock,并验证了模型别名。接下来可阅读以下指南: * [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md):改为通过 Anthropic API 配置 Claude。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Azure OpenAI [Azure OpenAI Service](https://learn.microsoft.com/en-us/azure/ai-services/openai/) 通过资源专用端点提供由 Azure 托管的 OpenAI 模型部署。AISIX 允许应用通过统一的 OpenAI 兼容网关端点访问这些部署。 此配置适用于需要使用 AISIX 身份验证、模型允许列表、限流和用量核算的 Azure OpenAI 部署。AISIX 可以使用资源 API Key 或 Entra ID 客户端凭证向上游进行身份验证。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 包含一个部署的 Azure OpenAI 资源。 * 资源 API Key,或已获得该资源访问权限且包含 `tenant_id`、`client_id` 和 `client_secret` 的 Entra ID 应用注册。 * Azure OpenAI 资源主机和部署名称。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 使用 Azure 目录服务提供方创建服务提供方密钥。控制平面会派生 `azure-openai` 适配器,因此不要发送 `adapter`: ``` # 请替换为实际值 export AZURE_OPENAI_API_KEY="YOUR_AZURE_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "azure-prod", "provider": "azure", "api_key": "'"$AZURE_OPENAI_API_KEY"'", "api_base": "https://acme-west.openai.azure.com", "allowed_environments": ["'"$ENV_ID"'"] }' | jq -r '.provider_key.id') ``` Dashboard 的 Azure 服务提供方表单接受资源 API Key。AISIX Cloud Admin API 也接受将上述 Entra ID 凭证 JSON 作为 `api_key` 值,但不接受将该凭证放在 `config` 中。 创建模型,并将 Azure 部署名称设为 `model_name`: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gpt-4o-azure", "model_name": "gpt4o-prod", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') ``` 创建可访问该模型的调用方 API Key: ``` AZURE_CALLER_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "azure-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 请选择与 Azure OpenAI 资源管理方式相匹配的身份验证方案。下面两个示例都是用于新网关的完整资源文件,并使用相同的模型和调用方 Key 配置。对于现有网关,请将其中一个示例的条目添加到其当前[资源文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中对应的集合。缺少的集合只创建一次,并保留无关资源。 配置任一身份验证方案前,请选择应用将发送给 AISIX 的调用方 API Key: ``` # 请替换为实际值 export AZURE_CALLER_KEY="YOUR_CALLER_API_KEY" ``` 在两个身份验证方案中,`provider` 用于标记上游,`adapter` 选择 Azure OpenAI,`api_base` 指向 Azure OpenAI 资源主机。AISIX 也接受不带域名的资源名称,例如 `acme-west`。模型的 `provider_key` 必须与所选服务提供方密钥的 `display_name` 匹配,`model_name` 是 Azure 部署名称,而不是底层模型 ID。 调用方 Key 的 `allowed_models` 值必须与模型别名匹配。网关会从 `AZURE_CALLER_KEY` 读取明文调用方 Key,并且只存储其哈希。服务提供方密钥 Secret 遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中说明的凭证处理方式。 ### 使用资源 API Key 身份验证[​](#使用资源-api-key-身份验证 "使用资源 API Key 身份验证的直接链接") 当 Azure OpenAI 资源使用资源 API Key 管理时,请使用此选项。导出密钥以供加载器插值: ``` # 请替换为实际值 export AZURE_OPENAI_API_KEY="YOUR_AZURE_API_KEY" ``` 在完整资源文件中使用已导出的服务提供方 Key 和调用方 Key: resources.yaml ``` _format_version: "1" provider_keys: - display_name: azure-prod provider: azure adapter: azure-openai api_key: ${AZURE_OPENAI_API_KEY} api_base: https://acme-west.openai.azure.com models: - display_name: gpt-4o-azure provider: azure model_name: gpt4o-prod provider_key: azure-prod api_keys: - display_name: azure-caller key_env: AZURE_CALLER_KEY allowed_models: ["gpt-4o-azure"] ``` 服务提供方密钥从环境中插入 Azure OpenAI 资源 API Key。切勿在文件中写入明文 Secret。 ### 使用 Entra ID 身份验证[​](#使用-entra-id-身份验证 "使用 Entra ID 身份验证的直接链接") 当 Azure OpenAI 资源需要通过 Entra ID 应用注册访问时,请使用此选项。将客户端凭证导出为 JSON 值: ``` # 请替换为实际值 export AZURE_ENTRA_CREDENTIAL='{"tenant_id":"YOUR_TENANT_ID","client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET"}' ``` 在完整资源文件中使用已导出的客户端凭证和调用方 Key: resources.yaml ``` _format_version: "1" provider_keys: - display_name: azure-aad-prod provider: azure adapter: azure-openai api_key: ${AZURE_ENTRA_CREDENTIAL} api_base: https://acme-west.openai.azure.com models: - display_name: gpt-4o-azure provider: azure model_name: gpt4o-prod provider_key: azure-aad-prod api_keys: - display_name: azure-caller key_env: AZURE_CALLER_KEY allowed_models: ["gpt-4o-azure"] ``` JSON 凭证必须包含 `tenant_id`、`client_id` 和 `client_secret`。`client_secret` 应填写 Secret 值,而不是 Secret ID。对于国家云或主权云,请在 JSON 凭证中添加 `authority_host`;公共 Azure 则应省略。该值必须是纯 HTTP(S) Origin,例如 `https://login.microsoftonline.us`。 AISIX 使用服务提供方密钥的 `api_base` 和模型的 `model_name` 构建出站 Chat Completions URL: ``` https://<resource>.openai.azure.com/openai/deployments/<deployment>/chat/completions?api-version=2024-10-21 ``` ### 验证并加载资源[​](#验证并加载资源 "验证并加载资源的直接链接") 如果 AISIX 安装在本地,请在加载前验证完整文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。 ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求。无论服务提供方密钥使用哪种上游身份验证方案,请求都完全相同。 ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AZURE_CALLER_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-azure", "messages": [ { "role": "user", "content": "Say hello from Azure OpenAI." } ] }' ``` 网关会返回 OpenAI 兼容响应,其中包含面向调用方的别名: ``` { "id": "cmpl_azure_example", "object": "chat.completion", "model": "gpt-4o-azure", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello from Azure OpenAI!" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 7, "completion_tokens": 5, "total_tokens": 12 } } ``` 对于使用资源 API Key 的服务提供方密钥,AISIX 会发送 Azure `api-key` 请求头。对于 Entra ID 服务提供方密钥,AISIX 会发送 `Authorization: Bearer <token>`。 在 Azure OpenAI 指标、日志或配额用量中检查测试请求。如果 AISIX 返回上游身份验证错误,请检查资源 API Key 或 Entra ID 凭证。如果返回上游路由错误,请检查 `api_base`、`model_name` 中的部署名称,以及部署支持的 Azure API 版本。 ## 准备生产环境[​](#准备生产环境 "准备生产环境的直接链接") AISIX 当前使用 `api-version=2024-10-21` 发送 Azure OpenAI 请求。请确认 Azure OpenAI 部署支持此 API 版本,并跟踪 Azure 的 [API 版本弃用计划](https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation)。 Azure 可能会在成功响应中附加 `prompt_filter_results` 和 `content_filter_results`。AISIX 接受这些 Azure 扩展字段,并向调用方返回标准的 OpenAI 兼容响应。 对于企业代理、私有端点或测试端点,请将 `api_base` 设置为 AISIX 应调用的确切主机。AISIX 会追加 Azure 部署路径,并拒绝查询字符串、片段和嵌入的用户信息。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Azure OpenAI,并验证了模型别名。接下来可阅读以下指南: * [OpenAI](https://docs.apiseven.com/ai-gateway/providers/openai.md):改为通过 OpenAI API 配置模型,而不是使用 Azure 部署。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Baseten [Baseten](https://docs.baseten.co/inference/model-apis/overview) 通过共享模型目录和专用模型部署提供托管推理。使用 AISIX 后,应用可以通过一个 OpenAI 兼容 API 调用这些模型,同时由网关管理凭证、模型访问、限流和用量核算。 Baseten 通过两种不同的界面提供模型,所选界面决定要配置的端点: * **Model APIs** — 位于单个固定端点的共享多租户开放权重模型目录。本页使用该界面。 * **专用部署** — 部署到自有 Baseten 工作区的模型所使用的逐部署端点。请参阅[路由到专用部署](#route-to-a-dedicated-deployment)。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * 从工作区 API Key 页面获取的 Baseten API Key。请参阅 [Baseten API Key](https://docs.baseten.co/organization/api-keys)。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Baseten 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 Baseten 暴露 OpenAI 兼容 API,因此 AISIX 通过 `openai` 适配器连接。请为所用的 Baseten 界面设置 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Baseten 凭证和 API 根路径的服务提供方密钥: ``` # 请替换为实际值 export BASETEN_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "baseten-prod", "provider": "baseten", "api_key": "'"${BASETEN_API_KEY}"'", "api_base": "https://inference.baseten.co/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `baseten`。AISIX Cloud Admin API 从目录服务提供方派生适配器;`adapter` 字段仅接受 BYO 服务提供方密钥。 ❷ `api_key` 存储 Baseten API Key。它遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 是 Baseten Model APIs 根路径,且已包含 `/v1` 路径。AISIX 会向其追加端点路径,因此不要添加 `/chat/completions`。Baseten 是 AISIX Cloud Admin API 可以填充该值的目录服务提供方之一:省略 `api_base` 时,创建操作仍会成功,并解析为 `https://inference.baseten.co/v1`。仍建议显式设置该值,因为以后读取资源时,只有该值能够区分 Model APIs 服务提供方密钥和专用部署服务提供方密钥。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Baseten Model APIs 标识符使用 `publisher/model-name` 命名空间,与发布权重的上游仓库一致。它们区分大小写,且不同发布方的大小写形式并不统一:`deepseek-ai/DeepSeek-V4-Pro` 和 `zai-org/GLM-5.2` 使用混合大小写,而 `openai/gpt-oss-120b` 全部为小写。请从 [Baseten Model APIs 概述](https://docs.baseten.co/inference/model-apis/overview)逐字复制标识符,不要手动重新输入。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "baseten-deepseek-v4-pro", "model_name": "deepseek-ai/DeepSeek-V4-Pro", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。Baseten 模型标识符包含斜杠,因此使用较短的别名也能让客户端配置更易读。 ❷ `model_name` 是 Baseten 模型标识符,例如 `deepseek-ai/DeepSeek-V4-Pro`、`openai/gpt-oss-120b` 或 `zai-org/GLM-5.2`。 ❸ `provider_key_id` 将别名关联到 Baseten 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在响应中返回一次,请安全保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "baseten-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。 写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export BASETEN_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "baseten-prod" provider: "baseten" adapter: "openai" api_key: ${BASETEN_API_KEY} api_base: "https://inference.baseten.co/v1" models: - display_name: "baseten-deepseek-v4-pro" provider: "baseten" model_name: "deepseek-ai/DeepSeek-V4-Pro" provider_key: "baseten-prod" api_keys: - display_name: "baseten-caller" key_env: CALLER_API_KEY allowed_models: - "baseten-deepseek-v4-pro" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "baseten-deepseek-v4-pro", "messages": [ { "role": "user", "content": "Say hello from Baseten." } ] }' ``` 网关返回 OpenAI 兼容响应,其中回显面向调用方的别名 `baseten-deepseek-v4-pro`,而不是上游标识符 `deepseek-ai/DeepSeek-V4-Pro`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base` 和 `model_name` 中的 Baseten 模型标识符。最常见的原因是 `model_name` 大小写不匹配,因为上游标识符区分大小写。 ## 路由到专用部署[​](#route-to-a-dedicated-deployment "路由到专用部署的直接链接") 专用部署不会在共享 Model APIs 主机上响应。Baseten 会为每个部署提供由模型 ID 派生的独立主机名,而 OpenAI 兼容路由位于环境范围内的路径段下: ``` https://model-{model_id}.api.baseten.co/environments/production/sync/v1 ``` 有关当前 URL 形式以及工作区中可用的环境名称,请参阅[调用模型](https://docs.baseten.co/inference/calling-your-model)。 这会对网关配置产生两个影响: * 为每个专用部署创建一个**独立的服务提供方密钥**,并将 `api_base` 设置为该部署的 URL。AISIX Cloud Admin API 只会填充共享 Model APIs 根路径,因此这里实际上必须设置 `api_base`。 * 别名上的 `model_name` 是部署本身提供的模型名称,通常是原始权重标识符,而不是 Baseten Model APIs 目录标识符。 在专用部署服务提供方密钥上保留 `baseten` 服务提供方值,使其用量核算、指标和访问日志仍与其他 Baseten 流量归为一组。专用部署提供的模型不在定价目录覆盖范围内,因此应将其费率设置为组织定价覆盖项,而不是更换服务提供方值。请参阅[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)和[成本元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 ## 使用推理模型[​](#使用推理模型 "使用推理模型的直接链接") Baseten Model APIs 上的若干模型会输出推理轨迹。AISIX 无需为它们进行额外配置: * **推理输出。** Baseten 在 `reasoning_content` 中返回推理,该字段已经是 AISIX 处理流式和非流式响应时的规范字段。与在厂商特定 `delta` 路径下传输推理的服务提供方不同,Baseten 不需要在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides) 覆盖项。 * **推理控制。** AISIX 不会显式建模每个请求参数。它不识别的顶层字段会通过 `openai` 适配器原样转发给上游,因此 Baseten 记录的逐模型推理控制项——部分模型使用顶层 `reasoning_effort`,其他模型使用顶层 `chat_template_args` 对象——会原样到达 Baseten。请查看 [Baseten 推理](https://docs.baseten.co/inference/model-apis/reasoning),确认每个模型接受的控制项,因为它因模型而异,而不是因账户而异。 Baseten 未配置参数重命名,因此 Token 限制字段也会按发送时的名称传递。请发送目标 Baseten 模型文档所规定的字段名。 ## 端点支持[​](#端点支持 "端点支持的直接链接") Baseten 支持的别名可用于标准化聊天路由;当配置的 `api_base` 提供 Embeddings 路由时,也可用于 `/v1/embeddings`。Baseten Embeddings Inference 部署会暴露 OpenAI 兼容 `/v1/embeddings` 路由,因此当服务提供方密钥指向该部署 URL 时,Embedding 别名可以正常工作。 由于别名解析到 `openai` 适配器,调用 `/v1/messages` 的 Anthropic 风格客户端会由 AISIX 转换为 OpenAI 请求形态。AISIX 不会分发到 Baseten 原生的 Anthropic 形态路由。 以 `openai/` 开头的 Baseten 模型标识符(例如 `openai/gpt-oss-120b`)不会让别名成为 OpenAI 服务提供方模型。服务提供方值仍为 `baseten`,因此按服务提供方身份而不是适配器执行门禁的路由(图像生成、视频生成和 rerank)会拒绝该别名。完整路由矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md#endpoint-compatibility)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 接入 Baseten,并验证了模型别名。接下来可以阅读: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Baseten 专用部署和共享 Model APIs 目录之间进行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # 自带端点 私有模型服务器(例如 [vLLM](https://docs.vllm.ai/)、[SGLang](https://docs.sglang.ai/) 和 [Ollama](https://ollama.com/))可以从你控制的基础设施公开 OpenAI 兼容 API。AISIX 可以将模型流量路由到这些服务器,或路由到位于自有模型之前的私有代理。 如果应用需要继续通过 OpenAI 兼容 API 调用 AISIX,同时由 AISIX 将流量转发到私有或隔离网络中的模型服务,请使用 BYO 端点。该端点必须接受 OpenAI 兼容的 Chat Completions 请求。 如需使用已按各引擎文档中的 API 格式验证过的 AISIX Cloud 步骤,请参阅专门的 [Ollama](https://docs.apiseven.com/ai-gateway/providers/ollama.md) 或 [vLLM](https://docs.apiseven.com/ai-gateway/providers/vllm.md) 指南。对于 SGLang 等其他私有 OpenAI 兼容服务器,请使用本页的通用 AISIX Cloud 资源格式。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 可访问的 OpenAI 兼容端点及其提供的模型名称。示例使用提供 `meta-llama/Llama-3.1-8B-Instruct` 的 vLLM。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 使用 `byo` 作为服务提供方标识符,选择 `openai` 适配器,并显式设置端点: ``` PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "vllm-private", "provider": "byo", "adapter": "openai", "api_key": "not-used-by-vllm", "api_base": "http://10.0.0.5:8000/v1", "allowed_environments": ["'"$ENV_ID"'"] }' | jq -r '.provider_key.id') ``` AISIX Cloud Admin API 使用 `provider: "byo"`,以便用量数据区分自定义端点和目录服务提供方。对于开源 AISIX 网关,`resources.yaml` 中的 `provider` 可以是 `vllm` 等描述性标签。两种方式都要求 `api_key` 非空;仅当端点忽略身份验证时才使用占位值。 创建模型: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "llama-3-private", "model_name": "meta-llama/Llama-3.1-8B-Instruct", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') ``` 创建可访问该模型的调用方 API Key: ``` BYO_CALLER_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "byo-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 在[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)中配置 BYO 定价。AISIX Cloud 模型请求不接受开源网关使用的 `cost` 配置块。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 许多私有运行的推理服务器不需要 API Key。对于无需身份验证的端点,请在服务提供方密钥中使用非空占位值;AISIX 会将其作为 Bearer Token 发送,你的服务器可以忽略该值。 请使用服务器预期的端点根地址,例如 vLLM 使用 `http://host:8000/v1`、SGLang 使用 `http://host:30000/v1`、Ollama 使用 `http://host:11434/v1`。以下示例使用 `http://10.0.0.5:8000/v1`。 选择应用将发送给 AISIX 的调用方 API Key: ``` # 请替换为实际值 export BYO_CALLER_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源。 resources.yaml ``` _format_version: "1" provider_keys: - display_name: vllm-private provider: vllm adapter: openai api_key: not-used-by-vllm api_base: http://10.0.0.5:8000/v1 models: - display_name: llama-3-private provider: vllm model_name: meta-llama/Llama-3.1-8B-Instruct provider_key: vllm-private cost: input_per_1k: 0.0 output_per_1k: 0.0 api_keys: - display_name: byo-caller key_env: BYO_CALLER_KEY allowed_models: ["llama-3-private"] ``` * `provider` 是适合当前环境的任意简短标签。 * `adapter` 选择 OpenAI 兼容的上游格式。 * `api_key` 是无需身份验证的端点所使用的非空占位值。对于需要身份验证的端点,请从环境变量引用真实凭证(例如 `api_key: ${VLLM_API_KEY}`),不要在文件中写入明文 Secret。 * `api_base` 是端点根地址。如果 `/v1` 是服务器路由的一部分,请将其包含在内。 * 在模型条目中,`display_name` 是调用方在 `model` 中发送的别名。 * `model_name` 是端点预期的上游 ID。对于 vLLM 和 SGLang,请使用所提供的模型名称;对于 Ollama,请使用本地模型标签,例如 `llama3.1:8b`。 * `provider_key` 通过服务提供方密钥的 `display_name` 将模型别名关联到服务提供方密钥。 * `cost` 为可选字段,用于提供下文所述的定价元数据。 调用方 Key 的 `allowed_models` 值必须与模型别名匹配。网关会从 `BYO_CALLER_KEY` 读取明文调用方 Key,并且只存储其哈希。服务提供方密钥 Secret 遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中说明的凭证处理方式。 ### 添加价格元数据[​](#add-pricing-metadata "添加价格元数据的直接链接") 目录服务提供方会携带来自 models.dev 目录的价格。BYO 端点不在该目录中,因此如果需要 Token 成本核算,请自行设置定价元数据。 将模型条目中的零成本占位值替换为实际的每 1K 个 Token 费率: resources.yaml(模型成本) ``` cost: input_per_1k: 0.10 output_per_1k: 0.30 ``` 两个值的单位都是每 1,000 个 Token 的美元价格。`input_per_1k` 适用于提示词 Token,`output_per_1k` 适用于补全 Token。存在 `cost` 配置块时,这两个字段都为必填项。 开源网关会将这些元数据用于用量事件和 `least_cost` 路由,但不会据此执行预算限制。AISIX Cloud 不会使用 `resources.yaml` 中的 `cost` 配置块;请通过[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)单独配置 BYO 定价。资源文件字段请参阅[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 ### 验证并加载配置[​](#验证并加载配置 "验证并加载配置的直接链接") 如果 AISIX 安装在本地,请在加载前验证完整文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供所引用的环境变量,再启动网关。如果这些变量已经可供本地安装的网关进程使用,请向该进程发送 `SIGHUP` 以重新加载文件: ``` kill -HUP "$(pgrep -x aisix)" ``` 如果新增了变量或更改了变量值,请改用更新后的进程环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。 ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 使用已创建的调用方 API Key 和模型别名,通过代理发送请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${BYO_CALLER_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "llama-3-private", "messages": [ { "role": "user", "content": "Say hello from the private model." } ] }' ``` 响应应为 OpenAI 兼容的 Chat Completions 响应,并回显面向调用方的别名。请在端点访问日志中检查来自 AISIX 的 `POST /v1/chat/completions` 条目。 如果 AISIX 返回上游路由或连接错误,请检查 `api_base`、所提供的模型名称和端点可访问性。 ## 支持其他端点[​](#支持其他端点 "支持其他端点的直接链接") 私有端点必须实现应用通过 AISIX 调用的每个 OpenAI 兼容路由。当端点提供兼容的 Embeddings 路由时,AISIX 可以转发 Embedding 请求。其他路由有额外的服务提供方要求;请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 对于请求或响应格式上的细微差异,请在服务提供方密钥上配置[服务提供方专用覆盖](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将私有 OpenAI 兼容端点连接到 AISIX。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md):使用定价元数据执行 AISIX Cloud 预算限制。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Cerebras [Cerebras Inference](https://inference-docs.cerebras.ai/) 在 Cerebras 推理系统上托管开放权重模型。AISIX 将这些模型置于统一的 OpenAI 兼容 API 之后,并集中管理上游凭证、调用方访问权限、限流和用量核算。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * 从 [Cerebras Cloud 控制台](https://cloud.cerebras.ai/)获取的 Cerebras API Key。 * 已安装 `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Cerebras 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 Cerebras API 与 OpenAI 兼容,因此 AISIX 通过 `openai` 适配器连接,并使用 Cerebras API 根路径作为 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Cerebras 凭证和 API 根路径的服务提供方密钥: ``` # 请替换为实际值 export CEREBRAS_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cerebras-prod", "provider": "cerebras", "api_key": "'"${CEREBRAS_API_KEY}"'", "api_base": "https://api.cerebras.ai/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `cerebras`。AISIX Cloud Admin API 从目录服务提供方派生适配器;`adapter` 字段仅接受 BYO 服务提供方密钥。 ❷ `api_key` 存储 Cerebras API Key。Cerebras 使用 HTTP Bearer 身份认证,这正是 `openai` 适配器已经发送的形式。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://api.cerebras.ai/v1`,与 Cerebras 为 [OpenAI 客户端库](https://inference-docs.cerebras.ai/resources/openai)记录的 `baseURL` 根路径相同。它已包含 `/v1` 路径,因此 AISIX 会直接向其追加 `/chat/completions` 等端点路径。对于 `cerebras` 目录服务提供方,此字段为可选项;省略时 AISIX Cloud Admin API 会填入相同的值。示例仍显式设置该字段,使配置中始终可以看到每个密钥指向的根路径。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Cerebras 模型 ID 是不带厂商前缀的裸标识符,即使权重来自其他厂商也是如此。OpenAI 开放权重模型在 Cerebras 上为 `gpt-oss-120b`,Google 模型为 `gemma-4-31b`。创建别名前,请在 [Cerebras 模型目录](https://inference-docs.cerebras.ai/models/overview)中查看当前列表;该目录较短,并会随模型的新增和退役而轮换。当前 ID 包括 `gpt-oss-120b`、`gemma-4-31b` 和 `zai-glm-4.7`。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cerebras-gptoss-prod", "model_name": "gpt-oss-120b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Cerebras 模型 ID,例如 `gpt-oss-120b` 或 `gemma-4-31b`。不要从托管相同权重的其他服务提供方沿用 `openai/gpt-oss-120b` 等带前缀的 ID。 ❸ `provider_key_id` 将别名关联到 Cerebras 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cerebras-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export CEREBRAS_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "cerebras-prod" provider: "cerebras" adapter: "openai" api_key: ${CEREBRAS_API_KEY} api_base: "https://api.cerebras.ai/v1" models: - display_name: "cerebras-gptoss-prod" provider: "cerebras" model_name: "gpt-oss-120b" provider_key: "cerebras-prod" api_keys: - display_name: "cerebras-caller" key_env: CALLER_API_KEY allowed_models: - "cerebras-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证��服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "cerebras-gptoss-prod", "messages": [ { "role": "user", "content": "Say hello from Cerebras." } ] }' ``` 网关返回 OpenAI 兼容响应,其中回显面向调用方的别名 `cerebras-gptoss-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base` 和 `model_name` 中的 Cerebras 模型 ID。 ## 发送 Token 限制[​](#发送-token-限制 "发送 Token 限制的直接链接") Cerebras 遵循当前 OpenAI 参数命名,并在 [Chat Completions](https://inference-docs.cerebras.ai/api-reference/chat-completions) 中使用 `max_completion_tokens` 表示生成 Token 上限。因此 AISIX 服务提供方目录中的 Cerebras 条目不会配置参数重命名,AISIX 会把调用方发送的 `max_completion_tokens` 原样转发给 Cerebras。其他一些 OpenAI 兼容上游仍要求旧的 `max_tokens` 名称,并为其配置了重命名,因此可用于 Cerebras 的请求体不一定能直接用于每个 openai 适配器服务提供方。 如果现有客户端发送旧的 `max_tokens` 名称,而你需要以上游当前名称传递它,请在服务提供方密钥上添加重命名: ``` { "request": { "param_renames": { "max_tokens": "max_completion_tokens" } } } ``` 该重命名适用于引用此服务提供方密钥的每个模型。请参阅[服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 控制推理强度[​](#控制推理强度 "控制推理强度的直接链接") Cerebras 接受 Chat Completions 正文顶层的标准 OpenAI `reasoning_effort` 参数。AISIX 不会剥离无法识别的顶层参数,因此该值会原样到达上游: ``` { "model": "cerebras-gptoss-prod", "messages": [ { "role": "user", "content": "Plan a three-step migration." } ], "reasoning_effort": "low" } ``` 接受的值因模型而异: | 模型 | `reasoning_effort` 值 | 默认值 | | -------------- | ------------------------------- | -------- | | `gpt-oss-120b` | `low`, `medium`, `high` | `medium` | | `gemma-4-31b` | `none`, `low`, `medium`, `high` | `none` | | `zai-glm-4.7` | 使用 `none` 禁用推理 | 启用推理 | 请在 [Cerebras 推理文档](https://inference-docs.cerebras.ai/capabilities/reasoning)中确认所配置模型接受的值,因为某个模型接受的值可能会被另一模型拒绝。 Cerebras 目录条目未设置推理字段覆盖项,因此 AISIX 会保留上游已在规范 `reasoning_content` 字段中返回的流式和非流式推理。如果 Cerebras 模型在其他 `delta` 路径上传输推理,请在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 路由延迟敏感流量[​](#路由延迟敏感流量 "路由延迟敏感流量的直接链接") 在按观测延迟对目标排序的路由模型中,Cerebras 别名是一个实用目标。创建 `strategy` 设为 `least_latency` 的路由模型,并将 Cerebras 别名与回退目标一同列出。AISIX 按近期上游延迟的移动平均值对目标排序,流式请求使用首 Token 时间,并在排序前探测尚无样本的目标。请参阅[按成本、延迟或负载路由](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md#route-by-cost-latency-or-load)。 ## 端点支持[​](#端点支持 "端点支持的直接链接") Cerebras 是仅提供推理的上游,因此只有部分代理界面适用于 Cerebras 支持的别名。 | 路由 | Cerebras 别名的行为 | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/responses` | 通过聊天适配器路径上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持。没有对应聊天语义的 OpenAI Responses 专用字段会被忽略。 | | `/v1/messages` | 通过转换支持 Anthropic 形态的调用方。`/v1/messages/count_tokens` 的 Token 计数要求使用 Anthropic 支持的模型。 | | `/v1/embeddings` | 不可用。Cerebras 提供语言模型,但不发布 Embedding 模型,因此请把 Embedding 路由到其他服务提供方。请参阅 [Embedding](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/images/generations` | 拒绝。该路由只接受服务提供方为 `openai` 的模型。 | | `/v1/rerank` | 拒绝。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/videos` | 拒绝。该路由仅接受自身服务提供方允许列表,其中不包含 `cerebras`。 | | `/passthrough/cerebras/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用:路由认领此前缀,`target_url` 设为 `https://api.cerebras.ai/v1` 根地址;在调用方 Key 的 `allowed_routes` 上授予该路由。服务提供方原生路径以有限的网关标准化中继。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 接入 Cerebras,并验证了模型别名。接下来可以阅读: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Cerebras 与另一个服务提供方之间进行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Cloudflare Workers AI [Cloudflare Workers AI](https://developers.cloudflare.com/workers-ai/) 为 Cloudflare 网络上托管的模型提供无服务器推理。AISIX 为这些模型提供面向应用的 OpenAI 兼容 API,并由网关管理 Cloudflare Token、调用方访问权限、限流和用量核算。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * Cloudflare 账户 ID 和 Workers AI API Token。在 Cloudflare 控制台中打开 Workers AI 页面并选择 **Use REST API**,按 [REST API 入门](https://developers.cloudflare.com/workers-ai/get-started/rest-api/)所述创建 Token 并复制账户 ID。 * 已安装 `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Workers AI 支持的 Chat Completions 和原生 Responses 创建服务提供方密钥、模型别名和调用方 API Key。 Cloudflare Workers AI 是社区目录服务提供方。AISIX 接受 `cloudflare-workers-ai` 作为服务提供方值,并选择使用 Bearer 身份认证的 `openai` 适配器。AISIX 不会提供精选基础 URL 或服务提供方特定的请求和响应重写,因此必须配置账户范围的 `api_base`。 控制台将该服务提供方标记为传输格式未经验证的社区条目。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Cloudflare 凭证和账户范围 API 根路径的服务提供方密钥: ``` # 请替换为实际值 export CLOUDFLARE_API_TOKEN="YOUR_PROVIDER_API_KEY" export CLOUDFLARE_ACCOUNT_ID="YOUR_CLOUDFLARE_ACCOUNT_ID" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cloudflare-workers-ai-prod", "provider": "cloudflare-workers-ai", "api_key": "'"${CLOUDFLARE_API_TOKEN}"'", "api_base": "https://api.cloudflare.com/client/v4/accounts/'"${CLOUDFLARE_ACCOUNT_ID}"'/ai/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为目录 ID `cloudflare-workers-ai`。AISIX Cloud Admin API 从目录服务提供方派生适配器;`adapter` 字段仅接受 BYO 服务提供方密钥,因此不要在此设置。 ❷ `api_key` 存储 Workers AI API Token。Cloudflare 使用 `Authorization: Bearer` 请求头认证 REST API,这正是 `openai` 适配器已经发送的形式。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 是账户范围的根路径 `https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/ai/v1`。Cloudflare 在 [OpenAI 兼容 API 端点](https://developers.cloudflare.com/workers-ai/configuration/open-ai-compatibility/)中记录的完整端点为 `https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1/chat/completions`。AISIX 会向 `api_base` 追加 `/chat/completions` 等端点路径,因此该值必须止于 `/ai/v1`。如果误粘贴完整端点 URL,AISIX 会移除可识别的后缀和末尾斜杠,但应存储较短的根路径形式。 ❹ `apis.responses` 声明 Workers AI 在同一账户范围的根地址提供 Responses API。这样,AISIX 会使用 Cloudflare 原生格式,而不是通过 Chat Completions 转换请求。 警告 请始终在 Cloudflare Workers AI 服务提供方密钥上设置 `api_base`。 对于社区目录服务提供方,省略 `api_base` 时,AISIX 会回退到公共模型目录发布的基础 URL。Cloudflare Workers AI 的发布值为 `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1`。由于每个 Cloudflare 账户都有自己的端点,该值是模板而不是已解析的 URL。AISIX 不会替换占位符,且会原样存储回退值而不重新验证,因此创建请求仍会成功。随后,存储的根路径会保留字面量 `${CLOUDFLARE_ACCOUNT_ID}`,而不是账户 ID,第一次请求将在上游失败。该服务提供方不存在可用的共享默认值。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Workers AI 模型 ID 始终以 `@cf/` 开头,后跟发布方和模型名称:`@cf/<publisher>/<model>`。请把完整字符串写入 `model_name`,包括 `@cf/` 前缀以及 `-fp8-fast` 等任何精度或变体后缀。删除前缀或复用其他主机为相同权重发布的裸 ID,会导致上游模型错误。 Cloudflare 模型目录当前包含以下 ID: | Cloudflare 模型 ID | 说明 | | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | [`@cf/openai/gpt-oss-120b`](https://developers.cloudflare.com/workers-ai/models/gpt-oss-120b/) | 本指南用于演示 Responses 和 Chat Completions。 | | [`@cf/meta/llama-3.3-70b-instruct-fp8-fast`](https://developers.cloudflare.com/workers-ai/models/llama-3.3-70b-instruct-fp8-fast/) | Chat Completions 模型;Cloudflare 当前没有说明该模型支持 Responses。 | | [`@cf/qwen/qwen3-30b-a3b-fp8`](https://developers.cloudflare.com/workers-ai/models/qwen3-30b-a3b-fp8/) | Chat Completions 模型;Cloudflare 当前没有说明该模型支持 Responses。 | 创建别名前,请在 [Workers AI 模型目录](https://developers.cloudflare.com/workers-ai/models/)中查看当前列表。Cloudflare 当前说明 GPT-OSS 同时支持 Responses 和 Chat Completions;除非其他文本生成模型的文档明确新增 Responses 支持,否则应将其视为仅支持 Chat Completions 的选项。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cloudflare-gptoss-prod", "model_name": "@cf/openai/gpt-oss-120b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是完整的 Workers AI 模型 ID,例如 `@cf/openai/gpt-oss-120b`。 ❸ `provider_key_id` 将别名关联到 Cloudflare Workers AI 服务提供方密钥。 有关为预算核算和用量报告关联成本元数据的信息,请参阅[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cloudflare-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export CLOUDFLARE_API_TOKEN="YOUR_PROVIDER_API_KEY" export CLOUDFLARE_ACCOUNT_ID="YOUR_CLOUDFLARE_ACCOUNT_ID" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "cloudflare-workers-ai-prod" provider: "cloudflare-workers-ai" adapter: "openai" api_key: ${CLOUDFLARE_API_TOKEN} api_base: "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1" apis: responses: {} models: - display_name: "cloudflare-gptoss-prod" provider: "cloudflare-workers-ai" model_name: "@cf/openai/gpt-oss-120b" provider_key: "cloudflare-workers-ai-prod" api_keys: - display_name: "cloudflare-caller" key_env: CALLER_API_KEY allowed_models: - "cloudflare-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "cloudflare-gptoss-prod", "input": "Say hello from Cloudflare Workers AI." }' ``` AISIX 会将请求发送至 Cloudflare 原生 Responses 端点,在上游请求中把别名替换为 Workers AI 模型 ID,并在响应中恢复该别名。 如果请求失败,请按顺序排查以下三个原因: 1. 上游身份认证失败表示 `api_key` 值有误,或 Token 缺少 Workers AI 权限。 2. 上游路由或账户错误表示 `api_base` 有误。确认账户 ID 路径段是真实账户 ID,且该值止于 `/ai/v1`。 3. 上游模型错误表示 `model_name` 有误。确认 ID 仍带有 `@cf/` 前缀。 ## 补充社区目录未提供的配置[​](#补充社区目录未提供的配置 "补充社区目录未提供的配置的直接链接") 具有 AISIX 精选适配器映射的服务提供方会随适配器一同提供请求和响应调整。如果上游对面向调用方的参数使用不同名称,网关会在参数离开前对其重命名。Cloudflare Workers AI 没有此类映射,因此**未为它注册任何参数重命名或推理字段映射**。AISIX 会使用调用方提供的字段名,把 Chat Completions 正文发送到 `/ai/v1` 根路径,并按标准 OpenAI Chat Completions JSON 读取响应。 只要 Cloudflare 界面与 OpenAI 形态一致,该默认行为就是正确的。如果存在差异,请在服务提供方密钥上显式配置,而不是改造每个客户端: ``` { "request": { "param_renames": { "max_completion_tokens": "max_tokens" } }, "response": { "reasoning_field": "delta.reasoning" } } ``` * `request.param_renames` 会在请求发出时重命名顶层参数。当 Workers AI 模型拒绝客户端已经发送的名称时使用该配置。如果请求同时携带两个名称,AISIX 会使用原始面向调用方名称中的值。 * `response.reasoning_field` 把非标准流式 `delta` 路径中的推理映射到规范 `delta.reasoning_content` 字段。当模型在 `reasoning_content` 之外的位置传输推理时使用该配置。 覆盖项会应用于引用该服务提供方密钥的每个模型,因此请先用非生产别名验证。完整字段目录请参阅[服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 AISIX 不会剥离其未原生建模的顶层参数。Cloudflare 支持但 AISIX 没有类型化字段的参数仍会原样到达上游。因此,只有参数名称不同时才需要重命名,而不是仅仅因为网关不熟悉该参数。 ## 控制推理强度[​](#控制推理强度 "控制推理强度的直接链接") `@cf/openai/gpt-oss-120b` 模型提供推理强度控制,接受 `low`、`medium` 和 `high`。无法识别的顶层参数会透传,因此请在 Chat Completions 正文顶层发送该参数: ``` { "model": "cloudflare-gptoss-prod", "messages": [ { "role": "user", "content": "Plan a three-step migration." } ], "reasoning_effort": "low" } ``` Workers AI 的推理支持因模型而异,有些模型完全不提供推理控制。发送参数前,请在具体模型的[模型页面](https://developers.cloudflare.com/workers-ai/models/)确认,因为不接受该参数的模型可能会拒绝请求。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Cloudflare Workers AI 通过其 OpenAI 兼容根路径提供文本生成和文本 Embedding,因此只有部分 AISIX 代理界面适用于 Workers AI 支持的别名。 | 路由 | Cloudflare Workers AI 别名的行为 | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/embeddings` | 支持。Cloudflare 在同一 `/ai/v1` 根路径下实现 OpenAI 兼容 Embedding,因此请在同一个服务提供方密钥上创建第二个别名,并将其 `model_name` 设为 `@cf/baai/bge-m3` 等 Embedding 模型。请参阅 [Embedding](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 Cloudflare 原生 Responses API。如果没有此声明,AISIX 会使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/messages` | 通过转换支持 Anthropic 形态的调用方。`/v1/messages/count_tokens` 的 Token 计数要求使用 Anthropic 支持的模型。 | | `/v1/images/generations` | 拒绝。该路由只接受服务提供方为 `openai` 的模型。 | | `/v1/rerank` | 拒绝。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/videos` | 返回未实现错误。该路由仅向固定服务提供方集合分发,其中不包含 `cloudflare-workers-ai`。 | | `/passthrough/cloudflare-workers-ai/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用:路由认领此前缀,`target_url` 设为账号级 `/ai/v1` 根地址;在调用方 Key 的 `allowed_routes` 上授予该路由。这样的路由只能到达 `/ai/v1` 下的路径,因此 Cloudflare 原生 `/ai/run/@cf/...` 端点位于根路径之外,无法经它访问。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 接入 Cloudflare Workers AI,并验证了模型别名。接下来可以阅读: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Cloudflare Workers AI 与另一个服务提供方之间进行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Cohere [Cohere](https://docs.cohere.com/) 提供 Command 模型以及生成、Embedding 和 rerank API。AISIX 将这些能力置于由网关管理的凭证、调用方访问权限、限流和用量核算之后。 Cohere 发布了原生 API,以及用于 OpenAI 形态请求的[兼容性 API](https://docs.cohere.com/docs/compatibility-api)。本指南使用兼容性 API 处理 Chat Completions 和 Embedding,然后为 rerank 单独配置原生 API。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * 从 [Cohere 控制台](https://dashboard.cohere.com/api-keys)获取的 Cohere API Key。 * 已安装 `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Cohere 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 AISIX 通过 `openai` 适配器连接 Cohere 兼容性 API。Chat Completions 和 Embedding 无需请求转换。Cohere rerank 使用原生 API,并要求使用[添加 Rerank 模型](#add-a-rerank-model)中配置的独立服务提供方密钥。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Cohere 凭证和 API 根路径的服务提供方密钥: ``` # 请替换为实际值 export COHERE_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cohere-prod", "provider": "cohere", "api_key": "'"${COHERE_API_KEY}"'", "api_base": "https://api.cohere.ai/compatibility/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `cohere`。AISIX Cloud Admin API 从目录服务提供方派生适配器;`adapter` 字段仅接受 BYO 服务提供方密钥。 ❷ `api_key` 存储 Cohere API Key。它遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 指向 Cohere 兼容性 API。该路径在 `/v1` 版本段之前包含 `/compatibility`,因为 OpenAI 形态路由与 Cohere 原生 API 使用不同的前缀。AISIX 会向该基础路径追加 `/chat/completions`。对于 `cohere` 目录服务提供方,该字段为可选项;省略时 AISIX Cloud Admin API 会填入相同的值。示例仍显式设置该字段,使配置中始终可以看到每个密钥指向的界面。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Cohere 模型 ID 由系列名称和发布日期组成:`command-a-03-2025` 是 `command-a` 系列 2025 年三月的快照,能力变体会在日期前添加后缀,例如 `command-a-reasoning-08-2025` 或 `command-a-vision-07-2025`。日期是 ID 的一部分,因此根据目录 ID 创建的模型别名会固定到一个快照。当前 ID 请查看 [Cohere 模型列表](https://docs.cohere.com/docs/models)。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cohere-command-a-prod", "model_name": "command-a-03-2025", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Cohere 模型 ID,例如 `command-a-03-2025`、`command-a-plus-05-2026` 或 `command-a-reasoning-08-2025`。 ❸ `provider_key_id` 将别名关联到 Cohere 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在响应中返回一次,请安全保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cohere-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export COHERE_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "cohere-prod" provider: "cohere" adapter: "openai" api_key: ${COHERE_API_KEY} api_base: "https://api.cohere.ai/compatibility/v1" models: - display_name: "cohere-command-a-prod" provider: "cohere" model_name: "command-a-03-2025" provider_key: "cohere-prod" api_keys: - display_name: "cohere-caller" key_env: CALLER_API_KEY allowed_models: - "cohere-command-a-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "cohere-command-a-prod", "messages": [ { "role": "user", "content": "Say hello from Cohere." } ] }' ``` 网关返回 OpenAI 兼容响应,其中回显面向调用方的别名 `cohere-command-a-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base` 和 `model_name` 中的 Cohere 模型 ID。上游返回 404 通常表示 `api_base` 指向 Cohere 原生 API 根路径,而不是兼容性路径。 ## 控制推理强度[​](#控制推理强度 "控制推理强度的直接链接") Cohere 支持推理的 Command 模型(例如 `command-a-reasoning-08-2025` 和 `command-a-plus-05-2026`)在不同 API 界面上以不同方式提供思考能力。AISIX 路由到兼容性 API,因此调用方通过 OpenAI 形态的 `reasoning_effort` 字段进行控制: ``` { "reasoning_effort": "none" } ``` Cohere 兼容性 API 的该字段接受 `none` 和 `high`,分别映射为禁用和启用思考。该界面未记录原生 API 的 Token 预算控制,因此请求无法通过兼容性路由限制推理 Token 数量。当前字段行为请参阅 Cohere 的[推理](https://docs.cohere.com/docs/reasoning)文档。 AISIX 会保留响应中的 `reasoning_content`,并把 `reasoning` 标准化到该规范字段。Cohere 服务提供方密钥不带推理字段覆盖项。如果模型在其他 `delta` 路径下传输推理,请在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 添加 Rerank 模型[​](#add-a-rerank-model "添加 Rerank 模型的直接链接") `/v1/rerank` 路由接受服务提供方值为 `openai`、`cohere` 或 `jina` 的模型,因此该路由允许 Cohere 支持的别名。以下两个细节决定请求能否到达 Cohere: * Cohere rerank 不属于兼容性 API,而是发布在原生 API 主机上。 * rerank 路由会向服务提供方密钥基础路径追加 `/rerank`;如果基础路径尚未以 `/v1` 结尾,还会插入 `/v1` 路径段。因此,指向 `https://api.cohere.ai/compatibility/v1` 的密钥会构造 `https://api.cohere.ai/compatibility/v1/rerank`,这并不是 rerank 端点。 在 AISIX Cloud 中,为原生 API 根路径创建第二个 Cohere 服务提供方密钥: ``` RERANK_PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cohere-rerank", "provider": "cohere", "api_key": "'"${COHERE_API_KEY}"'", "api_base": "https://api.cohere.com", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$RERANK_PROVIDER_KEY_ID" ``` ❶ `api_base` 是不带版本段的原生 API 根路径。rerank 路由会自行添加版本,并把请求解析到 Cohere 的 [v1 rerank 端点](https://docs.cohere.com/v1/reference/rerank)。 警告 只要基础路径尚未以 `/v1` 结尾,rerank 路由就会插入 `/v1` 路径段,因此无法通过 `/v1/rerank` 访问 Cohere 的 [v2 rerank](https://docs.cohere.com/reference/rerank) 路径。把 `api_base` 设置为 `https://api.cohere.com/v2` 会构造 `https://api.cohere.com/v2/v1/rerank`,并在上游失败。 创建 rerank 模型别名和范围仅限该别名的调用方密钥: ``` RERANK_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cohere-rerank-prod", "model_name": "rerank-v3.5", "provider_key_id": "'"${RERANK_PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') RERANK_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "cohere-rerank-caller", "allowed_models": ["'"${RERANK_MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 对于开源 AISIX 网关,请将 `cohere-rerank` 添加到 `provider_keys`,并将 `cohere-rerank-prod` 添加到 `models`。将现有的 `cohere-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(重排序资源) ``` provider_keys: - display_name: "cohere-rerank" provider: "cohere" adapter: "openai" api_key: ${COHERE_API_KEY} api_base: "https://api.cohere.com" models: - display_name: "cohere-rerank-prod" provider: "cohere" model_name: "rerank-v3.5" provider_key: "cohere-rerank" api_keys: - display_name: "cohere-caller" key_env: CALLER_API_KEY allowed_models: - "cohere-command-a-prod" - "cohere-rerank-prod" ``` 按照上文所述验证声明式资源文件并重新加载或重启,然后使用现有调用方密钥发送 rerank 请求: ``` export RERANK_API_KEY="$CALLER_API_KEY" ``` Rerank 模型 ID 使用独立于 Command 系列的命名:`rerank-v3.5`,以及两个 Rerank 4.0 变体 `rerank-v4.0-fast` 和 `rerank-v4.0-pro`。该路由会解析到 Cohere v1 rerank 端点,因此在生产别名指向所选 ID 前,请先在 [rerank 模型概述](https://docs.cohere.com/docs/rerank-overview)中确认该端点提供此 ID。 通过代理发送 rerank 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/rerank" \ -H "Authorization: Bearer ${RERANK_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "cohere-rerank-prod", "query": "How do I rotate a provider credential?", "documents": [ "Provider keys store the upstream credential.", "Caller API keys authorize model access.", "Rate limits apply per caller key." ], "top_n": 2 }' ``` AISIX 只会把 `model` 字段重写为 `rerank-v3.5`,并原样转发正文,因此 Cohere 的 `top_n` 参数会按原样到达上游。响应保留 Cohere rerank 形态:一个按 `relevance_score` 排序的 `results` 数组以及一个 `meta` 对象。AISIX 会从响应中读取 `meta.billed_units.input_tokens` 进行用量核算,因此 rerank 流量会与聊天流量一同出现在网关日志和预算总计中。 ## Cohere 端点支持[​](#cohere-端点支持 "Cohere 端点支持的直接链接") 根据支持模型别名的 Cohere 服务提供方密钥不同,以下路由的行为也不同。 | 路由 | Cohere 支持模型的行为 | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 通过兼容性 API 基础路径提供支持。 | | `/v1/embeddings` | 支持。`openai` 适配器会向兼容性基础路径追加 `/embeddings`,即 Cohere 的 OpenAI 形态 Embedding 路由。在 `model_name` 中使用 `embed-v4.0` 等 Cohere [Embedding 模型](https://docs.cohere.com/docs/cohere-embed) ID。 | | `/v1/responses` | 通过聊天适配器桥接。AISIX 会返回 Responses 形态结果,而不是转发到原生 Responses API;没有对应聊天语义的 OpenAI Responses 专用字段会被忽略。请参阅 [Responses API](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/rerank` | 使用原生 API 根路径上的第二个服务提供方密钥时受支持。请参阅[添加 Rerank 模型](#add-a-rerank-model)。 | | `/v1/images/generations` | 不支持。该路由只接受服务提供方值为 `openai` 的模型。 | | `/v1/videos` | 不支持。视频路由的服务提供方允许列表中不包含 Cohere。 | | `/v1/messages` | 通过转换支持 Anthropic 形态的调用方。`/v1/messages/count_tokens` 的 Token 计数要求使用 Anthropic 支持的模型。 | | `/passthrough/cohere/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用;在调用方 Key 的 `allowed_routes` 上授予该路由。一条路由绑定一个固定的 `target_url` 和服务提供方密钥,因此要同时访问兼容性基础地址和原生根地址,需要在不同前缀下配两条路由,各绑一把 Cohere 服务提供方密钥。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 接入 Cohere,验证了模型别名,并添加了 rerank 路由。接下来可以阅读: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为这些别名配置路由、重试行为或成本元数据。 * [Rerank](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md):查看 rerank 请求契约及其服务提供方要求。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Cohere 与另一个服务提供方之间进行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # 服务提供方兼容性 服务提供方兼容性同时取决于面向调用方的端点和模型别名背后的上游服务提供方配置。一个模型可以在通用聊天端点正常工作,但仍会被某个服务提供方专属端点拒绝。 AISIX 从两个层面判断兼容性。[适配器协议族](https://docs.apiseven.com/ai-gateway/providers/adapters.md)决定如何为上游服务提供方编码聊天类请求。端点规则决定所选代理路由是否接受模型的服务提供方或适配器协议族。 ## 端点兼容性[​](#endpoint-compatibility "端点兼容性的直接链接") 请根据调用方 API 格式和服务提供方支持要求选择代理路由。 | 需求 | 路由 | 服务提供方支持 | | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 广泛聊天兼容性 | `/v1/chat/completions` | OpenAI、Anthropic、Bedrock、Vertex AI、Azure OpenAI,以及通过已配置适配器接入的 OpenAI 兼容服务提供方。 | | [文本补全](https://docs.apiseven.com/ai-gateway/endpoints/text-completions.md) | `/v1/completions` | 模型的服务提供方密钥使用 `openai` 适配器,且已配置的上游实现旧版 `/completions` 路由时可用。其他适配器返回 `501 not_implemented`。 | | Anthropic 风格客户端 | `/v1/messages` | 使用 `anthropic` 适配器或声明 `apis.messages` 的服务提供方密钥会原生转发;其他受支持的上游使用转换。文本支持范围最广。图片、文档和工具调用支持取决于所选服务提供方适配器。签名的思考历史仍为 Anthropic 专属。 | | Anthropic Token 计数 | `/v1/messages/count_tokens` | 目标服务提供方密钥使用 `anthropic` 适配器或声明 `apis.messages`,且上游必须实现 Token 计数路由。 | | 流式文本聊天 | 带 `stream: true` 的 `/v1/chat/completions` 或 `/v1/messages` | 服务提供方支持范围与所选端点一致。路由模型可以在 AISIX 发送响应字节之前执行故障转移,但响应流开始后不能切换目标。Chat Completions 音频输出是例外:AISIX 目前不会保留 `delta.audio`。 | | 向量嵌入 | `/v1/embeddings` | 支持 OpenAI 兼容上游、Bedrock 上的 Amazon Titan 和 Cohere 向量嵌入模型,以及 Vertex AI 上的 Google 发布方向量嵌入模型。其他服务提供方和模型组合返回 `501 not_implemented`。 | | OpenAI Responses API | `/v1/responses` | 声明 `apis.responses` 的服务提供方密钥,以及未配置 `apis` 声明的 OpenAI 密钥,会原生转发。其他上游在服务提供方适配器支持转换后的请求形态时使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。桥接路径会忽略没有 Chat 等价项的 OpenAI 专属字段。 | | [聊天音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md) | `/v1/chat/completions` | 当上游实现 OpenAI 聊天音频形态时,可通过 `openai` 或 `azure-openai` 适配器进行非流式音频输入和输出。每个符合条件的路由目标都必须满足相同要求。AISIX 会保留 `input_audio`、`modalities`、`audio` 和 `message.audio`,但不会跨服务提供方协议转换这些字段。 | | 图片生成 | `/v1/images/generations` | 已配置服务提供方为 OpenAI 的模型。 | | [图像编辑](https://docs.apiseven.com/ai-gateway/endpoints/image-editing.md) | `/v1/images/edits` | 已配置服务提供方为 OpenAI 的模型。请求为 `multipart/form-data`;网关只改写 `model` 字段,其余表单内容原样转发。 | | [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md) | `/v1/videos` 及其状态和内容路由 | 已配置服务提供方为 `alibaba`(Wan)、`zhipuai` 或 `zhipu`(CogVideoX)、`volcengine`(Ark Seedance)、`runwayml` 或 `runway`(Runway Gen 系列及由 Runway 托管的模型)、`openai`(Sora)的模型。仅支持文生视频。其他服务提供方返回 `501 not_implemented`。参见[视频生成支持](#video-generation-support)。 | | 音频 | `/v1/audio/transcriptions`、`/v1/audio/translations`、`/v1/audio/speech` | OpenAI 风格上游音频路由。AISIX 会转发音频格式,不会在不同服务提供方协议族之间转换音频。 | | [文件、批处理和微调](https://docs.apiseven.com/ai-gateway/endpoints/batch-files-fine-tuning.md) | `/v1/files`、`/v1/batches`、`/v1/fine_tuning/jobs` 及其相关路由 | 服务提供方密钥使用 `openai` 或 `azure-openai` 适配器的直接模型。Anthropic、Bedrock 和 Vertex AI 使用不同的文件和任务 API,不会通过这些路由进行转换。 | | Realtime WebSocket | `/v1/realtime` | 使用 `openai` 或 `azure-openai` 适配器的直接模型。上游必须实现 OpenAI Realtime WebSocket 路径和事件协议;AISIX 会中继 Frame,不执行跨协议转换。 | | Rerank | `/v1/rerank` | 支持 Cohere 和 Jina,或使用 `openai` 服务提供方值且实现 `/v1/rerank` 的 OpenAI 兼容上游。公开 OpenAI API 不提供此端点。 | | 服务提供方原生路由 | 已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),按约定为 `/passthrough/<provider>/*rest` | 路由 `target_url` 指向的任意上游。请求需匹配路由配置的路径前缀或入站 host,且调用方 Key 必须在 `allowed_routes` 列表中授予路由名称。网关标准化有限。 | ## 视频生成支持[​](#video-generation-support "视频生成支持的直接链接") 视频路由按模型别名自身的 `provider` 值分发,而不是按上游模型名称;AISIX 不维护模型 ID 允许列表,只会把别名中配置的上游模型名称按下表的固定映射转发出去,能否生成成功仍取决于该模型是否接受转发后的请求形态。这些路由只接受直连别名——路由模型或合议模型别名会返回 `400`。交付方式描述 `GET /v1/videos/{video_id}/content` 如何返回成品文件:`302` 重定向到服务提供方的签名 URL,或由网关带凭证获取后再流式转发给调用方。 | `provider` 值 | 视频模型 | `seconds` 映射为 | `size` 映射为 | 交付方式 | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------ | | `alibaba` | [Wan 和 HappyHorse 文生视频](https://docs.apiseven.com/ai-gateway/providers/qwen.md#generate-videos-with-wan),例如 `wan2.7-t2v`、`wan2.2-t2v-plus` 和 `happyhorse-1.1-t2v` | `parameters.duration` | `parameters.size`,格式为 `WIDTH*HEIGHT`;Wan 2.7 和 HappyHorse 改用 `resolution` 和 `ratio` 档位,请省略该字段 | 重定向 | | `zhipuai`、`zhipu` | [CogVideoX](https://docs.apiseven.com/ai-gateway/providers/zhipuai.md#generate-videos-with-cogvideox),例如 `cogvideox-3` | `duration` | `size`,原样转发 | 重定向 | | `volcengine` | [Ark Seedance](https://docs.apiseven.com/ai-gateway/providers/volcengine-ark.md#generate-videos-with-seedance),例如 `doubao-seedance-2-0-260128` | `duration` | 校验后丢弃;Ark 使用 `resolution` 和 `ratio` 档位 | 重定向 | | `runwayml`、`runway` | 文生视频端点上的 [Runway Gen 系列和由 Runway 托管的模型](https://docs.apiseven.com/ai-gateway/providers/runwayml.md),例如 `gen4.5` 和 `veo3.1` | `duration` | `ratio`,格式为 `WIDTH:HEIGHT` | 重定向 | | `openai` | [Sora](https://docs.apiseven.com/ai-gateway/providers/openai.md#generate-videos-with-sora):`sora-2`、`sora-2-pro` | `seconds`,以字符串形式发送,schema 接受 `4`、`8` 或 `12` | `size`,原样转发;各模型接受的分辨率范围不同 | 网关流式传输 | OpenAI 已于 2026 年 3 月 24 日[弃用 Videos API 和 Sora 2 系列模型](https://developers.openai.com/api/docs/deprecations),并将于 2026 年 9 月 24 日将其从 API 中移除。 有两个 `provider` 值虽然其厂商发布了视频 API,但不在该允许列表内:`alibaba-cn` 和 `zai` 访问的 API 根路径与各自支持视频的对应值不同,因此视频别名必须使用 `alibaba` 或 `zhipuai`。 这些路由只建模文生视频。除 `model`、`prompt`、`seconds` 和 `size` 之外的请求字段会被忽略而不是拒绝,其中包括 `input_reference`,因此图生视频请求只会依据提示词生成。服务提供方用于列出、删除、混剪、编辑或延长视频的路由同样未建模。这些能力以及负向提示词、随机种子等服务提供方原生生成字段,请使用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 ## 服务提供方专属支持[​](#provider-specific-support "服务提供方专属支持的直接链接") 聊天和 Responses 路由支持流式文本输出。Chat Completions 中的音频输出目前仅支持非流式;如需增量双向音频,请使用 Realtime WebSocket。下表说明额外端点支持和重要的服务提供方边界。 | 服务提供方配置 | 端点支持和边界 | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [OpenAI](https://docs.apiseven.com/ai-gateway/providers/openai.md) | 支持 Chat Completions、Responses、向量嵌入、图片生成、图像编辑、音频和 Sora 视频生成。公开 OpenAI API 不提供 Rerank 端点。 | | [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md) | 原生支持 Messages 和 Token 计数。Chat Completions 和 Responses 使用转换。不支持向量嵌入、图片生成和 Rerank。 | | [Amazon Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md) | 支持 Chat Completions 和 Responses。向量嵌入仅限 Amazon Titan 和 Cohere 向量嵌入模型 ID。不支持图片生成和 Rerank。 | | [Google Vertex AI](https://docs.apiseven.com/ai-gateway/providers/google-vertex-ai.md) | 支持 Chat Completions 和 Responses。向量嵌入仅限 Google 发布方模型。不支持图片生成和 Rerank。 | | [Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md) | 支持 Chat Completions 和 Responses。Azure OpenAI 适配器未实现向量嵌入、图片生成或 Rerank。 | | [DeepSeek](https://docs.apiseven.com/ai-gateway/providers/deepseek.md) | 支持 Chat Completions。AISIX Cloud 会在目录中声明 DeepSeek 的原生 Responses 和兼容 Anthropic 的 Messages 路由;开源网关可在服务提供方密钥上声明相同路由。不支持图片生成和 Rerank。 | | [Gemini](https://docs.apiseven.com/ai-gateway/providers/gemini.md) 和 [Mistral](https://docs.apiseven.com/ai-gateway/providers/mistral.md) | 支持 Chat Completions 和桥接的 Responses 请求。不支持图片生成和 Rerank。 | | [Groq](https://docs.apiseven.com/ai-gateway/providers/groq.md) | 当服务提供方密钥声明 `apis.responses` 时,支持 Chat Completions 和原生 Responses API。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。不支持图片生成和 Rerank。 | | [Together AI](https://docs.apiseven.com/ai-gateway/providers/together.md) | 通过兼容 OpenAI 的基础地址支持 Chat Completions、桥接的 Responses、Embedding、音频转录、音频翻译和文本转语音。`togetherai` 服务提供方值不支持规范化图片生成、视频生成和 Rerank;这些 Together 原生路由请使用透传路由。 | | [Qwen](https://docs.apiseven.com/ai-gateway/providers/qwen.md) | 通过 Model Studio 兼容 OpenAI 的基础地址支持 Chat Completions、服务提供方密钥声明 `apis.responses` 时的原生 Responses,以及 Embedding。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。原生 Messages 使用另一个地区 Base,且 Model Studio 未提供 Count Tokens 文档。仅服务提供方值恰好为 `alibaba` 时支持视频生成;`alibaba-cn` 不在视频路由允许列表中。规范化路由不支持图片生成和 Rerank。 | | [OpenRouter](https://docs.apiseven.com/ai-gateway/providers/openrouter.md) 和 [Fireworks AI](https://docs.apiseven.com/ai-gateway/providers/fireworks-ai.md) | 支持 Chat Completions、在服务提供方密钥声明 `apis.responses` 时支持各自的原生 Responses API,以及向量嵌入(当别名指向上游在其 OpenAI 兼容基础地址上发布的向量嵌入模型时)。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。不支持图片生成、视频生成和 Rerank:`openrouter` 和 `fireworks-ai` 服务提供方值不在这些路由的允许列表中。 | | [Cohere](https://docs.apiseven.com/ai-gateway/providers/cohere.md) | 通过 Cohere 兼容 API 基础地址支持 Chat Completions、桥接的 Responses 和向量嵌入。支持 Rerank,因为 `cohere` 是 Rerank 路由接受的三个服务提供方值之一;需要另一个指向 Cohere 原生 API 根地址的服务提供方密钥。不支持图片生成和视频生成。 | | [Zhipu AI](https://docs.apiseven.com/ai-gateway/providers/zhipuai.md) | 支持 Chat Completions、桥接的 Responses、转换后的 Messages、Embedding、音频转录、文本转语音、Realtime WebSocket 中继和规范化视频生成。原生图片生成、Rerank 和高级 CogVideoX 请求仍可通过透传路由访问;不支持规范化图片生成、音频翻译和 Rerank。 | | [Perplexity](https://docs.apiseven.com/ai-gateway/providers/perplexity.md) | 支持 Sonar Chat Completions 和桥接的 Responses。Perplexity 标准 Embedding 模型只有使用 API Base 包含 `/v1` 的独立服务提供方密钥时才能通过 `/v1/embeddings` 使用;Sonar Chat Base 不支持。图片生成、视频生成和 Rerank 不受支持。 | | [Cerebras](https://docs.apiseven.com/ai-gateway/providers/cerebras.md) | 支持 Chat Completions 和桥接的 Responses。上游未在配置的基础地址上提供 Embedding 模型,因此不可使用 Embedding。图片生成、视频生成和 Rerank 不受支持。 | | [Hugging Face](https://docs.apiseven.com/ai-gateway/providers/huggingface.md) | 当服务提供方密钥声明 `apis.responses` 时,支持 Chat Completions 和原生 Responses API。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。共享路由器的 OpenAI 兼容基础地址不提供 Embedding。图片生成、视频生成和 Rerank 不受支持。 | | [Moonshot AI](https://docs.apiseven.com/ai-gateway/providers/moonshotai.md) | 支持 Chat Completions。声明 `apis.responses` 可使用 Moonshot 原生 Responses API,该 API 当前仅支持 `kimi-k3`;否则 AISIX 会通过 Chat Completions 桥接 Responses。原生 Messages 和其他服务提供方路由需要透传路由。不支持图片生成、视频生成和 Rerank。 | | [Baseten](https://docs.apiseven.com/ai-gateway/providers/baseten.md) | 支持 Chat Completions 和桥接的 Responses 请求。当服务提供方密钥的 `api_base` 指向提供 OpenAI 兼容 `/v1/embeddings` 路由的 Baseten 部署时,向量嵌入可用。不支持图片生成、视频生成和 Rerank,即使 Baseten 模型 ID 以 `openai/` 开头也是如此——服务提供方值是 `baseten`,而不是 `openai`。 | | [Jina](https://docs.apiseven.com/ai-gateway/providers/jina.md) | 通过 Jina API 根地址上的 OpenAI 形态路由支持向量嵌入。原生支持 Rerank,因为 `jina` 是 Rerank 路由接受的三个服务提供方值之一,并且与向量嵌入共用相同的 API 根地址和服务提供方密钥。测试用 `jina-ai/jina-vlm` 模型在该根地址上支持 Chat Completions;Responses 和 Messages 通过此实验路由使用 AISIX 转换。其他 Jina 别名不支持这些 Chat 形态端点。不支持图片和视频生成:`jina` 服务提供方值不在这些路由的允许列表中。 | | [RunwayML](https://docs.apiseven.com/ai-gateway/providers/runwayml.md) | 仅支持视频生成,因为 `runwayml`(以及简写 `runway`)位于视频路由的服务提供方允许列表中。Chat Completions、Responses 和向量嵌入会在上游失败——Runway 不提供聊天或向量嵌入 API。不支持图片生成和 Rerank:`runwayml` 服务提供方值不在这些路由的允许列表中。对于网关尚未建模的 Runway 接口(例如图生视频),请使用透传路由。 | | [火山引擎方舟](https://docs.apiseven.com/ai-gateway/providers/volcengine-ark.md) | 支持 Chat Completions、Embedding,以及服务提供方密钥声明 `apis.responses` 时在方舟 OpenAI 兼容 Base 上使用原生 Responses。同一密钥还可声明方舟独立的原生 Messages 和 Count Tokens Base。`volcengine` 位于视频路由允许列表中,因此支持视频生成。不支持规范化图片生成和 Rerank。BytePlus 也支持原生 Responses,但没有 Messages 和 Count Tokens 协议面的文档。 | | [Cloudflare Workers AI](https://docs.apiseven.com/ai-gateway/providers/cloudflare-workers-ai.md) | 支持 Chat Completions;当服务提供方密钥声明 `apis.responses` 且模型兼容时支持原生 Responses;当别名指向账户范围 OpenAI 兼容根地址上的 Embedding 模型时支持 Embedding。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。该服务提供方值不支持图片生成、视频生成和 Rerank。 | | [Databricks](https://docs.apiseven.com/ai-gateway/providers/databricks.md) | 支持 Chat Completions、桥接的 Responses,以及当别名指向配置的 OpenAI 兼容根地址上的 Embedding 模型时支持 Embedding。其服务提供方值不支持图片生成、视频生成和 Rerank;服务提供方原生路由请使用透传路由。 | | [DeepInfra](https://docs.apiseven.com/ai-gateway/providers/deepinfra.md) | 支持 Chat Completions、桥接的 Responses、Embedding,以及服务提供方密钥声明 `apis.messages` 时的原生 Messages 和 Count Tokens。兼容模型可以使用音频路由。其服务提供方值不支持图片生成、视频生成和 Rerank;服务提供方原生路由请使用透传。 | | [NVIDIA NIM](https://docs.apiseven.com/ai-gateway/providers/nvidia-nim.md) | 托管 NVIDIA 服务提供方支持 Chat Completions、桥接的 Responses,以及别名指向兼容模型时的 Embedding。自行托管的 LLM NIM 可在服务提供方密钥声明两种 API 接口后使用原生 Responses、Messages 和 Token 计数。其他 NVIDIA API 可能需要使用各自端点的透传路由。 | | [SiliconFlow](https://docs.apiseven.com/ai-gateway/providers/siliconflow.md) | 通过其 OpenAI 形态 API 根地址支持 Chat Completions、桥接的 Responses、转换后的 Messages、Embedding、音频转录和文本转语音。音频翻译会在上游失败。`siliconflow` 服务提供方值不支持图片生成、视频生成和 Rerank;原生 Messages 和其他服务提供方路由仍可通过透传路由访问。 | | [W\&B Inference](https://docs.apiseven.com/ai-gateway/providers/wandb-inference.md) | 支持 Chat Completions、桥接的 Responses 和转换后的 Messages。W\&B Serverless Inference 不提供 Embedding、图片生成、视频生成或 Rerank 端点。其原生模型列表仍可通过透传路由访问。 | | [Amazon Nova API](https://docs.apiseven.com/ai-gateway/providers/amazon-nova.md)、[Meta Llama API](https://docs.apiseven.com/ai-gateway/providers/meta-llama-api.md)、[Nebius Token Factory](https://docs.apiseven.com/ai-gateway/providers/nebius-token-factory.md) 和 [Novita AI](https://docs.apiseven.com/ai-gateway/providers/novita-ai.md) | 支持 Chat Completions 和桥接的 Responses。Messages 调用方可以使用 AISIX 中的 Chat 转换。Embedding 要求服务提供方配置的 API 根地址提供兼容模型和路由。这些服务提供方值不支持图片生成、视频生成和 Rerank。 | | [OVHcloud AI Endpoints](https://docs.apiseven.com/ai-gateway/providers/ovhcloud-ai-endpoints.md) 和 [DigitalOcean Gradient AI](https://docs.apiseven.com/ai-gateway/providers/digitalocean-gradient-ai.md) | 支持 Chat Completions,并在服务提供方密钥声明 `apis.responses` 时支持各自的原生 Responses API。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。Messages 调用方可以使用 Chat 转换。Embedding 要求配置的 API 根地址提供兼容模型。这些服务提供方值不支持图片生成、视频生成和 Rerank。 | | [Snowflake Cortex](https://docs.apiseven.com/ai-gateway/providers/snowflake-cortex.md) | 支持 Chat Completions 以及 Responses 和 Messages 桥接。Snowflake 仅限 Claude 的原生 Messages 路由仍可通过透传路由访问。AISIX 规范化 Embedding 路由与 Snowflake 原生 `POST /api/v2/cortex/inference:embed` 协议不兼容;请使用带独立服务提供方密钥的透传路由调用,或使用其他 Embedding 服务提供方。`snowflake-cortex` 服务提供方值不支持图片生成、视频生成和 Rerank。 | | [MiniMax](https://docs.apiseven.com/ai-gateway/providers/minimax.md) | 支持 Chat Completions、桥接的 Responses,以及服务提供方密钥声明 `apis.messages` 时的原生 Messages。MiniMax-M3 提供 Count Tokens 文档。OpenAI 兼容根地址未提供 Embedding 文档,且规范化图片生成、视频生成和 Rerank 不支持该服务提供方值。 | | [ModelScope](https://docs.apiseven.com/ai-gateway/providers/modelscope.md) | 支持 Chat Completions 和桥接的 Responses 请求。Embedding 取决于已配置的上游模型和路由,因为 AISIX 会转发 OpenAI 形态的请求体,而不执行服务提供方专属转换。其服务提供方值不支持图片生成、视频生成和 Rerank。 | | [xAI](https://docs.apiseven.com/ai-gateway/providers/xai.md) | 支持 Chat Completions、转换后的 Messages 和兼容 OpenAI 的 Realtime WebSocket 路由。在服务提供方密钥上声明 `apis.responses` 可使用 xAI 原生 Responses API;否则 AISIX 会通过 Chat Completions 桥接 Responses。规范化路由无法使用 Embedding 和 Rerank。包括媒体和模型列表 API 在内的其他 xAI 原生 HTTP 路由仍可通过透传访问。xAI 已将 Chat Completions 和兼容 Anthropic 的 Messages API 标记为弃用,并建议新集成使用 Responses。 | | [其他公开 OpenAI 兼容服务提供方](https://docs.apiseven.com/ai-gateway/providers/openai-compatible-vendors.md) | 必须提供 OpenAI 兼容 Chat Completions 路由。向量嵌入取决于上游路由。Rerank 还要求使用 Rerank 路由接受的服务提供方值。 | | [Ollama](https://docs.apiseven.com/ai-gateway/providers/ollama.md) | 通过 BYO `openai` 适配器支持 Chat Completions,并在服务提供方密钥声明 `apis.responses` 时支持原生 Responses。Messages 请求默认使用 Chat 转换;由于 Token 计数不可用,Ollama 原生 Messages 格式请使用透传。Embedding 取决于已安装模型。图片生成、视频生成和 Rerank 不接受 `byo` 和 `ollama` 服务提供方值。 | | [vLLM](https://docs.apiseven.com/ai-gateway/providers/vllm.md) | 当托管模型具备所需任务时,支持 Completions、Chat Completions、在服务提供方密钥声明 `apis.responses` 时支持原生 Responses,以及 Embedding、音频转录和音频翻译。经身份验证的 vLLM Messages、Token 计数和 Rerank 请使用透传。图片生成、视频生成、文本转语音和规范化 Rerank 不受支持。 | | [私有 OpenAI 兼容端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md) | 必须实现应用调用的每个上游路由。向量嵌入取决于私有端点,服务提供方专属路由还可能施加额外的服务提供方值限制。 | ## 端点规则[​](#endpoint-rules "端点规则的直接链接") 以上表格是主要路由参考。以下规则用于说明服务提供方身份、适配器协议族和端点行为不一致的情况。 * Chat Completions 是覆盖最广的标准化路由。对于非 OpenAI 上游,面向服务提供方的请求在网关后仍可以使用 Anthropic、Bedrock、Vertex AI、Azure OpenAI 或其他适配器专属格式。OpenAI 聊天音频字段仍仅适用于 `openai` 和 `azure-openai` 适配器及兼容的上游模型。 * Responses 使用服务提供方专属处理。由 OpenAI 提供支持的模型以及声明 `apis.responses` 的服务提供方密钥会转发到上游 Responses API。其他服务提供方通过 Chat 适配器路径上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md),并返回 Responses 形态的结果;没有 Chat 等价项的 OpenAI 特定字段会在此路径上被忽略。 * 图片生成是 OpenAI 服务提供方路由。OpenAI 兼容厂商可以为 Chat Completions 使用 OpenAI 适配器,但当其服务提供方值不是 `openai` 时,仍会被此路由拒绝。 * 向量嵌入通过解析后的适配器进行分发。OpenAI 适配器会转发 OpenAI 请求形态,而 Bedrock 和 Vertex 适配器会为受支持的向量嵌入模型系列转换请求。音频仍使用 OpenAI 风格转发,不会在不同服务提供方协议族之间进行转换。 * Rerank 使用路由专属服务提供方允许列表。接受的服务提供方值为 `openai`、`cohere` 和 `jina`,但已配置上游必须提供 `/v1/rerank`。`openai` 值支持兼容的 Rerank 服务提供方,并不表示公开 OpenAI API 提供此端点。 * Anthropic Messages 支持原生 Anthropic 协议路由和转换后的上游。AISIX 可以将文本、图片、文档和工具调用历史转换为标准化请求,但所选服务提供方适配器决定哪些转换后的内容能到达上游。Anthropic `thinking` 和 `redacted_thinking` 历史块不会向其他服务提供方重放。Token 计数要求服务提供方密钥使用 `anthropic` 适配器或声明 `apis.messages`,且上游必须实现该路由。 AISIX 会保留 `reasoning_content`,并将 `reasoning` 标准化到该规范字段。如果 OpenAI 兼容服务提供方从不同的 `delta` 路径流式输出推理内容,请在服务提供方密钥上配置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 内容转换边界[​](#content-translation-boundaries "内容转换边界的直接链接") 跨服务提供方的功能支持取决于面向调用方的端点和转换方向。不要假设一个方向的结果适用于所有服务提供方协议族组合。 当 Anthropic 形态的 `/v1/messages` 请求发送到受支持的非 Anthropic 上游时,AISIX 会将受支持的内容转换为标准化请求,包括文本、base64 和 URL 图片、文档、工具定义、工具调用和工具结果。所选服务提供方适配器可能只支持其中一部分内容。OpenAI 兼容适配器会保留图片部分,而当前 Bedrock 和 Vertex AI 聊天适配器使用从多模态用户内容中提取的文本。签名的 Anthropic 思考历史会被丢弃,因为其他服务提供方无法重放。 当 OpenAI 形态的 `/v1/chat/completions` 请求发送到其他服务提供方协议族时,可移植的文本和工具字段支持范围最广。非文本处理取决于所选适配器和上游 API。例如,即使 OpenAI 兼容上游可以接受原始 `image_url` 部分,某个服务提供方适配器仍可能只使用多模态消息中拼接后的文本。 如果应用依赖服务提供方专属内容,请优先选择匹配的面向调用方端点和服务提供方协议族。有关准确的 Anthropic 形态转换行为,请参阅 [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md);有关反向转换,请参阅[使用 OpenAI 客户端访问 Anthropic 上游](https://docs.apiseven.com/ai-gateway/endpoints/openai-client-to-anthropic.md)。 --- # Databricks [Databricks Model Serving](https://docs.databricks.com/aws/en/machine-learning/model-serving/score-foundation-models) 在 Databricks 工作区的端点后托管基础模型。AISIX 为这些端点提供面向应用的统一 OpenAI 兼容 API,并管理工作区 Token、调用方访问权限、限流和用量核算。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * 已启用 Model Serving 且至少包含一个可查询 Serving Endpoint 的 Databricks 工作区。 * 该工作区的[工作区实例名称](https://docs.databricks.com/aws/en/workspace/workspace-details),即登录时逐工作区 URL 的主机部分。在 AWS 上类似 `dbc-a1b2c3d4-e5f6.cloud.databricks.com`,在 Azure 上类似 `adb-<workspace-id>.<number>.azuredatabricks.net`,在 Google Cloud 上类似 `<workspace-id>.<number>.gcp.databricks.com`。 * Databricks API Token,其身份对 AISIX 将访问的每个 Serving Endpoint 都具有 [`CAN QUERY` 权限](https://docs.databricks.com/aws/en/security/auth/access-control#serving-endpoint-acls)。示例使用工作区 Personal Access Token。Databricks 建议生产环境使用 [OAuth 机器到机器认证](https://docs.databricks.com/aws/en/dev-tools/auth/oauth-m2m),但 AISIX 会把 Bearer Token 作为静态服务提供方密钥凭证存储,不会刷新。使用短期 OAuth Access Token 时,请在过期前刷新服务提供方密钥凭证。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Databricks 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 Databricks 是提供 OpenAI 兼容 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,并使用工作区特定的 Serving 根路径作为 `api_base`。AISIX 不会提供精选基础 URL 或服务提供方特定的请求和响应重写。下文还会说明 Databricks 的 Token 限制参数名称。 Databricks 提供两套兼容 OpenAI 的工作区接口。每个基础 URL 必须与自己的模型命名方案配对: | Databricks 接口 | `api_base` | 上游 `model_name` | | -------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------- | | 本指南使用的 Model Serving Endpoint | `https://<workspace-instance>/serving-endpoints` | Serving Endpoint 名称,例如 `databricks-claude-sonnet-4-5` 或自定义名称。 | | Unity AI Gateway Model Service(Beta) | `https://<workspace-instance>/ai-gateway/mlflow/v1` | 完全限定的 Model Service 名称,例如 `system.ai.claude-sonnet-4-5`。 | Databricks 建议新访问其托管基础模型时使用 Beta Model Service。Model Serving 接口仍受支持,并覆盖预置吞吐量、外部模型和兼容 OpenAI 的自定义端点。两种请求结构请参阅[查询 Chat 模型](https://docs.databricks.com/aws/en/machine-learning/model-serving/query-chat-models)。不要把 `system.ai.*` Model Service 名称与下方 `/serving-endpoints` 基础地址混用。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Databricks Token 和工作区 Serving 根路径的服务提供方密钥: ``` # 请替换为实际值 export DATABRICKS_HOST="dbc-a1b2c3d4-e5f6.cloud.databricks.com" export DATABRICKS_TOKEN="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "databricks-prod", "provider": "databricks", "api_key": "'"${DATABRICKS_TOKEN}"'", "api_base": "https://'"${DATABRICKS_HOST}"'/serving-endpoints", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `databricks`。AISIX Cloud Admin API 接受该值,因为 `databricks` 是 models.dev 目录 ID,并根据社区目录规则派生使用 Bearer 身份认证的 `openai` 适配器。`adapter` 字段仅接受 BYO 服务提供方密钥,因此不要在此发送。 ❷ `api_key` 存储 Databricks API Token。Databricks 使用 HTTP Bearer 身份认证其 OpenAI 兼容界面,这正是 `openai` 适配器已经发送的形式。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://<workspace-instance>/serving-endpoints`。Databricks 在 [Model Serving 中的外部模型](https://docs.databricks.com/aws/en/machine-learning/foundation-models/external-models)中把该根路径记录为 OpenAI 客户端的 `base_url`,完整聊天端点因此为 `https://<workspace-instance>/serving-endpoints/chat/completions`。AISIX 会向 `api_base` 追加 `/chat/completions` 等端点路径,因此配置值必须止于 `/serving-endpoints`。如果改为粘贴完整端点 URL,AISIX 会移除末尾的 `/chat/completions` 和任何末尾斜杠,但应配置上述根路径。 警告 Databricks 必须设置 `api_base`。Databricks 没有共享公共 API 主机:每个请求都发往你自己的工作区实例,因此 AISIX 无法代为提供该值。 对于社区目录服务提供方,省略 `api_base` 时,AISIX Cloud Admin API 会回退到 models.dev 目录条目发布的基础 URL。Databricks 条目发布的是 `https://${DATABRICKS_HOST}/ai-gateway/mlflow/v1`。这是 Unity AI Gateway Model Service 根路径,但其中的工作区主机仍是未解析模板。AISIX 不会替换占位符,因此服务提供方密钥会存储字面量 `${DATABRICKS_HOST}`,导致上游请求失败。显式设置 `api_base` 还能确保其 API 界面与所选模型命名方案匹配。 本指南不涵盖[路由优化 Serving Endpoint](https://docs.databricks.com/aws/en/machine-learning/model-serving/query-route-optimization)。它们使用专用 Endpoint URL 和 Endpoint 范围 OAuth 凭证,而不是此处显示的工作区 URL 与 Personal Access Token。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 在 Databricks 上,AISIX 在 `model` 中发送给上游的值是工作区中的 Serving Endpoint 名称,而不是厂商模型 ID。两个工作区可以使用不同端点名称提供相同权重,因此应从自己的工作区读取名称,而不是从厂商目录中获取。 端点名称分为两类: | 端点类型 | 命名方式 | 示例 | | ---------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------ | | Databricks 托管、按 Token 计费的基础模型 | Databricks 会预置该端点。名称带有 `databricks-` 前缀,并使用连字符而不是点号表示模型版本。 | `databricks-claude-sonnet-4-5` | | 兼容 OpenAI 的自定义、预置吞吐量或外部模型端点 | 创建端点时自行选择名称,不使用前缀,也没有命名规则。 | `openai-chat-endpoint` | 当前按 Token 计费的端点名称包括 `databricks-claude-sonnet-4-5`、`databricks-gpt-oss-120b` 和 `databricks-gemini-2-5-pro`。Databricks 新增和退役托管模型时,该集合会轮换,因此创建别名前,请对照 [Databricks 托管基础模型列表](https://docs.databricks.com/aws/en/machine-learning/foundation-model-apis/supported-models)或工作区中的 Serving 页面确认名称。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "databricks-sonnet-prod", "model_name": "databricks-claude-sonnet-4-5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Databricks Serving Endpoint 名称。不要从介绍厂商自有 API 的页面沿用 `claude-sonnet-4-5` 等底层厂商模型 ID。工作区中不存在的端点名称会在上游失败,而不是在创建别名时失败。 ❸ `provider_key_id` 将别名关联到 Databricks 服务提供方密钥。凭证只能访问其身份获准查询的 Serving Endpoint。一个服务提供方密钥可以服务所有获准 Endpoint 的别名,也可以使用独立身份和密钥,在不同 Endpoint 组之间保持最小权限边界。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "databricks-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export DATABRICKS_TOKEN="YOUR_PROVIDER_API_KEY" export DATABRICKS_HOST="YOUR_DATABRICKS_WORKSPACE_HOST" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用以下完整的声明式资源文件。对于现有网关,请把这些条目合并到[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely),并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "databricks-prod" provider: "databricks" adapter: "openai" api_key: ${DATABRICKS_TOKEN} api_base: "https://${DATABRICKS_HOST}/serving-endpoints" models: - display_name: "databricks-sonnet-prod" provider: "databricks" model_name: "databricks-claude-sonnet-4-5" provider_key: "databricks-prod" api_keys: - display_name: "databricks-caller" key_env: CALLER_API_KEY allowed_models: - "databricks-sonnet-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "databricks-sonnet-prod", "messages": [ { "role": "user", "content": "Say hello from Databricks." } ], "max_tokens": 64 }' ``` 网关返回 OpenAI 兼容响应,其中回显面向调用方的别名 `databricks-sonnet-prod`。工作区主机、Token 和端点名称是三个独立值,因此每种失败模式都有不同的表现: | 现象 | 可能原因 | | ----------------------- | ----------------------------------------------------------------------------------- | | 上游身份认证错误 | Databricks API Token 已过期,或它所属的工作区与 `api_base` 中的主机不同。 | | 上游返回 `403` 权限错误 | Token 身份不具备该 Serving Endpoint 的 `CAN QUERY` 权限。 | | 端点路径返回上游 `404` | `api_base` 未止于 `/serving-endpoints`,导致 AISIX 构造了 Databricks 不提供的路径。 | | 指明端点名称的上游错误 | `model_name` 与工作区中的 Serving Endpoint 不匹配。 | ## 设置 Token 限制参数[​](#设置-token-限制参数 "设置 Token 限制参数的直接链接") [Databricks 基础模型 REST API 参考](https://docs.databricks.com/aws/en/machine-learning/foundation-model-apis/api-reference)使用 `max_tokens` 表示生成 Token 上限,而部分 OpenAI 客户端和集成使用较新的 `max_completion_tokens` 名称。 对于上游仍要求旧名称的精选服务提供方,AISIX 服务提供方目录会注册并自动应用重命名。Databricks 是社区目录条目,因此未注册重命名:AISIX 会原样转发调用方发送的名称。因此,发送 `max_completion_tokens` 的客户端会把文档 API 未命名的参数传给 Databricks。 如果客户端发送 `max_completion_tokens`,请在服务提供方密钥上配置请求重命名。 在 AISIX Cloud 中,就地更新现有服务提供方密钥。`request` 块会被整体替换,而不是逐字段合并。前面创建的服务提供方密钥没有请求覆盖项,因此下面的块是完整的。如果密钥已经包含请求覆盖项,请先获取其详情,并在替换块中包含所有希望保留的设置。提供空的 `request` 对象会清除已存储的块。 无论通过 AISIX Cloud 还是资源文件更新,覆盖项都会影响引用该服务提供方密钥的每个模型别名。如果该密钥承载生产流量,请先在仅供非生产别名使用的单独服务提供方密钥上验证相同覆盖项,并在受控变更窗口内更新共享密钥。 ``` curl -sS -X PATCH "$AISIX_CP/provider_keys/$PROVIDER_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "request": { "param_renames": { "max_completion_tokens": "max_tokens" } } }' ``` 该请求省略了 `response` 和凭证字段,因此这些设置保持不变,模型也会继续引用同一个服务提供方密钥。 对于开源 AISIX 网关,请在 `provider_keys` 中现有的 `databricks-prod` 条目上添加下面的 `request.param_renames` 映射。保留该条目的所有其他字段以及其他条目和集合,不要创建第二个顶层 `provider_keys` 键: resources.yaml(服务提供方密钥) ``` provider_keys: - display_name: "databricks-prod" provider: "databricks" adapter: "openai" api_key: ${DATABRICKS_TOKEN} api_base: "https://${DATABRICKS_HOST}/serving-endpoints" request: param_renames: max_completion_tokens: max_tokens ``` 按照上文所述验证声明式资源文件并重新加载或重启。该重命名会重写流经服务提供方密钥的每个请求中的顶层参数,因此适用于引用它的每个模型别名。请求同时携带两个名称时,AISIX 会保留面向调用方的源名称中的值。请参阅[服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 验证时,请发送把 `max_completion_tokens` 设为较小值的 Chat Completions 请求,并确认补全结果在该长度处截断。 ## 发送推理控制参数[​](#发送推理控制参数 "发送推理控制参数的直接链接") Databricks 在统一的 OpenAI 形态接口后重新提供多个厂商的模型,因此推理控制取决于 Endpoint 后的模型系列。Databricks 在[查询推理模型](https://docs.databricks.com/aws/en/machine-learning/model-serving/query-reason-models)中记录当前控制项。AISIX 会原样转发无法识别的顶层 Chat Completions 参数,但上游接受的字段和值仍取决于具体模型。 对于 GPT OSS Endpoint,请在正文顶层发送 `reasoning_effort`。以下示例假设已在 `databricks-gpt-oss-120b` Serving Endpoint 上创建第二个别名 `databricks-gptoss-prod`: ``` { "model": "databricks-gptoss-prod", "messages": [ { "role": "user", "content": "Plan a three-step migration." } ], "reasoning_effort": "low" } ``` GPT OSS 接受 `low`、`medium` 或 `high`。其他模型系列使用不同值或 Anthropic 风格的 `thinking` 对象,因此请确认具体 Endpoint 的控制项。 Databricks 会把 Claude 扩展思考 Chat 输出作为由推理块和文本块组成的带类型数组返回。AISIX `openai` 适配器要求 `message.content` 或 `delta.content` 为字符串,因此无法在规范化 `/v1/chat/completions` 路由上解码该结构。需要 Claude 推理块时,请通过透传路由使用 Databricks 原生端点。透传路由会保留上游响应,且不会重写 AISIX 模型别名。AISIX 会从 `messages` 检测 Chat 信封,并在上游响应包含受支持的用量字段时记录 Token 用量。 ## 访问 Databricks 原生路由[​](#访问-databricks-原生路由 "访问 Databricks 原生路由的直接链接") Databricks 提供 AISIX `/v1/responses` 桥接不会调用的原生 Responses 路由: | Databricks 路由 | AISIX 透传路径 | 适用范围 | | ---------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------- | | `POST /serving-endpoints/open-responses` | `POST /passthrough/databricks/open-responses` | 以 Open Responses 格式访问 Databricks 托管的开放模型、Anthropic Claude 和 Google Gemini。 | | `POST /serving-endpoints/responses` | `POST /passthrough/databricks/responses` | 访问 Databricks 托管的 OpenAI 模型所提供的原生 OpenAI Responses API。 | 本页的 `/passthrough/databricks` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为工作区 Serving 根地址(`https://<workspace-instance>/serving-endpoints`)并挂上 Databricks 服务提供方密钥;在调用方 Key 的 `allowed_routes` 上授予该路由。 以下示例访问跨服务提供方的 Open Responses 路由。请在 `model` 中发送 Databricks Serving Endpoint 名称,而不是 AISIX 别名: ``` curl -sS -X POST "$AISIX_PROXY/passthrough/databricks/open-responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "databricks-claude-sonnet-4-5", "input": [ { "role": "user", "content": "Plan a three-step migration." } ], "max_output_tokens": 256 }' ``` 支持的字段及各服务提供方的行为,请参阅[使用 Open Responses API 查询模型](https://docs.databricks.com/aws/en/machine-learning/model-serving/query-open-responses-models)。透传路由不会执行 Databricks 专用规范化,而是原样转发请求和响应。AISIX 会从 `input` 检测 Responses 信封,并记录响应携带的所有受支持 Token 维度,包括输入、输出、缓存和推理详情。这些计数只用于遥测:透传流量不会推进 `tpm` 或 `tpd` 计数器、确定模型成本,也不会增加预算支出。如果服务提供方响应省略所有受支持的 Token 字段,记录的 Token 计数会保持为零。 Databricks 也可通过 `POST /serving-endpoints/{endpoint-name}/invocations` 原生调用端点,该路由不是 OpenAI 形态。请使用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)访问它。 透传路由不借用模型别名,而是直接转发到 `{target_url}/{rest}`。由于路由的 `target_url` 以 `/serving-endpoints` 结尾,通配符剩余部分应从端点名称开始。不要在透传路径中重复 `serving-endpoints`: ``` curl -sS -X POST "$AISIX_PROXY/passthrough/databricks/databricks-claude-sonnet-4-5/invocations" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "Say hello from Databricks." } ], "max_tokens": 64 }' ``` 原生 Invocations 请求通过路径指定 Endpoint,正文中不携带顶层 `model` 字段,因此该调用仅应用调用方 API Key 限流。在 inject 模式透传路由上,模型范围请求数限制根据请求正文中指向路由服务提供方已配置模型的 `model` 字段匹配。必须产生 Token 用量或计入模型 Token 配额的流量,应优先使用规范化 AISIX 端点。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Databricks 别名通过 `openai` 适配器解析,因此路由支持情况取决于 Serving Endpoint 的实现以及每条路由自身的服务提供方规则。 | 路由 | Databricks 别名的行为 | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | Databricks 返回兼容 OpenAI 的字符串内容时支持,包括 `stream: true`。Claude 扩展思考响应使用带类型的内容块数组,因此需要透传路由。 | | `/v1/responses` | 通过 Chat 适配器路径上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持,因为别名的服务提供方值为 `databricks` 而不是 `openai`。它不会调用 Databricks 原生 `/serving-endpoints/responses` 或 `/serving-endpoints/open-responses` 路由。没有 Chat 等价项的 OpenAI 特定 Responses 字段会被忽略。 | | `/v1/messages` | 通过转换支持 Anthropic 形态的调用方。Claude 系列 Serving Endpoint 也会被转换,因为别名解析到 `openai` 适配器,而不是 Anthropic 适配器。Claude 扩展思考响应与 `/v1/chat/completions` 具有相同的内容块限制。`/v1/messages/count_tokens` 要求服务提供方值为 `anthropic` 的模型,因此此处不可用。 | | `/v1/embeddings` | 当别名指定 Databricks Embedding Serving Endpoint 时受支持。Databricks 在[使用自定义 Model Serving 提供自定义 LLM](https://docs.databricks.com/aws/en/machine-learning/model-serving/serve-custom-llms)中记录了针对同一 `/serving-endpoints` 根路径的 `client.embeddings.create`,因此一个服务提供方密钥可以同时服务 Chat 和 Embedding 别名。请参阅 [Embedding](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/images/generations` | 拒绝。该路由只接受服务提供方为 `openai` 的模型。 | | `/v1/rerank` | 拒绝。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/videos` | 拒绝。该路由的服务提供方允许列表中不包含 `databricks`。 | | `/passthrough/databricks/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 Databricks 原生路由,包括 `/responses`、`/open-responses` 和 Endpoint Invocations。路由会转发到其 `target_url`,且不会重写 AISIX 别名。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段;其他操作保持不透明。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 接入 Databricks,并验证了模型别名。接下来可以阅读: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Databricks 端点与另一个服务提供方之间进行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # DeepInfra [DeepInfra](https://docs.deepinfra.com/) 为多个发布方的开放权重模型提供托管推理服务。应用通过稳定的 AISIX 别名调用这些模型,而不会获得上游 API Token。一个服务提供方密钥既可使用 DeepInfra 的 OpenAI 兼容根地址处理 Chat,也可使用其同级的 Anthropic 兼容根地址处理原生 Messages 和 Count Tokens。 ## 前提条件[​](#前提条件 "前提条件的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或采用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 部署方式。配置网关以加载声明式资源文件。 * 从 [DeepInfra 控制台](https://deepinfra.com/dash/api_keys)获取的 DeepInfra API Token。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为以 DeepInfra 为后端的 Chat Completions、Messages 和 Count Tokens 创建服务提供方密钥、模型别名和调用方 API Key。 DeepInfra 是一个提供 OpenAI 和 Anthropic 兼容 API 的社区目录服务提供方。AISIX 对主要 API 根地址使用 `openai` 适配器,并在同一个服务提供方密钥上单独声明原生 Messages 协议面。AISIX 不提供经过维护的基础 URL,也不提供服务提供方特定的请求和响应重写规则。 对于 DeepInfra,AISIX Cloud Admin API 会返回 `community_badge: true`。控制台将其归入**所有服务提供方(社区)**,并将其传输协议兼容性标记为推定兼容,而非已验证兼容。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 DeepInfra 凭证和 API 根路径的服务提供方密钥: ``` # 替换为你的值 export DEEPINFRA_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "deepinfra-prod", "provider": "deepinfra", "api_key": "'"${DEEPINFRA_API_KEY}"'", "api_base": "https://api.deepinfra.com/v1", "apis": { "messages": { "base": "https://api.deepinfra.com/anthropic" } }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `deepinfra`。AISIX Cloud Admin API 会根据目录条目推导适配器;`adapter` 字段仅适用于 BYO 服务提供方密钥,在目录服务提供方密钥中发送该字段会返回 400 错误。对于 `deepinfra`,推导出的适配器为 `openai`。 ❷ `api_key` 存储 DeepInfra API Token。DeepInfra 使用 HTTP Bearer 身份认证来验证 OpenAI 兼容接口,这正是 `openai` 适配器已采用的认证方式。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ 对 DeepInfra 而言,`api_base` 是**必填项**。models.dev 的 `deepinfra` 条目没有发布 `api` 字段,因此 AISIX Cloud Admin API 没有可回退使用的缓存默认值。省略 `api_base` 会返回 400 错误,说明 models.dev 未发布该服务提供方的默认基础 URL。 ❹ `apis.messages` 在同级 Base 上声明 DeepInfra 完整的 Anthropic 兼容协议面。Messages 和 Count Tokens 都使用此 Base 和同一凭证。 该命令将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 #### 为什么基础 URL 在 `/v1` 处结束[​](#为什么基础-url-在-v1-处结束 "为什么基础-url-在-v1-处结束的直接链接") DeepInfra 的 OpenAI SDK 示例将 `base_url` 设置为 `https://api.deepinfra.com/v1/openai`。DeepInfra 还在 `/v1` 下直接提供相同 API,包括 [`/v1/chat/completions`](https://docs.deepinfra.com/api-reference/chat-completions/openai-chat-completions)、`/v1/embeddings`、`/v1/images/generations` 和 `/v1/audio/*`。 AISIX 会把端点路径追加到 `api_base`,因此直接使用 `https://api.deepinfra.com/v1` 根地址更实用。一个服务提供方密钥即可提供 Chat、原生 Messages、Count Tokens、Embedding 和音频别名,透传路由还可访问兼容图片端点和 DeepInfra 原生路由。 还需了解以下两种相关行为: * 如果粘贴完整的直接端点 URL,AISIX 会先移除 `/chat/completions` 等已知端点后缀及其末尾斜杠,再构建上游 URL。因此,将 `api_base` 设置为 `https://api.deepinfra.com/v1/chat/completions` 仍可正常工作,但建议使用根路径形式以保持值清晰易读。 * AISIX 不会为非 OpenAI 厂商补充缺失的路径段。将 `api_base` 设置为裸主机 `https://api.deepinfra.com` 会生成上游 URL `https://api.deepinfra.com/chat/completions`,而 DeepInfra 并不提供该路径。请使用 DeepInfra 文档中的根路径,不要依赖 AISIX 修复较短的形式。将 `api_base` 留空也无法解决问题:对于非 OpenAI 服务提供方,网关不会回退到 OpenAI 主机,而是返回上游配置错误,以免将 DeepInfra Token 泄露给其他厂商。 ### 创建模型[​](#创建模型 "创建模型的直接链接") DeepInfra 模型 ID 以权重发布方作为命名空间,格式为 `<publisher>/<Model-Name>`,与相同权重对应的 Hugging Face 仓库 ID 一致。其大小写并不统一,发布方路径段使用的是 Hub 组织名称,而非厂商品牌名称——例如,GLM 模型发布在 `zai-org` 下,而不是 `zhipuai`。请从 [DeepInfra 模型目录](https://deepinfra.com/models)逐字复制 ID,不要手动重新输入。 当前可用的 ID 包括: | 模型 ID | 说明 | | ----------------------------------------- | ----------------------------------------------------------------- | | `deepseek-ai/DeepSeek-V3.2` | 推理模型;在 `reasoning_content` 中返回推理内容。 | | `openai/gpt-oss-120b` | 开放权重模型;`reasoning_effort` 接受 `low`、`medium` 和 `high`。 | | `meta-llama/Llama-3.3-70B-Instruct-Turbo` | 非推理指令模型。 | 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "deepinfra-deepseek-prod", "model_name": "deepseek-ai/DeepSeek-V3.2", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方通过 `model` 发送的别名。 ❷ `model_name` 是完整的 DeepInfra 模型 ID,包含发布方路径段。上游会拒绝 `DeepSeek-V3.2` 这类不带命名空间的标识符。 ❸ `provider_key_id` 将该别名关联到 DeepInfra 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且仅在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "deepinfra-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送到网关的调用方 API Key: ``` export DEEPINFRA_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "deepinfra-prod" provider: "deepinfra" adapter: "openai" api_key: ${DEEPINFRA_API_KEY} api_base: "https://api.deepinfra.com/v1" apis: messages: base: "https://api.deepinfra.com/anthropic" models: - display_name: "deepinfra-deepseek-prod" provider: "deepinfra" model_name: "deepseek-ai/DeepSeek-V3.2" provider_key: "deepinfra-prod" api_keys: - display_name: "deepinfra-caller" key_env: CALLER_API_KEY allowed_models: - "deepinfra-deepseek-prod" ``` 如果 AISIX 安装在本地,请先验证文件再加载: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件所引用的环境变量,然后启动网关。仅当现有网关进程已经能够访问这些变量时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请根据[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)调整验证和启动命令。在两个命令中挂载此 `resources.yaml` 文件,并通过 `-e` 传入文件引用的每个环境变量。资源加载后,为下方的通用验证请求做好准备: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关源站地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送聊天补全请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "deepinfra-deepseek-prod", "messages": [ { "role": "user", "content": "Say hello from DeepInfra." } ] }' ``` 网关会返回 OpenAI 兼容响应,并在其中回显面向调用方的别名 `deepinfra-deepseek-prod`。 使用 Count Tokens 请求验证声明的 Messages Base;该请求不会生成模型响应: ``` curl -sS -X POST "$AISIX_PROXY/v1/messages/count_tokens" \ -H "x-api-key: ${AISIX_API_KEY}" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "deepinfra-deepseek-prod", "messages": [ { "role": "user", "content": "Count this DeepInfra prompt." } ] }' ``` 成功响应包含 `input_tokens`。如果 Chat Completions 正常而此请求失败,请检查 `apis.messages.base` 的值。 如果 Chat Completions 请求失败,请根据症状定位原因: | 症状 | 可能原因 | | ------------------------------ | ---------------------------------------------------------------------------------------------- | | 上游身份认证错误 | `api_key` 中的 DeepInfra Token 错误或已撤销。 | | 上游返回 404 | `api_base` 未指向提供 Chat Completions 的 DeepInfra 根地址,或 `model_name` 省略了发布方前缀。 | | 尚未发送请求便出现上游配置错误 | 服务提供方密钥上的 `api_base` 为空。 | ## 选择 DeepInfra API 协议面[​](#选择-deepinfra-api-协议面 "选择 DeepInfra API 协议面的直接链接") DeepInfra 在同一主机上提供多种请求协议面: | DeepInfra 协议面 | 路径 | 能否通过本指南配置的服务提供方密钥访问 | | ---------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | 直接兼容 OpenAI 的协议面 | `/v1/chat/completions`、`/v1/embeddings`、`/v1/images/generations` 和 `/v1/audio/...` | 可以。规范化 AISIX 路由覆盖 Chat、Embedding 和音频;图片生成需要透传路由。 | | OpenAI SDK 兼容根地址 | `/v1/openai/...` | 本指南的规范化路由不使用。DeepInfra 将其作为 OpenAI SDK 客户端的等价基础地址。 | | Anthropic Messages 和 Count Tokens | `/anthropic/v1/messages` 和 `/anthropic/v1/messages/count_tokens` | 可以,通过已声明的 Messages 协议面访问。 | | 原生推理 | `/v1/inference/{model}` | 可以,通过透传路由访问。 | 服务提供方密钥上的 `apis.messages` 声明会把两条 Messages 路由发送到 DeepInfra,而不会改变该密钥的 `openai` 适配器。因此,同一凭证和模型别名可同时用于 Chat Completions、原生 Messages 和 Count Tokens。 该声明不会改变 Chat Completions,也不会改变其他使用 `api_base` 的路由。应用需要 DeepInfra Anthropic 兼容格式时可使用 `/v1/messages`,其他工作负载仍可使用规范化 OpenAI 兼容路由。 ## 设置生成 Token 上限[​](#设置生成-token-上限 "设置生成 Token 上限的直接链接") 这是最可能影响 DeepInfra 别名的一项请求结构差异,也是采用社区目录流程的直接结果。 DeepInfra 在[聊天补全](https://docs.deepinfra.com/chat/overview)文档中使用 `max_tokens` 表示生成 Token 上限。部分 OpenAI 客户端和集成使用较新的 `max_completion_tokens` 名称。AISIX 目录中的若干精选服务提供方带有重命名规则,会在请求离开网关前将较新名称转换为旧名称。`deepinfra` 没有 AISIX 精选适配器映射,因此**没有为其注册重命名规则**,AISIX 会原样转发调用方所发送的参数名称。 实际结果如下: * 调用方发送 `max_tokens` 时,DeepInfra 会收到其文档中定义的参数名称,并应用该上限。 * 调用方发送 `max_completion_tokens` 时,DeepInfra 会收到其文档未定义的参数名称,因此无法保证上游行为:请求可能失败,或上限可能不生效。 如果客户端发送当前 OpenAI 参数名称,请自行在服务提供方密钥上注册重命名规则: ``` { "request": { "param_renames": { "max_completion_tokens": "max_tokens" } } } ``` 该重命名规则适用于引用此服务提供方密钥的所有模型。如果请求同时携带两个名称,AISIX 会使用原始调用方参数名称对应的值。请参阅[服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 控制推理输出[​](#控制推理输出 "控制推理输出的直接链接") DeepInfra 接受聊天补全请求体顶层的标准 OpenAI `reasoning_effort` 参数,也接受包含 `effort` 和 `enabled` 字段的 `reasoning` 对象。设置 `"enabled": false` 等同于设置 `reasoning_effort: "none"`。AISIX 不会移除无法识别的顶层参数,因此这两种形式都会原样传递到上游: ``` { "model": "deepinfra-deepseek-prod", "messages": [ { "role": "user", "content": "Plan a three-step migration." } ], "reasoning_effort": "low" } ``` DeepInfra 为受支持的推理模型记录了 `none`、`low`、`medium` 和 `high`。模型可用性和行为仍可能不同,因此请在 [DeepInfra 推理文档](https://docs.deepinfra.com/chat/reasoning)及模型目录页面中确认所用模型的控制项。对非推理模型使用这些参数不会产生任何效果。 在响应侧,DeepInfra 通过 `reasoning_content` 返回模型的思考内容;这已经是 AISIX 保留并标准化到的规范字段。上述模型无需配置响应覆盖项。 由于 `deepinfra` 未注册响应重写规则,此行为取决于所配置模型的特性,并非 AISIX 强制保证。如果新增的模型在其他 `delta` 路径中流式返回推理内容,请在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides),使流式客户端仍可在 `delta.reasoning_content` 中找到它。请使用流式请求进行验证,而不是非流式请求,因为该覆盖项应用于流式 delta 路径。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") DeepInfra 提供多种推理模态,但规范化 AISIX 路由支持同时取决于上游基础 URL 和模型的 `deepinfra` 服务提供方值。 | 路由 | 使用 DeepInfra 别名时的行为 | | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/responses` | 通过 Chat 适配器路径上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持。没有 Chat 等价项的 OpenAI 特定 Responses 字段会被忽略。 | | `/v1/messages` 和 `/v1/messages/count_tokens` | 由于本指南声明了 `apis.messages`,请求会发送到 DeepInfra 原生 Anthropic 兼容路由。如果没有此声明,Messages 会转换为 Chat Completions,而 Count Tokens 不可用。 | | `/v1/embeddings` | 支持。DeepInfra 在同一个 OpenAI 兼容根路径上提供 Embedding 模型,因此一个服务提供方密钥可同时覆盖聊天和 Embedding 别名。请创建单独的模型别名,并将其 `model_name` 设置为 Embedding 模型 ID。请参阅 [Embedding](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/audio/transcriptions`、`/v1/audio/translations` 和 `/v1/audio/speech` | 本指南配置的服务提供方密钥在别名指向兼容 DeepInfra 音频模型时支持。请参阅 DeepInfra [音频 API 参考](https://docs.deepinfra.com/api-reference/audio/openai-audio-transcriptions)和[语音与音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md)。 | | `/v1/images/generations` | 拒绝。该路由仅接受服务提供方为 `openai` 的模型。可通过注入本指南所建服务提供方密钥的透传路由,在 `/passthrough/deepinfra/images/generations` 访问 DeepInfra 兼容图片端点。 | | `/v1/rerank` | 拒绝。该路由仅接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/videos` | 拒绝。该路由仅接受其自身服务提供方允许列表中的值,其中不包含 `deepinfra`。 | | `/passthrough/deepinfra/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用,路径拼接规则如下所述。 | DeepInfra 模型 ID 即使以 `openai/` 开头(例如 `openai/gpt-oss-120b`),也不会使该别名成为 OpenAI 服务提供方模型。其服务提供方值仍为 `deepinfra`,因此基于服务提供方身份而非适配器进行限制的路由——图片生成、视频生成和 rerank——会拒绝该别名。完整路由矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md#endpoint-compatibility)。 本页的 `/passthrough/deepinfra` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://api.deepinfra.com/v1` 并挂上 DeepInfra 服务提供方密钥;在调用方 Key 的 `allowed_routes` 上授予该路由。 在前缀匹配的透传路由上,AISIX 会将通配符剩余部分追加到路由的 `target_url`。如果目标和通配符路径包含相同 API 版本路径段,AISIX 会移除重复项: * `/passthrough/deepinfra/models` 会解析为 `https://api.deepinfra.com/v1/models`。 * `/passthrough/deepinfra/images/generations` 会解析为 DeepInfra 兼容 OpenAI 的图片端点。请求体包含 `model` 时,必须使用 DeepInfra 模型 ID,而非 AISIX 别名。 * `/passthrough/deepinfra/v1/inference/deepseek-ai/DeepSeek-V3.2` 会解析为 DeepInfra 原生推理端点。由于路由的 `target_url` 已以 `/v1` 结尾,AISIX 会移除重复的 `v1` 路径段。 透传路由会转发服务提供方原生请求和响应体,而不会重写 AISIX 别名。AISIX 会从每个请求中检测兼容 OpenAI 的 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。Anthropic 兼容协议面使用服务提供方密钥上单独声明的 `apis.messages.base`;指向 `/v1` 的透传路由无法跳转到同级 `/anthropic` 根地址。请参阅[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已经将 AISIX 连接到 DeepInfra 并验证了模型别名。接下来可继续阅读以下指南: * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):注册该社区目录服务提供方默认不包含的参数重命名规则和响应映射。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 DeepInfra 与提供同一开放权重模型的另一服务提供方之间进行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点及服务提供方特定的限制。 --- # DeepSeek [DeepSeek](https://api-docs.deepseek.com/) 通过托管 API 提供其语言和推理模型。应用通过稳定的 AISIX 别名调用这些模型,网关则确保 DeepSeek 凭证不会出现在客户端代码中。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [DeepSeek 平台](https://platform.deepseek.com/api_keys)获取的 DeepSeek API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由 DeepSeek 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 由于 DeepSeek 提供 OpenAI 兼容 API,AISIX 会通过 `openai` 适配器进行连接,并使用 DeepSeek API 根地址作为 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 DeepSeek 凭证和 API 根地址的服务提供方密钥,并允许其在该环境中使用: ``` # 请替换为实际值 export DEEPSEEK_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "deepseek-prod", "provider": "deepseek", "api_key": "'"${DEEPSEEK_API_KEY}"'", "api_base": "https://api.deepseek.com", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `deepseek`。AISIX Cloud Admin API 会从目录服务提供方派生适配器;`adapter` 字段仅在 BYO 服务提供方密钥上被接受。 ❷ `api_key` 存储 DeepSeek API Key。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ 对此目录服务提供方,`api_base` 为可选字段,因为省略时 AISIX Cloud Admin API 会填入相同的根地址。请显式设置该字段,使上游根地址在资源上保持可见。AISIX 会将端点路径追加到 `api_base`,因此请使用服务商根地址 `https://api.deepseek.com`,末尾不要带 `/chat/completions`。该值传到网关时绝不能是空值:对于使用 `openai` 适配器但服务提供方不是 `openai` 的情况,AISIX 不会回退到 `api.openai.com`,而是会返回上游配置错误。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "deepseek-v4-flash-prod", "model_name": "deepseek-v4-flash", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 DeepSeek 模型 ID,例如 `deepseek-v4-flash` 或 `deepseek-v4-pro`。 ❸ `provider_key_id` 将别名关联到 DeepSeek 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问模型别名的调用方 API Key 资源。网关会生成密钥值,明文只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "deepseek-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值通过 ID 引用模型,因此该密钥只能访问已创建的别名。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export DEEPSEEK_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "deepseek-prod" provider: "deepseek" adapter: "openai" api_key: ${DEEPSEEK_API_KEY} api_base: "https://api.deepseek.com" models: - display_name: "deepseek-v4-flash-prod" provider: "deepseek" model_name: "deepseek-v4-flash" provider_key: "deepseek-prod" api_keys: - display_name: "deepseek-caller" key_env: CALLER_API_KEY allowed_models: - "deepseek-v4-flash-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-v4-flash-prod", "messages": [ { "role": "user", "content": "Say hello from DeepSeek." } ] }' ``` 网关会返回 OpenAI 兼容响应,其中回显面向调用方的别名 `deepseek-v4-flash-prod`。请在 DeepSeek 平台用量页面确认该请求。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 DeepSeek 模型 ID。 ## 使用思考模式[​](#使用思考模式 "使用思考模式的直接链接") DeepSeek V4 默认以 `high` 强度启用思考模式。如需对 Chat Completions 请求禁用思考,请在请求体中添加以下字段: ``` { "thinking": { "type": "disabled" } } ``` 启用思考时,请将顶层 `reasoning_effort` 字段设置为 DeepSeek 原生支持的三个等级之一:`low`、`high` 或 `max`。为兼容客户端,DeepSeek 也接受 `medium` 和 `xhigh`,并将二者都映射为 `high`。思考模式下,`temperature` 和 `top_p` 等采样字段不起作用。详情请参阅[思考模式](https://api-docs.deepseek.com/guides/thinking_mode)。 AISIX 会将这些控制项转发给 DeepSeek,并在流式和非流式响应的 `reasoning_content` 字段中保留返回的推理内容。当请求包含 `tools` 时,DeepSeek 要求保留并重放之前每一轮助手消息的 `reasoning_content`,包括模型没有进行工具调用的轮次。应用负责重放这些助手消息;省略该字段会导致 DeepSeek 返回 HTTP 400。 ## 访问 DeepSeek 原生 API 形态[​](#访问-deepseek-原生-api-形态 "访问 DeepSeek 原生 API 形态的直接链接") DeepSeek 提供原生 [Responses API](https://api-docs.deepseek.com/guides/responses_api) 和 [Anthropic 兼容 API](https://api-docs.deepseek.com/guides/anthropic_api),AISIX Cloud 无需任何配置即可访问两者:DeepSeek 目录条目自带下面这份声明,因此对 DeepSeek 别名发起的 `/v1/responses` 和 `/v1/messages` 会直达 DeepSeek 自己的路由,而不是被转换成 Chat Completions。 ``` { "apis": { "responses": {}, "messages": { "base": "https://api.deepseek.com/anthropic" } } } ``` `responses` 不带 `base`,因为 DeepSeek 就在该密钥已指向的 API Root 上提供它。该声明在密钥仍指向那个 Root 时生效;把 `api_base` 改指到自建端点就会失效,因为它描述的是 DeepSeek 的路径而不是你的。如果你用自己的网关代理 DeepSeek 且提供同样的路由,请在密钥上自行声明。参见[声明 API 协议面](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#declare-the-api-surfaces)。 开源 AISIX 网关没有目录,请在 `resources.yaml` 的服务提供方密钥条目上声明。 没有该声明时: | AISIX 配置或路由 | 上游行为 | | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 使用目录 DeepSeek 别名的 `/v1/responses` | 在 DeepSeek Chat Completions 上使用 AISIX [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。它不会调用 DeepSeek 原生 `/responses` 路由,且会忽略没有对应 Chat 语义的 Responses 专用字段。 | | `/passthrough/deepseek/responses` | 调用 DeepSeek 原生 Responses 路由。请在 `model` 中发送上游模型 ID,而不是 AISIX 别名。声明 `apis.responses` 可以用 AISIX 别名到达同一条路由,通常那才是你想要的。 | | 使用目录 DeepSeek 别名的 `/v1/messages` | 将 Anthropic 形态的调用方请求转换为 DeepSeek Chat Completions,而不会调用 DeepSeek `/anthropic/v1/messages` 路由。 | | 使用 `adapter: anthropic` 和 `api_base: https://api.deepseek.com/anthropic` 的单独 BYO 服务提供方密钥 | 使用 Anthropic 适配器调用 DeepSeek Anthropic 兼容 Messages 路由,代价是多一把密钥和多一个模型别名。在目录密钥上声明 `apis.messages` 可以用同一个别名到达同一条路由。 | | 使用目录 DeepSeek 别名的 `/v1/completions` | 无法访问 DeepSeek FIM Completion(Beta)路由;该路由仅在 `/beta` API Root 下提供。 | | `/passthrough/deepseek/beta/completions` | 调用 [FIM Completion(Beta)](https://api-docs.deepseek.com/api/create-completion)。请在 `model` 中发送 `deepseek-v4-pro`;AISIX 不会在透传路由上重写别名。 | 本页的 `/passthrough/deepseek` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 DeepSeek 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。路由会转发原生 Responses 请求和响应,且不会重写 AISIX 别名。AISIX 会从 `input` 检测 Responses 信封,并记录响应携带的所有受支持 Token 维度,包括输入、输出、缓存和推理详情。这些计数仅用于遥测:透传流量不会推进 `tpm` 或 `tpd` 计数器、解析模型成本,也不会增加预算消耗。如果响应不含任何可识别的 Token 字段,记录的 Token 数量为零。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") | 路由 | 使用 DeepSeek 目录别名时的行为 | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/responses` | 直达 DeepSeek 原生 Responses API(由目录条目声明)。推理输出项得以保留,而 Chat Completions 转换承载不了它们。 | | `/v1/messages` | 直达 DeepSeek 的 Anthropic 兼容路由(由目录条目声明),因此提示词缓存断点和思考块得以保留。`/v1/messages/count_tokens` 在同一条路由上可用。 | | `/v1/completions` | 无法访问 DeepSeek FIM。请改用 `/passthrough/deepseek/beta/completions` 并发送 `deepseek-v4-pro`。 | | `/v1/embeddings` | 不可用。DeepSeek 未在此 API Root 上提供 Embedding 端点。 | | `/v1/audio/*` | 不可用。DeepSeek 未提供匹配的 OpenAI 形态音频路由。 | | `/v1/images/generations` | 拒绝。该路由只接受服务提供方为 `openai` 的模型。 | | `/v1/rerank` | 拒绝。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/videos` | 拒绝。该路由的服务提供方允许列表不包含 `deepseek`。 | | `/passthrough/deepseek/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用,支持 `/responses` 和 `/models` 等服务提供方原生路由,但需遵循上述别名和用量限制。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 DeepSeek,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 DeepSeek 和另一个服务提供方之间进行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # DigitalOcean Gradient AI [DigitalOcean Gradient AI Serverless Inference](https://docs.digitalocean.com/products/inference/how-to/si-endpoints/) 提供对基础模型的托管访问,无需自行运维模型服务基础设施。AISIX 会将上游模型 ID 映射为稳定别名,并控制其使用权限。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 可调用 Serverless Inference 的 Gradient AI 模型访问密钥或 DigitalOcean Personal Access Token。 * 所选 [DigitalOcean Inference 模型](https://docs.digitalocean.com/products/inference/details/models/)的访问权限。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` DigitalOcean 是提供 OpenAI 兼容推理 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行身份认证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` export DIGITALOCEAN_INFERENCE_KEY="YOUR_MODEL_ACCESS_KEY" PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "digitalocean-prod", "provider": "digitalocean", "api_key": "'"${DIGITALOCEAN_INFERENCE_KEY}"'", "api_base": "https://inference.do-ai.run/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` 使用 `digitalocean` 作为目录服务提供方 ID。AISIX 会派生 `openai` 适配器;在目录密钥上显式发送适配器会返回校验错误。 API Base 包含 `/v1`。AISIX 会向该 Base 追加所选端点的路径。 `apis.responses` 声明会把 Responses 请求发送至同一 API Base 上的 DigitalOcean 原生端点,而不是通过 Chat Completions 转换。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 为 Gradient AI 当前提供的模型创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "digitalocean-gpt-oss-prod", "model_name": "openai-gpt-oss-120b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` 请使用 DigitalOcean 模型 ID,而不是原始发布方的仓库名称。创建其他别名前,请在模型参考中确认当前可用性。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "digitalocean-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export DIGITALOCEAN_INFERENCE_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "digitalocean-prod" provider: "digitalocean" adapter: "openai" api_key: ${DIGITALOCEAN_INFERENCE_KEY} api_base: "https://inference.do-ai.run/v1" apis: responses: {} models: - display_name: "digitalocean-gpt-oss-prod" provider: "digitalocean" model_name: "openai-gpt-oss-120b" provider_key: "digitalocean-prod" api_keys: - display_name: "digitalocean-caller" key_env: CALLER_API_KEY allowed_models: - "digitalocean-gpt-oss-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "digitalocean-gpt-oss-prod", "input": "Say hello from DigitalOcean Gradient AI." }' ``` AISIX 会将 `openai-gpt-oss-120b` 连同配置的凭证转发至 DigitalOcean 原生 Responses 端点,然后在响应中恢复 AISIX 别名。 ## 通过透传使用原生 Messages[​](#通过透传使用原生-messages "通过透传使用原生 Messages的直接链接") 上述服务提供方密钥已经会把 Responses 请求发送到 DigitalOcean 原生端点。DigitalOcean 还在同一 API Base 上提供原生 [Messages 端点](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/)。除非使用下方服务提供方原生方案,否则 Messages 仍会经过转换: | AISIX 路由 | 上游行为 | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 使用 DigitalOcean 别名的 `/v1/messages` | 将 Anthropic 格式调用方请求转换为 DigitalOcean Chat Completions,不会调用 DigitalOcean 原生 `/v1/messages` 路由。 | | `/passthrough/digitalocean/messages` | 调用 DigitalOcean 原生 Messages 路由,但不声明成对的协议面。请使用该端点支持的 DigitalOcean 模型 ID。Count Tokens 仍不可用。 | DigitalOcean 接受 AISIX 在原生 Messages 请求中使用的 `x-api-key` 请求头,但未提供 Count Tokens。请继续通过透传访问此集成,不要声明 `apis.messages`,因为该声明把两条路由表示为一个完整协议面。 本页的 `/passthrough/digitalocean` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://inference.do-ai.run/v1`;在调用方 Key 的 `allowed_routes` 上授予路由名称。路径中省略 `/v1` 是因为路由目标已包含它;即使重复,开头的 `v1` 段也会去重。透传路由不会重写 AISIX 别名。AISIX 会从每个请求中检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") | 路由 | 使用 DigitalOcean 目录别名时的行为 | | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 DigitalOcean 原生 Responses API。如果没有此声明,AISIX 会使用基于 Chat 的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/messages` | 通过转换为 Chat Completions 支持。由于配置的服务提供方密钥没有声明原生 Messages 协议面,`/v1/messages/count_tokens` 不可用。 | | `/v1/embeddings` | 别名指向 `qwen3-embedding-0.6b` 等 DigitalOcean 嵌入模型时支持。 | | `/v1/audio/speech` | 别名指向 `qwen3-tts-voicedesign` 等文本转语音模型时,请求可以到达 DigitalOcean,但响应并非端到端兼容 OpenAI。DigitalOcean 会把 Base64 音频封装在 JSON 数据 Envelope 中,AISIX 会原样中继,而不会解码为二进制音频。应用支持 DigitalOcean 原生响应协议时,请使用 `/passthrough/digitalocean/audio/speech` 并解码 `data[0].b64_json`。 | | `/v1/audio/transcriptions` 和 `/v1/audio/translations` | 不可用。DigitalOcean 未提供这些路由。 | | `/v1/images/generations` | 规范化 AISIX 路由只接受 `openai` 服务提供方值,因此会被拒绝。请使用兼容的 DigitalOcean 模型 ID 通过 `/passthrough/digitalocean/images/generations` 调用原生路由。 | | `/v1/videos` | 未为 `digitalocean` 服务提供方实现。请通过 `/passthrough/digitalocean/videos` 提交 DigitalOcean 原生视频作业,通过 `/passthrough/digitalocean/video/generations/{job_id}` 轮询,并可通过 `/passthrough/digitalocean/videos/{video_id}/content` 下载已完成的 MP4。 | | `/v1/rerank` | 规范化 AISIX 路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值,因此会被拒绝。 | | `/passthrough/digitalocean/async-invoke` | 为支持的图片、音频和文本转语音模型调用 DigitalOcean 异步端点。请使用服务提供方原生请求格式。 | | `/passthrough/digitalocean/models` | 列出配置的 DigitalOcean 凭证可访问的模型 ID。 | 网关完整端点矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 故障排查[​](#故障排查 "故障排查的直接链接") | 现象 | 检查项 | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | 上游返回 `401` 或 `403` | 确认凭证具备推理访问权限。对于模型访问密钥,请验证其模型范围和所有 VPC 限制;受 VPC 限制的调用方必须使用 VPC 本地 DNS 解析器。 | | 上游返回 `404` | 在 `api_base` 中保留 `/v1`,并验证 DigitalOcean 模型 ID。 | | 找不到模型 | 使用相同上游凭证查询 DigitalOcean `GET /v1/models`,并确认模型访问密钥包含所选模型。 | | 创建服务提供方密钥时返回 `400` | 使用 `provider: "digitalocean"`,且不要设置 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 DigitalOcean Gradient AI,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):配置网关侧的请求数和 Token 限制。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 DigitalOcean 与其他服务提供方之间执行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # Fireworks AI [Fireworks AI](https://docs.fireworks.ai/) 为生成式 AI 模型目录提供托管推理服务。应用通过稳定的 AISIX 别名调用所选模型,网关则保管 Fireworks 凭证。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Fireworks 控制台](https://fireworks.ai/api-keys)获取的 Fireworks API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Fireworks 支持的 Chat Completions 和原生 Responses 创建服务提供方密钥、模型别名和调用方 API Key。 由于 Fireworks AI 提供 OpenAI 兼容 API,AISIX 会通过 `openai` 适配器连接,并使用 Fireworks API 根地址作为 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Fireworks 凭证和 API 根地址的服务提供方密钥,并允许其进入该环境: ``` # 请替换为实际值 export FIREWORKS_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "fireworks-prod", "provider": "fireworks-ai", "api_key": "'"${FIREWORKS_API_KEY}"'", "api_base": "https://api.fireworks.ai/inference/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为目录服务提供方 ID `fireworks-ai`。连字符是该标识符的一部分;仅使用 `fireworks` 会被拒绝并返回 `400 INVALID_REQUEST`。 ❷ `api_key` 存储 Fireworks API Key。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `api_base` 指向 Fireworks 推理 API。`/inference` 路径段不可省略:Fireworks 在 `https://api.fireworks.ai/inference/v1` 下提供 OpenAI 兼容推理路由,而用于列出和创建 Fireworks API Key 的账户管理 REST API 位于 `https://api.fireworks.ai/v1`。删除 `/inference` 会让服务提供方密钥指向错误的 API 接口。 ❹ `apis.responses` 声明 Fireworks 在同一推理根地址提供 Responses API。这样,AISIX 就能使用 Fireworks 的原生请求和响应格式,而不必通过 Chat Completions 转换。 AISIX 会把端点路径追加到 `api_base`,因此请使用 API 根地址,末尾不要包含 `/chat/completions`。追加端点路径前会移除末尾斜杠,因此 `https://api.fireworks.ai/inference/v1/` 和 `https://api.fireworks.ai/inference/v1` 的解析结果相同。 此服务提供方的 `api_base` 可选。省略时,AISIX Cloud Admin API 会填入 `https://api.fireworks.ai/inference/v1`。显式设置该值可以在资源上直观显示上游根地址。Fireworks 专用部署使用相同的推理根地址;如需更改目标,请将 `model_name` 指向 `accounts/<ACCOUNT_ID>/deployments/<DEPLOYMENT_ID>`。 此命令会将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Fireworks 文本模型资源名称是完全限定的账户路径,而不是简单名称。由 Fireworks 发布的 Serverless 文本模型使用 `accounts/fireworks/models/<name>` 格式,例如 `accounts/fireworks/models/gpt-oss-120b`。对于此 Chat 模型,`gpt-oss-120b` 这样的扁平 OpenAI 风格名称无效。 其他 Fireworks 推理 API 可能使用不同的模型 ID 形式。例如 Embedding 指南使用 `fireworks/qwen3-embedding-8b`。请使用相应端点和模型文档中的准确标识符,不要强制将每个 ID 写成 `accounts/...` 形式。 请从 [Fireworks 模型概览](https://docs.fireworks.ai/models/overview)复制完整标识符,不要手动拼接。部分目录条目会将 `models` 路径段替换为 `routers`,自行部署的模型则在第一个路径段中使用你自己的账户名称。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "fireworks-gptoss-prod", "model_name": "accounts/fireworks/models/gpt-oss-120b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。调用方不会看到该账户路径。 ❷ `model_name` 是 Fireworks 模型 ID,例如 `accounts/fireworks/models/gpt-oss-120b`。 ❸ `provider_key_id` 将该别名关联到 Fireworks 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。API 会生成密钥值,并且只返回一次明文: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "fireworks-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值通过模型 ID 引用模型。明文密钥只在此响应中返回,请安全保存。 新资源会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链��接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export FIREWORKS_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "fireworks-prod" provider: "fireworks-ai" adapter: "openai" api_key: ${FIREWORKS_API_KEY} api_base: "https://api.fireworks.ai/inference/v1" apis: responses: {} request: param_renames: max_completion_tokens: max_tokens models: - display_name: "fireworks-gptoss-prod" provider: "fireworks-ai" model_name: "accounts/fireworks/models/gpt-oss-120b" provider_key: "fireworks-prod" api_keys: - display_name: "fireworks-caller" key_env: CALLER_API_KEY allowed_models: - "fireworks-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "fireworks-gptoss-prod", "input": "Say hello from Fireworks AI.", "store": false }' ``` AISIX 会将请求发送至 Fireworks 的原生 Responses 端点,在上游请求中把 AISIX 别名替换为配置的 Fireworks 模型 ID,并在响应中恢复该别名。示例关闭了 Fireworks 默认启用的响应存储。如果请求失败,请检查服务提供方密钥凭证、`/inference/v1` API 根地址和完整的 `accounts/...` 模型 ID。 规范化 AISIX 路由通过 Fireworks 的[原生 Responses API](https://docs.fireworks.ai/guides/response-api)创建响应。使用下文所述的 `/passthrough/fireworks-ai` 前缀时,可通过 `GET /passthrough/fireworks-ai/responses` 列出已存储响应,并通过 `GET` 或 `DELETE /passthrough/fireworks-ai/responses/{response_id}` 检索或删除响应。 ## 通过透传使用原生 Messages[​](#通过透传使用原生-messages "通过透传使用原生 Messages的直接链接") Fireworks 还提供[兼容 Anthropic 的 Messages API](https://docs.fireworks.ai/tools-sdks/anthropic-compatibility)。原生 Messages 请使用透传,因为 Fireworks 未实现 `/v1/messages/count_tokens`,而 AISIX 会将该路由视为已声明 Messages 协议面的一部分。 | 配置和路由 | 上游行为 | | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | | 目录别名调用 `/v1/messages` | AISIX 将 Anthropic 格式请求转换为 Chat Completions,不会调用 Fireworks 原生 Messages API。 | | `/passthrough/fireworks-ai/messages` | 使用原样请求和响应体调用 Fireworks 原生 Anthropic 兼容 Messages API。请使用 Fireworks 模型 ID,而非 AISIX 别名。 | 本页的 `/passthrough/fireworks-ai` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 Fireworks 推理 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。透传路由不会重写 AISIX 模型别名。AISIX 会从每个请求中检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 ## 了解 Token 限制参数改写[​](#了解-token-限制参数改写 "了解 Token 限制参数改写的直接链接") Fireworks 文档将 `max_tokens` 作为其 Chat Completions 路由的输出限制参数,而当前 OpenAI SDK 和许多 Agent 框架会发送 `max_completion_tokens`。AISIX Cloud 通过 `fireworks-ai` 目录条目的内置请求覆盖项处理该差异。开源 AISIX 网关不会自行添加该目录覆盖项,因此 `resources.yaml` 示例显式配置相同重命名。 配置该改写后,有以下三项重要影响: * 调用方无需使用 Fireworks 专用代码路径。发送 `max_completion_tokens` 的客户端到达 Fireworks 时,`max_tokens` 会设置为相同的值。 * 如果同一个请求同时包含这两个字段,`max_completion_tokens` 的值会替换 `max_tokens`。较新的字段优先,因为它更可能是调用方有意设置的值。 * 重命名适用于此服务提供方密钥所服务的每个标准化路由的出站正文,而不仅是 Chat Completions。透传路由是例外,因为它会原样中继正文;在该路由上请发送 Fireworks 预期的字段名称。 对于省略该字段的请求,Fireworks 会应用自己的默认输出限制,因此长文本生成应设置显式限制。当前参数参考请参阅 [Querying text models](https://docs.fireworks.ai/guides/querying-text-models)。 警告 服务提供方密钥上提供的 `request` 配置块会替换内置配置块,而不是与其合并。如果为此服务提供方密钥添加自己的请求覆盖项,请同时重新声明 `param_renames`,否则该改写将停止应用: ``` { "request": { "param_renames": { "max_completion_tokens": "max_tokens" }, "default_headers": { "X-Team": "platform" } } } ``` 对于开源 AISIX 网关,添加其他请求设置时请保留该重命名: ``` request: param_renames: max_completion_tokens: max_tokens default_headers: X-Team: platform ``` 完整的覆盖配置结构请参阅[服务提供方专用覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 使用推理模型[​](#使用推理模型 "使用推理模型的直接链接") Fireworks 提供两种互斥的推理控制方式,每种方式的支持情况取决于具体模型: * `reasoning_effort`,可接受的推理强度因模型而异,包括 `low`、`medium` 和 `high`。 * `thinking` 对象,其中 `type` 设置为 `enabled`,且 `budget_tokens` 至少为 `1024`。 请求不能同时设置两者。AISIX 会将自己未建模的顶层请求字段原样转发到上游,因此任一种控制项都能不经修改地到达 Fireworks: ``` { "model": "fireworks-gptoss-prod", "messages": [{ "role": "user", "content": "Plan a cache invalidation strategy." }], "reasoning_effort": "medium" } ``` Fireworks 通常在 `reasoning_content` 中返回推理输出,该字段已经是 AISIX 的规范字段,但部分模型会改在 `content` 中返回。因此,此服务提供方不需要 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides) 覆盖项:对于非流式响应,AISIX 会将 `reasoning_content` 保留为 `choices[0].message.reasoning_content`;对于流式响应,则保留为 `delta.reasoning_content`。 对于在工具调用间交错推理的模型,请保留完整的助手 `reasoning_content`,并在下一次工具调用请求中发送助手消息时包含它。AISIX 会保留字段,但不会管理或重放应用对话状态。请查看 [Reasoning](https://docs.fireworks.ai/guides/reasoning),了解所选模型的控制项和重放要求。 ## 查看端点支持情况[​](#查看端点支持情况 "查看端点支持情况的直接链接") Fireworks 支持的别名可用于下列路由。完整端点矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 | 路由 | 使用 `fireworks-ai` 服务提供方密钥时的行为 | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/completions` | 对接受旧版基于 Prompt 的 Completions 格式的 Fireworks 模型提供支持。 | | `/v1/embeddings` | 目标是 Fireworks Embedding 模型时支持。请使用 [Embedding 指南](https://docs.fireworks.ai/guides/querying-embeddings-models)中的端点特定模型 ID,例如 `fireworks/qwen3-embedding-8b`。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 Fireworks 原生 Responses API。如果没有此声明,AISIX 会使用基于 Chat 的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/messages` | 通过转换为 Chat Completions 支持,而非 Fireworks 原生 Messages API。配置的服务提供方密钥未声明 Messages 协议面,因此 AISIX 会拒绝 `/v1/messages/count_tokens`;Fireworks 也未实现该上游路由。 | | `/v1/rerank` | `fireworks-ai` 不在路由允许列表中,因此不支持。请通过 `/passthrough/fireworks-ai/rerank` 调用 Fireworks 原生重排 API,并发送端点特定模型 ID。 | | `/v1/audio/*` | 不支持。Fireworks 未在此 API Base 下提供匹配的 OpenAI 兼容语音或转录路由;受支持的音频和视频输入通过多模态 Chat 模型发送。 | | `/v1/images/generations` | 不支持。该路由要求模型配置的服务提供方为 `openai`。Fireworks 原生图片生成工作流只能通过 `/passthrough/fireworks-ai/workflows/...` 访问。 | | `/v1/videos` | 不支持。该路由有自己的服务提供方允许列表,其中不包含 `fireworks-ai`。 | | `/passthrough/fireworks-ai/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 AISIX 未建模的服务提供方原生端点。 | 在前缀匹配的透传路由上,AISIX 会将剩余路径拼接到路由的 `target_url`。由于 `https://api.fireworks.ai/inference/v1` 目标以 API 版本路径段结尾,以 `v1/` 开头的透传路径会去重,因此 `/passthrough/fireworks-ai/v1/<path>` 和 `/passthrough/fireworks-ai/<path>` 都会解析为 `https://api.fireworks.ai/inference/v1/<path>`。以该目标为准的路由保持在推理 API 下,无法访问 `https://api.fireworks.ai/v1/accounts/...` 上的 Fireworks 账号或部署管理路由。 透传授权来自调用方 API Key 的 `allowed_routes` 列表——它必须授予路由名称;模型允许列表不管控这些路径。在 `raw` 路由上 Token 数和基于 Token 的成本保持为零,但调用方 Key 的请求数限制仍会生效。请参阅[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Fireworks AI,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Fireworks AI 与另一个服务提供方之间执行故障转移。 * [服务提供方专用覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):上游 API 与其适配器不同时,调整请求和响应格式。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # Gemini (Google AI Studio) [Google Gemini](https://ai.google.dev/gemini-api/docs) 是可通过 Google AI Studio 和 Google Cloud Vertex AI 使用的多模态模型系列。本指南将 Google AI Studio 端点接入 AISIX,使应用能够通过网关管理的凭证、访问控制、速率限制和用量核算来调用 Gemini。 本指南使用 Google AI Studio 端点。如需改为通过 Google Cloud 路由 Gemini,请使用 [Google Vertex AI](https://docs.apiseven.com/ai-gateway/providers/google-vertex-ai.md)。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Google AI Studio](https://aistudio.google.com/apikey) 获取的 Google AI Studio API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为以 Gemini 为后端的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 由于 Google AI Studio 提供兼容 OpenAI 的端点,AISIX 通过 `openai` 适配器连接,并将 Google AI Studio API 根地址用作 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Google AI Studio 凭证和 API 根地址的服务提供方密钥,并允许该环境使用此密钥: ``` # 请替换为实际值 export GEMINI_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "${AISIX_CP}/provider_keys" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gemini-prod", "provider": "google", "api_key": "'"${GEMINI_API_KEY}"'", "api_base": "https://generativelanguage.googleapis.com/v1beta/openai", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "${PROVIDER_KEY_ID}" ``` ❶ `provider` 为 `google`,即 Google AI Studio 的目录服务提供方 ID。AISIX Cloud Admin API 会从目录服务提供方推导适配器;只有 BYO 服务提供方密钥才接受 `adapter` 字段。 ❷ `api_key` 存储 Google AI Studio API Key。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ 对于此目录服务提供方,`api_base` 是可选字段,因为省略时 AISIX Cloud Admin API 会填入相同的值。显式设置该字段可使上游根地址在资源中保持可见。请使用末尾不带斜杠的根地址;AISIX 会向其追加 `/chat/completions`。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "${AISIX_CP}/environments/${ENV_ID}/models" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gemini-flash-prod", "model_name": "gemini-3.6-flash", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "${MODEL_ID}" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Gemini 模型 ID,例如 `gemini-3.6-flash`。请从 [Gemini 模型](https://ai.google.dev/gemini-api/docs/models)页面选择稳定 ID,并在部署前检查其生命周期;Google 会按照公布的计划停用旧的稳定版和预览版 ID。 ❸ `provider_key_id` 将别名关联到 Gemini 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key 资源。服务器会生成密钥值,并仅在响应中返回一次明文: ``` AISIX_API_KEY=$(curl -sS -X POST "${AISIX_CP}/environments/${ENV_ID}/api_keys" \ -H "Authorization: Bearer ${AISIX_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gemini-app", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "${AISIX_API_KEY}" ``` `allowed_models` 的值通过 ID 引用模型。请安全存储明文密钥;之后无法再次获取。 新资源会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export GEMINI_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用以下完整的声明式资源文件。对于现有网关,请把这些条目合并到[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely),并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "gemini-prod" provider: "google" adapter: "openai" api_key: ${GEMINI_API_KEY} api_base: "https://generativelanguage.googleapis.com/v1beta/openai" models: - display_name: "gemini-flash-prod" provider: "google" model_name: "gemini-3.6-flash" provider_key: "gemini-prod" api_keys: - display_name: "gemini-app" key_env: CALLER_API_KEY allowed_models: - "gemini-flash-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-flash-prod", "messages": [ { "role": "user", "content": "Say hello from Gemini." } ] }' ``` 网关返回兼容 OpenAI 的响应,其中会回显面向调用方的别名 `gemini-flash-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 Gemini 模型 ID。 ## 使用 Gemini 思考和工具[​](#使用-gemini-思考和工具 "使用 Gemini 思考和工具的直接链接") Google 的 OpenAI 兼容 Chat 端点接受 `reasoning_effort`。AISIX 会原样转发该字段及其他未建模的顶层字段,因此调用方可以使用所选 Gemini 模型支持的强度: ``` { "model": "gemini-flash-prod", "messages": [{"role": "user", "content": "Plan a safe database migration."}], "reasoning_effort": "medium" } ``` `extra_body.google` 下的 Gemini 专用控制项(例如 `thinking_config`)也会透传。不要在同一请求中同时发送 `reasoning_effort` 和 Google 的思考强度或思考预算控制项,因为它们配置的是同一行为。对于 `gemini-3.6-flash` 及更新模型,请移除 `temperature`、`top_p` 和 `top_k` 等已弃用的采样字段;AISIX 会转发这些字段,而不会代替你移除。 Gemini 3 工具调用在 `tool_calls[].extra_content.google.thought_signature` 中携带必需的思考签名。在 `/v1/chat/completions` 上继续函数调用轮次时,请保留完整的助手 `tool_calls` 对象,并将其与工具结果一起原样发回。AISIX 会保留这些原始对象,但不会管理应用的对话状态。 多步 Gemini 3 工具循环不要使用 `/v1/responses` 或转换后的 `/v1/messages` 路由。这些桥接会重建可移植的工具调用字段,而不会重放 Google 专用思考签名,因此下一次 Gemini 请求可能因验证错误返回 `400`。请参阅 [OpenAI 兼容性的思考签名](https://ai.google.dev/gemini-api/docs/generate-content/thought-signatures#openai)。 ## 查看端点支持情况[​](#查看端点支持情况 "查看端点支持情况的直接链接") Google AI Studio OpenAI 兼容 API 提供的路由多于 AISIX 当前为 `google` 服务提供方建模的路由。请选择同时满足两层约束的路由: | 路由 | 使用 `google` 服务提供方密钥时的行为 | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括流式传输,以及所选模型接受的多模态图像、音频或视频输入。 | | `/v1/embeddings` | 支持使用单独的 Gemini Embedding 模型别名,例如 `gemini-embedding-2`。 | | `/v1/responses` | 通过基于 Chat 的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持,而不会调用 Google 原生 Interactions API。没有对应 Chat 语义的字段会被忽略。 | | `/v1/messages` | 通过转换到 Chat Completions 提供支持。`/v1/messages/count_tokens` 不可用,因为它要求使用 Anthropic 支持的模型。 | | `/v1/completions` | 不受 Google 兼容 API 支持;该 API 记录的是 Chat Completions,而不是旧版 Prompt Completions 路由。 | | `/v1/audio/*` | 不支持。请通过 Chat Completions 发送受支持的音频输入;Gemini 语音生成和 Live API 使用不同的原生 API。 | | `/v1/images/generations` | 拒绝,因为标准化 AISIX 路由要求 `provider: openai`,即使 Google 提供 OpenAI 兼容图像路由也不例外。请通过 `/passthrough/google/images/generations` 发送当前 Google 图像模型 ID。 | | `/v1/videos` | 拒绝,因为 `google` 不在标准化视频路由的服务提供方允许列表中。请通过 `/passthrough/google/videos` 提交 Google OpenAI 兼容视频任务,并通过 `/passthrough/google/videos/<id>` 轮询。 | | `/v1/rerank` | 不支持。AISIX 路由的服务提供方允许列表不包含 `google`,Google 也未在此处提供匹配的 Rerank 路由。 | | `/v1/files`、`/v1/batches` | 无法构成端到端 AISIX 工作流。Google 支持 OpenAI 兼容的批处理创建和状态查询,但文件上传和下载需要使用此目录路由之外的原生 API。 | | `/passthrough/google/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 OpenAI 兼容 API Base 下的原始路由。 | 本页的 `/passthrough/google` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为目录 `api_base` 并挂上此服务提供方密钥;在调用方 API Key 的 `allowed_routes` 上授予路由名称。该目标以 `/v1beta/openai` 结尾,因此透传始终位于 Google OpenAI 兼容 API 区域内,无法访问 `models/<model>:generateContent`、`models/<model>:streamGenerateContent`、`interactions`、原生文件操作或 Live API 等同级原生路由。这些原生 API 还使用不同的请求形态和 API Key 请求头,因此不要在此目录服务提供方密钥后构造原生 Gemini 路径。 透传会转发请求和响应正文,但不会重写 AISIX 模型别名,因此请发送准确的 Google 模型 ID。AISIX 会从每个请求中检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。透传流量记录的 Token 不会推进 `tpm` 或 `tpd` 计数器、确定模型成本,也不会增加预算支出;调用方 Key 的请求次数限制仍适用于每次调用。请参阅[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已通过 Google AI Studio 将 AISIX 连接到 Gemini,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [Google Vertex AI](https://docs.apiseven.com/ai-gateway/providers/google-vertex-ai.md):改为通过 Google Cloud 路由 Gemini。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Google Vertex AI [Google Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs) 是 Google Cloud 面向 Gemini 和合作伙伴模型的托管平台。AISIX 为应用提供统一的兼容 OpenAI API,以调用这些由 Vertex 托管的模型。 此配置适用于需要使用 AISIX 认证、模型允许列表、速率限制和用量核算的 Vertex 托管模型。AISIX 使用 GCP OAuth2 Bearer Token 向 Vertex 认证,并可从服务账号密钥签发该 Token。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 已在目标 GCP 项目中启用 Vertex AI API。 * 目标模型支持的 Vertex 位置,以及可调用该模型的服务账号。当前 Gemini 示例使用 `global`。 * GCP 项目 ID 和 Vertex 模型 ID。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 创建 Vertex 服务提供方密钥、模型别名和调用方 API Key。服务提供方密钥存储 GCP 项目、区域和凭证模式;模型则选择 Vertex 发布方模型 ID。 ### 创建 Vertex 服务提供方密钥[​](#创建-vertex-服务提供方密钥 "创建 Vertex 服务提供方密钥的直接链接") 使用 GCP 凭证设置创建 Vertex 服务提供方密钥: ``` PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "vertex-prod", "provider": "google-vertex", "api_base": "https://aiplatform.googleapis.com", "config": { "project": "my-gcp-project", "region": "global", "service_account_json": { "type": "service_account", "private_key": "-----BEGIN PRIVATE KEY-----\nYOUR_SERVICE_ACCOUNT_PRIVATE_KEY\n-----END PRIVATE KEY-----\n", "client_email": "vertex-sa@my-gcp-project.iam.gserviceaccount.com", "token_uri": "https://oauth2.googleapis.com/token" } }, "allowed_environments": ["'"$ENV_ID"'"] }' | jq -r '.provider_key.id') ``` ❶ `provider` 选择 Google Vertex 目录条目,该条目通过 Vertex 协议适配器路由流量。 ❷ AISIX Cloud 要求为此平台服务提供方设置 `api_base`。对于 `global` 位置,请使用 `https://aiplatform.googleapis.com`;`https://global-aiplatform.googleapis.com` 并非全局端点。对于区域位置,请使用与 `config.region` 匹配的 `https://<region>-aiplatform.googleapis.com`。代理或私有端点可以替代任一 Origin。 ❸ `config` 是结构化凭证,包含 `project`、`region`,且必须恰好包含一种凭证模式。示例使用嵌套对象形式的 `service_account_json`。通过 `config` 提供凭证时,请省略 `api_key`;此服务提供方会拒绝非空的 `api_key`。 除非你已经自行管理短期 GCP 访问 Token,否则请使用 `service_account_json`。AISIX 会签名 JWT、签发并缓存 OAuth Token,并在到期前刷新。如果使用 `access_token`,你需要负责刷新它。当前适配器不会发现应用默认凭证、元数据服务器凭证或工作负载身份联合凭证。 服务提供方密钥中的机密信息遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中介绍的凭证处理行为。 该命令保存返回的服务提供方密钥 ID,以供模型资源使用。`allowed_environments` 允许该环境引用此密钥。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 将面向调用方的别名映射到 Vertex 模型 ID: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gemini-prod", "model_name": "gemini-3.6-flash", "provider_key_id": "'"$PROVIDER_KEY_ID"'" }' | jq -r '.model.id') ``` ❶ `model_name` 是 Vertex 发布方模型 ID。当前示例 [Gemini 3.6 Flash](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/gemini/3-6-flash) 已在 `global` 正式发布。Google 说明该模型会忽略自定义 temperature、top-P 和 top-K 值,因此通过 AISIX 调用时请省略 `temperature` 和 `top_p`。请求还必须以用户消息结尾。Google 会拒绝最后一轮角色为 `model` 的 GenerateContent 请求,而 AISIX 会将最后一条 OpenAI `assistant` 消息映射为该角色。 ❷ `provider_key_id` 将模型关联到上一步保存的 Vertex 凭证。 其他受支持的示例包括 Vertex 上的 Claude、Llama 等兼容 OpenAI 的 MaaS 模型,以及 Mistral 和 AI21 的合作伙伴发布方模型。 AISIX 根据 `model_name` 选择 Vertex 路由: | 模型 ID 系列 | AISIX 如何将其发送到 Vertex | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | Gemini 模型,例如 `gemini-*` | 使用 Google Gemini 发布方路由。 | | Claude 模型,例如 `claude-*` | 使用 Anthropic 发布方路由,并采用 Anthropic Messages 请求体。 | | 兼容 OpenAI 的 MaaS 模型,例如 Llama、DeepSeek、Qwen、GPT-OSS、MiniMax、Moonshot 或 Z.ai | 使用 Vertex 兼容 OpenAI 的 chat-completions 路由。 | | Mistral 和 AI21 模型 | 使用合作伙伴发布方路由,并采用兼容 OpenAI 的请求体。 | ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问 Vertex 支持的模型别名的 API Key 资源。服务器会生成密钥,并仅返回一次明文: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "vertex-caller", "allowed_models": ["'"$MODEL_ID"'"] }' | jq -r '.plaintext') ``` `allowed_models` 通过 ID 引用模型,因此调用方只能使用 Vertex 支持的别名。请安全存储明文密钥;读取端点不会再次返回它。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 对于开源网关,请设置 `adapter: vertex`,并将项目、区域和凭证模式放入服务提供方密钥的 `api_key` 值中。以下示例从环境变量读取结构化凭证: ``` export VERTEX_CREDENTIAL='{"project":"my-gcp-project","region":"global","service_account_json":{"type":"service_account","private_key":"YOUR_PRIVATE_KEY","client_email":"vertex-sa@my-gcp-project.iam.gserviceaccount.com","token_uri":"https://oauth2.googleapis.com/token"}}' ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: vertex-prod provider: google-vertex adapter: vertex api_key: ${VERTEX_CREDENTIAL} api_base: https://aiplatform.googleapis.com models: - display_name: gemini-prod provider: google-vertex model_name: gemini-3.6-flash provider_key: vertex-prod api_keys: - display_name: vertex-caller key_env: VERTEX_CALLER_KEY allowed_models: - gemini-prod ``` 凭证必须包含 `project`、`region`,以及 `access_token` 或 `service_account_json` 中的恰好一个。对于其他 Vertex 发布方,请使用上文介绍的相同 `model_name` 值。 对于区域 OSS 配置,可以省略 `api_base`,AISIX 会推导 `https://<region>-aiplatform.googleapis.com`。当 `region: global` 时请显式设置它,因为正确的 Origin 是 `https://aiplatform.googleapis.com`;使用代理或私有端点时也应显式设置。 导出调用方密钥: ``` export VERTEX_CALLER_KEY="YOUR_CALLER_API_KEY" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,为通用验证请求设置 `AISIX_API_KEY`: ``` export AISIX_API_KEY="$VERTEX_CALLER_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 chat-completions 请求。示例使用 Gemini,它要求至少包含一条用户或助手消息。 ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-prod", "messages": [ { "role": "user", "content": "Say hello from Vertex." } ] }' ``` 网关返回兼容 OpenAI 的响应,其中包含面向调用方的别名: ``` { "object": "chat.completion", "model": "gemini-prod", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello from Vertex!" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 4, "completion_tokens": 4, "total_tokens": 8 } } ``` 在 Vertex 日志、指标、配额用量或服务提供方侧请求记录中查找测试请求。如果 AISIX 返回 Token 签发或上游认证错误,请检查服务账号密钥、区域、Vertex API 启用状态、IAM 角色和模型访问权限。 ## 端点和内容支持[​](#端点和内容支持 "端点和内容支持的直接链接") Vertex AI 提供的能力多于当前 AISIX `vertex` 适配器能够转换的范围。网关行为同时取决于调用方路由和 `model_name` 所选择的发布方系列。 | 路由 | 使用 `google-vertex` 服务提供方密钥时的行为 | | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括流式传输。当前 Gemini 发布方转换仅支持文本;合作伙伴发布方的行为取决于其协议。 | | `/v1/embeddings` | 支持 Google 发布方的文本嵌入模型,例如 `gemini-embedding-001`。AISIX 将文本输入发送到 `publishers/google/models/<model>:predict`;不支持合作伙伴和多模态嵌入格式。使用 `gemini-embedding-001` 时,每个请求只发送一个输入字符串。AISIX 会将输入数组作为一个上游请求转发,但该模型只接受一个输入,包含多项的数组可能被拒绝。 | | `/v1/responses` | 通过基于 Chat 的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持,并非原生 Vertex Responses 端点。没有 Chat 等价项的字段会被忽略。 | | `/v1/messages` | 通过转换为 Chat 支持。因为配置的服务提供方是 `google-vertex`,即使使用 Vertex 托管的 Claude 模型,也无法使用 `/v1/messages/count_tokens`。 | | `/v1/completions` | Vertex 适配器不支持。 | | `/v1/images/generations`、`/v1/audio/*`、`/v1/videos` 和 `/v1/rerank` | Vertex 适配器或这些路由的服务提供方规则不支持,即使 Vertex 另有原生媒体服务。 | | `/v1/files`、`/v1/batches` 和 `/v1/fine_tuning/jobs` | 不支持,因为 AISIX 作业接口不接受 `vertex` 适配器。 | | `/passthrough/google-vertex/*` | 即使配置了[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),也不能作为调用原生 Vertex API 的变通方案。透传路由会绕过适配器,因此凭证注入既不会从服务账号 JSON 签发 OAuth Token,也不会从结构化凭证提取访问 Token。 | 对于 Gemini 发布方模型,AISIX 当前会序列化文本部分、系统指令和基本生成设置。它不会序列化图片、音频或视频部分、函数声明和工具结果、Gemini 特定的思考控制或思维签名。工具消息会被简化为用户文本,非文本响应部分不会返回。 不要将当前 Vertex 适配器用于 Gemini 函数调用循环。Gemini 3 要求应用在工具使用期间重放思维签名,但此适配器既不返回也不接受这些签名。通过 Responses 或 Messages 桥接访问 Gemini 时同样存在此限制。 AISIX 会将 Vertex 的各项 Token 计数映射到规范化响应,而不只是它们的总和。思考 Token(`thoughtsTokenCount`)按 Vertex 的计费口径计入 `completion_tokens`,并在 `completion_tokens_details.reasoning_tokens` 中单独标明。上下文缓存命中(`cachedContentTokenCount`)仍是 `prompt_tokens` 的子集,在 `prompt_tokens_details.cached_tokens` 中报告。 以上是 Chat Completions 的字段名。同样的数值到达 [Responses](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md) 调用方时叫 `output_tokens_details.reasoning_tokens` 和 `input_tokens_details.cached_tokens`;[Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md) 调用方看到的缓存命中是 `cache_read_input_tokens`,且没有单独的 reasoning 计数器——该协议本身没有这一概念。 ## Vertex 发布方路由[​](#vertex-发布方路由 "Vertex 发布方路由的直接链接") 发布方选择基于前缀。如果 `model_name` 不匹配受支持的前缀,网关会在发送服务提供方请求前拒绝该请求,并返回不支持发布方的配置错误。 示例使用 Gemini,因为它是 Google 的主要发布方路径。对于合作伙伴模型,请先在 Vertex 项目中验证确切的模型 ID、配额和区域可用性,再向调用方公开别名。 一个服务提供方密钥只对应一个项目和位置。如果合作伙伴模型仅在其他位置可用,请创建另一个服务提供方密钥;更改 `model_name` 不会改变 Vertex 资源路径使用的位置。 [服务提供方密钥的请求和响应覆盖设置](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)可应用于 Vertex 路由,但在兼容 OpenAI 的路由上最为直接有效。Gemini 原生的 `contents` 格式并不匹配所有 OpenAI 风格的覆盖目标。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Google Vertex AI,并验证了模型别名。接下来可阅读以下指南: * [Gemini(Google AI Studio)](https://docs.apiseven.com/ai-gateway/providers/gemini.md):使用 AI Studio API Key 而不是 Google Cloud 项目来配置 Gemini。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Groq [Groq](https://console.groq.com/docs) 为一系列开放模型提供托管推理。AISIX 为应用提供稳定的模型别名和调用方密钥,同时将 Groq 凭证保留在网关中。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Groq 控制台](https://console.groq.com/keys)获取的 Groq API Key。 * `curl`. ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Groq 支持的 Chat Completions 和原生 Responses 创建服务提供方密钥、模型别名和调用方 API Key。 由于 Groq 提供兼容 OpenAI 的 API,AISIX 通过 `openai` 适配器连接,并将 Groq API 根地址用作 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Groq 凭证和 API 根地址的服务提供方密钥: ``` # 请替换为实际值 export GROQ_API_KEY="YOUR_PROVIDER_API_KEY" curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "groq-prod", "provider": "groq", "api_key": "'"${GROQ_API_KEY}"'", "api_base": "https://api.groq.com/openai/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' ``` ❶ `provider` 为 `groq`。AISIX Cloud Admin API 会从目录服务提供方推导适配器;适配器字段仅接受用于 BYO 服务提供方密钥。 ❷ `api_key` 存储 Groq API Key。该值在存储前加密,读取端点绝不会返回它。它遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 已包含 `/openai/v1` 路径。AISIX 会向其追加所选端点的路径。对于此目录服务提供方,该字段是可选的,因为省略时 AISIX Cloud Admin API 会填入相同的值。示例显式设置该字段,使上游根地址在资源中保持可见。 ❹ `apis.responses` 声明 Groq 在同一根地址提供 Responses API。这样,AISIX 就能使用 Groq 的原生请求和响应格式,而不必通过 Chat Completions 转换。 AISIX Cloud 当前保留了将 `max_completion_tokens` 重命名为 `max_tokens` 的旧版兼容规则。Groq 仍接受 `max_tokens`,但现已弃用该字段,建议使用 `max_completion_tokens`。 下方开源配置有意省略此覆盖设置,以便当前客户端直接发送 `max_completion_tokens`。 从响应中复制 `provider_key.id` 值(例如使用 `jq -r '.provider_key.id'`),并将其导出: ``` export PROVIDER_KEY_ID="YOUR_PROVIDER_KEY_ID" ``` ### 创建模型[​](#创建模型 "创建模型的直接链接") Groq 模型的可用性会随时间变化。创建模型别名前,请在 [Groq 模型列表](https://console.groq.com/docs/models)中查看当前模型 ID。 创建调用方将在请求中发送的模型别名: ``` curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "groq-gptoss-prod", "model_name": "openai/gpt-oss-120b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Groq 模型 ID,例如 `openai/gpt-oss-120b`。 ❸ `provider_key_id` 将别名关联到 Groq 服务提供方密钥。 保存响应中的 `model.id` 值: ``` export MODEL_ID="YOUR_MODEL_ID" ``` ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key 资源。网关会生成密钥值,并仅在响应中返回一次明文: ``` curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "groq-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' ``` `allowed_models` 的值必须引用已保存的模型 ID。从响应中复制 `plaintext` 值(它只会显示一次),并将其导出为调用方密钥: ``` export AISIX_API_KEY="YOUR_CALLER_API_KEY" ``` 写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export GROQ_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "groq-prod" provider: "groq" adapter: "openai" api_key: ${GROQ_API_KEY} api_base: "https://api.groq.com/openai/v1" apis: responses: {} models: - display_name: "groq-gptoss-prod" provider: "groq" model_name: "openai/gpt-oss-120b" provider_key: "groq-prod" api_keys: - display_name: "groq-caller" key_env: CALLER_API_KEY allowed_models: - "groq-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "groq-gptoss-prod", "input": "Say hello from Groq." }' ``` AISIX 会将请求发送至 Groq 的原生 Responses 端点,在上游请求中把 AISIX 别名替换为配置的 Groq 模型 ID,并在响应中恢复该别名。如果请求失败,请检查服务提供方密钥凭证、API 根地址和 Groq 模型 ID。 ## 端点和兼容性边界[​](#端点和兼容性边界 "端点和兼容性边界的直接链接") Groq 在很大程度上兼容 OpenAI,但并非完全兼容。AISIX 会转发额外的 Chat 请求字段,而非过滤它们,因此 Groq 会实施自身的模型和参数规则。Groq 兼容性指南指出,`logprobs`、`logit_bias`、`top_logprobs` 和 `messages[].name` 会返回 `400`,且 `n` 必须为 `1`。Groq API 参考还将 `frequency_penalty`、`presence_penalty`、`metadata` 和 `store` 标记为不支持。 `temperature` 为 `0` 时,上游会将其转换为 `1e-8`。对于音频转录和翻译,Groq 不支持 `vtt` 或 `srt` 输出。最新列表请参阅 [Groq 的 OpenAI 兼容性指南](https://console.groq.com/docs/openai)。 | 路由 | 使用 `groq` 服务提供方密钥时的行为 | | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括流式传输。AISIX 会转发 `tools`、`response_format` 和 `reasoning_effort` 等字段;实际支持情况仍取决于所选 Groq 模型。示例 GPT-OSS 模型支持工具使用、结构化输出,以及 `low`、`medium` 或 `high` 推理强度。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送到 [Groq 原生 Responses API](https://console.groq.com/docs/responses-api)。Groq 目前将该 API 标记为 Beta,且并不支持 OpenAI Responses 的所有字段。如果没有此声明,AISIX 会使用基于 Chat 的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/messages` | 通过转换为 Chat 支持,并非原生 Groq Messages API。因为配置的服务提供方不是 Anthropic,无法使用 `/v1/messages/count_tokens`。 | | `/v1/audio/transcriptions`、`/v1/audio/translations` 和 `/v1/audio/speech` | 支持,但需要为当前 Groq 语音转文本或文本转语音模型分别创建别名。配置音频别名前,请检查 Groq 模型列表。 | | `/v1/files` 和 `/v1/batches` | 通过 Groq 兼容 OpenAI 的文件和批处理 API 支持。按照[批处理、文件和微调](https://docs.apiseven.com/ai-gateway/endpoints/batch-files-fine-tuning.md)中的说明,使用 Groq 别名作为路由模型。Groq 对批处理应用折扣价格,但 AISIX 使用别名配置的同步价格估算批处理成本;请勿将该估算视为服务提供方账单。 | | `/v1/fine_tuning/jobs` | 与 Groq 微调不兼容。AISIX 在 `api_base` 下转发 OpenAI `/fine_tuning/jobs` 协议,而 Groq 的封闭 Beta API 使用 `/openai/v1` 根地址以外的 `/v1/fine_tunings`,且请求体不同。 | | `/v1/embeddings` 和 `/v1/completions` | 不支持,因为 Groq 不提供这些上游端点。 | | `/v1/images/generations`、`/v1/videos` 和 `/v1/rerank` | Groq 或这些 AISIX 路由的服务提供方规则不支持。 | 规范化 Chat 响应会保留标准内容、工具调用、推理文本和 Token 总数。AISIX 会将 Groq 原生 `message.reasoning` 值返回为 `reasoning_content`,但不会保留 `x_groq`、用量时序详情、`usage_breakdown`,以及未建模的引用和注解字段等 Groq 特定元数据。 原生声明会在规范化的 AISIX 路由上保留模型别名重写和模型访问控制,因此 Groq Responses 不再需要单独的透传路由。对于 AISIX 未规范化、但位于同一 API 根地址下的其他 Groq 端点,可配置一条使用自选前缀并以 `https://api.groq.com/openai/v1` 为 `target_url` 的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。请在调用方 Key 的 `allowed_routes` 中授予该路由名称,并发送上游模型 ID,因为透传不会重写别名。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Groq,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Groq 和第二个服务提供方之间配置故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Hugging Face [Hugging Face Inference Providers](https://huggingface.co/docs/inference-providers) 会将请求路由到由多个推理服务商提供的开放权重模型。AISIX 将该目录置于统一的 OpenAI 兼容 API 之后,并由网关管理凭证、调用方访问权限、限流和用量核算。 Hugging Face 与单一服务商上游不同,它使用路由层:由请求中的模型 ID 而不是 URL 决定哪个推理服务商提供该模型。 本指南介绍共享的 Inference Providers 路由器。专用 Hugging Face Inference Endpoint 具有独立的部署主机名,无法通过路由器 URL 访问。仅当其服务引擎提供应用所需的 OpenAI 路由(例如 `/v1/chat/completions` 或 `/v1/embeddings`)时,才将该部署配置成[私有 OpenAI 兼容端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)。自定义端点或任务原生端点并不会自动兼容 OpenAI。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 在 [Access Tokens](https://huggingface.co/settings/tokens) 中创建、具备 **Make calls to Inference Providers** 权限的 Hugging Face Access Token。 * 仍有 Inference Providers Credit 的 Hugging Face 账号。 * `curl` 和 `jq`。 Hugging Face Access Token 是账户级凭证,而不是针对单个服务商的 API Key。一个 Token 可以授权调用路由器可选择的所有推理服务商,因此 AISIX 中的一个服务提供方密钥即可覆盖整个路由器目录。请将 Token 的权限限制为 Inference Providers,确保 AISIX 中存储的凭证不能同时读取或写入 Hub 仓库。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Hugging Face 支持的 Chat Completions 和原生 Responses 创建服务提供方密钥、模型别名和调用方 API Key。 由于 Hugging Face 提供 OpenAI 兼容 API,AISIX 会通过 `openai` 适配器连接,并使用 Inference Providers 路由器作为 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Hugging Face Token 和路由器根地址的服务提供方密钥: ``` # 请替换为实际值 export HF_TOKEN="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "huggingface-prod", "provider": "huggingface", "api_key": "'"${HF_TOKEN}"'", "api_base": "https://router.huggingface.co/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `huggingface`。AISIX Cloud Admin API 会从目录服务提供方派生适配器;`adapter` 字段仅在 BYO 服务提供方密钥上被接受。 ❷ `api_key` 存储 Hugging Face Access Token。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `api_base` 是 Inference Providers 路由器的根地址。其主机为 `router.huggingface.co`,而不是某个模型专用的主机;`/v1` 是位于所有路由推理服务商之前的 OpenAI 兼容接口。AISIX 会追加端点路径,因此 Chat 路由会解析为 `https://router.huggingface.co/v1/chat/completions`。如果省略 `api_base`,AISIX Cloud 会从目录中填入相同的路由器 URL;显式设置该值可使资源内容自解释。 ❹ `apis.responses` 声明路由器在同一根地址提供 Responses API。这样,AISIX 会使用 Hugging Face 原生格式,而不是通过 Chat Completions 转换请求。 此命令会将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Hugging Face 模型 ID 是 `<org>/<model>` 格式的 Hub 仓库 ID,不同发布方的大小写并不统一:`openai/gpt-oss-120b` 全部为小写,而 `Qwen/Qwen3-235B-A22B-Thinking-2507` 和 `deepseek-ai/DeepSeek-V4-Pro` 使用混合大小写。请从[支持的模型列表](https://huggingface.co/inference/models)原样复制 ID,不要手动输入;创建模型别名前,还应在该列表中确认模型当前仍在提供服务。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "hf-gptoss-prod", "model_name": "openai/gpt-oss-120b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Hugging Face 模型 ID,例如 `openai/gpt-oss-120b` 或 `deepseek-ai/DeepSeek-V4-Pro`。AISIX 会将此字符串原样转发到路由器。 ❸ `provider_key_id` 将该别名关联到 Hugging Face 服务提供方密钥。 ### 固定推理服务商[​](#固定推理服务商 "固定推理服务商的直接链接") Hugging Face 接受模型 ID 上的可选后缀,用于控制由哪个推理服务商处理请求。该后缀是模型字符串的一部分,因此应设置在 `model_name` 中: | `model_name` 值 | 路由行为 | | ------------------------------- | -------------------------------------------------------------- | | `openai/gpt-oss-120b` | 自动路由,默认选择当前可用且速度最快的推理服务商。 | | `openai/gpt-oss-120b:groq` | 固定到指定的推理服务商。 | | `openai/gpt-oss-120b:cheapest` | 按每个输出 Token 的价格路由到成本最低的服务商。 | | `openai/gpt-oss-120b:fastest` | 路由到吞吐量最高的服务商。这是默认策略。 | | `openai/gpt-oss-120b:preferred` | 按 Hugging Face Inference Providers 设置中配置的偏好顺序路由。 | 当前后缀语法请参阅 [Hugging Face Chat Completion 文档](https://huggingface.co/docs/inference-providers/en/tasks/chat-completion)。 后缀会改变延迟、价格以及实际运行模型的后端,因此请将固定服务商和策略路由的变体视为不同上游。请为每个变体创建一个模型别名,不要原地切换后缀,使限流和用量记录仍可归属到该路由选择。 如果准确的 AISIX 成本和预算计算很重要,请固定推理服务商。使用 `:fastest`、`:cheapest` 或 `:preferred` 时,所选服务商和价格都可能变化,因此请验证或覆盖别名成本元数据。相关字段请参阅[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md)。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且只在响应中返回一次,请安全保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "huggingface-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。 网关会自动获取新资源,无需重启。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export HF_TOKEN="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "huggingface-prod" provider: "huggingface" adapter: "openai" api_key: ${HF_TOKEN} api_base: "https://router.huggingface.co/v1" apis: responses: {} models: - display_name: "hf-gptoss-prod" provider: "huggingface" model_name: "openai/gpt-oss-120b" provider_key: "huggingface-prod" api_keys: - display_name: "huggingface-caller" key_env: CALLER_API_KEY allowed_models: - "hf-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "hf-gptoss-prod", "input": "Say hello from Hugging Face." }' ``` AISIX 会将请求发送至 Hugging Face 原生 Responses 端点,在上游请求中把别名替换为 Hub 模型 ID,并在响应中恢复该别名。如果请求失败,请检查服务提供方密钥的 `api_key` 和 `api_base`,验证 `model_name` 中 Hub 仓库 ID 的精确大小写,确认 Token 具备 Inference Providers 权限且账号仍有 Inference Providers Credit。服务商可用性还因模型而异,因此请在[支持的模型列表](https://huggingface.co/inference/models)中确认该模型当前仍在提供服务。 ## 控制推理输出[​](#控制推理输出 "控制推理输出的直接链接") 路由器上的推理模型在 Chat Completions 请求体中接受顶层 `reasoning_effort` 字段: ``` { "reasoning_effort": "low" } ``` 常见值包括 `none`、`minimal`、`low`、`medium`、`high` 和 `xhigh`,但是否支持、默认值以及哪些值有实际含义,取决于模型及为其提供服务的推理服务商。路由器没有记录统一的启用或禁用开关,也没有数字形式的推理预算字段,因此在依赖某项具体设置前,请在 [Hugging Face Chat Completion 文档](https://huggingface.co/docs/inference-providers/en/tasks/chat-completion)中确认模型接受的值。AISIX 会将该字段转发到路由器,而不进行解释。 AISIX 的 `huggingface` 目录条目没有 `response.reasoning_field` 覆盖项。AISIX 会识别 `delta.reasoning_content` 和 `delta.reasoning`,并将后者规范化为 `reasoning_content`。由于同一个 Hub 仓库 ID 可以由不同推理服务商提供,固定的服务商可能会在其他 `delta` 路径下流式返回推理内容。此时,请在固定别名专用的服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides),不要在其他所有别名都会继承的共享路由器服务提供方密钥上设置。 ## 支持的代理路由[​](#支持的代理路由 "支持的代理路由的直接链接") Hugging Face 服务提供方值会解析到 `openai` 适配器,但共享路由器只实现更广泛 OpenAI API 的一部分,其后的服务商和模型能力也可能不同。 | 路由 | 使用 `huggingface` 服务提供方密钥时的行为 | | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括流式传输。AISIX 会转发函数工具、`response_format`、`reasoning_effort` 和 VLM `image_url` 内容。实际工具使用、结构化输出、推理和视觉支持取决于 Hub 模型及本次请求选择的推理服务商。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 Hugging Face 原生 [Responses API](https://huggingface.co/docs/inference-providers/guides/responses-api)。路由器支持流式传输、结构化输出、推理控制、函数工具和远程 MCP,具体取决于模型与提供服务的推理服务商。如果没有此声明,AISIX 会使用基于 Chat 的桥接,并丢失没有 Chat 等价项的字段。 | | `/v1/messages` | 通过转换为 Chat Completions 支持,而非原生 Hugging Face Messages API。由于配置的服务提供方不是 Anthropic,`/v1/messages/count_tokens` 不可用。 | | `/v1/embeddings` | 路由器的 OpenAI 兼容 `/v1` 接口不提供。Hugging Face 通过任务特定的特征提取接口提供 Embedding,但 AISIX 不会将 OpenAI Embeddings 请求体转换到该接口。专用 Inference Endpoint 只有在 Text Embeddings Inference 等服务引擎提供 `/v1/embeddings` 时才可用。 | | `/v1/completions`、`/v1/audio/*`、`/v1/files`、`/v1/batches` 和 `/v1/fine_tuning/jobs` | 配置的共享路由器根地址上不可用。Hugging Face 另有文本生成和语音等任务原生接口,但这些 AISIX 路由不会转换到或访问它们。 | | `/v1/images/generations`、`/v1/videos` 和 `/v1/rerank` | 不支持 `huggingface` 服务提供方值。Hugging Face 可能提供相关原生任务,但这些 AISIX 路由会在转发前拒绝该服务提供方。 | 规范化 Chat 响应会保留内容、本地函数调用、规范化推理和基本 Token 用量,但不会保留所有路由器或服务商字段,例如 `created`、`system_fingerprint`、选项索引和 Log Probabilities,或任意服务商特定元数据。 规范化路由现在会提供 Hugging Face 原生 Responses 格式,同时保留 AISIX 别名和模型访问控制。仅当路由器操作未被 AISIX 规范化时才使用透传,并发送准确的 Hugging Face 模型 ID,因为透传不会重写别名。 本页的 `/passthrough/huggingface` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为配置的 `https://router.huggingface.co/v1` 根地址;在调用方 Key 的 `allowed_routes` 上授予该路由。这样的路由可以访问 `/v1/models`,但无法跳出该根地址访问 `/hf-inference/models/<model>` 等同级任务原生路径。由于目标已以 `/v1` 结尾,AISIX 会移除重复的前导 `v1` 路径段,因此 `/passthrough/huggingface/models` 和 `/passthrough/huggingface/v1/models` 都会到达 `https://router.huggingface.co/v1/models`。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Hugging Face,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Hugging Face 与另一个服务提供方之间执行故障转移。 * [服务提供方专用覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):上游 API 与其适配器不同时,调整请求和响应格式。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # Jina [Jina AI](https://jina.ai/) 为搜索和检索应用提供 Embedding 和重排序模型。AISIX 让应用通过网关的 OpenAI 兼容 Embeddings 路由和统一重排序路由调用这些模型,同时管理 Jina 凭证、调用方访问权限和限流。 Jina 通过同一个 API 根地址提供 Embedding 和重排序服务,因此一个服务提供方密钥可以支持两类模型。本指南先配置一个 Embedding 模型,再为重排序模型复用该服务提供方密钥。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Jina AI API 控制台](https://jina.ai/api-dashboard/)获取的 Jina API Key。一个密钥可授权使用包括 Embedding 和重排序在内的所有 Jina API 产品。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Jina 支持的 Embeddings 路由创建服务提供方密钥、模型别名和调用方 API Key。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Jina 凭证和 API 根地址的服务提供方密钥: ``` # 请替换为实际值 export JINA_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "jina-prod", "provider": "jina", "api_key": "'"${JINA_API_KEY}"'", "api_base": "https://api.jina.ai/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `jina`,这是 AISIX 重排序路由能够识别的服务提供方值。Jina 不在 models.dev 中,但 AISIX Cloud 会把它作为直接支持的服务提供方接受,并为 Embeddings 及其他 OpenAI 形态路由派生 `openai` 适配器。`adapter` 字段仅在 BYO 服务提供方密钥上被接受。 ❷ `api_key` 存储 Jina API Key,并在上游调用中作为 Bearer Token 发送。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `api_base` 是带版本的 Jina API 根地址。Embeddings 路由会将 `/embeddings` 追加到该值,重排序路由则会识别末尾的 `/v1`,再追加 `/rerank`,因此两个路由都能从同一个服务提供方密钥组成正确的上游 URL。此字段可选;省略时,AISIX Cloud Admin API 会填入相同的规范值。若密钥指向不同的 Jina 部署,请显式设置该字段。 该命令将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 此示例使用 [`jina-embeddings-v5-text-small`](https://jina.ai/models/jina-embeddings-v5-text-small/),这是当前的 1024 维文本 Embedding 模型。Jina 还提供面向文本、图片、音频、视频和 PDF 输入的多模态 v5 模型。由于规范化 AISIX 路由只接受字符串,这些非文本输入结构需要透传路由。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "jina-embed-prod", "model_name": "jina-embeddings-v5-text-small", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是准确的 Jina 模型 ID。由于 Jina 不在 models.dev 中,控制台不会为此服务提供方建议模型 ID;请自行输入 Jina 当前模型目录中的 ID。 ❸ `provider_key_id` 将该别名关联到 Jina 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且只在响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "jina-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID,使该密钥只能访问已创建的别名。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export JINA_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "jina-prod" provider: "jina" adapter: "openai" api_key: ${JINA_API_KEY} api_base: "https://api.jina.ai/v1" models: - display_name: "jina-embed-prod" provider: "jina" model_name: "jina-embeddings-v5-text-small" provider_key: "jina-prod" api_keys: - display_name: "jina-caller" key_env: CALLER_API_KEY allowed_models: - "jina-embed-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Embeddings 请求,并将 `dimensions` 设置为低于模型默认值的数值: ``` curl -sS -X POST "$AISIX_PROXY/v1/embeddings" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "jina-embed-prod", "input": "AISIX keeps the provider credential on the gateway side.", "dimensions": 128 }' -o jina-embed-response.json jq '.data[0].embedding | length' jina-embed-response.json ``` 此命令应输出 `128`。向量长度与请求的 `dimensions` 一致,说明可选字段已到达 Jina,并由其将模型默认的 1024 维输出截断为请求的尺寸。 AISIX 会在兼容 OpenAI 的 Embeddings 响应中重建接受的 Dense 结果。响应中的 model 字段会回显面向调用方的别名;AISIX 会保留 Float 或 Base64 向量、索引,以及 Prompt 和总 Token 计数,但不会保留 `image_tokens`、`audio_tokens` 或 `video_tokens` 等 Jina 专属用量字段。如果请求失败,请检查服务提供方密钥的 `api_key` 和 `api_base`,以及 `model_name` 中的 Jina 模型 ID。 ## 发送 Jina 专用 Embedding 字段[​](#send-jina-specific-embedding-fields "发送 Jina 专用 Embedding 字段的直接链接") 已建模的 `/v1/embeddings` 路由只接受 `model`、字符串或字符串数组形式的 `input`、`encoding_format` 和 `dimensions`。AISIX 会将调用方的单字符串或数组输入结构保留到上游。Jina 使用 `embedding_type` 而非 `encoding_format` 表示输出编码。 `task`、`embedding_type`、`normalized` 和 `truncate` 等 Jina 专属字段会在请求到达 Jina 前被丢弃。图片、音频、视频或 PDF 文档的对象输入不匹配 AISIX 请求 Schema,会在解码时被拒绝。Jina Sparse Embedding 和 v4 Multi-vector 响应也超出 AISIX 响应 Schema,会导致上游响应解码失败。这些请求或响应结构请使用透传路由。 如需发送这些字段,请改为通过透传路由调用 Jina,该路由会原样转发请求体。本页的 `/passthrough/jina` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://api.jina.ai/v1` 并挂上 Jina 服务提供方密钥;在调用方 Key 的 `allowed_routes` 上授予该路由: ``` curl -sS -X POST "$AISIX_PROXY/passthrough/jina/embeddings" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "jina-embeddings-v5-text-small", "task": "retrieval.passage", "embedding_type": "float", "normalized": true, "truncate": true, "input": [ "Provider keys store the upstream credential.", "Caller API keys authorize model access." ] }' ``` 路由不会改写正文,因此 `model` 必须是上游模型 ID,而不是别名。它注入路由上配置的服务提供方密钥,而不是从调用方密钥的模型允许列表借用;存在多个 Jina 密钥时,请给每把密钥各配一条路由。 该路由会把剩余路径追加到其 `target_url`,组成 `https://api.jina.ai/v1/embeddings`,并原样中继响应体。透传检测依据正文键,而不是端点,因此该 Embeddings 请求体中的顶层 `input` 会让 AISIX 应用 Responses 风格的提取和用量规则。只有响应包含受支持的 Token 字段时,AISIX 才会记录用量。不要依赖透传核算处理 Jina 特有的响应形状。路由行为和限制请参阅[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),当前模型特定字段请参阅 [Embedding API 参考](https://jina.ai/embeddings/)。 ## 添加重排序模型[​](#add-a-rerank-model "添加重排序模型的直接链接") `/v1/rerank` 路由接受服务提供方值为 `openai`、`cohere` 或 `jina` 的模型。对于 `jina`,协议为恒等映射:Jina 重排序 API 使用与网关统一重排序契约相同的请求字段(`model`、`query`、`documents` 和可选参数)及 `results` 响应格式,因此 AISIX 只会将 `model` 字段改写为上游模型 ID,并原样转发正文。 Jina 的重排序服务与 Embeddings 同样位于 `https://api.jina.ai/v1` 根地址,因此上文创建的服务提供方密钥已经可以访问,无需像重排序端点位于 OpenAI 兼容接口之外的服务提供方那样,在不同 API 根地址上创建第二个服务提供方密钥(可对比 [Cohere 重排序设置](https://docs.apiseven.com/ai-gateway/providers/cohere.md#add-a-rerank-model))。重排序路由会在服务提供方密钥 Base 后追加 `/rerank`,且仅在 Base 末尾没有 `/v1` 时才插入 `/v1` 路径段,因此规范的 Jina Base 会组成 `https://api.jina.ai/v1/rerank`,而不会重复版本路径段。 在 AISIX Cloud 中,创建重排序模型别名和仅限该模型的调用方密钥: ``` RERANK_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "jina-rerank-prod", "model_name": "jina-reranker-v3.5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') RERANK_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "jina-rerank-caller", "allowed_models": ["'"${RERANK_MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 对于开源 AISIX 网关,请将 `jina-rerank-prod` 添加到现有 `models` 集合。将现有 `jina-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(重排序模型访问) ``` models: - display_name: "jina-rerank-prod" provider: "jina" model_name: "jina-reranker-v3.5" provider_key: "jina-prod" api_keys: - display_name: "jina-caller" key_env: CALLER_API_KEY allowed_models: - "jina-embed-prod" - "jina-rerank-prod" ``` 按照上文说明校验并重新加载或重启声明式资源文件,然后使用现有调用方密钥发送重排序请求: ``` export RERANK_API_KEY="$CALLER_API_KEY" ``` 重排序模型 ID 使用独立于 Embedding 代际的命名方式。[`jina-reranker-v3.5`](https://jina.ai/models/jina-reranker-v3.5/) 是当前的多语言、多文档重排模型,可直接替代 `jina-reranker-v3`。当前目录请参阅 [Reranker API 参考](https://jina.ai/reranker/)。 通过代理发送重排序请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/rerank" \ -H "Authorization: Bearer ${RERANK_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "jina-rerank-prod", "query": "How do I rotate a provider credential?", "documents": [ "Provider keys store the upstream credential.", "Caller API keys authorize model access.", "Rate limits apply per caller key." ], "top_n": 2 }' ``` AISIX 只会将 `model` 字段改写为 `jina-reranker-v3.5`,并原样转发正文,因此 Jina 的 `top_n`、`return_documents`、`max_doc_length` 和 `return_embeddings` 等可选参数会按写入内容到达上游。响应保留 Jina 的重排序格式:`results` 数组按 `relevance_score` 排序,每项包含候选项的 `index`,并在请求时包含文档或文档 Embedding。Jina 的重排序响应会携带模型名称,AISIX 会将该字段改写回请求所使用的别名,因此它显示的是 `jina-rerank-prod` 而不是 `jina-reranker-v3.5`。AISIX 会将 `usage.total_tokens` 读取为重排用量和成本核算的输入 Token。 ## 实验性 Chat Completions[​](#experimental-chat-completions "实验性 Chat Completions的直接链接") Jina 在同一 API 根地址上为确切模型 ID `jina-ai/jina-vlm` 提供实验性的兼容 OpenAI `/v1/chat/completions` 端点。它接受文本和图片输入,但 Jina 将其描述为仅供测试,不保证可用性、扩展性或生产就绪程度。请勿将其作为生产依赖。 如需测试,请在现有服务提供方密钥上创建 `model_name: "jina-ai/jina-vlm"` 的独立模型别名。直接 `/v1/chat/completions` 请求会到达 Jina 原生 Chat 路由。`/v1/responses` 和 `/v1/messages` 会通过 Chat Completions 使用 AISIX 转换,因此仍受 [Responses](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)和 [Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)中所述桥接限制。 Jina DeepSearch 是位于 `https://deepsearch.jina.ai/v1` 的另一项 Chat 形态产品。请为它配置独立的服务提供方密钥和模型别名。若使用透传,请另建一条以 DeepSearch 基础地址为目标、注入 DeepSearch 服务提供方密钥的透传路由。 ## 提供成本元数据[​](#supply-cost-metadata "提供成本元数据的直接链接") Jina 未在 models.dev 目录中定价。这些别名不存在自动目录价格,因此 `least_cost` 路由和成本估算只会使用你提供的定价。在 AISIX Cloud 中通过[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)设置费率;在开源 AISIX 网关中使用模型的 `cost` 字段,详见[成本元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。请把 Jina 发布的费率换算为每 1,000 Token 的美元价格。 规范化 Embeddings 路由会记录 Jina 的 `usage.prompt_tokens`。如果 Jina 模型只返回 `usage.total_tokens`,AISIX 会使用总数执行每分钟 Token 限制,但在用量事件中记录零输入 Token。Rerank 会将 Jina 的 `usage.total_tokens` 映射到输入 Token。透传会记录存在的 `prompt_tokens` 或 `input_tokens` 以及 `completion_tokens` 或 `output_tokens`,但不会把 Jina 仅含 `total_tokens` 的响应映射为输入用量。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Jina 服务提供方密钥会为 OpenAI 形态的路由解析 `openai` 适配器,重排序路由则直接按 `jina` 服务提供方值分发: | 路由 | 使用 `jina` 模型别名时的行为 | | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/embeddings` | 默认支持字符串输入和单个 Dense Float 输出。已建模的格式会转发 `model`、字符串或字符串数组形式的 `input`、`encoding_format` 和 `dimensions`,但 Jina 使用 `embedding_type` 选择 Base64、Binary 或 Unsigned Binary 输出。有关这些编码、原生字段、多模态输入及其他输出格式,请使用[发送 Jina 专用 Embedding 字段](#send-jina-specific-embedding-fields)中所示的透传路由。 | | `/v1/rerank` | 使用 Jina 重排序模型别名时支持。`jina` 是该路由接受的三个服务提供方值之一。请参阅[添加重排序模型](#add-a-rerank-model)。 | | `/v1/chat/completions` | 仅 Jina 在此 Root 上用于测试的 `jina-ai/jina-vlm` 模型支持。请参阅[实验性 Chat Completions](#experimental-chat-completions)。Embedding 和重排序别名会在 Chat 路由上失败。 | | `/v1/responses` 和 `/v1/messages` | 仅对实验性 VLM 别名通过 Chat 转换支持。它们并非 Jina 原生路由,并保留各自桥接限制。`/v1/messages/count_tokens` 仍仅支持 Anthropic。 | | `/v1/completions`、`/v1/audio/*`、`/v1/files`、`/v1/batches` 和 `/v1/fine_tuning/jobs` | 与此 Root 上的 Jina API 不兼容。Jina 的音频和视频支持是指多模态 v5 Embedding 输入,而不是规范化 AISIX 音频或视频生成端点。Jina 原生批量 Embedding 使用不同的路径和契约。 | | `/v1/images/generations` 和 `/v1/videos` | 不支持 `jina` 服务提供方值。 | | `/passthrough/jina/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用,相对于路由目标解析。可用于原生 Embedding 字段、多模态输入、分类器、训练,以及 `/batch/embeddings` 等原生批处理路径。路由要求准确的上游模型 ID,并保留响应正文。只有检测到的请求信封和响应字段采用受支持的 Token 形状时,才会记录用量。 | 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Jina,验证了 Embedding 别名,并添加了重排序路由。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为这些别名配置路由、重试行为或成本元数据。 * [重排序](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md):查看重排序请求契约及其服务提供方要求。 * [Embeddings](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md):查看已建模的 Embeddings 请求格式和服务提供方行为。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # Meta Llama API Meta Llama API 通过 API Key 认证提供对 Llama 模型的直接托管访问。AISIX 为应用提供稳定的调用方 API,同时保存上游凭证、控制模型访问并记录用量。 本页介绍 `api.llama.com` 上的 Llama API,不涵盖 Meta 在 `api.meta.ai` 上提供的独立 Model API。 ## 前提条件[​](#prerequisites "前提条件的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * Meta Llama API Key,以及计划使用的模型的访问权限。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 创建模型服务提供方密钥、模型别名和调用方 API Key。 Llama API 是一个提供兼容 OpenAI 端点的社区目录模型服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行认证。 ### 创建模型服务提供方密钥[​](#create-a-provider-key "创建模型服务提供方密钥的直接链接") 导出上游凭证: ``` export LLAMA_API_KEY="YOUR_LLAMA_API_KEY" ``` 创建模型服务提供方密钥: ``` PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "llama-api-prod", "provider": "llama", "api_key": "'"${LLAMA_API_KEY}"'", "api_base": "https://api.llama.com/compat/v1/", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` `provider` 必须是目录 ID `llama`。不要添加 `adapter`:AISIX 会为目录模型服务提供方推导出 `openai` 适配器,并且仅接受 BYO 模型服务提供方密钥显式设置适配器。 API 基础 URL 包含 `/compat/v1/`。AISIX 会规范化末尾斜杠并追加 `/chat/completions`,从而生成上游路由 `https://api.llama.com/compat/v1/chat/completions`。 请勿将该基础地址替换为 `https://api.llama.com/v1`。后者采用 Meta 原生 Llama API 协议,其 Chat 响应和流式事件结构不同于 OpenAI Chat Completions。AISIX `openai` 适配器要求使用 `/compat/v1` 接口。 ### 创建模型[​](#create-a-model "创建模型的直接链接") 列出上游账号可用的模型: ``` curl -sS "https://api.llama.com/compat/v1/models" \ -H "Authorization: Bearer ${LLAMA_API_KEY}" \ | jq -r '.data[].id' ``` 为返回的某个模型 ID 创建面向调用方的别名。此示例使用 Meta 当前[官方 Llama API 客户端示例](https://github.com/meta-llama/llama-api-python/blob/main/examples/chat.py)中的 Llama 4 Maverick 模型: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "llama-api-prod", "model_name": "Llama-4-Maverick-17B-128E-Instruct-FP8", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` `display_name` 是应用向 AISIX 发送的稳定别名。`model_name` 是发送给 Meta 的确切且区分大小写的 ID。请使用该账号 `/models` 请求返回的 ID,因为可用性可能因账号和 API 版本而变化。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建仅限访问此模型的调用方密钥: ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "llama-api-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` 明文调用方密钥仅在资源创建时返回。请安全存储。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送到网关的调用方 API Key: ``` export LLAMA_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "llama-api-prod" provider: "llama" adapter: "openai" api_key: ${LLAMA_API_KEY} api_base: "https://api.llama.com/compat/v1/" models: - display_name: "llama-api-prod" provider: "llama" model_name: "Llama-4-Maverick-17B-128E-Instruct-FP8" provider_key: "llama-api-prod" api_keys: - display_name: "llama-api-caller" key_env: CALLER_API_KEY allowed_models: - "llama-api-prod" ``` 如果 AISIX 安装在本地,请在加载前验证该文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中设置所引用的环境变量并启动网关。仅当这些变量已在进程中可用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,为下方的通用验证请求做好准备: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证模型服务提供方连接[​](#verify-the-provider-connection "验证模型服务提供方连接的直接链接") 导出 AISIX 网关源地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 发送聊天请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "llama-api-prod", "messages": [ { "role": "user", "content": "Say hello from the Meta Llama API." } ] }' ``` AISIX 将 `llama-api-prod` 解析为 `Llama-4-Maverick-17B-128E-Instruct-FP8`,向 Llama API 兼容端点发送经过 Bearer Token 认证的请求,并返回兼容 OpenAI 的响应。 ## 端点覆盖范围[​](#endpoint-coverage "端点覆盖范围的直接链接") 配置的 API 根地址是 Meta 的 OpenAI 兼容接口。AISIX 路由行为如下: | 路由 | 使用 `llama` 模型别名时的行为 | | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 通过 Meta `/compat/v1/chat/completions` 路由支持。Llama 4 模型可在 Chat 中接受图片内容块;这是视觉输入,不是图片生成。 | | `/v1/responses` | 通过 AISIX 跨服务提供方桥接支持,该桥接会将请求转换为 Chat Completions,再把结果转换回 Responses 结构。AISIX 不会把此请求转发到 Meta Responses 路由。没有 Chat 等价项的 OpenAI 特定字段会被忽略。 | | `/v1/messages` | 通过 AISIX Anthropic 到 Chat 的转换支持。`/v1/messages/count_tokens` 仍仅限 Anthropic 后端目标。 | | `/v1/embeddings` 和 `/v1/completions` | 不支持。Meta `/compat/v1` 根地址不提供这些路由。 | | `/v1/audio/*`、`/v1/images/generations`、`/v1/videos` 和 `/v1/rerank` | 不支持。路由特定的服务提供方门禁或 Meta 端点覆盖范围不接受此配置。 | | `/v1/batches` | 不支持。Meta 兼容根地址不提供此路由。 | | `/v1/files` 和 `/v1/fine_tuning/jobs` | 尚未验证。Meta 兼容根地址提供匹配路由,但此 AISIX 工作流尚未完成端到端验证,且上游缺少文件内容路由。在测试所需操作前请勿依赖。 | | `/passthrough/llama/*rest` | 通过以 `/compat/v1` 基础地址为目标的已配置[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用,可用于 AISIX 未建模的 `/moderations` 等兼容 Meta 路由。透传会保留请求体和响应体。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 | 透传不会重写 `model` 字段,因此原生操作需要模型时请发送确切的上游模型 ID。`/passthrough/llama` 前缀假定一条透传路由认领它:`target_url` 设为 `/compat/v1` 基础地址,凭证注入使用此服务提供方密钥;在调用方 Key 的 `allowed_routes` 上授予该路由。如果为 Meta 原生 `/v1` 资源添加第二个 `llama` 密钥,请在独立前缀下再建一条路由并绑定那把密钥。不要将规范化 Chat 路由到原生密钥,因为其响应协议不兼容 OpenAI。 转换与端点详情请参阅 [Responses](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)、[Anthropic Messages](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)和[模型服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 故障排除[​](#troubleshooting "故障排除的直接链接") | 现象 | 检查项 | | ---------------------------------- | ------------------------------------------------------------------------------------- | | 上游返回 `401` 或 `403` | 确认 `LLAMA_API_KEY` 有效,并且账户可以使用所选模型。 | | 上游返回 `404` | 确认 API 基础 URL 包含 `/compat/v1`,并从经过认证的 `/models` 响应中复制当前模型 ID。 | | 创建模型服务提供方密钥时返回 `400` | 使用 `provider: "llama"`,且不设置 `adapter` 字段。 | | AISIX 返回模型访问被拒绝 | 确认调用方密钥的 `allowed_models` 包含模型资源 ID。 | ## 后续步骤[​](#next-steps "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Meta Llama API 并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [模型服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md):轮换上游凭证或配置模型服务提供方特定的覆盖设置。 * [模型服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和模型服务提供方特定的限制。 --- # MiniMax [MiniMax](https://platform.minimax.io/docs/guides/quickstart) 通过其平台 API 提供托管生成式模型。应用通过稳定的 AISIX 别名调用 MiniMax,同时网关确保上游凭证不会出现在客户端代码中。 ## 前提条件[​](#prerequisites "前提条件的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [MiniMax 平台](https://platform.minimax.io/)获取的 MiniMax API Key。 * `curl` 和 `jq`。 ## 设置正确的基础 URL[​](#set-the-correct-base-url "设置正确的基础 URL的直接链接") MiniMax 为相同的模型提供两个上游接口: | 接口 | 根地址 | 请求格式 | | ---------------------------------------------------------------------------------- | ---------------------------------- | ----------------------- | | [OpenAI SDK](https://platform.minimax.io/docs/api-reference/text-openai-api) | `https://api.minimax.io/v1` | OpenAI chat completions | | [Anthropic SDK](https://platform.minimax.io/docs/api-reference/text-anthropic-api) | `https://api.minimax.io/anthropic` | Anthropic Messages | `minimax` 的社区目录条目发布的地址是 `https://api.minimax.io/anthropic/v1`,这是兼容 Anthropic 的接口,并明确包含原本由 Anthropic SDK 追加的版本路径;但目录默认分配的是 `openai` 适配器。两者并不匹配。如果省略 `api_base`,AISIX 会接受模型服务提供方密钥并填入该目录值,随后向期望 Anthropic Messages 格式的端点发送 OpenAI chat-completions 格式的请求,导致通过该别名的所有调用在上游失败。 警告 在 `minimax` 模型服务提供方密钥上始终将 `api_base` 设置为 `https://api.minimax.io/v1`。网关会将 `/chat/completions` 等端点路径追加到所配置的根地址,因此该根地址必须是 MiniMax 兼容 OpenAI 的 `/chat/completions` 所在的根地址。 下文配置的模型服务提供方密钥使用 `api_base` 处理 Chat Completions,并为 Messages 和 Count Tokens 单独声明 Base。参见[使用兼容 Anthropic 的接口](#use-the-anthropic-compatible-surface)。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为以 MiniMax 为后端的 Chat Completions、Messages 和 Count Tokens 创建模型服务提供方密钥、模型别名和调用方 API Key。 MiniMax 是一个社区目录模型服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行认证。由于目录发布的基础 URL 不是适配器所需的根地址,你还必须显式设置 `api_base`。请参阅[设置正确的基础 URL](#set-the-correct-base-url)。 ### 创建模型服务提供方密钥[​](#create-a-provider-key "创建模型服务提供方密钥的直接链接") 创建用于存储 MiniMax 凭证和 API 根地址的模型服务提供方密钥: ``` # 请替换为实际值 export MINIMAX_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "minimax-prod", "provider": "minimax", "api_key": "'"${MINIMAX_API_KEY}"'", "api_base": "https://api.minimax.io/v1", "apis": { "messages": { "base": "https://api.minimax.io/anthropic" } }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `minimax`。由于 `minimax` 是 models.dev 目录条目,AISIX Cloud Admin API 会接受该值,并从目录推导出适配器;`adapter` 字段仅适用于 BYO 模型服务提供方密钥。 ❷ `api_key` 存储 MiniMax API Key。MiniMax 使用 HTTP Bearer 认证其兼容 OpenAI 的接口,这也正是 `openai` 适配器发送的认证方式。该值遵循[模型服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://api.minimax.io/v1`,即 MiniMax 为 OpenAI 客户端库记录的 `base_url`。这是本页最重要的字段。省略它不会导致创建调用失败,因为目录发布了默认值;但会导致后续每个聊天请求失败,因为该默认值指向兼容 Anthropic 的根地址。 ❹ `apis.messages` 在同级 Base 上声明 MiniMax 的 Anthropic 兼容 Messages 和 Count Tokens 路由。MiniMax-M3 是本指南使用的模型,其 Count Tokens 已有文档说明。 仅供 MiniMax-M3 别名使用的服务提供方密钥应保留此声明。对于其他代次的模型,请使用不带 `apis.messages` 的单独服务提供方密钥,除非 MiniMax 已提供该模型支持 Count Tokens 的文档。 该命令将返回的模型服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#create-a-model "创建模型的直接链接") MiniMax 模型 ID 区分大小写,且不包含供应商前缀。其模式为 `MiniMax-<generation>`:供应商名称两部分的首字母 `M` 均为大写,后接可含小数的代次编号;某一代次的低延迟变体还可能带有 `-highspeed` 后缀。请勿转换为小写,也不要添加来自聚合服务的 `minimax/` 前缀。 当前模型 ID 包括: | 模型 ID | 说明 | | ------------------------ | ---------------------------------------------------------------------------- | | `MiniMax-M3` | 最新代次。在兼容 OpenAI 的 chat-completions 路由上接受文本、图像和视频输入。 | | `MiniMax-M2.7` | 上一代旗舰模型,仅接受文本输入。 | | `MiniMax-M2.7-highspeed` | 同一代次的低延迟变体。 | `MiniMax-M2.5`、`MiniMax-M2.5-highspeed`、`MiniMax-M2.1` 和 `MiniMax-M2` ID 作为早期代次仍保留在目录中。创建别名前,请查看 [MiniMax 模型文档](https://platform.minimax.io/docs/api-reference/api-overview)了解当前列表。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "minimax-m3-prod", "model_name": "MiniMax-M3", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 MiniMax 发布的确切模型 ID,例如 `MiniMax-M3`。 ❸ `provider_key_id` 将别名关联到 MiniMax 模型服务提供方密钥。 如需了解模型成本元数据和 AISIX Cloud 定价,请参阅[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并仅在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "minimax-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 的值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送到网关的调用方 API Key: ``` export MINIMAX_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "minimax-prod" provider: "minimax" adapter: "openai" api_key: ${MINIMAX_API_KEY} api_base: "https://api.minimax.io/v1" apis: messages: base: "https://api.minimax.io/anthropic" models: - display_name: "minimax-m3-prod" provider: "minimax" model_name: "MiniMax-M3" provider_key: "minimax-prod" api_keys: - display_name: "minimax-caller" key_env: CALLER_API_KEY allowed_models: - "minimax-m3-prod" ``` 如果 AISIX 安装在本地,请在加载前验证该文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中设置所引用的环境变量并启动网关。仅当这些变量已在进程中可用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,为下方的通用验证请求做好准备: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证模型服务提供方连接[​](#verify-the-provider-connection "验证模型服务提供方连接的直接链接") 导出 AISIX 网关源地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 chat-completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax-m3-prod", "messages": [ { "role": "user", "content": "Say hello from MiniMax." } ] }' ``` 网关返回兼容 OpenAI 的响应,其中会回显面向调用方的别名 `minimax-m3-prod`。 使用同一别名验证 MiniMax-M3 Count Tokens 路由: ``` curl -sS -X POST "$AISIX_PROXY/v1/messages/count_tokens" \ -H "x-api-key: ${AISIX_API_KEY}" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax-m3-prod", "messages": [ { "role": "user", "content": "Count this MiniMax prompt." } ] }' ``` 成功响应包含 `input_tokens`。如果 Chat Completions 正常而此请求失败,请检查 `apis.messages.base` 的值,并确认别名仍指向 MiniMax-M3。 如果 Chat Completions 请求失败,请按以下顺序检查: 1. 模型服务提供方密钥上的 `api_base`。上游返回 404,或上游错误提及非预期的请求字段,通常表示密钥仍指向 `https://api.minimax.io/anthropic/v1`,而不是 `https://api.minimax.io/v1`。 2. 如果上游返回认证错误,请检查模型服务提供方密钥上的 `api_key`。 3. 检查 `model_name` 的拼写和大小写。MiniMax 模型 ID 区分大小写。 ## 使用兼容 Anthropic 的接口[​](#use-the-anthropic-compatible-surface "使用兼容 Anthropic 的接口的直接链接") AISIX 可以把 Anthropic 形态请求转换为 MiniMax Chat Completions,但该桥接无法保留 MiniMax 完整的 Anthropic 兼容协议。本指南中的模型服务提供方密钥因此在同一凭证和别名上声明原生 Messages 协议面。原生与转换行为参见 [Anthropic Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md)。 该声明会把 `/v1/messages` 和 `/v1/messages/count_tokens` 发送到 `https://api.minimax.io/anthropic`,而 Chat Completions 继续使用 `api_base`。MiniMax-M3 提供 Count Tokens 文档;不要由此推断平台列出的所有模型都支持该接口。 ## 了解社区目录路径[​](#understand-the-community-catalog-path "了解社区目录路径的直接链接") 特色模型服务提供方包含由 AISIX 维护的适配器、认证方案、默认基础 URL,以及上游所需的请求或响应重写规则。`minimax` 不包含这些设置。控制台将它归入社区目录,AISIX 仅代为做出三项决定: * 适配器为 `openai`。 * 认证方案为 HTTP Bearer。 * 默认基础 URL 为 models.dev 为该模型服务提供方发布并缓存在 AISIX 模型服务提供方元数据中的值。 其他所有设置都需要由你提供。实际使用中,这意味着: * **你需要负责基础 URL。** 对于此模型服务提供方,发布的默认值与分配的适配器不匹配,因此应按照[设置正确的基础 URL](#set-the-correct-base-url)显式设置。仅当 models.dev 根本未发布模型服务提供方基础 URL 时,AISIX 才会以 400 错误拒绝创建调用;`minimax` 发布了默认值,因此请求会成功,而不匹配的问题会在之后暴露。 * **未注册任何请求或响应重写规则。** AISIX 将调用方的 Chat Completions 请求体转发给 MiniMax,不重命名任何参数,并从规范路径 `delta.reasoning_content` 规范化推理内容。它不会保留 MiniMax 独立的 `reasoning_details` 数组。请参阅[配置请求和响应覆盖设置](#configure-request-and-response-overrides)。 * **AISIX 不会为你跟踪上游契约。** MiniMax 更改其传输格式时,目录条目不会随之更改。MiniMax API 更新后,请使用非生产别名验证一个代表性请求。 用量记录仍会将该模型服务提供方密钥标记为品牌为 `minimax` 的目录密钥,并标记为非特色,因此可在用量数据中区分社区目录流量。 这些差异并不意味着 `minimax` 是能力较弱的上游。它是受支持的目录模型服务提供方,与任何其他别名一样支持调用方密钥、允许列表、速率限制和用量核算。在 AISIX Cloud 中,匹配的预算同样生效。区别仅在于由谁负责传输契约。 ## 配置请求和响应覆盖设置[​](#configure-request-and-response-overrides "配置请求和响应覆盖设置的直接链接") 由于 `minimax` 没有 AISIX 精选适配器映射,模型服务提供方密钥是记录 MiniMax 特定传输差异的唯一位置。除非配置 `request.param_renames`,否则 AISIX 会原样发送顶层请求字段。MiniMax-M3 当前同时接受 `max_tokens` 和 `max_completion_tokens`,因此本指南中的模型无需重命名。仅当所选模型要求不同字段名称时才添加重命名。 MiniMax-M3 的 `reasoning_split` 默认为 `false`,思考内容会保留在 `content` 的 `<think>` 标签中,AISIX 会保留该内容。如果将 `reasoning_split` 设置为 `true`,MiniMax 还会发出 `reasoning_content` 和 `reasoning_details` 数组。在 `/v1/chat/completions` 上,AISIX 会保留 `reasoning_content`,但丢弃 `reasoning_details`;Responses 桥接不会公开这两个字段。`response.reasoning_field` 覆盖设置也无法保留该数组。MiniMax 在包含工具的交错思考对话历史中要求完整数组,因此通过规范化 Chat 或 Responses 端点进行多轮工具循环时,请保持拆分推理关闭。应用依赖完整 Anthropic 思考和工具使用协议时,请使用[兼容 Anthropic 的接口](#use-the-anthropic-compatible-surface)。 如果其他模型从非标准 `delta` 路径流式返回标量推理内容,请在模型服务提供方密钥上将 `response.reasoning_field` 设置为该路径。AISIX 会将其映射到调用方看到的 `delta.reasoning_content`。请针对配置的模型用流式请求验证任何覆盖设置。 覆盖设置会应用于引用该模型服务提供方密钥的每个模型,因此请先使用非生产别名进行测试。请参阅[模型服务提供方特定的覆盖设置](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 连接中国平台[​](#connect-the-china-platform "连接中国平台的直接链接") MiniMax 在中国大陆运营独立平台,拥有自己的开发者控制台和主机名。它在目录中显示为独立的模型服务提供方 ID `minimax-cn`,且两个平台分别签发各自的 API Key,因此中国平台需要单独的模型服务提供方密钥。 同样需要修正基础 URL:目录默认值指向兼容 Anthropic 的根地址,而当前兼容 OpenAI 的根地址为 `https://api.minimax.cn/v1`。 ``` { "display_name": "minimax-cn-prod", "provider": "minimax-cn", "api_key": "YOUR_MINIMAX_CN_API_KEY", "api_base": "https://api.minimax.cn/v1", "apis": { "messages": { "base": "https://api.minimax.cn/anthropic" } }, "allowed_environments": ["YOUR_ENVIRONMENT_ID"] } ``` 目录为两个平台列出了相同的模型 ID,但不能保证特定代次的可用性相同。因此请根据[中国平台文档](https://platform.minimax.cn/docs/guides/quickstart)验证,而不要假定两者完全一致。 此中国平台示例中的 `apis.messages` 也仅适用于 MiniMax-M3。除非 MiniMax 已提供其他代次支持 Count Tokens 的文档,否则供其使用的密钥应省略该声明。 ## 端点覆盖范围[​](#endpoint-coverage "端点覆盖范围的直接链接") 此别名使用 MiniMax 兼容 OpenAI 的文本和多模态 Chat 接口。MiniMax 还提供原生图片、视频、语音、音乐和文件 API,但其路径和请求体与 AISIX 规范化媒体及作业协议不匹配。 | 路由 | MiniMax 别名的行为 | | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持,包括 `stream: true`。MiniMax-M3 可在此处接受图片和视频输入以进行多模态理解;该路由不会生成图片或视频。 | | `/v1/responses` | 通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持。AISIX 会将请求转换为 Chat Completions,而非调用 MiniMax `/v1/responses` 端点。没有 Chat 等价项的 OpenAI 特定 Responses 字段会被忽略。 | | `/v1/messages` 和 `/v1/messages/count_tokens` | 由于本指南声明了 `apis.messages`,请求会发送到 MiniMax 的 Anthropic 兼容路由。MiniMax-M3 提供 Count Tokens 文档;其他代次的模型可能不支持。 | | `/v1/embeddings` | 不要假定支持。AISIX 会将 OpenAI 格式的嵌入请求体原样转发到 `{api_base}/embeddings`,但 MiniMax 当前公开 API 文档未定义兼容 OpenAI 的嵌入协议或嵌入模型。请参阅[嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/images/generations` | 返回 400 错误而被拒绝。MiniMax 图片生成使用原生 `/v1/image_generation` 协议,可通过透传路由访问。 | | `/v1/rerank` | 返回 400 错误而被拒绝。该路由仅接受 `openai`、`cohere` 和 `jina` 模型服务提供方值。 | | `/v1/videos` | 返回 501 Not Implemented。MiniMax 视频生成使用原生 `/v1/video_generation` 协议,可通过透传路由访问。 | | `/passthrough/minimax/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 `/image_generation`、`/video_generation`、`/t2a_v2` 和 `/files/retrieve` 等原生路由。AISIX 会转发原生请求体和响应而不进行转换。 | 本页的 `/passthrough/minimax` 路径假定一条透传路由认领该前缀,`target_url` 设为 MiniMax 的 API 根地址并挂上此服务提供方密钥;在调用方 Key 的 `allowed_routes` 上授予路由名称。一条路由只中继到一个固定目标,因此配置了多个 MiniMax 账号或基础 URL 时,请为每个账号另建一条路由。AISIX 不会重写原生请求体中的 `model` 值。它会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 使用以本指南基础地址为目标的路由时,透传请求会基于 `https://api.minimax.io/v1` 解析。该根地址已以版本路径结尾,当透传路径的开头版本路径与其匹配时,网关会去除一个重复的版本路径。因此,`/passthrough/minimax/v1/image_generation` 和 `/passthrough/minimax/image_generation` 都会到达 `https://api.minimax.io/v1/image_generation`,而不是重复的 `/v1/v1/` URL。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 现在,你已将 AISIX 连接到 MiniMax 并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 MiniMax 和第二个模型服务提供方之间配置故障转移。 * [模型服务提供方特定的覆盖设置](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应格式。 * [模型服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和模型服务提供方特定的限制。 --- # Mistral AI [Mistral AI](https://docs.mistral.ai/) 开发并托管 Mistral 模型系列。AISIX 使应用能够使用网关签发的调用方密钥调用其 Chat 和兼容 API 接口。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Mistral 控制台](https://console.mistral.ai/api-keys)获取的 Mistral API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Mistral 支持的 chat-completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 由于 Mistral 提供兼容 OpenAI 的 API,AISIX 通过 `openai` 适配器连接,并将 Mistral API 根地址用作 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Mistral 凭证和 API 根地址的服务提供方密钥: ``` # 请替换为实际值 export MISTRAL_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "mistral-prod", "provider": "mistral", "api_key": "'"${MISTRAL_API_KEY}"'", "api_base": "https://api.mistral.ai/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `mistral`。AISIX Cloud Admin API 会从目录服务提供方推导适配器;适配器字段仅接受用于 BYO 服务提供方密钥。 ❷ `api_key` 存储 Mistral API Key。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 已包含 `/v1` 路径。AISIX 会向其追加 `/chat/completions`。对于此目录服务提供方,该字段是可选的,因为省略时 AISIX Cloud Admin API 会填入相同的值;但示例显式设置该字段,使上游根地址在资源中保持可见。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 以 `-latest` 结尾的 Mistral 模型 ID 会跟踪该模型的最新快照。如需固定特定版本,请使用 [Mistral 模型列表](https://docs.mistral.ai/models/overview)中带日期的模型 ID。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "mistral-large-prod", "model_name": "mistral-large-latest", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Mistral 模型 ID,例如 `mistral-large-latest` 或 `mistral-small-latest`。如果对 `mistral-small-latest` 使用结构化推理,请先阅读[了解结构化响应](#%E4%BA%86%E8%A7%A3%E7%BB%93%E6%9E%84%E5%8C%96%E5%93%8D%E5%BA%94),再启用该功能。 ❸ `provider_key_id` 将别名关联到 Mistral 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在响应中返回一次,请安全保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "mistral-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。 网关会自动获取新资源,无需重启。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export MISTRAL_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "mistral-prod" provider: "mistral" adapter: "openai" api_key: ${MISTRAL_API_KEY} api_base: "https://api.mistral.ai/v1" models: - display_name: "mistral-large-prod" provider: "mistral" model_name: "mistral-large-latest" provider_key: "mistral-prod" api_keys: - display_name: "mistral-caller" key_env: CALLER_API_KEY allowed_models: - "mistral-large-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "mistral-large-prod", "messages": [ { "role": "user", "content": "Say hello from Mistral." } ] }' ``` 网关返回兼容 OpenAI 的响应,其中会回显面向调用方的别名 `mistral-large-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 Mistral 模型 ID。 ## 了解结构化响应[​](#了解结构化响应 "了解结构化响应的直接链接") 当 `message.content` 或每个流式 `delta.content` 为字符串时,标准 Mistral Chat 响应可通过规范化 AISIX 端点正常工作。文本和 OpenAI 风格的图片输入块会转发给 Mistral Large 3 等兼容的多模态模型。 当前 Mistral 推理模型可能返回不同的数据结构。当设置 `reasoning_effort: "high"` 时,Mistral 会在 `content` 中返回由 `ThinkChunk` 和 `TextChunk` 对象组成的数组。AISIX OpenAI 适配器当前要求内容为字符串,因此会对这些响应返回上游解码错误。这同样适用于 `/v1/chat/completions` 以及最终使用同一 Chat 适配器的 Responses 和 Messages 桥接。`response.reasoning_field` 覆盖设置无法转换内容数组。 对于 `mistral-small-latest` 等支持推理的模型,请在规范化端点上使用 `reasoning_effort: "none"`。如需保留结构化推理并重放完整思考历史,请通过 `/passthrough/mistral/chat/completions` 调用 Mistral 原生 Chat 协议,并发送上游 Mistral 模型 ID,而非 AISIX 别名。本页的 `/passthrough/mistral` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 Mistral 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。路由会保留响应体,原生流式响应增量中继。 Mistral 还支持大于 `1` 的 `n`,但 AISIX 在规范化 Chat 路由上只返回第一个选项。当应用需要全部选项或其他服务提供方原生响应结构时,请使用透传。 ## 端点覆盖[​](#端点覆盖 "端点覆盖的直接链接") 本指南中的模型别名对应 Chat 模型。请为嵌入、转录、语音或其他能力创建使用相应 Mistral 模型 ID 的独立别名。 | 路由 | 使用 Mistral 别名时的行为 | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持内容为标量的响应,包括 `stream: true`、函数工具,以及所选模型支持的文本或图片输入。不支持结构化推理内容数组。 | | `/v1/responses` | 通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持。该桥接会转换为 Chat Completions,而非调用原生 Mistral Responses API。没有 Chat 等价项的字段会被忽略,且仍受结构化推理限制。 | | `/v1/messages` | 通过转换为 Chat Completions,为采用 Anthropic 协议的调用方提供支持。该别名以 OpenAI 为后端,因此 `/v1/messages/count_tokens` 会返回 400 错误。 | | `/v1/embeddings` | 使用 `mistral-embed` 等独立别名时支持。AISIX 会转发 `dimensions`,但 Mistral 将缩减维度字段命名为 `output_dimension`;如需使用,请配置请求参数重命名。 | | `/v1/audio/transcriptions` | 使用 `voxtral-mini-latest` 等转录别名时支持。AISIX 会中继 Mistral 响应,包括服务提供方特定字段,但会缓冲流式响应,而非逐步中继事件。 | | `/v1/audio/translations` | 不支持,因为 Mistral 未发布此路由。 | | `/v1/audio/speech` | 路径可到达 Mistral TTS,但协议不兼容 OpenAI。请发送 `voice_id` 等原生字段,并预期获得 Base64 JSON 或经过缓冲的 Mistral SSE 负载,而非原始音频字节。AISIX 不会转换该协议。 | | `/v1/files` | 支持上传、列出、检索、删除和内容下载。Mistral 的 `/v1/files/{id}/url` 签名 URL 路由可通过透传路由访问,但需要原始 Mistral 文件 ID。透传路由不会解码规范化上传所返回的 AISIX 路由 ID。 | | `/v1/batches` | 不支持。AISIX 转发 OpenAI `/v1/batches` 路径,而 Mistral 使用 `/v1/batch/jobs`。 | | `/v1/fine_tuning/jobs` | 不支持。AISIX 转发 OpenAI 作业接口并要求 `training_file`;Mistral 当前公开 API 未发布兼容的微调作业路由。 | | `/v1/completions` | 不支持。Mistral 代码补全使用原生 `/v1/fim/completions` 协议。 | | `/v1/images/generations` | 会返回 400 错误,因为该路由只接受 `openai` 服务提供方模型。Mistral 图片生成是内置工具,而非此 OpenAI 图片路由。 | | `/v1/rerank` | 会返回 400 错误,因为该路由不接受 `mistral` 服务提供方。Mistral 提供分类 API,而非此重排协议。 | | `/passthrough/mistral/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于原生 Mistral 路由及原始请求和响应体。服务提供方 SSE 响应增量中继。 | 透传路由适用于 Mistral 原生 OCR、内容审核、分类、FIM、批处理、Agents、Conversations 和结构化推理。例如,使用以 `https://api.mistral.ai/v1` 为目标的路由时,`/passthrough/mistral/ocr` 和 `/passthrough/mistral/v1/ocr` 都会解析为 `https://api.mistral.ai/v1/ocr`,因为 AISIX 会移除一个重复的版本路径段。 AISIX 不会重写透传请求体中的 `model` 值。路由提供上游基础 URL,inject 模式下还提供服务提供方密钥凭证;一条路由绑定一个目标和凭证,因此不同的 Mistral 账号或基础地址请配置独立路由。AISIX 会从每个请求中检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Mistral,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Mistral 和第二个服务提供方之间配置故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # ModelScope [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) 是面向开放权重模型的模型社区和托管推理平台。AISIX 为应用提供用于这些模型的统一兼容 OpenAI API,同时管理凭证、调用方访问权限、速率限制和用量核算。 ## 前提条件[​](#prerequisites "前提条件的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 ModelScope 账户获取的 ModelScope API Token。ModelScope [API-Inference 文档](https://modelscope.cn/docs/model-service/API-Inference/intro)说明了 Token 可用于推理请求前适用的账户激活和配额规则。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 ModelScope 支持的 chat-completions 路由创建模型服务提供方密钥、模型别名和调用方 API Key。 ModelScope 是提供兼容 OpenAI API-Inference 服务的社区目录模型服务提供方。AISIX 通过 `openai` 适配器连接,使用 Bearer Token 认证上游请求,并将 ModelScope API 根地址用作 `api_base`。发送生产流量前,请阅读[提供 AISIX 未策划的传输细节](#supply-the-wire-details-aisix-does-not-curate)。 ### 创建模型服务提供方密钥[​](#create-a-provider-key "创建模型服务提供方密钥的直接链接") 创建用于存储 ModelScope 凭证和 API 根地址的模型服务提供方密钥: ``` # 请替换为实际值 export MODELSCOPE_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "modelscope-prod", "provider": "modelscope", "api_key": "'"${MODELSCOPE_API_KEY}"'", "api_base": "https://api-inference.modelscope.cn/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `modelscope`。由于该 ID 存在于缓存的 models.dev 目录中,AISIX Cloud Admin API 会接受此值,并应用目录的默认规则:使用 `openai` 适配器和 HTTP Bearer 认证。不要设置 `adapter` 字段,AISIX Cloud Admin API 仅接受在 BYO 模型服务提供方密钥上设置该字段。 ❷ `api_key` 存储 ModelScope API Token。`openai` 适配器会在 `Authorization: Bearer` 请求头中发送该 Token。该值遵循[模型服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://api-inference.modelscope.cn/v1`,这是 ModelScope 兼容 OpenAI 的 chat-completions 端点 `https://api-inference.modelscope.cn/v1/chat/completions` 所在的 API 根地址。AISIX 会将 `/chat/completions` 等端点路径追加到存储的值。对于 `modelscope`,此字段可选,因为省略时控制平面会从目录填入相同的根地址。示例显式设置该字段,以便配置中清楚显示每个密钥所指向的根地址。 警告 请存储 API 根地址,而不是完整端点 URL,也不是不带路径的主机地址。如果粘贴的值末尾带有 `/chat/completions`,AISIX 会将其移除,但不会为非 OpenAI 主机合成 `/v1` 路径。将 `api_base` 设置为 `https://api-inference.modelscope.cn` 会生成指向 `https://api-inference.modelscope.cn/chat/completions` 的上游请求,而 ModelScope 不提供该路径。 这些示例面向 ModelScope 中国站。ModelScope 国际站使用 `https://api-inference.modelscope.ai/v1`;如果 Token 和模型来自 `modelscope.ai`,请显式设置该根地址。目录默认值仍为 `.cn` 根地址,因此省略 `api_base` 不会自动选择国际站。 该命令将返回的模型服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#create-a-model "创建模型的直接链接") ModelScope 模型 ID 带有组织命名空间。每个 ID 都复用了 ModelScope 模型页面的 `organization/model` 路径,包括大小写。AISIX 模型服务提供方目录中的当前 ID 包括: | 模型 ID | 上下文窗口 | 说明 | | ------------------------------------ | ------------- | ---------------------------------------- | | `Qwen/Qwen3-235B-A22B-Instruct-2507` | 262,144 Token | 指令模型,不输出推理内容。 | | `Qwen/Qwen3-235B-A22B-Thinking-2507` | 262,144 Token | 相同权重的推理变体。 | | `Qwen/Qwen3-Coder-30B-A3B-Instruct` | 262,144 Token | 编程和软件 Agent 模型。 | | `ZhipuAI/GLM-4.6` | 202,752 Token | 在 `ZhipuAI` 组织下提供的 GLM 旗舰模型。 | 创建别名前,请在模型的 ModelScope 页面上确认 ID,因为 API-Inference 提供的模型集合会随时间变化。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "modelscope-qwen-prod", "model_name": "Qwen/Qwen3-235B-A22B-Instruct-2507", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是完整的 ModelScope 模型 ID,包括组织前缀。省略该前缀,或复用同一权重在其他托管平台上的无前缀 ID(例如 `qwen3-235b-a22b-instruct-2507`),都会导致上游返回找不到模型的错误。 ❸ `provider_key_id` 将别名关联到 ModelScope 模型服务提供方密钥。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并仅在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "modelscope-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 的值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送到网关的调用方 API Key: ``` export MODELSCOPE_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "modelscope-prod" provider: "modelscope" adapter: "openai" api_key: ${MODELSCOPE_API_KEY} api_base: "https://api-inference.modelscope.cn/v1" models: - display_name: "modelscope-qwen-prod" provider: "modelscope" model_name: "Qwen/Qwen3-235B-A22B-Instruct-2507" provider_key: "modelscope-prod" api_keys: - display_name: "modelscope-caller" key_env: CALLER_API_KEY allowed_models: - "modelscope-qwen-prod" ``` 如果 AISIX 安装在本地,请在加载前验证该文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中设置所引用的环境变量并启动网关。仅当这些变量已在进程中可用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,为下方的通用验证请求做好准备: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证模型服务提供方连接[​](#verify-the-provider-connection "验证模型服务提供方连接的直接链接") 导出 AISIX 网关源地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 chat-completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "modelscope-qwen-prod", "messages": [ { "role": "user", "content": "Say hello from ModelScope." } ] }' ``` 网关返回兼容 OpenAI 的响应,其中会回显面向调用方的别名 `modelscope-qwen-prod`。如果请求失败,请检查模型服务提供方密钥的 `api_key`、`api_base` 根地址,以及 `model_name` 中带组织前缀的模型 ID。 ## 在 ModelScope 与阿里云百炼之间选择[​](#choose-between-modelscope-and-alibaba-cloud-model-studio "在 ModelScope 与阿里云百炼之间选择的直接链接") ModelScope 和阿里云百炼都提供 Qwen 模型,但它们是独立的上游,在 AISIX 中使用不同的模型服务提供方 ID。选择错误的上游会导致上游认证或找不到模型错误,而不是在创建时返回配置错误,因此请先确认凭证由哪项服务签发。 | | ModelScope | 阿里云百炼 | | -------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------ | | 模型服务提供方 ID | `modelscope` | `alibaba` | | 目录层级 | 社区 | 精选 | | 设置指南 | 本页 | [Qwen(阿里云)](https://docs.apiseven.com/ai-gateway/providers/qwen.md) | | API 根地址 | `https://api-inference.modelscope.cn/v1` | 特定于地域的 DashScope 兼容 OpenAI 根地址 | | 凭证 | ModelScope API Token | 按地域签发的 DashScope API Key | | 模型 ID 格式 | 带组织命名空间的仓库路径,例如 `Qwen/Qwen3-235B-A22B-Instruct-2507` | 百炼模型名称,例如 `qwen-plus` | | 已建模的 `/v1/videos` 路由 | 拒绝 | 支持 | 相同区别也适用于 GLM。ModelScope 在 `ZhipuAI` 组织下提供 GLM 权重,但由 `modelscope` 模型服务提供方支持的 GLM 别名,并不等同于由 [Zhipu AI(GLM)](https://docs.apiseven.com/ai-gateway/providers/zhipuai.md)中介绍的精选 `zhipuai` 模型服务提供方支持的别名。按模型服务提供方标签分派的网关接口(例如已建模的[视频生成路由](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md))依据模型上记录的模型服务提供方,而不是依据上游恰好提供的权重来决定行为。 ## 提供 AISIX 未策划的传输细节[​](#supply-the-wire-details-aisix-does-not-curate "提供 AISIX 未策划的传输细节的直接链接") 对于具有 AISIX 精选适配器映射的模型服务提供方,目录会记录适配器、认证方案、默认 API 根地址以及所有请求或响应特性。ModelScope 没有此类映射。它通过目录的默认规则解析:获得 `openai` 适配器和 Bearer 认证,并被标记为来源于社区;除非操作人员按密钥覆盖,否则其传输兼容性会被假定为 OpenAI 格式。超出该假设的所有设置都需要由你配置。 实际使用中: * **未注册参数重命名规则。** AISIX 会按照调用方发送的形式原样转发顶层 chat-completions 参数。某些精选模型服务提供方会为 `max_completion_tokens` 等字段设置重命名规则;ModelScope 没有此类规则,因此适用于已重命名模型服务提供方的请求体并不会自动适用于此处,反之亦然。 * **未注册响应字段重新映射。** AISIX 已经会将到达 `message.reasoning_content`、`delta.reasoning_content` 或 `message.reasoning` 的推理内容规范化到标准 `reasoning_content` 字段。除非进行映射,否则不会重新映射从其他流式 `delta` 路径传递的推理内容。 * **不适用模型服务提供方范围的推理控制。** ModelScope 没有发布跨越其所提供模型的通用推理开关、推理强度级别或思考 Token 预算,因此推理行为取决于各个模型。请按模型 ID 进行验证:`Qwen/Qwen3-235B-A22B-Thinking-2507` 的设计会进行推理,而 `Qwen/Qwen3-235B-A22B-Instruct-2507` 则不会。 这两类调整都是模型服务提供方密钥字段。将它们添加到创建模型服务提供方密钥的请求中,或声明式资源文件中的模型服务提供方密钥条目中: ``` { "request": { "param_renames": { "max_completion_tokens": "max_tokens" } }, "response": { "reasoning_field": "delta.thinking" } } ``` 仅当 ModelScope 提供的特定模型拒绝客户端已发送的参数名称时,才使用 `request.param_renames`;仅当流式响应从 `delta.reasoning_content` 以外的路径携带推理内容时,才使用 `response.reasoning_field`。有关字段目录以及每个覆盖设置适用的适配器,请参阅[模型服务提供方特定的覆盖设置](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 模型服务提供方密钥上的覆盖设置会应用于引用它的每个模型,因此请先使用非生产别名验证变更。出于同样原因,如果所提供模型的行为不同,可以考虑为每个组织命名空间使用一个模型服务提供方密钥:`Qwen/*` 和 `ZhipuAI/*` 共享一个端点,但属于不同的模型系列。通过每个新别名发送缓冲和流式请求,并在将流量路由到该别名前,确认客户端读取的字段均存在。 ## 核算成本和共享配额[​](#account-for-cost-and-shared-quota "核算成本和共享配额的直接链接") 对于规范化模型请求,托管控制平面使用确切的 `(provider, model name)` 对解析每个请求的成本;没有匹配的组织覆盖设置时,会回退到 models.dev 目录的默认值。ModelScope 目录条目发布的输入和输出价格均为零,因此这些用量事件会记录 Token 数量,但解析出的支出为 `$0.00`。根据该支出评估的预算永远不会增长,`least_cost` 路由组也会将该别名视为免费。 如果成本报告或预算必须反映组织使用 ModelScope 流量的实际成本,请为模型服务提供方 `modelscope` 和配置时使用的确切模型名称添加组织定价覆盖设置,其中包括组织前缀。请参阅[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)。 网关后的所有调用方共享同一个上游 ModelScope 账户,因此上游配额拒绝会同时影响所有调用方。请设置网关侧限制,避免单个调用方耗尽共享账户:将速率限制关联到模型别名、调用方 API Key,或同时关联到两者。请参阅 [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md)。 ## 端点覆盖范围[​](#endpoint-coverage "端点覆盖范围的直接链接") ModelScope API-Inference 提供多个 OpenAI 和 Anthropic 格式端点,但只有部分规范化 AISIX 代理接口适用于 ModelScope 支持的别名。下表所称“支持”说明 AISIX 如何处理请求,并不表示 AISIX 会调用 ModelScope 同名原生端点。 | 路由 | ModelScope 别名的行为 | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/completions` | 不支持。ModelScope API-Inference 不提供旧版 Completions 路径。 | | `/v1/responses` | 通过 Chat 适配器路径上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持。它不会调用 ModelScope 原生 `/v1/responses` 端点,且没有 Chat 等价项的 Responses 字段会被忽略。需要原生 Responses 语义时请使用透传路由。 | | `/v1/messages` | 通过转换为 Chat Completions 支持 Anthropic 格式调用方,并不调用 ModelScope 原生 `/v1/messages` 端点。 | | `/v1/messages/count_tokens` | 此指南中的 `modelscope` 配置会被拒绝,因为规范化计数器要求 Anthropic 后端模型。可通过透传路由访问 ModelScope 原生计数器。 | | `/v1/embeddings` | 通过 `openai` 适配器分派,因此仅当配置的模型由上游 `/v1/embeddings` 路径提供时才有效。AISIX 模型服务提供方目录中的 ModelScope 条目是文本聊天模型。请参阅[嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/audio/*`、`/v1/files`、`/v1/batches` 和 `/v1/fine_tuning/jobs` | 此服务提供方不可用。ModelScope API-Inference 不在配置的 API 根地址下提供兼容路径。 | | `/v1/images/generations` | 返回 400 错误而被拒绝。该路由仅接受模型服务提供方为 `openai` 的模型。可通过透传路由访问 ModelScope 原生异步图片生成工作流。 | | `/v1/rerank` | 返回 400 错误而被拒绝。该路由仅接受 `openai`、`cohere` 和 `jina` 模型服务提供方值。 | | `/v1/videos` | 返回 `501 not_implemented` 而被拒绝。该路由按模型服务提供方标签分派,`modelscope` 不在其接受的标签中,即使是 `zhipuai` 模型服务提供方可在此路由上驱动的 GLM 权重也不例外。 | | `/passthrough/modelscope/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于模型服务提供方原生路由,包括 `/responses`、`/messages`、`/messages/count_tokens`、`/images/generations` 和 `/tasks/{task_id}`。 | ModelScope 原生 API 接口不同于规范化 AISIX 接口。例如,ModelScope 图片生成会在 `/v1/images/generations` 启动异步作业并返回任务 ID,应用随后轮询 `/v1/tasks/{task_id}`。使用以本指南 API 根地址为目标的透传路由时,请通过 `/passthrough/modelscope/images/generations` 和 `/passthrough/modelscope/tasks/{task_id}` 调用这些路由。启动作业时发送 `X-ModelScope-Async-Mode: true`,轮询时发送 `X-ModelScope-Task-Type: image_generation`,并在原生请求体中使用确切的 ModelScope 图片模型 ID。 这些路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领 `/passthrough/modelscope` 前缀,`target_url` 设为 `https://api-inference.modelscope.cn/v1` 并用 ModelScope 服务提供方密钥做凭证注入;在调用方 Key 的 `allowed_routes` 上授予路由名称。前导 `/v1` 与目标末尾路径段重复时会被移除,因此在 `/passthrough/modelscope` 后添加它会到达相同上游 URL。网关不会重写请求体中的 AISIX 别名,原生 `model` 字段也不会选择凭证——路由绑定一个目标和服务提供方密钥,不同的 ModelScope 账号或根地址请使用独立路由。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。AISIX 会增量中继服务提供方 SSE,而不是缓冲事件。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 现在,你已将 AISIX 连接到 ModelScope 并验证了模型别名。接下来可阅读以下指南: * [模型服务提供方特定的覆盖设置](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当此上游与 `openai` 适配器的假设不同时,调整请求和响应格式。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):从 ModelScope 故障转移到提供相似权重的第二个模型服务提供方。 * [Qwen(阿里云)](https://docs.apiseven.com/ai-gateway/providers/qwen.md):当凭证来自百炼时,改为配置精选阿里云百炼上游。 * [模型服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和模型服务提供方特定的限制。 --- # Moonshot AI(Kimi) [Moonshot AI](https://platform.moonshot.ai/) 通过托管 API 提供 Kimi 模型系列。应用通过稳定的 AISIX 别名调用 Kimi,同时网关确保 Moonshot 凭证不会出现在客户端代码中。 ## 前提条件[​](#prerequisites "前提条件的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Kimi API 平台](https://platform.moonshot.ai/)获取的 Moonshot API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Moonshot 支持的 chat-completions 路由创建模型服务提供方密钥、模型别名和调用方 API Key。 由于 Moonshot AI 提供兼容 OpenAI 的 API,AISIX 通过 `openai` 适配器连接,并使用创建凭证所在区域的 API 根地址。 ### 创建模型服务提供方密钥[​](#create-a-provider-key "创建模型服务提供方密钥的直接链接") Moonshot AI 通过两个独立主机提供 API,目录将它们建模为两个不同的模型服务提供方 ID。请选择与创建 API Key 的控制台相匹配的组合: | 模型服务提供方 ID | API 根地址 | 适用情况 | | ----------------- | ---------------------------- | -------------------- | | `moonshotai` | `https://api.moonshot.ai/v1` | 密钥在全球平台签发。 | | `moonshotai-cn` | `https://api.moonshot.cn/v1` | 密钥在中国平台签发。 | 两个主机是具有独立控制台的不同部署,因此一个平台签发的密钥无法在另一个平台上认证。请选择与密钥匹配的模型服务提供方 ID,不要将一个 ID 指向另一个平台的主机:用量记录和成本报告会根据模型服务提供方 ID 归属流量。 对于新建服务提供方密钥,两个 ID 的 `api_base` 都是可选字段。AISIX Cloud Admin API 会为 `moonshotai` 填入全球根地址,为 `moonshotai-cn` 填入中国根地址。示例显式设置该字段,使目标平台保持可见。 在区域默认值修正前创建的旧 `moonshotai` 密钥可能仍固定到中国根地址。使用全球平台凭证更新此类配置时,请显式设置全球根地址。 以下示例使用 `moonshotai`。如果账户位于中国平台,请在所有位置分别替换为 `moonshotai-cn` 和 `https://api.moonshot.cn/v1`。 创建用于存储 Moonshot 凭证和 API 根地址的模型服务提供方密钥,并保存其 ID: ``` # 请替换为实际值 export MOONSHOT_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "moonshot-prod", "provider": "moonshotai", "api_key": "'"${MOONSHOT_API_KEY}"'", "api_base": "https://api.moonshot.ai/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `moonshotai`,不是 `moonshot` 或 `kimi`。AISIX Cloud Admin API 仅接受目录中的模型服务提供方 ID,并会以 `400 INVALID_REQUEST` 拒绝其他拼写。AISIX Cloud Admin API 会从目录模型服务提供方推导适配器;`adapter` 字段仅接受用于 BYO 模型服务提供方密钥。 ❷ `api_key` 存储 Moonshot API Key,并作为 Bearer Token 发送。该值在存储前加密,读取端点绝不会返回它。它遵循[模型服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 已包含 `/v1` 路径,因为 Moonshot AI 在 `/v1` 下而非主机根地址上提供兼容 OpenAI 的接口。AISIX 会将端点路径追加到该值,因此应使用 `https://api.moonshot.ai/v1`,末尾不要带 `/chat/completions`。如需路由到中国平台,请创建单独的模型服务提供方密钥,将 `provider` 设置为 `moonshotai-cn`,并将 `api_base` 设置为 `https://api.moonshot.cn/v1`。 ❹ `apis.responses` 告诉 AISIX 把 `/v1/responses` 转发到 Moonshot 原生 Responses API,而不是通过 Chat Completions 转换请求。两个区域的 API 根地址都实现了该路由,该路由当前仅支持 `kimi-k3`。 该命令将返回的模型服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#create-a-model "创建模型的直接链接") Moonshot 模型 ID 遵循 `kimi-<generation>` 模式,并可带有用于特定任务或吞吐量变体的可选后缀。例如,`kimi-k2.6` 是通用模型,`kimi-k2.7-code` 是编程模型,`kimi-k2.7-code-highspeed` 是其高吞吐量变体。`kimi-k3` 是当前旗舰模型。Moonshot AI 会停用早期 `kimi-k2-*-preview` ID 等较旧快照,因此固定 ID 前,请对照 [Kimi 模型列表](https://platform.kimi.ai/docs/models)确认。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "kimi-k3-prod", "model_name": "kimi-k3", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。别名与上游 ID 相互独立,因此不需要包含代次编号。 ❷ `model_name` 是 Moonshot 模型 ID。本示例使用 `kimi-k3`,因为 Moonshot 原生 Responses API 当前仅支持该模型。其他模型 ID 包括 `kimi-k2.6` 和 `kimi-k2.7-code`;请准确保留点号和其他标点。 ❸ `provider_key_id` 将别名关联到 Moonshot 模型服务提供方密钥。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。网关会生成密钥值,并仅在创建响应中返回一次明文,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "moonshot-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 的值通过 ID 引用模型,因此该密钥只能访问你创建的别名。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送到网关的调用方 API Key: ``` export MOONSHOT_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "moonshot-prod" provider: "moonshotai" adapter: "openai" api_key: ${MOONSHOT_API_KEY} api_base: "https://api.moonshot.ai/v1" apis: responses: {} models: - display_name: "kimi-k3-prod" provider: "moonshotai" model_name: "kimi-k3" provider_key: "moonshot-prod" api_keys: - display_name: "moonshot-caller" key_env: CALLER_API_KEY allowed_models: - "kimi-k3-prod" ``` 如果 AISIX 安装在本地,请在加载前验证该文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中设置所引用的环境变量并启动网关。仅当这些变量已在进程中可用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,为下方的通用验证请求做好准备: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证模型服务提供方连接[​](#verify-the-provider-connection "验证模型服务提供方连接的直接链接") 导出 AISIX 网关源地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 chat-completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k3-prod", "messages": [ { "role": "user", "content": "Say hello from Kimi." } ] }' ``` 网关返回兼容 OpenAI 的响应,其中会回显面向调用方的别名 `kimi-k3-prod`。如果请求失败,请检查模型服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 Moonshot 模型 ID。如果密钥在 Moonshot 控制台中有效,但认证失败,通常表示 `api_base` 主机与签发该密钥的平台不匹配。 使用同一 K3 别名验证原生 Responses 路由: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k3-prod", "input": "Say hello from Kimi through the Responses API." }' ``` 由于模型服务提供方密钥声明了 `apis.responses`,AISIX 会把该请求转发到 Moonshot 原生路由,而不是通过 Chat Completions 转换。 ## 使用思考模式[​](#use-thinking-mode "使用思考模式的直接链接") 当前 Kimi 代次使用不同的推理控制。已配置的 Kimi K3 模型会对每个请求进行推理。请在顶层设置其推理强度: ``` { "reasoning_effort": "high" } ``` AISIX 会将自身未建模的顶层请求字段(包括 `thinking`)原样转发给上游,因此使用此控制无需模型服务提供方密钥覆盖设置。不同模型代次的推理控制存在差异: | 模型 | 推理控制 | 跨轮保留思考 | | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `kimi-k2.6` | `thinking.type` 接受 `enabled`(默认)或 `disabled`。 | `thinking.keep` 默认为 `null`;设置为 `all` 可保留历史 `reasoning_content`。 | | `kimi-k2.7-code` 和 `kimi-k2.7-code-highspeed` | 推理始终启用。省略 `thinking`,或使用唯一接受的类型 `enabled`。 | 始终启用。唯一接受的显式 `thinking.keep` 值是 `all`。 | | `kimi-k3` | 推理始终启用,且不支持 `thinking` 对象。将顶层 `reasoning_effort` 设置为 `low`、`high` 或 `max`(默认)。 | 始终启用。 | 对于 Kimi K2.6,可使用以下请求字段关闭推理: ``` { "thinking": { "type": "disabled" } } ``` 有关每个模型接受的参数,请查阅 [Kimi 思考模式指南](https://platform.kimi.ai/docs/guide/use-thinking-models)。 Moonshot AI 在 `reasoning_content` 字段中返回推理文本,这也是 AISIX 已经规范化到的标准字段。在流式响应中,`reasoning_content` 增量先于 `content` 增量到达;在非流式响应中,该字段位于 `choices[0].message.reasoning_content`。由于上游格式已经匹配,`moonshotai` 目录条目未设置 `response.reasoning_field` 覆盖规则,也不需要设置。仅当某个上游从其他 `delta` 路径流式返回推理内容时,才设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 对于 K3 和 K2.7 工具循环或多轮对话,请将 AISIX 返回的完整助手消息追加到下一次 Chat Completions 请求。AISIX 会在该路由上保留消息级 `reasoning_content`。如果只复制 `content` 和 `tool_calls`,会丢失这些模型要求的推理历史。K2.6 设置 `thinking.keep` 为 `all` 时同样适用。 推理 Token 和最终答案 Token 共享 Moonshot AI 的 `max_completion_tokens` 预算。已弃用的 `max_tokens` 字段仍可接受。当推理密集型提示词返回的内容被截断时,请提高限制。 ## 查看端点支持[​](#review-endpoint-support "查看端点支持的直接链接") Moonshot 主要提供 Chat Completions,以及兼容 OpenAI 的文件和批处理管理。AISIX 行为同时取决于适配器和特定路由的服务提供方检查: | 路由 | 使用 Moonshot 别名时的行为 | | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持,包括流式传输、工具、结构化输出,以及兼容 Kimi 模型上的图片或视频内容块。 | | `/v1/responses` | 当模型服务提供方密钥像本页示例一样声明 `apis.responses` 时,`kimi-k3` 会使用 Moonshot 原生 Responses API。其他 Kimi 模型当前不支持此原生路由。如果没有此声明,AISIX 会通过 Chat Completions 转换请求,无法保留 Responses 专属字段。 | | `/v1/messages` | 默认转换到 Chat Completions,因此不会把 Moonshot 推理历史保留为 Anthropic 思考块。Moonshot 原生 Messages 路由要求 Bearer 身份认证,且不提供 `/v1/messages/count_tokens`,因此与 `apis.messages` 不兼容;需要原生格式时,请使用带身份认证的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 | | `/v1/files` 和 `/v1/batches` | 通过 `openai` 适配器支持。AISIX 会重写返回的资源 ID,使后续文件和批处理调用路由到同一别名。上传的批处理 JSONL 文件中的每个请求必须使用上游 Kimi 模型 ID(例如 `kimi-k2.6`);AISIX 不会重写文件中的模型名称。 | | `/v1/embeddings`、`/v1/completions`、`/v1/audio/*` 和 `/v1/fine_tuning/jobs` | 不支持。Moonshot 未为这些路由记录兼容的上游端点。 | | `/v1/images/generations` | 返回 `400` 而被拒绝。该路由要求模型服务提供方为 `openai`。 | | `/v1/rerank` | 返回 `400` 而被拒绝。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/videos` | 返回 `501 not_implemented` 而被拒绝。路由允许列表不包含 `moonshotai`。Kimi 的视频能力是通过 Chat 输入理解视频,而非生成视频。 | | `/passthrough/moonshotai/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于路由 `/v1` 目标下的 Moonshot 原生路由。 | 规范化 `/v1/files` 返回的路由 ID 适用于后续规范化文件和批处理路由,但它不是原始 Moonshot 文件 ID。当 Kimi Chat 消息必须以 `ms://<file-id>` 引用上传的图片或视频时,请通过 `/passthrough/moonshotai/files` 上传和管理资源,使应用获得原生 ID。 对于 AISIX 未建模的 Moonshot 原生端点,请使用[模型服务提供方透传](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。本页的 `/passthrough/moonshotai` 路径假设已有一条路由声明该前缀,并将 `target_url` 设为 `https://api.moonshot.ai/v1`;还需在调用方 API Key 的 `allowed_routes` 中授权该路由名称: ``` curl -sS -X GET "$AISIX_PROXY/passthrough/moonshotai/v1/models" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 透传会保留调用方认证;inject 模式路由会把路由服务提供方密钥的凭证注入上游。当请求路径以路由 `target_url` 末尾已有的相同版本路径开头时,AISIX 会合并重复部分,因此上述请求会到达 `https://api.moonshot.ai/v1/models`,而不是重复的 `/v1/v1` 路径。 其他实用原生路径包括 `/tokenizers/estimate-token-count`、`/users/me/balance`、`/files` 和 `/batches`。透传不会重写 AISIX 模型别名或资源 ID,并会增量中继上游响应和 SSE。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。每条路由绑定一个固定目标,inject 模式下还绑定一把服务提供方密钥,因此使用多个 Moonshot 账号或根地址时请分别建路由。 Moonshot 兼容 Anthropic 的 API 使用独立的 `https://api.moonshot.ai/anthropic` 根地址。它不在本指南使用的 `/v1` 根地址下,因此以该根地址为目标的路由无法访问它。请为兼容 Anthropic 的 API 配置独立的 inject 模式透传路由;AISIX 会把模型服务提供方密钥作为 Bearer 身份认证发送,同时保留原生请求和响应体。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Moonshot AI 并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Moonshot AI 和第二个模型服务提供方之间配置故障转移。 * [模型服务提供方特定的覆盖设置](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应格式。 * [模型服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和模型服务提供方特定的限制。 --- # Nebius Token Factory [Nebius Token Factory](https://docs.tokenfactory.nebius.com/api-reference/inference/create-chat-completion) 为模型目录提供托管推理服务。AISIX 为应用提供稳定别名,同时由网关保存 Token Factory API Key。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一个 Nebius Token Factory API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` Nebius 是提供 OpenAI 兼容 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行身份认证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` export NEBIUS_API_KEY="YOUR_NEBIUS_API_KEY" PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nebius-prod", "provider": "nebius", "api_key": "'"${NEBIUS_API_KEY}"'", "api_base": "https://api.tokenfactory.nebius.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` 不要在目录服务提供方密钥中添加 `adapter`。AISIX 会从目录中派生 `openai` 适配器和 Bearer 身份认证方案。即使同步目录中已有相同值,显式设置 API Base 仍可在配置中清楚显示目标地址。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Nebius 模型 ID 包含发布方命名空间。请使用完整 ID 创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nebius-llama-prod", "model_name": "meta-llama/Llama-3.3-70B-Instruct", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` 如需使用其他模型,请从当前 Nebius 模型目录中复制相应 ID,不要删除或更改发布方前缀。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nebius-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export NEBIUS_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "nebius-prod" provider: "nebius" adapter: "openai" api_key: ${NEBIUS_API_KEY} api_base: "https://api.tokenfactory.nebius.com/v1" models: - display_name: "nebius-llama-prod" provider: "nebius" model_name: "meta-llama/Llama-3.3-70B-Instruct" provider_key: "nebius-prod" api_keys: - display_name: "nebius-caller" key_env: CALLER_API_KEY allowed_models: - "nebius-llama-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "nebius-llama-prod", "messages": [ { "role": "user", "content": "Say hello from Nebius Token Factory." } ] }' ``` 上游请求使用 `POST /v1/chat/completions`、准确的 Nebius 模型 ID,以及 `Authorization: Bearer <NEBIUS_API_KEY>`。 ## 查看模型能力[​](#查看模型能力 "查看模型能力的直接链接") Nebius Token Factory 在同一 API 根地址上提供 Chat、推理、视觉、嵌入、重排和图片模型。能力仍取决于所选模型。本指南中的 `meta-llama/Llama-3.3-70B-Instruct` 是当前的纯文本 Chat 模型,支持函数工具和结构化输出,但不是推理或视觉模型。 在规范化 Chat Completions 请求上,AISIX 会转发 OpenAI 风格的工具、结构化输出控制、带类型的图片或视频内容块,以及 `reasoning_effort` 等顶层字段。对于支持推理的 Nebius 模型,AISIX 会将上游 `reasoning_content` 或 `reasoning` 规范化为返回的助手消息中的 `reasoning_content`。当 `n` 大于 `1` 时 Nebius 可返回多个选项,但 AISIX 在规范化 Chat 路由上只返回第一个选项。应用需要全部选项或其他服务提供方原生响应结构时,请使用透传路由。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") | 路由 | 使用 Nebius 别名时的行为 | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持,包括流式传输、工具、结构化输出、推理,以及所选模型支持的多模态内容。 | | `/v1/completions` | 对接受旧版 Completions 协议的 Nebius 模型,通过 `openai` 适配器支持。 | | `/v1/responses` | 通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持;该桥接会转换为 Chat Completions,而非调用 Nebius 原生 Responses API。没有 Chat 等价项的字段(包括状态和原生工具语义)会被忽略;Responses 推理控制和 Nebius 推理输出不会保留。需要原生 Responses 语义时请使用透传路由。 | | `/v1/messages` | 通过 Anthropic 到 Chat 的转换支持,并非 Nebius 原生 Messages API。桥接不会将 Nebius 推理保留为 Anthropic 思考块。`/v1/messages/count_tokens` 要求 Anthropic 后端模型,因此会拒绝此配置。 | | `/v1/embeddings` | 使用当前 Nebius 嵌入模型(例如 `Qwen/Qwen3-Embedding-8B`)的独立别名时支持。 | | `/v1/files` | 支持上传、列出、检索、删除和内容下载。AISIX 会重写返回的文件 ID,使后续规范化调用路由到同一别名。 | | `/v1/fine_tuning/jobs` | 支持创建、列出、检索和取消。在创建请求中,`model` 必须是上游 Nebius 基础模型 ID,而非 AISIX 别名。 | | `/v1/batches` 和 `/v1/audio/*` | 不支持。Nebius 未在此 API 根地址上发布兼容的 OpenAI Batch 或音频路由。 | | `/v1/images/generations` | 返回 `400` 而被拒绝,因为规范化路由要求 `provider: openai`。可通过透传路由使用 Nebius 原生图片生成路由。 | | `/v1/rerank` | 返回 `400` 而被拒绝,因为规范化路由只接受 `openai`、`cohere` 和 `jina`。可通过透传路由使用 Nebius 原生重排路由。 | | `/v1/videos` | 返回 `501 not_implemented` 而被拒绝。Nebius 不提供视频生成路由;向兼容 Chat 模型输入视频是另一项能力。 | | `/passthrough/nebius/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 `/v1` 目标下的 Nebius 原生路由,包括 `/responses`、`/images/generations`、`/rerank` 和 `/models`。 | 规范化文件和微调响应使用 AISIX 路由 ID。Nebius 独有的 `/files/{id}/link` 以及微调 `/events` 或 `/checkpoints` 等路由,需要通过透传路由使用原始 Nebius ID。路由不会解码 AISIX 路由 ID,因此工作流需要这些原生操作时,请从一开始就通过透传路由创建和管理资源。 本页的 `/passthrough/nebius` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://api.tokenfactory.nebius.com/v1` 并挂上 Nebius 服务提供方密钥;在调用方 Key 的 `allowed_routes` 上授予该路由。 透传路由不会重写 AISIX 模型别名或资源 ID,请在原生请求体中发送确切的 Nebius 模型 ID。由于路由的 `target_url` 以 `/v1` 结尾,`/passthrough/nebius/responses` 和 `/passthrough/nebius/v1/responses` 都会到达 `https://api.tokenfactory.nebius.com/v1/responses`;AISIX 会移除一个重复的版本路径段。 透传路由绑定固定的目标和凭证,而不是从调用方可访问的模型别名借用;模型允许列表也不管控它。不同的 Nebius 账号或 API 根地址请各配一条路由。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。除非挂载 hold-back 输出安全护栏,否则路由会增量中继服务提供方响应和 SSE。文件和微调管理调用属于零 Token 操作,AISIX 不会将 Nebius 训练费用计入推理成本核算。请参阅[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 ## 故障排查[​](#故障排查 "故障排查的直接链接") | 现象 | 检查项 | | ------------------------------ | ---------------------------------------------------------- | | 上游返回 `401` 或 `403` | 确认 Nebius API Key 和项目访问权限。 | | 上游返回 `404` | 确认 `api_base` 中包含 `/v1`,并验证请求的路由与模型兼容。 | | 找不到模型 | 保留发布方命名空间以及模型名称的大小写。 | | 创建服务提供方密钥时返回 `400` | 使用 `provider: "nebius"`,且不要设置 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Nebius Token Factory,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [API Key 与模型限流](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limits.md):为别名配置请求数和 Token 限制。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Nebius 与提供同一模型的其他服务提供方之间执行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # Novita AI [Novita AI](https://novita.ai/docs/api-reference/model-apis-llm-create-chat-completion) 为语言模型目录提供托管推理服务。应用通过稳定的 AISIX 别名选择这些模型,并使用网关颁发的调用方密钥进行身份认证。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一个 Novita AI API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` Novita AI 是提供 OpenAI 兼容 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行身份认证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` export NOVITA_API_KEY="YOUR_NOVITA_API_KEY" PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "novita-prod", "provider": "novita-ai", "api_key": "'"${NOVITA_API_KEY}"'", "api_base": "https://api.novita.ai/openai/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` 服务提供方 ID 包含 `-ai` 后缀。`novita` 不是 AISIX 目录 ID。 API Base 必须包含 `/openai`。本指南使用 Novita 文档中的 `/openai/v1` 根地址,AISIX 会追加 `/chat/completions`,生成 `https://api.novita.ai/openai/v1/chat/completions`。Novita 也接受不带版本路径段的 `/openai`,这是当前同步目录的值。使用裸主机会将流量发送到 Novita 未为 LLM 推理提供的路由。 AISIX 会为此目录服务提供方派生 `openai` 适配器。请从请求中省略 `adapter`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 使用包含发布方命名空间的 Novita 模型 ID 创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "novita-deepseek-prod", "model_name": "deepseek/deepseek-v3.2", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` 模型 ID 和可用性会随 Novita 目录更新而变化。请从 Novita 模型列表复制当前 ID,并保留其发布方前缀和大小写。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "novita-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export NOVITA_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "novita-prod" provider: "novita-ai" adapter: "openai" api_key: ${NOVITA_API_KEY} api_base: "https://api.novita.ai/openai/v1" models: - display_name: "novita-deepseek-prod" provider: "novita-ai" model_name: "deepseek/deepseek-v3.2" provider_key: "novita-prod" api_keys: - display_name: "novita-caller" key_env: CALLER_API_KEY allowed_models: - "novita-deepseek-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "novita-deepseek-prod", "messages": [ { "role": "user", "content": "Say hello from Novita AI." } ] }' ``` AISIX 会将 `deepseek/deepseek-v3.2` 转发到 Novita 的 OpenAI 兼容 Chat 端点,并携带 Novita API Key。 ## 查看模型能力[​](#查看模型能力 "查看模型能力的直接链接") 本指南中的 `deepseek/deepseek-v3.2` 是当前的纯文本模型,支持推理、函数工具和结构化输出。Novita Chat API 还支持因模型而异的图片、视频和音频输入,文本或音频输出,以及 `enable_thinking` 和 `separate_reasoning` 等控制项。AISIX 会将带类型的内容块、工具、结构化输出配置和未知顶层请求字段转发到兼容 OpenAI 的上游。 AISIX 会规范化 Novita Chat 响应中的 `reasoning_content` 字段,但不会保留某些 Novita 模型在跨工具调用的交错思考中需要的可选 `reasoning_details` 数组。使用这些模型时请改用透传路由,并重放完整的原生助手消息。Novita 也接受大于 `1` 的 `n`,但 AISIX 在规范化 Chat 路由上只返回第一个选项。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") | 路由 | 使用 Novita 别名时的行为 | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括流式传输、工具、结构化输出、推理,以及所选模型支持的多模态内容。 | | `/v1/completions` | 对兼容的 Novita 模型,通过 `openai` 适配器支持。 | | `/v1/responses` | 通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持,该桥接会转换为 Chat Completions。Novita 未在此 API 根地址上发布原生 Responses 路由。没有 Chat 等价项的字段会被忽略,返回的 Responses 输出不会保留 Novita 推理。 | | `/v1/messages` | 通过 Anthropic 到 Chat 的转换访问兼容 OpenAI 的根地址。桥接不会将 Novita 推理保留为 Anthropic 思考块。`/v1/messages/count_tokens` 要求 Anthropic 后端模型,因此会拒绝此配置。 | | `/v1/embeddings` | 使用此根地址提供的 Novita 嵌入模型的独立别名时支持。 | | `/v1/files` 和 `/v1/batches` | 通过 `openai` 适配器支持。AISIX 会重写返回的文件和批处理 ID,使规范化后续调用路由到同一别名。上传的批处理 JSONL 文件中,每个请求必须使用上游 Novita 模型 ID;AISIX 不会重写文件内容,且 Novita 要求一个批处理文件只使用一个模型。 | | `/v1/fine_tuning/jobs` 和 `/v1/audio/*` | 不支持。Novita 未在配置的 OpenAI 根地址下发布兼容路由。通过兼容 Chat 模型输入或输出音频是另一项能力。 | | `/v1/images/generations` | 返回 `400` 而被拒绝,因为规范化路由要求 `provider: openai`。Novita 图片生成 API 使用配置的 API Base 之外的独立主机根路径。 | | `/v1/rerank` | 返回 `400` 而被拒绝,因为规范化路由不接受 `novita-ai`。可通过透传路由访问 Novita 原生 `/openai/v1/rerank` 路由。 | | `/v1/videos` | 返回 `501 not_implemented` 而被拒绝,因为规范化路由不支持 `novita-ai`。Novita 视频生成 API 使用配置的 API Base 之外的独立主机根路径;向兼容 Chat 模型输入视频是另一项能力。 | | `/passthrough/novita-ai/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于路由 `target_url` 下的 Novita 原生路由,包括 `/rerank` 和 `/models`。 | 文件和批处理管理调用记录的 Token 为零。当规范化批处理检索首次发现作业完成时,AISIX 会下载输出文件,并将其汇总 Token 用量和计算成本归属到路由别名。 Novita 还在 `https://api.novita.ai/anthropic` 提供兼容 Anthropic 的 API。该同级根地址不在本指南使用的 `/openai/v1` 根地址下,因此以 OpenAI 兼容根地址为目标的透传路由无法访问它。原生 Anthropic 用法需要另一条以该根地址为 `target_url` 的透传路由,并在调用方 Key 的 `allowed_routes` 上授予。 透传路由始终停留在其 `target_url` 之下,因此以 `/openai/v1` 根地址为目标的路由无法访问 Novita 主机根路径下的 `/v3` 图片、视频或音频 API。对于可访问路径,它不会重写 AISIX 模型别名或资源 ID。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。AISIX 会增量中继服务提供方响应和 SSE,而不是缓冲它们。 本页的 `/passthrough/novita-ai` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://api.novita.ai/openai/v1` 并用 Novita 服务提供方密钥做凭证注入;在调用方 Key 的 `allowed_routes` 上授予路由名称。一条路由绑定一个目标和凭证,不同的 Novita 账号或根地址请使用独立路由。 ## 故障排查[​](#故障排查 "故障排查的直接链接") | 现象 | 检查项 | | ------------------------------ | ------------------------------------------------------------------ | | 上游身份认证错误 | 确认 `NOVITA_API_KEY` 处于有效状态。 | | 上游返回 `404` | 在 `api_base` 中保留 `/openai`,并确认请求的路由存在于该根地址下。 | | 找不到模型 | 从 Novita 复制包含完整发布方命名空间的模型 ID。 | | 创建服务提供方密钥时返回 `400` | 使用 `provider: "novita-ai"` 并省略 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Novita AI,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方特定覆盖](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当 Novita 与 `openai` 适配器存在差异时调整请求和响应格式。 * [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md):访问 AISIX 未做标准化的 Novita 原生路由。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # NVIDIA NIM [NVIDIA NIM](https://docs.api.nvidia.com/nim/) 将模型封装为可在自有基础设施中运行的推理微服务。NVIDIA 也通过托管 API 端点提供部分 NIM。应用通过稳定的 AISIX 别名选择这些模型,同时由网关保存 NVIDIA API Key。 本指南配置 `https://integrate.api.nvidia.com/v1` 上共享的托管 LLM Chat API,以及发布兼容 `/v1/embeddings` 路由的 Embedding 模型。API Catalog 还包含使用模型特定路径、请求体或主机的检索、视觉生成、语音及其他 NIM。托管目录及可用模型会随时间变化,因此将此共享配置用于其他 NIM 系列前,请查看所选模型的 API 参考。 ## 前提条件[​](#前提条件 "前提条件的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或采用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 部署方式。配置网关以加载声明式资源文件。 * 一个用于托管 NIM API 的 NVIDIA API Key,可从 [build.nvidia.com](https://build.nvidia.com/) 上的模型页面生成。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 NVIDIA 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 NVIDIA 是社区目录服务提供方,其共享托管 LLM 端点接受 OpenAI Chat Completions 请求。AISIX 通过 `openai` 适配器连接,使用 Bearer Token 对上游请求进行身份认证,并将 NVIDIA API Root 用作 `api_base`。AISIX 不会注册 NVIDIA 特定的请求或响应重写。有关与标准 OpenAI 格式不同的字段,请参阅[配置 NVIDIA 特定行为](#supply-nvidia-specific-behavior)。 Dashboard 将 NVIDIA 归入 **All providers (community)**,并将其传输协议兼容性标记为推定兼容,而非已验证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "�创建服务提供方密钥的直接链接") 创建用于保存 NVIDIA 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export NVIDIA_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nvidia-prod", "provider": "nvidia", "api_key": "'"${NVIDIA_API_KEY}"'", "api_base": "https://integrate.api.nvidia.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `nvidia`。AISIX Cloud Admin API 接受该值,因为 `nvidia` 是其缓存的 models.dev 目录 ID 之一;它会根据目录的社区默认规则分配 `openai` 适配器和 Bearer 身份认证。`adapter` 字段仅适用于 BYO 服务提供方密钥,因此不要在此设置。 ❷ `api_key` 保存 NVIDIA API Key。NVIDIA 使用 HTTP Bearer 身份认证来认证托管 NIM API,这正是 `openai` 适配器已发送的认证方式。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://integrate.api.nvidia.com/v1`,这是 NVIDIA 为共享托管 LLM API 记录的 Root。Chat 路由以 `POST https://integrate.api.nvidia.com/v1/chat/completions` 的形式挂载在该 Root 下,而 AISIX 会向 `api_base` 追加 `/chat/completions`,因此该值必须止于 `/v1`。AISIX 会移除粘贴进来的 `/chat/completions` 等端点后缀以及尾部斜杠,但应将 Root 本身视为约定,不要依赖这种修正行为。 不要把这个 Root 复用于所有 API Catalog 条目。例如,托管重排序使用 `https://ai.api.nvidia.com` 下的检索专用端点,视觉生成 NIM 也会发布其他路径。若所选模型不使用共享 LLM 或 Embeddings 路由,请按照该模型 API 参考中的准确 API Root 创建独立的服务提供方密钥。 对于 `nvidia`,该字段可选:models.dev 在其 `api` 字段中发布了相同 URL;省略该字段时,AISIX Cloud Admin API 会自动填充。示例中显式设置该字段,以便每个密钥所指向的 Root 在配置中清晰可见。 警告 切勿让 `nvidia` 服务提供方密钥缺少已解析的 `api_base`。对于任何非 OpenAI 厂商,OpenAI 系列桥接不会回退到默认 OpenAI 主机,因此空的 Base URL 会在请求时产生上游配置错误,而不会将携带 NVIDIA 凭证的请求错误发送到其他厂商主机。 该命令将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 在共享托管 LLM 和 Embeddings 路由上,NVIDIA 通常按发布方组织为模型 ID 设置命名空间,格式为 `<publisher>/<model>`。发布方片段是这些 ID 的组成部分,不能省略。目前的示例如下: | 模型 ID | 发布方 | | ----------------------------------- | ------ | | `nvidia/nvidia-nemotron-nano-9b-v2` | NVIDIA | | `meta/llama-3.3-70b-instruct` | Meta | | `openai/gpt-oss-120b` | OpenAI | 大多数别名错误都源于以下两个命名细节: * 部分 NVIDIA 发布的模型名称已经以 `nvidia-` 开头,因此完整 ID 会重复该片段,例如 `nvidia/nvidia-nemotron-nano-9b-v2`。这是正确格式,并非拼写错误。 * `build.nvidia.com` 上的模型页面 URL 使用页面 Slug,而不是模型 ID。Llama 3.3 70B Instruct 页面路径中使用 `llama-3_3-70b-instruct`,而 API 模型 ID 是 `meta/llama-3.3-70b-instruct`。请从模型页面的代码示例中复制 ID,而不要从地址栏复制。 创建别名前,请在 [NVIDIA NIM API 参考](https://docs.api.nvidia.com/nim/)中查看相应模型页面,同时确认当前端点与请求正文中的模型 ID。部分特定领域 API 使用的模型值与带发布方命名空间的目录卡片名称不同。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nvidia-llama-prod", "model_name": "meta/llama-3.3-70b-instruct", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方通过 `model` 发送的别名。 ❷ `model_name` 是包含发布方片段的 NVIDIA 模型 ID。不要从提供相同权重但不使用发布方前缀的服务提供方沿用 `llama-3.3-70b-instruct` 等裸标识符。 ❸ `provider_key_id` 将该别名关联到 NVIDIA 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且仅在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "nvidia-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送到网关的调用方 API Key: ``` export NVIDIA_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "nvidia-prod" provider: "nvidia" adapter: "openai" api_key: ${NVIDIA_API_KEY} api_base: "https://integrate.api.nvidia.com/v1" models: - display_name: "nvidia-llama-prod" provider: "nvidia" model_name: "meta/llama-3.3-70b-instruct" provider_key: "nvidia-prod" api_keys: - display_name: "nvidia-caller" key_env: CALLER_API_KEY allowed_models: - "nvidia-llama-prod" ``` 如果 AISIX 安装在本地,请先验证文件再加载: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件所引用的环境变量,然后启动网关。仅当现有网关进程已经能够访问这些变量时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请根据[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)调整验证和启动命令。在两个命令中挂载此 `resources.yaml` 文件,并通过 `-e` 传入文件引用的每个环境变量。资源加载后,为下方的通用验证请求做好准备: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关源站地址: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送聊天补全请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "nvidia-llama-prod", "messages": [ { "role": "user", "content": "Say hello from NVIDIA NIM." } ] }' ``` 网关返回 OpenAI 兼容响应,其中会回显调用方面向的别名 `nvidia-llama-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base` Root,以及 `model_name` 中带发布方命名空间的模型 ID。上游 `404` 通常表示模型 ID 不正确、模型已不可用,或有效的目录模型被发送到了错误的共享路由。 ## 在托管 API 与自行托管 NIM 之间选择[​](#在托管-api-与自行托管-nim-之间选择 "在托管 API 与自行托管 NIM 之间选择的直接链接") NIM 微服务既可作为容器运行在自有基础设施中,也可通过 NVIDIA 托管 API 端点访问;只有托管 API 属于 `nvidia` 目录服务提供方。在自有集群中运行的 LLM NIM 会在自身地址(例如 `http://10.0.0.5:8000/v1`)上提供 OpenAI 兼容 API,并改为通过私有端点路径接入 AISIX。请使用[自带端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)进行配置。 | 对比项 | 托管 NIM API | 自行托管的 NIM 微服务 | | -------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | 服务提供方值 | `nvidia` | AISIX Cloud Admin API 中使用 `byo`,或在声明式 `resources.yaml` 中使用自定义标签 | | `adapter` 字段 | 不接受。适配器从目录中派生。 | 接受,并设置为 `openai`。 | | `api_base` | `https://integrate.api.nvidia.com/v1`;省略时使用目录中的默认值 | 必填。填写容器 Root,例如 `http://10.0.0.5:8000/v1`。 | | 模型 ID | 带发布方命名空间,例如 `meta/llama-3.3-70b-instruct` | 容器提供服务的模型名称 | | 定价元数据 | 可用时从 models.dev 获取;请核验计费信息,或在模型别名上覆盖 `cost` | 由你在模型别名上自行提供 `cost` | 同时运行两者是一种常见配置:一个服务提供方密钥用于托管 API 的突发容量,另一个 BYO 密钥用于自行托管的 NIM,并由路由模型在两个别名之间执行故障转移。请参阅[路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md)。 当前[自行托管 LLM NIM](https://docs.nvidia.com/nim/large-language-models/latest/reference/api-reference.html)提供多种 API:Chat Completions、文本 Completions、Responses、Messages 和 Token 计数。请在自行托管的服务提供方密钥上声明 Responses 和 Messages 接口。这样,规范化 `/v1/responses`、`/v1/messages` 和 `/v1/messages/count_tokens` 路由就能使用 NIM 原生格式,并沿用同一凭证和模型别名。 使用 AISIX Cloud 时,仅在自行托管的 BYO 服务提供方密钥创建请求中添加 `apis`。不要把此配置块添加到本页前文创建的托管 `nvidia` 目录密钥: ``` { "apis": { "responses": {}, "messages": {} } } ``` 对于开源网关,请把同一字段添加到 `provider_keys` 中对应的条目。以下局部配置块以 `nvidia-nim-local` 为示例条目名称;请保留该条目的其他字段及文件中的其余资源: resources.yaml(自行托管 NIM API 接口) ``` provider_keys: - display_name: "nvidia-nim-local" apis: responses: {} messages: {} ``` 没有单独设置 `base` 的条目会使用服务提供方密钥的 `api_base`。Chat Completions、Completions 和 Embeddings 仍通过 OpenAI 适配器处理。对于 AISIX 未规范化的 NIM 操作,例如列出模型、对输入进行 Token 化、检索已存储响应或取消响应,请使用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 NIM 不会验证 AISIX 在原生 Messages 路由上发送的 `x-api-key` 请求头。如果 NIM 前方带身份验证的反向代理要求 Bearer 身份验证,请改用透传路由处理 Messages 和 Token 计数。 ## 配置 NVIDIA 特定行为[​](#supply-nvidia-specific-behavior "配置 NVIDIA 特定行为的直接链接") 由于 `nvidia` 没有 AISIX 精选的适配器映射,AISIX 不会为其注册请求或响应重写。网关会原样发送 OpenAI 请求格式,这适用于 NVIDIA 的 Chat 路由;所有 NVIDIA 特定差异都需由你处理。请使用[服务提供方密钥覆盖](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)配置这些差异,覆盖配置会应用于引用该密钥的每个模型。 能力支持取决于具体模型和端点。某个目录条目支持工具、结构化输出、推理或多模态输入,不代表其他 NVIDIA 模型也接受相同字段或内容块格式。AISIX 会转发 OpenAI 形态的 Chat 字段和未知顶层参数;部分多模态 NIM 则需要模型专用路由、HTML 媒体标签或 NVCF 资产引用。请检查模型自身的推理参考,不要根据 NIM 系列名称推断支持范围。AISIX 还只返回兼容 OpenAI Chat 响应中的第一个 Choice;调用方需要全部生成结果时,请勿请求大于 `1` 的 `n`。 ### 推理控制因模型而异[​](#推理控制因模型而异 "推理控制因模型而异的直接链接") NVIDIA 未定义适用于整个服务提供方的统一推理字段。发布的每个模型都有自己的请求 Schema,因此启用或限制推理的控制方式因模型而异。例如,`nvidia/nvidia-nemotron-nano-9b-v2` 通过提示词中的 `/think` 和 `/no_think` 控制 Token 切换推理,而其他模型则接受 `reasoning_effort` 等顶层参数。在依赖某项控制前,请在 [NVIDIA NIM API 参考](https://docs.api.nvidia.com/nim/)中的对应模型页面确认;一个 NIM 接受的控制可能会被另一个 NIM 忽略或拒绝。 传递这些控制无需额外网关配置。提示词级控制 Token 位于消息内容中,而 AISIX 会将无法识别的顶层 Chat 参数原样转发到上游,因此模型特定参数会不加修改地发送到 NVIDIA: ``` { "model": "nvidia-nemotron-prod", "messages": [ { "role": "user", "content": "Plan a three-step migration." } ], "reasoning_effort": "low" } ``` 在响应侧,无论流式还是非流式响应,只要上游已在规范的 `reasoning_content` 字段中返回推理内容,AISIX 都会予以保留。如果某个 NIM 在不同的 `delta` 路径上流式返回推理内容,请在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ### Token 限制参数名称[​](#token-限制参数名称 "Token 限制参数名称的直接链接") 社区默认规则未为 `nvidia` 注册 `param_renames`,因此 AISIX 会沿用调用方发送的参数名称传递 `max_tokens` 和 `max_completion_tokens`。NVIDIA LLM API 文档使用 `max_tokens`。因此,客户端发送较新的 `max_completion_tokens` 时,该限制会以一个上游可能不处理的名称转发。如遇此情况,请在服务提供方密钥上添加重命名配置: ``` { "request": { "param_renames": { "max_completion_tokens": "max_tokens" } } } ``` 如果请求同时携带这两个名称,AISIX 会使用原始面向调用方名称所对应的值。 ## 将 Embeddings 路由到 NeMo Retriever 模型[​](#route-embeddings-to-nemo-retriever-models "将 Embeddings 路由到 NeMo Retriever 模型的直接链接") NVIDIA 在同一目录中发布 NeMo Retriever Embedding 模型,而 AISIX 通过同一 `openai` 适配器分发 `/v1/embeddings`,因此指向 Embedding 模型的别名可用于该路由。 多个 NVIDIA Embedding 字段需要特殊处理。NVIDIA 的非对称检索模型系列(例如 NV-EmbedQA 和 E5)要求将 `input_type` 设置为 `query` 或 `passage`,使用错误值会降低检索准确率。当前 Retriever NIM Schema 还可定义 `modality`、`embedding_type` 和 `truncate` 等字段。AISIX Embeddings 路由只会使用一组封闭字段构建上游请求正文,即 `model`、`input`、`encoding_format` 和 `dimensions`,因此调用方请求正文中的 NVIDIA 专用字段不会到达上游。 请改为通过 `request.default_body_fields` 在服务提供方密钥上设置该字段: ``` { "request": { "default_body_fields": { "input_type": "passage" } } } ``` AISIX 会在 Embeddings 路径(而不仅是 Chat 路径)上将这些字段合并到出站请求体中。由于服务提供方密钥覆盖会应用于引用该密钥的每个模型,因此请为每种检索模式分别创建一个服务提供方密钥:一个携带用于索引的 `input_type: passage`,另一个携带用于搜索的 `input_type: query`,再让相应模型别名指向各自密钥。 其他固定 NVIDIA 字段(例如 `truncate`)也可使用 `request.default_body_fields`。必须随请求或每项输入变化的值(例如混合 `modality` 数组)不能通过静态服务提供方密钥配置表达,需要使用透传路由。 不接受 `input_type` 的对称 Embedding 模型无需配置服务提供方密钥覆盖。字段定义请参阅 [`request.default_body_fields`](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#provider-keys),并在 [NVIDIA Embedding API 参考](https://docs.nvidia.com/nim/nemo-retriever/text-embedding/latest/reference.html)中确认你的模型是否要求 `input_type`。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") 由适配器分发的路由接受 `nvidia` 服务提供方值,而使用自身服务提供方允许列表的路由会拒绝该值。 | 路由 | 使用 NVIDIA 别名时的行为 | | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 在共享托管 LLM 路由上支持,包括 `stream: true`。模型能力仍取决于具体模型。 | | `/v1/completions` | AISIX 会通过 OpenAI 适配器转发此路由。当前自托管 LLM NIM 提供该路由,但 NVIDIA 未将其记录为共享托管 LLM API 的通用路由;仅当所选上游明确支持时使用。 | | `/v1/responses` | 托管服务提供方密钥使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md),该桥接会合成新响应,并丢弃状态、托管工具、Responses 输出控制项、除 `reasoning.effort` 之外的推理设置,以及没有 Chat 等价项的字段。合成的输出不会表示上游推理文本。声明 `apis.responses` 的自行托管 NIM 密钥会改为把请求发送至 NIM 原生端点。 | | `/v1/messages` 和 `/v1/messages/count_tokens` | 托管服务提供方密钥会通过 Chat 转换 Messages,不会返回 Anthropic `thinking` 块,也不支持规范化 Token 计数。声明 `apis.messages` 的自行托管 NIM 密钥会把这两类请求都发送至 NIM 原生端点。 | | `/v1/embeddings` | 当别名指向 NVIDIA Embedding 模型时支持。请参阅[将 Embeddings 路由到 NeMo Retriever 模型](#route-embeddings-to-nemo-retriever-models)。 | | `/v1/images/generations` | 对 NVIDIA 别名返回 `400` 并拒绝。NVIDIA Visual GenAI NIM 可提供原生兼容 OpenAI 的图片路由,但规范化 AISIX 路由只接受服务提供方为 `openai` 的模型。 | | `/v1/rerank` | 返回 `400` 并拒绝。该路由仅接受 `openai`、`cohere` 和 `jina` 服务提供方值。请参阅下方说明。 | | `/v1/videos` | 返回 `501 not_implemented` 并拒绝。Visual GenAI NIM 可在 `/v1/videos/generations` 提供原生视频生成,但规范化 AISIX 视频路由的服务提供方允许列表中不包含 `nvidia`。 | | `/v1/audio/*` | 会转发到兼容 OpenAI 的音频路径,但共享托管 LLM API 和自托管 LLM NIM 不提供这些路由。Speech NIM 使用独立 API;请通过以文档根地址为目标的透传路由访问。 | | `/v1/files`、`/v1/batches`、`/v1/fine_tuning/jobs` | AISIX 可通过 OpenAI 适配器分派这些路由,但共享托管 API 和当前自托管 LLM NIM 都不提供对应的 OpenAI Jobs API,因此上游会拒绝请求。NIM 模型定制或 LoRA 管理使用不同协议。 | | `/passthrough/nvidia/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于服务提供方原生路由,网关标准化能力有限。 | NVIDIA 确实发布了重排序模型,但即使不考虑服务提供方允许列表,也无法通过 `/v1/rerank` 访问。当前自托管 Retriever NIM 将其记录为 `POST /v1/ranking`,请求体包含 `query` 对象和 `passages` 数组;路径和请求体均不匹配规范化路由,托管目录重排还可能使用不同主机和路径。请使用所选模型的 [NVIDIA 重排序 API 参考](https://docs.nvidia.com/nim/nemo-retriever/text-reranking/latest/reference.html)中的端点和请求体,通过透传路由访问。 本页的 `/passthrough/nvidia` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://integrate.api.nvidia.com/v1` 并用 NVIDIA 服务提供方密钥做凭证注入;在调用方 Key 的 `allowed_routes` 上授予路由名称。路由绑定一个固定目标和凭证——请求体中的模型不会选择凭证,AISIX 别名也不会重写为上游模型 ID——因此其他根地址(例如 `https://ai.api.nvidia.com` 下的检索端点)上的 NIM 请另建路由。路由会增量中继包括 SSE 在内的上游响应。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。需要别名重写、Token 核算或 AISIX 成本估算时,请优先使用规范化推理路由。目录定价只是 AISIX 估算所用的元数据,并不代表 NVIDIA 的实际账单;目前许多 NVIDIA 目录模型的已发布成本为零或缺失。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 NVIDIA NIM 托管 API,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在托管 NIM API 和自行托管的 NIM 之间执行故障转移。 * [自带端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md):连接自行运行的 NIM 微服务。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点及服务提供方特定的限制。 --- # Ollama [Ollama](https://docs.ollama.com/api/openai-compatibility) 在本地或私有基础设施中运行语言模型,并提供 OpenAI 和 Anthropic 兼容 API。Ollama 继续在你的环境中提供推理服务,AISIX 则为其添加调用方密钥、稳定的模型别名、流量控制和用量报告。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 在 AISIX 网关可访问的主机上安装 Ollama 0.13.3 或更高版本。该版本开始提供本指南使用的原生 Responses 端点。 * `curl` 和 `jq`。 ## 准备 Ollama[​](#准备-ollama "准备 Ollama的直接链接") 拉取本指南使用的模型: ``` ollama pull gpt-oss:20b ``` Ollama 默认绑定到 `127.0.0.1:11434`。如果 AISIX 运行在另一个容器或主机上,请按照 [Ollama 服务器配置](https://docs.ollama.com/faq#how-do-i-configure-ollama-server)设置可访问的绑定地址。例如,可让前台服务器监听所有网络接口: ``` OLLAMA_HOST="0.0.0.0:11434" ollama serve ``` 警告 本地 Ollama API 不需要身份验证。绑定到 `0.0.0.0` 后,其他网络节点也能访问它。请使用防火墙、容器网络或 Kubernetes 策略限制监听网络,不要将该端口直接暴露到公网。 导出一个**可从 AISIX 网关访问**的 API 根地址: ``` # Docker Desktop 中的网关访问主机上的 Ollama export OLLAMA_API_BASE="http://host.docker.internal:11434/v1" ``` 根据部署拓扑选择地址: | AISIX 网关与 Ollama 的部署拓扑 | API 根地址示例 | | ----------------------------------------------- | ------------------------------------------------------ | | 两个进程位于同一主机 | `http://127.0.0.1:11434/v1` | | AISIX 位于 Docker Desktop 中,Ollama 位于主机上 | `http://host.docker.internal:11434/v1` | | 两个容器位于同一 Docker 网络 | `http://ollama:11434/v1` | | Kubernetes | `http://ollama.<namespace>.svc.cluster.local:11434/v1` | 在 Linux 上,`host.docker.internal` 可能需要显式配置 `host-gateway` 映射。从笔记本电脑成功发送请求,并不能证明 AISIX 网关容器能够访问同一地址。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` Ollama 是私有端点,而不是 AISIX 目录服务提供方。请使用 `byo` 服务提供方值进行配置,并显式选择 `openai` 适配器。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "ollama-local", "provider": "byo", "adapter": "openai", "api_key": "ollama", "api_base": "'"${OLLAMA_API_BASE}"'", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` AISIX 的服务提供方密钥 schema 要求 `api_key` 非空。Ollama 的 OpenAI 客户端示例使用 `ollama`,因为客户端要求提供一个值,但本地 Ollama 服务器会忽略该值。AISIX 会将此占位值作为 Bearer Token 发送;它不是安全控制措施。 BYO 密钥要求提供 `provider: "byo"`、非空的 `api_key` 和 `api_base`。本指南显式设置 `adapter: "openai"`;省略时,AISIX 会默认让 BYO 密钥使用 OpenAI 兼容适配器。`apis.responses` 声明会把 Responses 请求发送至 Ollama 原生端点,而不是通过 Chat Completions 转换。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 使用准确的本地 Ollama 模型标签: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "ollama-gpt-oss-prod", "model_name": "gpt-oss:20b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` 运行 `ollama ls` 查看已安装的模型标签。标签(包括 `:20b` 等后缀)会原样发送到上游。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "ollama-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export OLLAMA_API_BASE="http://host.docker.internal:11434/v1" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "ollama-local" provider: "ollama" adapter: "openai" api_key: "ollama" api_base: "${OLLAMA_API_BASE}" apis: responses: {} models: - display_name: "ollama-gpt-oss-prod" provider: "ollama" model_name: "gpt-oss:20b" provider_key: "ollama-local" api_keys: - display_name: "ollama-caller" key_env: CALLER_API_KEY allowed_models: - "ollama-gpt-oss-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ollama-gpt-oss-prod", "input": "Say hello from Ollama." }' ``` Ollama 应记录 `POST /v1/responses`。AISIX 会在上游请求中把别名替换为已安装的 Ollama 模型标签,并在响应中恢复该别名。 Ollama 从 0.13.3 版开始提供原生 `/v1/responses`。该端点支持流式传输、函数工具和推理摘要,但不支持通过 `previous_response_id` 或 `conversation` 保存状态。本指南中的声明会在规范化 AISIX 路由上保留这些受支持的原生语义,同时保留别名重写和模型访问控制。 ## 通过透传使用原生 Messages[​](#通过透传使用原生-messages "通过透传使用原生 Messages的直接链接") Ollama 还提供原生 Anthropic 形态的 Messages 路由,但没有 `/v1/messages/count_tokens`。需要原生 Messages 格式时,请使用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。不要为此工作流声明 `apis.messages`,也不要创建使用 `anthropic` 适配器的单独别名;这两种方式都表示包括 Count Tokens 在内的完整 Messages 协议面。参见[声明 API 协议面](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#declare-the-api-surfaces)。 透传不会重写 AISIX 别名,因此请发送已安装的 Ollama 模型标签。Ollama 的其他 Messages 限制仍然适用:它不支持强制 `tool_choice`、提示词缓存、引用和 Messages 批处理;扩展思考预算虽会被接受,但不会强制执行。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Ollama 文档列出了 OpenAI 兼容的 Chat Completions、Completions、Responses、Models 和 Embeddings 路由,还提供 [Anthropic 兼容的 Messages 路由](https://docs.ollama.com/api/anthropic-compatibility)。本指南的服务提供方密钥仅声明原生 Responses;其他路由继续遵循 `openai` 适配器或下表中的路由特定行为。 | 路由 | 使用本指南 Ollama 别名时的行为 | | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持;当已安装模型支持时,可使用流式传输、工具、结构化输出、视觉和推理控制项。 | | `/v1/completions` | 通过 OpenAI 适配器提供支持。Ollama 的 `prompt` 只接受字符串。 | | `/v1/embeddings` | 当别名指向已安装的 Embedding 模型时受支持。Ollama 和 AISIX 均接受字符串或字符串数组。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 Ollama 原生 Responses API。如果没有此声明,AISIX 会使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/messages` | 因为此服务提供方密钥使用 `adapter: openai`,所以通过 Chat 转换。Ollama 原生 Messages 格式请按上文使用透传。 | | `/v1/messages/count_tokens` | `openai` 适配器会拒绝该路由。即使使用单独的 Anthropic 适配器,Ollama 当前也未实现此端点。 | | `/v1/models` | 返回调用方可访问的 AISIX 模型别名,而不是 Ollama 中安装的模型。请使用 `ollama ls` 或透传路由查询 Ollama 模型清单。 | | `/v1/images/generations`、`/v1/rerank` | 返回 `400`,因为标准化路由不接受本指南的服务提供方标签(AISIX Cloud 中为 `byo`,资源文件中为 `ollama`)。 | | `/v1/videos` | 返回 `501 not_implemented`,因为这两个服务提供方标签均不在视频路由允许列表中。 | | `/v1/audio/*`、`/v1/files`、`/v1/batches`、`/v1/fine_tuning/jobs` | AISIX 可以转发这些 OpenAI 形态的路由,但 Ollama 未发布对应 API,上游会拒绝请求。 | | `/passthrough/byo/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 Ollama 原生路由。约定前缀在 AISIX Cloud 中为 `/passthrough/byo`,开源资源文件中为与本页服务提供方标签一致的 `/passthrough/ollama`。 | Ollama 的 OpenAI 兼容 Chat 路由当前不支持 `tool_choice`、`logit_bias`、`user` 或 `n`。AISIX 可以转发这些字段,但转发不会增加上游能力。使用视觉模型时,请在 `image_url` 内容部分发送 Base64 图像;Ollama 不支持在此路由上使用远程图像 URL。 上述 `/passthrough` 路径假定一条透传路由认领所选前缀,`target_url` 设为 Ollama 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。透传不会重写请求体中的 AISIX 别名,路由总是以其固定目标和绑定的服务提供方密钥中继,与请求的模型无关。它会增量中继包括 SSE 在内的上游响应。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。当需要别名重写、Token 核算或 AISIX 成本估算时,请优先使用标准化路由。Ollama 是没有目录定价的 BYO 端点;需要成本估算时,请在 AISIX Cloud 中配置[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md),或在开源模型资源中配置 `cost` 元数据。 ## 故障排除[​](#troubleshooting "故障排除的直接链接") | 现象 | 检查项 | | ------------------------------ | ------------------------------------------------------------------------------- | | 连接被拒绝或超时 | 从 AISIX 网关容器内测试 `OLLAMA_API_BASE`,不要只在主机上测试。 | | Ollama 仅监听 `127.0.0.1` | 通过受支持的服务配置设置 `OLLAMA_HOST`,然后重启 Ollama。 | | 找不到模型 | 运行 `ollama pull gpt-oss:20b`,并使用 `ollama ls` 验证标签。 | | 创建服务提供方密钥时返回 `400` | 请包含 `provider: "byo"`、`adapter: "openai"`、非空的 `api_key` 和 `api_base`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Ollama,并验证了模型别名。接下来可阅读以下指南: * [自带端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md):查看适用于私有 OpenAI 兼容服务器的可复用配置。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Ollama 和提供同一模型的其他服务提供方之间进行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # OpenAI [OpenAI](https://platform.openai.com/docs/) 通过 API 提供托管的 GPT 模型。应用通过稳定的 AISIX 别名调用这些模型,网关则确保 OpenAI 凭证不会出现在客户端代码中。 本指南涵盖通过同一个 OpenAI 服务提供方密钥承载的 GPT Chat 流量和 Sora 视频任务。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [OpenAI 平台](https://platform.openai.com/api-keys)获取的 OpenAI API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由 OpenAI 提供支持的路由创建服务提供方密钥、模型别名和调用方 API Key。 OpenAI 是网关原生支持的 OpenAI 兼容上游,该集成使用 `openai` 适配器。对于 OpenAI 规范端点,可以不设置 `api_base`;也可以设置该字段以指向保留 Bearer 身份认证和 OpenAI 路由形态的 OpenAI 兼容代理。 ### 创建服务提供方密钥[​](#create-a-provider-key "创建服务提供方密钥的直接链接") 创建用于存储 OpenAI 凭证的服务提供方密钥: ``` # 请替换为实际值 export OPENAI_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openai-prod", "provider": "openai", "api_key": "'"${OPENAI_API_KEY}"'", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') ``` ❶ `provider` 为 `openai`。这是唯一允许 AISIX 回退到默认基础 URL `https://api.openai.com/v1` 的服务提供方值。 ❷ `api_key` 存储 OpenAI API Key。该值在存储前会被加密,读取端点不会返回此值。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `allowed_environments` 列出创建模型时可以引用该服务提供方密钥的环境。 AISIX Cloud Admin API 会从目录服务提供方派生适配器;仅 BYO 服务提供方密钥接受 `adapter` 字段。 对于 OpenAI,可以省略 `api_base`。如需指向兼容 Bearer 身份认证的代理或区域网关,请显式设置 `api_base`。Azure OpenAI 服务本身应使用专用的 [Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md) 集成。该命令会将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#create-a-model "创建模型的直接链接") 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "gpt-5.6-sol-prod", "model_name": "gpt-5.6-sol", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 OpenAI 模型 ID。本指南使用 [OpenAI 模型目录](https://developers.openai.com/api/docs/models)中当前的旗舰模型 `gpt-5.6-sol`。如果其他当前模型的成本、延迟或模态更适合工作负载,请选择相应模型。 ❸ `provider_key_id` 将别名关联到 OpenAI 服务提供方密钥。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建可访问模型别名的调用方 API Key 资源。控制平面会生成密钥值,并仅在创建响应中返回一次明文: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openai-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') ``` `allowed_models` 值引用上一步获取的模型 ID。 请妥善保存明文密钥。控制平面仅存储哈希值;此响应之后无法再获取明文。 每次写入后,配置都会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export OPENAI_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "openai-prod" provider: "openai" adapter: "openai" api_key: ${OPENAI_API_KEY} models: - display_name: "gpt-5.6-sol-prod" provider: "openai" model_name: "gpt-5.6-sol" provider_key: "openai-prod" api_keys: - display_name: "openai-caller" key_env: CALLER_API_KEY allowed_models: - "gpt-5.6-sol-prod" ``` 如果 AISIX 安装在本地,请在加载文件前进行验证: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#verify-the-provider-connection "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.6-sol-prod", "messages": [ { "role": "user", "content": "Say hello from OpenAI." } ] }' ``` 网关会返回 OpenAI 兼容响应,其中回显面向调用方的别名 `gpt-5.6-sol-prod`。请在 [OpenAI 用量仪表板](https://platform.openai.com/usage)中确认该请求。如果请求因上游认证错误而失败,请检查服务提供方密钥的 `api_key`。 对于推理、工具调用和多轮工作流,OpenAI 建议使用 Responses API。通过同一别名发送原生 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.6-sol-prod", "input": "Say hello from the OpenAI Responses API." }' ``` 由于模型配置的服务提供方是 `openai`,AISIX 会重写模型别名,并将请求转发到 OpenAI 原生 Responses 端点,而不会使用跨服务提供方的 Responses 桥接。 ## 使用 Sora 生成视频[​](#generate-videos-with-sora "使用 Sora 生成视频的直接链接") 警告 OpenAI 已于 2026 年 3 月 24 日[弃用 Videos API 和 Sora 2 系列模型](https://developers.openai.com/api/docs/deprecations),并将于 2026 年 9 月 24 日将其从 API 中移除。届时以 `sora-2` 或 `sora-2-pro` 为上游的别名将停止工作,OpenAI 也未在该 API 上给出替代模型。 同一个服务提供方密钥即可驱动网关建模的[视频路由](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。创建第二个别名,指向 Sora 模型 `sora-2` 或 `sora-2-pro`: 在 AISIX Cloud 中创建视频别名和仅限该别名的调用方 Key: ``` VIDEO_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "sora-video-prod", "model_name": "sora-2", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$VIDEO_MODEL_ID" VIDEO_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openai-video-caller", "allowed_models": ["'"${VIDEO_MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 对于开源 AISIX 网关,请将 `sora-video-prod` 添加到现有 `models` 集合。将现有 `openai-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(视频模型访问) ``` models: - display_name: "sora-video-prod" provider: "openai" model_name: "sora-2" provider_key: "openai-prod" api_keys: - display_name: "openai-caller" key_env: CALLER_API_KEY allowed_models: - "gpt-5.6-sol-prod" - "sora-video-prod" ``` 按上文所述验证并重载或重启声明式资源文件,然后使用现有调用方 Key 发起视频请求: ``` export VIDEO_API_KEY="$CALLER_API_KEY" ``` 提交任务: ``` curl -sS -X POST "$AISIX_PROXY/v1/videos" \ -H "Authorization: Bearer ${VIDEO_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "sora-video-prod", "prompt": "A paper boat drifts down a rain-soaked street at dusk.", "seconds": 4, "size": "1280x720" }' ``` 在为此路由编写脚本前,需要了解以下五项服务提供方特定行为: * **OpenAI 是唯一具有默认 Base URL 的视频服务提供方。** 与本页的 Chat 别名一样,OpenAI 视频别名在未设置 `api_base` 时也能工作。其他视频服务提供方都要求在密钥上设置 `api_base`。 * **`seconds` 和 `size` 由 Sora 自行校验。** OpenAI 的视频创建 schema 为 `seconds` 接受 `4`、`8` 或 `12`,为 `size` 列出 `720x1280`、`1280x720`、`1024x1792` 和 `1792x1024`,但各模型页面公布的分辨率范围更窄,请查阅别名所指模型的页面。AISIX 会将 `seconds` 以字符串形式转发,并在校验 `size` 的 `WIDTHxHEIGHT` 格式后原样转发,因此格式正确但该模型不接受的取值由服务提供方拒绝,而不是由网关拒绝。 * **已完成的视频经网关流式传输。** Sora 通过需要鉴权的内容端点交付成品文件,而不是签名 URL,因此 `GET /v1/videos/{id}/content` 返回 `200` 和 MP4 字节,而不是 `302`。AISIX 会使用服务提供方凭证获取文件并逐块转发,凭证不会到达调用方,大文件也不会增加网关内存用量。请据此规划网关的出口带宽:这些字节会经过网关,且不计入模型限流。 * **`progress` 是真实百分比。** Sora 会报告任务进度,因此轮询响应会携带服务提供方自己的完成百分比。不报告进度的服务提供方在任务完成前保持 `0`。 * **图生视频需要透传路由。** 标准化请求只建模 `prompt`、`seconds` 和 `size`;包括 `input_reference` 在内的其他字段会被忽略而不是拒绝,因此混剪或以图引导的请求会静默地只依据提示词生成。这类请求请通过 `/passthrough/openai/v1/videos` 发送原生 multipart 正文,原生混剪路由同理。OpenAI SDK 客户端同样只能走这条路径,但需要单独创建一个客户端:把它的 base URL 指向 `${AISIX_PROXY}/passthrough/openai/v1`,而不是本页其他位置使用的 `${AISIX_PROXY}/v1`,并在调用方 Key 的 `allowed_routes` 中授予该路由名称。其视频创建方法始终发送 `multipart/form-data`,而建模路由不接受该格式。透传不会返回统一的 AISIX 视频对象或网关编码的任务 ID。 完整的提交、轮询和下载工作流(包括状态语义和轮询时的限流行为)请参阅[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ## 端点覆盖范围[​](#endpoint-coverage "端点覆盖范围的直接链接") OpenAI 提供多种使用不同模型类型的 API。请为应用所需的每个上游模型分别配置 AISIX 模型别名。 | 路由 | 使用 OpenAI 支持的别名时的行为 | | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持 OpenAI 请求和响应形态。仍需遵循模型特定的功能和参数限制。 | | `/v1/responses` | 重写模型别名后转发到 OpenAI 原生 Responses 端点。有状态字段、托管工具、推理控制项和上游 SSE 均保留在原生路径上。 | | `/v1/completions` | 转发到 OpenAI,但这是旧版端点,且所选模型必须支持该端点。 | | `/v1/embeddings` | 支持使用 OpenAI Embedding 模型(例如 `text-embedding-3-large`)的别名。 | | `/v1/images/generations` | 支持使用当前 OpenAI 图像模型的别名。 | | `/v1/images/edits` | 支持使用 OpenAI 图像编辑模型(如 `gpt-image-2`)的别名。请求为 `multipart/form-data`;参见[图像编辑](https://docs.apiseven.com/ai-gateway/endpoints/image-editing.md)。 | | `/v1/videos` 及其状态和内容路由 | 支持使用 Sora 模型别名(`sora-2` 或 `sora-2-pro`)。由于 OpenAI 通过需要鉴权的端点交付成品文件,内容路由会将 MP4 经网关流式传输,而不是重定向。参见[使用 Sora 生成视频](#generate-videos-with-sora)。 | | `/v1/audio/*` | 支持使用适当的语音、转录或翻译模型别名。 | | `/v1/realtime` | 支持以直接 Realtime 模型别名进行 WebSocket 中继。请参阅 [Realtime API](https://docs.apiseven.com/ai-gateway/endpoints/realtime.md)。 | | `/v1/files`、`/v1/batches`、`/v1/fine_tuning/jobs` | 通过 OpenAI 适配器提供支持。这些任务型路由选择凭证的方式不同于普通推理调用;请参阅[文件、批处理和微调](https://docs.apiseven.com/ai-gateway/endpoints/batch-files-fine-tuning.md)。 | | `/v1/messages` | 通过 OpenAI Chat 进行转换;OpenAI 不提供原生 Anthropic Messages 端点。 | | `/v1/messages/count_tokens` | 拒绝,因为此路由的 Token 计数要求使用 Anthropic 支持的模型。 | | `/v1/models` | 返回调用方可访问的 AISIX 模型别名,而不是 OpenAI 账户的模型清单。需要原生列表时,请使用 `/passthrough/openai/v1/models`。 | | `/v1/rerank` | AISIX 接受 `openai` 服务提供方值,但 OpenAI 公共 API 不提供 `/v1/rerank`,因此上游会拒绝调用。 | 对于 AISIX 尚未建模的 OpenAI 路由(例如内容审核或图像变体),请使用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。本页的 `/passthrough/openai` 路径假定一条路由认领该前缀,`target_url` 设为 OpenAI 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予该路由。透传使用 OpenAI 模型 ID 而不是 AISIX 别名,并具有不同的流式传输和用量核算行为。 ## 使用 OpenAI SDK[​](#use-an-openai-sdk "使用 OpenAI SDK的直接链接") 将 `AISIX_BASE_URL` 设置为 `${AISIX_PROXY}/v1`,并使用调用方密钥作为 API Key。请参阅 [OpenAI SDK](https://docs.apiseven.com/ai-gateway/getting-started/openai-sdk.md) 指南。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你已将 AISIX 连接到 OpenAI,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [使用 Chat Completions 输入和输出音频](https://docs.apiseven.com/ai-gateway/endpoints/chat-audio.md):向兼容的聊天模型发送录制音频,或保存模型生成的音频响应。 * [Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md):改为配置 Azure 托管的 OpenAI 部署。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看受支持的代理端点和服务提供方专属边界。 --- # 其他 OpenAI 兼容服务提供方 许多公开模型服务提供方都提供 OpenAI 兼容 API。当服务提供方接受通过 Bearer Token 认证的 OpenAI Chat Completions 请求并已列入 AISIX 服务提供方目录时,AISIX Cloud 可以连接到它。开源 AISIX 网关可在操作人员选择的服务提供方标签下使用任何具有相同协议和认证结构的可访问端点。 如果某个服务提供方在[服务提供方上游](https://docs.apiseven.com/ai-gateway/providers/overview.md)中已有专用配置,请按照对应页面操作。以下配置是适用于其他公开服务提供方的参数化模板;AISIX Cloud 路径假定该服务提供方已列入其目录。 对于私有或客户自行运营的服务器,请使用专用的 [Ollama](https://docs.apiseven.com/ai-gateway/providers/ollama.md)、[vLLM](https://docs.apiseven.com/ai-gateway/providers/vllm.md) 或[自定义端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)指南。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * OpenAI 兼容服务提供方的 API Key。对于 AISIX Cloud,该服务提供方必须列入 AISIX 服务提供方目录;开源资源工作流不使用该目录进行准入。 * `curl` 和 `jq`。 ## 选择服务提供方值[​](#select-provider-values "选择服务提供方值的直接链接") 对于 AISIX Cloud,请选择 AISIX 服务提供方目录中显示的准确 ID。对于开源资源文件,请选择稳定的服务提供方标签,例如服务提供方的小写名称。然后从服务提供方官方 API 参考中复制 API 根地址和模型 ID: ``` export PROVIDER_ID="YOUR_PROVIDER_ID" export PROVIDER_API_KEY="YOUR_PROVIDER_API_KEY" export PROVIDER_API_BASE="https://api.provider.example/v1" export UPSTREAM_MODEL_ID="publisher/model-id" export MODEL_ALIAS="provider-model-prod" ``` 以上地址和 ID 均为虚构占位符。运行配置前,请替换所有值。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由该服务提供方支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 AISIX 通过 `openai` 适配器连接,并使用服务提供方的 API 根地址作为 `api_base`。请为服务提供方密钥设置说明性标签,以便运维人员之后识别上游。 ### 创建服务提供方密钥[​](#create-a-provider-key "创建服务提供方密钥的直接链接") ``` PROVIDER_KEY_RESPONSE=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- <<EOF { "display_name": "community-provider-prod", "provider": "${PROVIDER_ID}", "api_key": "${PROVIDER_API_KEY}", "api_base": "${PROVIDER_API_BASE}", "allowed_environments": ["${ENV_ID}"] } EOF ) PROVIDER_KEY_ID=$(printf '%s' "$PROVIDER_KEY_RESPONSE" | jq -er '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` `provider` 必须与 AISIX 目录中的 ID 完全一致。AISIX Cloud Admin API 会为社区目录服务提供方派生 `openai` 适配器和 Bearer 认证。不要发送 `adapter` 字段;仅当 `provider` 为 `byo` 时才接受该字段。 没有专用配置页面的服务提供方是从已同步的公开目录接入,而不是来自网关内置服务提供方列表。如果创建操作返回提及目录的 `400 INVALID_REQUEST`,表示控制平面的当前目录中没有该服务提供方。联网部署会在启动时以及每 24 小时同步;打包的 On-Premises 部署默认使用内置快照,不会刷新。请在在线同步后重试、查看 [On-Premises 定价目录设置](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md#pricing-catalog),或改用[自定义端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)配置上游。 AISIX 会将端点路径追加到 `api_base`。如果官方端点要求 `/v1`、`/openai` 或 `/openai/v1` 等服务提供方专属前缀,请将其包含在内。显式设置根地址还可避免依赖最近一次目录同步所缓存的 API 基础地址。 服务提供方密钥中存储的凭证遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中说明的凭证处理行为。 ### 创建模型[​](#create-a-model "创建模型的直接链接") 将面向调用方的别名映射到服务提供方的准确模型 ID: ``` MODEL_RESPONSE=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @- <<EOF { "display_name": "${MODEL_ALIAS}", "model_name": "${UPSTREAM_MODEL_ID}", "provider_key_id": "${PROVIDER_KEY_ID}" } EOF ) MODEL_ID=$(printf '%s' "$MODEL_RESPONSE" | jq -er '.model.id') echo "$MODEL_ID" ``` `display_name` 是调用方在 `model` 中发送的别名。`model_name` 会原样发送到上游,因此请保留发布方命名空间、大小写、标点和版本后缀。 如需为预算核算或用量报告配置成本元数据,请参阅[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建仅限该模型资源的调用方密钥: ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "community-provider-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` 明文仅在创建调用方密钥时返回。请妥善保存。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export PROVIDER_ID="YOUR_PROVIDER_ID" export PROVIDER_API_BASE="YOUR_PROVIDER_API_BASE" export UPSTREAM_MODEL_ID="YOUR_UPSTREAM_MODEL_ID" export MODEL_ALIAS="YOUR_MODEL_ALIAS" export PROVIDER_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 开源网关会验证服务提供方标签的格式,但不要求它出现在 AISIX Cloud 目录中。请在服务提供方密钥和模型上使用同一标签。该标签还会在遥测数据中标识上游,并按约定用于 `/passthrough/example-provider/*` 等透传路由路径。 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "community-provider-prod" provider: "${PROVIDER_ID}" adapter: "openai" api_key: ${PROVIDER_API_KEY} api_base: "${PROVIDER_API_BASE}" models: - display_name: "${MODEL_ALIAS}" provider: "${PROVIDER_ID}" model_name: "${UPSTREAM_MODEL_ID}" provider_key: "community-provider-prod" api_keys: - display_name: "community-provider-caller" key_env: CALLER_API_KEY allowed_models: - "${MODEL_ALIAS}" ``` 如果 AISIX 安装在本地,请在加载文件前进行验证: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#verify-the-provider-connection "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @- <<EOF { "model": "${MODEL_ALIAS}", "messages": [ { "role": "user", "content": "Say hello through the configured provider." } ] } EOF ``` 响应应与 OpenAI 兼容,并包含面向调用方的别名。如果服务提供方提供请求日志或用量页面,请用其确认请求已到达预期的上游账号和模型。 如果网关返回上游认证错误,请检查服务提供方密钥的 `api_key`。如果返回上游路由错误,请检查 `api_base` 和 `UPSTREAM_MODEL_ID`。 ## 支持服务提供方专属行为[​](#support-provider-specific-behavior "支持服务提供方专属行为的直接链接") 服务提供方必须接受 OpenAI Chat Completions 请求。使用不同请求格式的服务提供方需要原生[适配器协议族](https://docs.apiseven.com/ai-gateway/providers/adapters.md)或兼容端点。 `openai` 适配器不会让每个规范化 AISIX 端点对所有服务提供方标签都可用: * `/v1/completions`、`/v1/embeddings`、`/v1/audio/*`、`/v1/files`、`/v1/batches` 和 `/v1/fine_tuning/jobs` 可通过此适配器分派,但只有上游实现对应 OpenAI 路由和字段时才可用。 * 对社区服务提供方标签,`/v1/responses` 会通过 Chat 使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。`/v1/messages` 同样会通过 Chat 转换请求和响应,而不是使用服务提供方原生 Messages 路由。 * `/v1/images/generations`、`/v1/rerank` 和 `/v1/videos` 实施服务提供方允许列表。即使上游提供同名路由,也可能拒绝社区服务提供方标签。 应用需要服务提供方原生路由或协议时,请配置一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md);按约定路由认领 `/passthrough/<标签>`,`target_url` 设为该服务提供方的 API 基础地址,且调用方 Key 必须在 `allowed_routes` 中授予该路由。透传不会重写模型别名,且流式传输和用量核算行为不同,因此采用前请查看其限制。规范化路由矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 AISIX 会保留 `reasoning_content`,并将 `reasoning` 标准化到该规范字段。如果服务提供方从不同的 `delta` 路径流式输出推理内容,请在服务提供方密钥上使用 [`response.reasoning_field` 覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看受支持的代理端点和服务提供方专属边界。 --- # OpenRouter [OpenRouter](https://openrouter.ai/docs/guides/overview/models) 通过一套 API 和凭证聚合多个服务提供方的模型。AISIX 将 OpenRouter 凭证保留在网关中,同时提供稳定的模型别名、调用方访问控制、速率限制和用量核算。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [OpenRouter 密钥页面](https://openrouter.ai/settings/keys)获取的 OpenRouter API Key。OpenRouter 密钥值以 `sk-or-` 开头。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 OpenRouter 支持的 Chat Completions 和原生 Responses 创建服务提供方密钥、模型别名和调用方 API Key。 由于 OpenRouter 提供 OpenAI 兼容 API,AISIX 会通过 `openai` 适配器连接,并将 OpenRouter API Root 用作 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 OpenRouter 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export OPENROUTER_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openrouter-prod", "provider": "openrouter", "api_key": "'"${OPENROUTER_API_KEY}"'", "api_base": "https://openrouter.ai/api/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `openrouter`。AISIX Cloud Admin API 会根据目录服务提供方推导适配器;`adapter` 字段仅适用于 BYO 服务提供方密钥。 ❷ `api_key` 存储 OpenRouter API Key。该值会在存储前加密,读取端点绝不会将其返回。它遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://openrouter.ai/api/v1`。OpenRouter 在其主机的 `/api` 路径下提供 API,因此该 Root 同时包含 /api 和 /v1,而不是 `https://openrouter.ai/v1`。AISIX 会在此值后追加端点路径,例如 `/chat/completions`。 ❹ `apis.responses` 声明 OpenRouter 在同一根地址提供 Responses API。这样,AISIX 就能使用 OpenRouter 的原生请求和响应格式,而不必通过 Chat Completions 转换。 请始终为 OpenRouter 显式设置 `api_base`。与多数精选目录服务提供方不同,OpenRouter 在 AISIX 中没有预先维护的默认 Base URL;如果省略 `api_base`,AISIX Cloud Admin API 将依赖同步的目录元数据,创建操作可能会以 `400 INVALID_REQUEST` 失败。 网关在请求时也会执行同一规则。当非 OpenAI 服务商的服务提供方密钥以空 `api_base` 到达网关时,OpenAI 系列桥接器不会回退到 OpenAI 公共主机,而会返回上游配置错误。因此,OpenRouter 凭证绝不会发送到 `api.openai.com`。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") OpenRouter 模型 ID 带有命名空间。上游 ID 的格式为 `vendor/model`,其中服务商前缀是 ID 的组成部分,而不是路由提示。创建模型别名前,请在 [OpenRouter 模型列表](https://openrouter.ai/models)中查看当前 ID。 命名约定有四种形式: * `vendor/model` 是基本形式,例如 `anthropic/claude-sonnet-5`、`openai/gpt-5.2-pro` 或 `deepseek/deepseek-v4-pro`。 * 变体后缀追加到 Slug 末尾,例如 `:free` 或 `:thinking`。 * 服务商名称前的 `~` 会解析为某个模型系列的最新版本,例如 `~anthropic/claude-sonnet-latest`。 * `openrouter/auto` 选择 OpenRouter 自身的 Auto Router,而不是具名模型。 模型别名和上游模型 ID 是两个不同的名称。`display_name` 是调用方放入请求 `model` 字段的 AISIX 别名,`model_name` 则是 OpenRouter 模型 ID。AISIX 会将 `model_name` 原样转发到上游,包括服务商前缀中的 `/`。它不会拆分 ID,也不会移除服务商部分。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openrouter-sonnet-prod", "model_name": "anthropic/claude-sonnet-5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。请使用简短的扁平名称。将带命名空间的上游 ID 复制到别名中,会降低客户端代码的可读性,也会让人难以分辨实际使用的是哪个别名。 ❷ `model_name` 是 OpenRouter 模型 ID,例如 `anthropic/claude-sonnet-5` 或 `openai/gpt-5.2-pro`。 ❸ `provider_key_id` 将别名关联到 OpenRouter 服务提供方密钥。 为每个要公开的 OpenRouter 模型分别创建一个别名。一个 OpenRouter 服务提供方密钥可以支持任意数量的别名,这样一套凭证就能覆盖多个服务商,同时每个别名仍拥有各自的允许列表条目和速率限制。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问模型别名的调用方 API Key 资源。网关会生成密钥值,明文只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "openrouter-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值通过模型 ID 引用模型,因此该密钥只能访问你创建的别名。写入后,配置会自动投射到关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export OPENROUTER_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "openrouter-prod" provider: "openrouter" adapter: "openai" api_key: ${OPENROUTER_API_KEY} api_base: "https://openrouter.ai/api/v1" apis: responses: {} models: - display_name: "openrouter-sonnet-prod" provider: "openrouter" model_name: "anthropic/claude-sonnet-5" provider_key: "openrouter-prod" api_keys: - display_name: "openrouter-caller" key_env: CALLER_API_KEY allowed_models: - "openrouter-sonnet-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "openrouter-sonnet-prod", "input": "Say hello from OpenRouter." }' ``` AISIX 会将请求发送至 OpenRouter 的原生 Responses 端点,在上游请求中把 AISIX 别名替换为带命名空间的模型 ID,并在响应中恢复该别名。 如果请求失败,请先检查以下 OpenRouter 特有原因: * 上游返回 `404` 通常表示 `model_name` 中缺少服务商前缀或前缀拼写错误。`claude-sonnet-5` 不是有效的 OpenRouter ID;`anthropic/claude-sonnet-5` 才是。 * 上游返回 `401` 通常表示 `api_key` 中保存的不是 OpenRouter 密钥。OpenRouter 不接受由模型原始服务商签发的密钥。 * 连接到意外主机时出现错误,通常表示 `api_base` 缺少 `/api` 路径段。 ## 通过透传使用原生 Messages[​](#通过透传使用原生-messages "通过透传使用原生 Messages的直接链接") 上述服务提供方密钥已经会把 Responses 请求发送到 OpenRouter 原生端点,同时保留 AISIX 模型别名。OpenRouter 还在同一 API Root 上提供原生 Messages API,但其文档使用 Bearer 身份认证,且未提供 Count Tokens。请继续通过透传访问原生 Messages,不要添加 `apis.messages`;该声明会发送 `x-api-key`,并把两条 Messages 路由表示为一个完整协议面。 调用 `/passthrough/openrouter/messages`,并发送带命名空间的 OpenRouter 模型 ID,因为透传不会重写别名。详细的路由行为和透传设置参见[OpenRouter 模型的端点支持情况](#endpoint-support-for-openrouter-models)。 ## 传递 OpenRouter 路由和推理控制参数[​](#传递-openrouter-路由和推理控制参数 "传递 OpenRouter 路由和推理控制参数的直接链接") AISIX 不会移除其未建模的顶层 Chat Completions 字段。未建模字段会原样转发到上游,因此 OpenRouter 自身的请求级控制参数会原封不动地到达 OpenRouter。 通过网关通常会使用以下两个 OpenRouter 控制对象: * `provider` 用于选择处理请求的上游服务商。它接受 `order`、`allow_fallbacks` 和 `require_parameters` 等字段。请参阅[服务提供方路由](https://openrouter.ai/docs/guides/routing/provider-selection)。 * `reasoning` 通过 `enabled`、`effort` 和 `max_tokens` 控制思维链行为,顶层 `reasoning_effort` 字段是推理强度设置的别名。请参阅[推理 Token](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens)。 以下请求固定提供服务的服务商、禁用 OpenRouter 故障转移,并请求较高的推理强度: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "openrouter-sonnet-prod", "messages": [ { "role": "user", "content": "Summarize the CAP theorem in two sentences." } ], "provider": { "order": ["anthropic"], "allow_fallbacks": false }, "reasoning": { "effort": "high" } }' ``` ### 读取推理输出[​](#读取推理输出 "读取推理输出的直接链接") 当模型公开推理文本时,OpenRouter 会在非流式路径的 `message.reasoning` 和流式路径的 `delta.reasoning` 中返回该文本,而不是使用其他 OpenAI 兼容上游采用的 `reasoning_content` 字段。部分模型不会公开其推理文本。 AISIX 会将二者标准化到规范的 `reasoning_content` 字段,因此无论上游使用哪种字段名称,客户端都读取 `choices[0].message.reasoning_content` 和 `choices[0].delta.reasoning_content`。当上游同时发送两个字段时,`reasoning_content` 优先。 此标准化逻辑内置于 `openai` 适配器的 OpenRouter 处理中。不要在 OpenRouter 服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides) 覆盖项。该覆盖项用于 AISIX 尚无法识别其推理路径的上游。 OpenRouter 还可能返回结构化 `reasoning_details` 数组;某些多轮推理和工具调用流程需要原样重放该数组。规范化 AISIX Chat 路径不会保留它。应用必须保留结构化推理状态时,请通过透传路由使用 OpenRouter 原生端点。 警告 服务提供方和推理控制参数是 OpenRouter 特有的请求字段。如果以后将别名重新指向其他服务提供方,或将其置于[多目标路由模型](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md)之后,AISIX 会把这些字段转发到实际处理请求的上游,而非 OpenRouter 上游可能会忽略或拒绝无法识别的字段。 ## OpenRouter 模型的端点支持情况[​](#endpoint-support-for-openrouter-models "OpenRouter 模型的端点支持情况的直接链接") OpenRouter 模型别名并不能访问所有代理路由。部分路由根据配置的服务提供方值而非适配器系列进行限制。 | 路由 | OpenRouter 支持情况 | | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions`,包括 `stream: true` | 通过 `openai` 适配器支持。 | | `/v1/completions` | 对接受 OpenRouter 旧版基于 Prompt 的 Completions 格式的模型提供支持。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 OpenRouter 原生 [Responses API](https://openrouter.ai/docs/api/reference/responses/overview)。如果没有此声明,AISIX 会通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)转换请求。 | | `/v1/messages` | 通过转换为 Chat Completions 支持,而非调用 OpenRouter 原生 [Anthropic Messages API](https://openrouter.ai/docs/api/api-reference/anthropic-messages/create-a-message)。没有 Chat 等价项的字段和响应块无法往返保留。原生协议请使用 `/passthrough/openrouter/messages`。 | | `/v1/messages/count_tokens` | 不可用。此 AISIX 路由要求采用 Anthropic 协议的服务提供方密钥,而 OpenRouter 集成使用 `openai` 适配器。 | | `/v1/embeddings` | 当别名指向 OpenRouter 嵌入模型时支持。AISIX 会将 OpenAI Embeddings 请求格式转发到 `https://openrouter.ai/api/v1/embeddings`。 | | `/v1/audio/speech` | 当别名指向 OpenRouter 语音模型时支持,因为 JSON 请求和上游路径兼容。 | | `/v1/audio/transcriptions` 和 `/v1/audio/translations` | 这些规范化路由不支持。AISIX 接受 OpenAI 风格的 Multipart 上传,而 OpenRouter 转录端点接受 JSON `input_audio` 对象,且 OpenRouter 未提供匹配的翻译路由。请使用 `/passthrough/openrouter/audio/transcriptions` 和 OpenRouter 原生 JSON 结构。 | | `/v1/images/generations` | 不可用。该路由只接受服务提供方值为 `openai` 的模型,且 OpenRouter 原生图片端点是 `/images`,而非 `/images/generations`。请使用 `/passthrough/openrouter/images` 和 [OpenRouter 图片请求](https://openrouter.ai/docs/guides/overview/multimodal/image-generation)。 | | `/v1/rerank` | 不可用。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。请使用 `/passthrough/openrouter/rerank` 和 OpenRouter 重排模型 ID 调用其原生路由。 | | `/v1/videos` 及其状态和内容路由 | 不可用。`openrouter` 服务提供方值会返回 `501 not_implemented`。对于 OpenRouter 原生[异步视频 API](https://openrouter.ai/docs/guides/overview/multimodal/video-generation),通过 `/passthrough/openrouter/videos` 提交,再使用返回的作业 ID 调用 `/passthrough/openrouter/videos/{jobId}` 和 `/passthrough/openrouter/videos/{jobId}/content`。 | | `/v1/files` | 不要将规范化文件路由用于 OpenRouter 原生文件引用。AISIX 会为其作业路由协议封装返回的文件 ID,但不会在原生 OpenRouter Messages 或 Responses 请求体中解封这些 ID。请使用 `/passthrough/openrouter/files` 保留 OpenRouter 原始文件 ID。 | | `/v1/batches` 和 `/v1/fine_tuning/jobs` | 不可用,因为 OpenRouter 未发布匹配的路由。 | | `/v1/models` | 返回调用方可访问的 AISIX 模型别名,而非 OpenRouter 模型目录。原生列表请使用 `/passthrough/openrouter/models`。 | | `/passthrough/openrouter/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用。 | 对于 AISIX 未标准化的路由,请使用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。本页的 `/passthrough/openrouter` 路径假定这样一条路由认领该前缀,`target_url` 设为 `https://openrouter.ai/api/v1`;在调用方 Key 的 `allowed_routes` 上授予该路由。网关会将剩余路径追加到路由的 `target_url`;如果路径开头的 `v1` 与目标末尾的 `/v1` 重复,则会移除一个 v1 路径段。因此,`/passthrough/openrouter/models` 和 `/passthrough/openrouter/v1/models` 都会到达 `https://openrouter.ai/api/v1/models`。 透传路由会原样转发请求体,不会重写模型别名。请发送带命名空间的 OpenRouter 模型 ID(例如 `anthropic/claude-sonnet-5`),而非 `openrouter-sonnet-prod`。路由会增量中继 SSE 响应。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。如果规范化端点的协议足够使用,并且需要 AISIX Token 与成本核算,请优先使用规范化端点。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 OpenRouter,并验证了模型别名。请继续阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 OpenRouter 和直接服务商账户之间进行故障转移。 * [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md):访问 AISIX 未标准化的 OpenRouter 路由。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # 选择服务提供方上游 服务提供方上游是 AISIX 网关解析面向调用方的模型别名后调用的模型服务。AISIX 会将上游凭证存储在服务提供方密钥中,并使用适配器按上游要求的格式发送请求。 请根据使用的端点和账号选择配置路径,而不只是根据模型系列选择。如果拥有 AI Studio API Key,请通过 Google AI Studio 配置 Gemini;如果模型托管在 Google Cloud 项目中,请使用 Google Vertex AI。 以下每种配置都同时支持 AISIX Cloud 和开源 AISIX 网关。每份服务提供方指南都包含两个产品的完整配置章节,随后提供共用的验证步骤。 ## 配置路径[​](#setup-paths "配置路径的直接链接") AISIX 支持直接集成、其他视频生成与重排序路由、社区目录条目以及通用 OpenAI 兼容端点等多类服务提供方配置。 ### 直接服务提供方与托管平台[​](#直接服务提供方与托管平台 "直接服务提供方与托管平台的直接链接") 请从直接服务提供方和托管平台配置中选择: | 配置 | 适用场景 | 适配器 | | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------- | | [OpenAI](https://docs.apiseven.com/ai-gateway/providers/openai.md) | 通过 OpenAI API 账号调用 GPT 聊天模型、向量嵌入、图片、音频或 Sora 视频生成。 | `openai` | | [Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md) | 模型托管在 Azure OpenAI 部署中。 | `azure-openai` | | [Anthropic](https://docs.apiseven.com/ai-gateway/providers/anthropic.md) | 通过 Anthropic API 调用 Claude。 | `anthropic` | | [AWS Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md) | 模型或推理配置文件托管在 AWS Bedrock 中。 | `bedrock` | | [Gemini(Google AI Studio)](https://docs.apiseven.com/ai-gateway/providers/gemini.md) | 使用 Google AI Studio API Key 调用 Gemini。 | `openai` | | [Google Vertex AI](https://docs.apiseven.com/ai-gateway/providers/google-vertex-ai.md) | Gemini 或其他 Vertex 发布方模型托管在 Google Cloud 项目中。 | `vertex` | | [Qwen(阿里云)](https://docs.apiseven.com/ai-gateway/providers/qwen.md) | 通过阿里云百炼 Model Studio 调用 Qwen 聊天模型或 Wan 视频生成。 | `openai` | | [DeepSeek](https://docs.apiseven.com/ai-gateway/providers/deepseek.md) | 通过 DeepSeek API 调用模型。 | `openai` | | [Groq](https://docs.apiseven.com/ai-gateway/providers/groq.md) | 调用 Groq 托管的模型。 | `openai` | | [Mistral AI](https://docs.apiseven.com/ai-gateway/providers/mistral.md) | 通过 Mistral API 调用模型。 | `openai` | | [Together AI](https://docs.apiseven.com/ai-gateway/providers/together.md) | 调用 Together AI 目录中的模型。 | `openai` | | [OpenRouter](https://docs.apiseven.com/ai-gateway/providers/openrouter.md) | 通过一个 OpenRouter 账号调用多个厂商的模型。 | `openai` | | [Fireworks AI](https://docs.apiseven.com/ai-gateway/providers/fireworks-ai.md) | 调用 Fireworks 托管的模型。 | `openai` | | [Perplexity](https://docs.apiseven.com/ai-gateway/providers/perplexity.md) | 调用基于搜索增强的 Sonar 模型。 | `openai` | | [Cohere](https://docs.apiseven.com/ai-gateway/providers/cohere.md) | 调用 Cohere Command 模型、向量嵌入或 Rerank。 | `openai` | | [Cerebras](https://docs.apiseven.com/ai-gateway/providers/cerebras.md) | 在 Cerebras 推理硬件上调用开放权重模型。 | `openai` | | [Moonshot AI(Kimi)](https://docs.apiseven.com/ai-gateway/providers/moonshotai.md) | 通过 Moonshot AI 平台调用 Kimi 模型。 | `openai` | | [Zhipu AI(GLM)](https://docs.apiseven.com/ai-gateway/providers/zhipuai.md) | 调用 GLM 聊天模型或 CogVideoX 视频生成。 | `openai` | | [Hugging Face](https://docs.apiseven.com/ai-gateway/providers/huggingface.md) | 通过 Hugging Face Inference Providers 路由调用开放权重模型。 | `openai` | | [Baseten](https://docs.apiseven.com/ai-gateway/providers/baseten.md) | 调用 Baseten Model 接口或专用 Baseten 部署。 | `openai` | ### 其他视频生成与重排序配置[​](#其他视频生成与重排序配置 "其他视频生成与重排序配置的直接链接") 另有三种配置适用于网关原生实现了视频或 Rerank 协议的服务提供方。`openai` 适配器负责构造其聊天和向量嵌入流量,而[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)和 [Rerank](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md) 路由则根据服务提供方值本身进行分发。目录覆盖范围因服务提供方和模型而异。对于会上报可计费用量的端点,如果 AISIX Cloud 没有匹配的目录价格,请通过[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)配置组织级覆盖项。模型选择和各端点的核算行为请参阅对应服务提供方页面: | 配置 | 适用场景 | 适配器 | | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -------- | | [Jina](https://docs.apiseven.com/ai-gateway/providers/jina.md) | 调用 Jina 向量嵌入模型,或通过 Rerank 路由调用重排序模型。 | `openai` | | [RunwayML](https://docs.apiseven.com/ai-gateway/providers/runwayml.md) | 通过视频路由运行 Runway Gen 或 Runway 托管的 Veo 视频任务。 | `openai` | | [火山引擎方舟(豆包)](https://docs.apiseven.com/ai-gateway/providers/volcengine-ark.md) | 通过火山引擎方舟调用豆包聊天模型或 Seedance 视频生成。 | `openai` | ### 社区目录服务提供方[​](#社区目录服务提供方 "社区目录服务提供方的直接链接") AISIX Cloud 还可以为 models.dev 中的社区目录服务提供方创建服务提供方密钥。这些服务提供方默认使用 `openai` 适配器,但 AISIX 不会为其维护服务提供方专属的请求改写、响应改写或基础 URL 特殊处理。开源网关可以使用相同的服务提供方标识符作为标签,但必须在 `resources.yaml` 中显式设置适配器和基础 URL。当服务提供方已在目录中提供,且需要服务提供方专属配置指南时,请使用以下页面: | 配置 | 适用场景 | 适配器 | | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | -------- | | [Amazon Nova API](https://docs.apiseven.com/ai-gateway/providers/amazon-nova.md) | 不通过 Bedrock,而是通过基于 API Key 的 Nova 直接端点调用 Nova 模型。 | `openai` | | [Cloudflare Workers AI](https://docs.apiseven.com/ai-gateway/providers/cloudflare-workers-ai.md) | 调用账号级 Cloudflare Workers AI 模型 ID,例如 `@cf/openai/gpt-oss-120b`。 | `openai` | | [Databricks](https://docs.apiseven.com/ai-gateway/providers/databricks.md) | 调用工作区中的 Databricks Model Serving 端点。 | `openai` | | [DeepInfra](https://docs.apiseven.com/ai-gateway/providers/deepinfra.md) | 通过 DeepInfra 的 OpenAI 兼容 API 调用其托管的开放权重模型。 | `openai` | | [DigitalOcean Gradient AI](https://docs.apiseven.com/ai-gateway/providers/digitalocean-gradient-ai.md) | 通过 DigitalOcean Serverless Inference 调用基础模型。 | `openai` | | [Meta Llama API](https://docs.apiseven.com/ai-gateway/providers/meta-llama-api.md) | 通过 Meta 的 OpenAI 兼容直接 API 调用 Llama 模型。 | `openai` | | [MiniMax](https://docs.apiseven.com/ai-gateway/providers/minimax.md) | 通过 OpenAI 兼容 API 根地址调用 MiniMax 模型。 | `openai` | | [ModelScope](https://docs.apiseven.com/ai-gateway/providers/modelscope.md) | 调用 ModelScope API-Inference 模型 ID。 | `openai` | | [Nebius Token Factory](https://docs.apiseven.com/ai-gateway/providers/nebius-token-factory.md) | 调用 Nebius Token Factory 托管的开放模型。 | `openai` | | [NVIDIA NIM](https://docs.apiseven.com/ai-gateway/providers/nvidia-nim.md) | 调用 NVIDIA 托管的 NIM API 或 NVIDIA 发布的模型 ID。 | `openai` | | [Novita AI](https://docs.apiseven.com/ai-gateway/providers/novita-ai.md) | 通过 Novita 的 LLM API 调用其托管的开放模型。 | `openai` | | [OVHcloud AI Endpoints](https://docs.apiseven.com/ai-gateway/providers/ovhcloud-ai-endpoints.md) | 通过 OVHcloud 的 OpenAI 兼容端点调用模型。 | `openai` | | [SiliconFlow](https://docs.apiseven.com/ai-gateway/providers/siliconflow.md) | 调用 SiliconFlow 托管的组织命名空间模型 ID。 | `openai` | | [Snowflake Cortex](https://docs.apiseven.com/ai-gateway/providers/snowflake-cortex.md) | 通过 Cortex REST API 调用 Snowflake 账号中的模型。 | `openai` | | [Weights & Biases Inference](https://docs.apiseven.com/ai-gateway/providers/wandb-inference.md) | 通过 W\&B Inference 调用开放模型。 | `openai` | | [xAI](https://docs.apiseven.com/ai-gateway/providers/xai.md) | 通过 xAI 的 OpenAI 兼容 API 调用 Grok 模型。 | `openai` | ### 其他 OpenAI 兼容端点[​](#其他-openai-兼容端点 "其他 OpenAI 兼容端点的直接链接") 对于其他接受 OpenAI 兼容 Chat Completions 请求的公开或私有端点,请选择相应的通用配置: | 配置 | 适用场景 | 适配器 | | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------- | | [其他 OpenAI 兼容服务提供方](https://docs.apiseven.com/ai-gateway/providers/openai-compatible-vendors.md) | 公开服务提供方公开了 OpenAI 兼容 API,但没有专用配置指南。 | `openai` | | [Ollama](https://docs.apiseven.com/ai-gateway/providers/ollama.md) | 在本地或私有 Ollama 服务器上运行模型。 | `openai` | | [vLLM](https://docs.apiseven.com/ai-gateway/providers/vllm.md) | 使用 vLLM 提供的 OpenAI 兼容服务器托管私有模型。 | `openai` | | [自定义端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md) | 运行其他私有 OpenAI 兼容端点,例如 SGLang 或内部代理。 | `openai` | 每种配置都会创建相同的网关资源:服务提供方密钥、模型别名和调用方 API Key。配置页面会提供该服务提供方所需的凭证、上游模型标识符、基础 URL 和适配器详情。请在[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)中对比路由支持范围,或在[适配器协议族](https://docs.apiseven.com/ai-gateway/providers/adapters.md)中查看上游请求格式。 --- # OVHcloud AI Endpoints [OVHcloud AI Endpoints](https://docs.ovhcloud.com/en/guides/public-cloud/ai-machine-learning/ai-endpoints-getting-started) 为托管模型提供推理端点。AISIX 为应用提供调用方密钥和稳定模型别名,以便访问这些端点。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具备写入权限的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一个 OVHcloud AI Endpoints 访问 Token。 * 所选模型的访问权限。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` OVHcloud 是提供 OpenAI 兼容端点的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行身份认证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` export OVHCLOUD_API_KEY="YOUR_OVHCLOUD_ACCESS_TOKEN" PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "ovhcloud-prod", "provider": "ovhcloud", "api_key": "'"${OVHCLOUD_API_KEY}"'", "api_base": "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` 使用目录 ID `ovhcloud` 并省略 `adapter`。AISIX 会派生 OpenAI 传输格式和 Bearer 身份认证。 API Base 是 OVHcloud 文档中所述的共享 OpenAI 兼容 Root,其中包含 `/v1`;AISIX 会向该 Base 追加所选端点的路径。 `apis.responses` 声明会把 Responses 请求发送至同一 API Base 上的 OVHcloud 原生端点,而不是通过 Chat Completions 转换。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 使用准确的 OVHcloud 模型 ID 创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "ovhcloud-gptoss-prod", "model_name": "gpt-oss-20b", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` OVHcloud 模型 ID 不一定与发布方的原始仓库 ID 一致。请复制 OVHcloud 显示的值,包括下划线、连字符和大小写。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "ovhcloud-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export OVHCLOUD_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "ovhcloud-prod" provider: "ovhcloud" adapter: "openai" api_key: ${OVHCLOUD_API_KEY} api_base: "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1" apis: responses: {} models: - display_name: "ovhcloud-gptoss-prod" provider: "ovhcloud" model_name: "gpt-oss-20b" provider_key: "ovhcloud-prod" api_keys: - display_name: "ovhcloud-caller" key_env: CALLER_API_KEY allowed_models: - "ovhcloud-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载前校验文件: ``` aisix validate --resources resources.yaml ``` 校验后,请在网关进程环境中提供所引用的环境变量并启动网关。仅当这些变量已可用于现有网关进程时才重新加载;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的校验和启动命令。挂载此 `resources.yaml` 文件,并在两个命令中使用 `-e` 传入该文件引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ovhcloud-gptoss-prod", "input": "Say hello from OVHcloud AI Endpoints.", "store": false }' ``` AISIX 会使用 Bearer 身份认证,将 OVHcloud 模型 ID 发送至原生 Responses 端点,然后在响应中恢复 AISIX 别名。OVHcloud 当前不管理 Responses 状态,因此要求设置 `store: false`。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") OVHcloud 模型别名无法访问每个代理路由。AISIX 在标准化推理路由上使用 `openai` 适配器,但部分路由还会限制配置的服务提供方值。 | 路由 | OVHcloud 支持情况 | | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions`,包括 `stream: true` | 支持。工具调用、结构化输出、视觉和其他能力取决于所选模型。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 OVHcloud 原生 [Responses API](https://docs.ovhcloud.com/en/guides/public-cloud/ai-machine-learning/ai-endpoints-responses-api)。请发送 `store: false`;该 API 不支持状态、`previous_response_id` 和内置工具,但支持自定义函数工具。 | | `/v1/messages` | 通过转换到 Chat Completions 支持 Anthropic 形态的调用方。`/v1/messages/count_tokens` 不可用,因为它要求使用 Anthropic 协议的服务提供方密钥。 | | `/v1/embeddings` | 当别名指向 `bge-m3` 等 OVHcloud Embedding 模型时受支持。 | | `/v1/audio/transcriptions` | 当别名指向 `whisper-large-v3` 等 OVHcloud 语音转文本模型时受支持。AISIX 会重写模型别名,并把 OpenAI 兼容的 multipart 表单转发到 OVHcloud [转录端点](https://docs.ovhcloud.com/en/guides/public-cloud/ai-machine-learning/ai-endpoints-audio-models)。 | | `/v1/audio/translations`、`/v1/audio/speech` | 在共享 OVHcloud OpenAI 兼容 Base 上不可用。OVHcloud 通过转录提示词处理翻译,并在单独的原生端点上提供[文本转语音模型](https://docs.ovhcloud.com/en/guides/public-cloud/ai-machine-learning/ai-endpoints-voice-virtual-assistant)。 | | `/v1/images/generations`、`/v1/videos`、`/v1/rerank` | 服务提供方值为 `ovhcloud` 的别名不可用;这些 AISIX 路由的服务提供方允许列表不包含该值。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名,而不是 OVHcloud 模型目录。请通过 `/passthrough/ovhcloud/models` 获取 OVHcloud 当前列表。 | | `/passthrough/ovhcloud/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 OVHcloud 原生路由,网关标准化有限。 | 本页的 `/passthrough/ovhcloud` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 OVHcloud API 基础地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。原生 Responses 应优先使用规范化 `/v1/responses` 路由,因为 AISIX 会重写模型别名、增量流式传输并解析用量。对于 AISIX 未规范化的 OVHcloud 操作,请使用透传;它会原样转发正文,因此应发送上游模型 ID,而不是 AISIX 别名。 网关级端点规则请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 故障排查[​](#故障排查 "故障排查的直接链接") | 现象 | 检查项 | | ------------------------------ | --------------------------------------------------------- | | 上游返回 `401` 或 `403` | 确认访问 Token 和项目权限。 | | 上游返回 `404` | 在 `api_base` 中保留 `/v1`,并准确复制 OVHcloud 模型 ID。 | | 找不到模型 | 检查 `model_name` 中的下划线、连字符和版本片段。 | | 创建服务提供方密钥时返回 `400` | 使用 `provider: "ovhcloud"` 并省略 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 OVHcloud AI Endpoints,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):将此别名与另一个欧洲端点一起路由。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特有限制。 --- # Perplexity [Perplexity Sonar](https://docs.perplexity.ai) 提供以搜索结果为依据的模型,将语言模型响应与网页检索相结合。应用通过稳定的 AISIX 别名调用 Sonar,同时由网关保存 Perplexity 凭证。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 配置。配置网关以加载声明式资源文件。 * 一个 Perplexity API Key。有关创建方法,请参阅 [Perplexity 快速入门](https://docs.perplexity.ai/docs/getting-started/quickstart)。 * 已安装 `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Perplexity 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 由于 Perplexity 提供 OpenAI 兼容的 Chat Completions API,AISIX 会通过 `openai` 适配器连接,并将 Perplexity API Root 用作 `api_base`。AISIX 不会注册 Perplexity 特定的请求或响应重写。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于保存 Perplexity 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export PERPLEXITY_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "perplexity-prod", "provider": "perplexity", "api_key": "'"${PERPLEXITY_API_KEY}"'", "api_base": "https://api.perplexity.ai", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `perplexity`。AISIX Cloud Admin API 会从目录服务提供方派生适配器;`adapter` 字段仅适用于 BYO 服务提供方密钥。 ❷ `api_key` 保存 Perplexity API Key。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 是裸主机 `https://api.perplexity.ai`,即 Perplexity 文档为 OpenAI SDK 客户端提供的 Base URL。其 OpenAI 兼容 Chat Completions 路由位于 `/chat/completions`,不包含版本片段,因此 Base 不带版本后缀。AISIX 会追加端点路径,生成 `https://api.perplexity.ai/chat/completions`。 对于此服务提供方,`api_base` 可选。省略时,AISIX Cloud Admin API 会填入 `https://api.perplexity.ai`。显式设置可让上游 Root 在资源中清晰可见。该值绝不能最终为空:对于 `openai` 以外使用 `openai` 适配器的服务提供方,AISIX 不会回退到 `api.openai.com`,而是返回上游配置错误,因此 Perplexity 凭证不会发送到公共 OpenAI 主机。 AISIX 会移除 `api_base` 末尾的端点片段,因此粘贴文档中的完整端点 URL `https://api.perplexity.ai/chat/completions` 后仍会解析为相同 Base。尾部斜杠也会被移除。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Perplexity 模型 ID 表示搜索层级,而不是参数数量或发布日期。它们是不带厂商命名空间和日期快照后缀的裸名称:`sonar` 用于快速生成有依据的回答,`sonar-pro` 用于更广泛的检索和更强的综合分析,`sonar-reasoning-pro` 用于带引用的多步推理,`sonar-deep-research` 用于耗时较长的研究报告。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "perplexity-sonar-pro-prod", "model_name": "sonar-pro", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Perplexity 模型 ID,例如 `sonar-pro` 或 `sonar`。 ❸ `provider_key_id` 将该别名关联到 Perplexity 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。密钥值由网关生成;明文仅在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "perplexity-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值通过模型 ID 引用模型,因此该密钥只能访问你创建的别名。写入后,配置会自动投射到关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export PERPLEXITY_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用以下完整的声明式资源文件。对于现有网关,请把这些条目合并到[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely),并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "perplexity-prod" provider: "perplexity" adapter: "openai" api_key: ${PERPLEXITY_API_KEY} api_base: "https://api.perplexity.ai" models: - display_name: "perplexity-sonar-pro-prod" provider: "perplexity" model_name: "sonar-pro" provider_key: "perplexity-prod" api_keys: - display_name: "perplexity-caller" key_env: CALLER_API_KEY allowed_models: - "perplexity-sonar-pro-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求。Sonar 会根据实时网页搜索生成回答,因此请提出一个需要当前信息的问题: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "perplexity-sonar-pro-prod", "messages": [ { "role": "user", "content": "Summarize the latest news about AI gateways in two sentences." } ] }' ``` 网关返回 OpenAI 兼容响应,其中会回显面向调用方的别名 `perplexity-sonar-pro-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 Perplexity 模型 ID。 ## 获取搜索引用[​](#获取搜索引用 "获取搜索引用的直接链接") Sonar 响应在 Perplexity 响应体顶层的 `citations` 和 `search_results` 中携带来源,这两个字段与 `choices` 同级。它们是 Perplexity 扩展,而不是 OpenAI Chat Completions 格式的一部分。AISIX 会将 Chat Completions 响应标准化为规范的 OpenAI 格式,因此通过 `/v1/chat/completions` 时,这两个字段不会到达调用方。 当应用需要来源列表时,请改为调用服务提供方原生路由。本页的 `/passthrough/perplexity` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 `https://api.perplexity.ai`;在调用方 Key 的 `allowed_routes` 上授予路由名称。AISIX 会原样转发请求体,注入路由绑定的服务提供方密钥凭证,并不加修改地返回上游响应: ``` curl -sS -X POST "$AISIX_PROXY/passthrough/perplexity/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "sonar-pro", "messages": [ { "role": "user", "content": "Summarize the latest news about AI gateways in two sentences." } ] }' ``` `perplexity` 路径片段是路由认领的前缀——按约定使用服务提供方名——而不是别名;请求体携带上游模型 ID `sonar-pro`,而不是别名。AISIX 仍会认证调用方密钥,该密钥必须在 `allowed_routes` 列表中授予此路由名称。 备注 网关会自动识别请求的 Chat 信封(`messages`),因此 Sonar 响应中受支持的用量数字会尽力记录到用量事件上。透传 Token 只用于遥测:它们不会推进 `tpm` 或 `tpd` 计数器、确定模型成本,也不会增加预算支出。请参阅[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)。 ## 设置推理强度[​](#设置推理强度 "设置推理强度的直接链接") Sonar 请求 Schema 提供 `reasoning_effort` 字段,其值可为 `minimal`、`low`、`medium` 和 `high`,但具体模型文档可能会缩小可接受值的范围。例如,Perplexity 当前为 [`sonar-deep-research`](https://docs.perplexity.ai/docs/sonar/models/sonar-deep-research) 记录了 `low`、`medium` 和 `high`。 AISIX 会将其未建模的请求字段不加修改地转发到上游,因此请将该字段添加到 Chat Completions 请求体。以下示例假设已创建第二个别名 `perplexity-sonar-research-prod`,且其 `model_name` 设置为 `sonar-deep-research`: ``` { "model": "perplexity-sonar-research-prod", "messages": [{ "role": "user", "content": "Compare the two proposals." }], "reasoning_effort": "high" } ``` AISIX 未为 Perplexity 注册 `response.reasoning_field` 映射,因此不会将 Perplexity 特定的推理字段提升到规范的 `reasoning_content` 位置。无论 Perplexity 将推理输出放在标准响应内容的哪个位置,都会原样到达调用方。如果未来某个 Perplexity 模型在独立的 `delta` 路径上流式返回推理内容,请在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 端点和成本边界[​](#端点和成本边界 "端点和成本边界的直接链接") Perplexity 目前提供独立的 Sonar、Agent、Search 和 Embeddings API。它们使用不同的路径前缀,因此本指南配置的 Sonar 服务提供方密钥不能通过标准化 AISIX 路由访问所有 API。 | 路由 | 使用 Perplexity 别名时的行为 | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/completions` | 不可用。Perplexity 未提供旧版 Prompt Completions 路由。 | | `/v1/responses` | 通过 Sonar Chat Completions 上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持,而不是使用 Perplexity 原生 [Agent API](https://docs.perplexity.ai/docs/agent-api/openai-compatibility)。没有对应 Chat 语义的字段会被忽略。需要原生 Responses 兼容契约时,请使用 `/passthrough/perplexity/v1/responses`,并发送 Agent API 模型 ID 或 Preset,而不是 AISIX 别名。 | | `/v1/messages` | 通过转换到 Sonar Chat Completions 支持兼容的 Anthropic 形态请求。`/v1/messages/count_tokens` 不可用,因为它要求使用 Anthropic 协议的服务提供方密钥。 | | `/v1/embeddings` | 不适用于上述 Sonar 服务提供方密钥:AISIX 会把 `/embeddings` 追加到裸主机,而 Perplexity 在 `/v1/embeddings` 提供[标准 Embedding](https://docs.perplexity.ai/docs/embeddings/quickstart)。请创建 `api_base: https://api.perplexity.ai/v1` 的单独服务提供方密钥,并为 `pplx-embed-v1-0.6b` 或 `pplx-embed-v1-4b` 创建别名。 | | `/v1/images/generations` | 拒绝。该路由仅接受所配置服务提供方为 `openai` 的模型。 | | `/v1/rerank` | 拒绝。该路由的允许列表为 `openai`、`cohere` 和 `jina`。 | | `/v1/videos` | 拒绝。该路由的允许列表中不包含 `perplexity`。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名。请通过 `/passthrough/perplexity/v1/models` 获取当前 Agent API 模型列表。 | | `/passthrough/perplexity/search` | 调用 Perplexity 原生 [Search API](https://docs.perplexity.ai/api-reference/search-post),并返回原始搜索结果。 | | `/passthrough/perplexity/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用。用于服务提供方原生的请求和响应格式。 | Perplexity 标准 Embedding 模型返回量化的 Base64 字符串,而不是浮点数组。AISIX 会保留该响应表示。调用方必须解码 `base64_int8` 或 `base64_binary`,并使用 [Perplexity 记录的相似度度量](https://docs.perplexity.ai/docs/embeddings/best-practices)。 另有两个边界会影响 Perplexity 流量的建模方式: * Sonar 不提供调用方定义的函数工具。[Sonar Pro Search](https://docs.perplexity.ai/docs/sonar/pro-search/tools) 可以调用 Perplexity 管理的搜索和 URL 获取工具,而 Agent API 提供更广泛的工具契约。请通过兼容的 Agent API 模型或其他服务提供方路由自定义函数调用工作负载。 * AISIX [成本元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)以每 1,000 个输入和输出 Token 的 USD 金额表示。除了提示词和补全 Token 外,Perplexity 还按引用 Token、搜索查询和推理 Token 对 `sonar-deep-research` 计费,因此仅按 Token 估算会低估该模型的实际支出。请将网关中 `sonar-deep-research` 的成本数据视为下限,并与 Perplexity 账单核对。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Perplexity,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为该别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Perplexity 与另一个服务提供方之间执行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Qwen(阿里云) [Qwen](https://www.alibabacloud.com/help/en/model-studio/) 是阿里云的语言和多模态模型系列,通过百炼 Model Studio(又称 DashScope)提供服务。应用通过稳定的 AISIX 别名调用 Qwen,网关负责保管 DashScope 凭证。 本指南涵盖通过同一个 Model Studio 服务提供方密钥承载的 Qwen Chat Completions、原生 Responses 和 Wan 视频任务。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Model Studio 国际站控制台](https://bailian.console.alibabacloud.com/)或[中国大陆 Model Studio 控制台](https://bailian.console.aliyun.com/)获取的、适用于计划使用区域的 DashScope API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由 Qwen 提供支持的 Chat Completions 和原生 Responses 创建服务提供方密钥、模型别名和调用方 API Key。示例使用新加坡区域端点。 由于阿里云百炼 Model Studio 提供 OpenAI 兼容端点,AISIX 通过 `openai` 适配器连接,并使用创建凭证所在区域的 DashScope API 根地址。 ### 创建服务提供方密钥[​](#create-a-provider-key "创建服务提供方密钥的直接链接") DashScope API Key 和端点具有区域属性。AISIX 目录为国际站和中国大陆分别提供服务提供方 ID,默认 API 根地址如下: | 服务提供方 ID | 默认 API 根地址 | 范围 | | ------------- | -------------------------------------------------------- | ---------------------- | | `alibaba` | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | 国际站,使用新加坡端点 | | `alibaba-cn` | `https://dashscope.aliyuncs.com/compatible-mode/v1` | 中国大陆,使用北京端点 | 一个区域签发的 API Key 无法用于另一区域的端点。如果需要同时路由到两个区域,请为每个区域创建一个服务提供方密钥。国际流量使用 `alibaba`,中国大陆流量使用 `alibaba-cn`,使用量记录和成本报告归属到匹配的目录。 阿里云建议生产环境使用[工作区专属域名](https://www.alibabacloud.com/help/en/model-studio/regions/)。上述共享 DashScope 根地址仍可用于现有集成,但专属域名提供工作区隔离和更高并发。下方示例使用新加坡形式;请将 `YOUR_WORKSPACE_ID` 替换为签发 API Key 的工作区。其他区域请使用 Model Studio 控制台中的匹配域名。 创建用于存储 DashScope 凭证和 API 根地址的服务提供方密钥,并获取其 ID: ``` # 请替换为实际值 export DASHSCOPE_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "qwen-prod", "provider": "alibaba", "api_key": "'"${DASHSCOPE_API_KEY}"'", "api_base": "https://YOUR_WORKSPACE_ID.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') ``` ❶ `provider` 为 `alibaba`,即 Model Studio 国际区域的目录服务提供方 ID。中国大陆区域请使用 `alibaba-cn`。AISIX Cloud Admin API 会从目录服务提供方派生适配器;仅 BYO 服务提供方密钥接受适配器字段。 ❷ `api_key` 存储 DashScope API Key。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `api_base` 已包含 `/compatible-mode/v1` 路径。请使用签发 API Key 的工作区和区域。省略该字段时,AISIX Cloud 会为 `alibaba` 使用共享国际根地址,为 `alibaba-cn` 使用共享北京根地址;这些目录默认值不会选择工作区专属域名。 ❹ `apis.responses` 声明 Model Studio 在同一区域根地址上提供 Responses API。随后 AISIX 会使用 Qwen 原生格式,而不是通过 Chat Completions 转换请求。 ### 创建模型[​](#create-a-model "创建模型的直接链接") 创建调用方将在请求中发送的模型别名,并获取其 ID: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "qwen-plus-prod", "model_name": "qwen3.7-plus", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Qwen 模型 ID。此示例使用当前的 `qwen3.7-plus` 模型;创建别名前,请在 [Model Studio 模型列表](https://www.alibabacloud.com/help/en/model-studio/models)中检查该模型在目标区域的可用性。 ❸ `provider_key_id` 将别名关联到 Qwen 服务提供方密钥。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建可访问模型别名的调用方 API Key 资源。明文密钥由服务器生成,并仅在响应中返回一次: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "qwen-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') ``` `allowed_models` 值必须引用已获取的模型 ID。请妥善保存明文密钥;之后无法再次获取。 新资源会自动投射到已关联的网关,因此该路由几乎可以立即调用。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export DASHSCOPE_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "qwen-prod" provider: "alibaba" adapter: "openai" api_key: ${DASHSCOPE_API_KEY} api_base: "https://YOUR_WORKSPACE_ID.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1" apis: responses: {} models: - display_name: "qwen-plus-prod" provider: "alibaba" model_name: "qwen3.7-plus" provider_key: "qwen-prod" api_keys: - display_name: "qwen-caller" key_env: CALLER_API_KEY allowed_models: - "qwen-plus-prod" ``` 如果 AISIX 安装在本地,请在加载文件前进行验证: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#verify-the-provider-connection "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen-plus-prod", "input": "Say hello from Qwen." }' ``` AISIX 会把请求发送到 Qwen 原生 Responses 端点,在上游请求中将别名替换为 Model Studio 模型 ID,并在响应中恢复该别名。请在 Model Studio 用量页面中确认该请求。如果请求因上游身份认证错误而失败,请检查服务提供方密钥凭证,并确认密钥与基础 URL 使用同一区域。 原生 Responses 路径支持流式传输、`previous_response_id`、推理强度和服务提供方托管工具,但具体可用性因模型和区域而异。 ## 通过透传使用原生 Messages[​](#通过透传使用原生-messages "通过透传使用原生 Messages的直接链接") Model Studio 还在另一个区域 `/apps/anthropic` Base 下提供 Anthropic 兼容 Messages API。该 API 接受 Bearer 或 `x-api-key` 身份认证,但仅提供 `/v1/messages` 文档,没有 `/v1/messages/count_tokens`。服务提供方密钥应省略 `apis.messages`,因为 AISIX 中的该声明覆盖两条路由。 应用需要 Qwen 原生 Messages 格式时,请配置专用[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),不要复用通用服务提供方前缀。将路由绑定到同一区域的 Qwen 服务提供方密钥,使 AISIX 能够注入其凭证。国际站示例使用 `/passthrough/alibaba-messages` 前缀,目标为 `https://YOUR_WORKSPACE_ID.ap-southeast-1.maas.aliyuncs.com/apps/anthropic`;中国大陆示例使用 `/passthrough/alibaba-cn-messages` 前缀,目标为 `https://YOUR_WORKSPACE_ID.cn-beijing.maas.aliyuncs.com/apps/anthropic`。[中国区域端点参考](https://help.aliyun.com/zh/model-studio/regions)列出了共享和工作区专属 Base。 调用 `/passthrough/alibaba-messages/v1/messages` 或 `/passthrough/alibaba-cn-messages/v1/messages`,并发送 `qwen3.7-plus` 等上游模型 ID,因为透传不会重写 AISIX 别名。Count Tokens 仍不可用。 ## 使用 Wan 和 HappyHorse 生成视频[​](#generate-videos-with-wan "使用 Wan 和 HappyHorse 生成视频的直接链接") 同一个服务提供方密钥即可驱动网关建模的[视频路由](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。创建第二个别名,指向 Model Studio 的文生视频模型——可以是 [Wan 2.7](https://www.alibabacloud.com/help/zh/model-studio/text-to-video-api-reference) 模型,也可以是 [HappyHorse](https://www.alibabacloud.com/help/zh/model-studio/happyhorse-text-to-video-api-reference) 文生视频模型,例如 `happyhorse-1.1-t2v`。两个系列使用同一组 DashScope 异步端点,因此下面的流程完全相同,区别只在上游模型名称: 在 AISIX Cloud 中创建视频别名和仅限该别名的调用方 Key: ``` VIDEO_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "wan-video-prod", "model_name": "wan2.7-t2v", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$VIDEO_MODEL_ID" VIDEO_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "qwen-video-caller", "allowed_models": ["'"${VIDEO_MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 对于开源 AISIX 网关,请将 `wan-video-prod` 添加到现有 `models` 集合。将现有 `qwen-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(视频模型访问) ``` models: - display_name: "wan-video-prod" provider: "alibaba" model_name: "wan2.7-t2v" provider_key: "qwen-prod" api_keys: - display_name: "qwen-caller" key_env: CALLER_API_KEY allowed_models: - "qwen-plus-prod" - "wan-video-prod" ``` 按上文所述验证并重载或重启声明式资源文件,然后使用现有调用方 Key 发起视频请求: ``` export VIDEO_API_KEY="$CALLER_API_KEY" ``` 提交任务: ``` curl -sS -X POST "$AISIX_PROXY/v1/videos" \ -H "Authorization: Bearer ${VIDEO_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "wan-video-prod", "prompt": "A paper boat drifts down a rain-soaked street at dusk.", "seconds": 5 }' ``` 在为此路由编写脚本前,需要了解以下六项服务提供方特定行为: * **只有 `alibaba` 这个 `provider` 值会被分发。** `alibaba-cn` 不在视频路由的允许列表内,因此中国内地区域的别名在提交时会返回未实现错误。如需访问中国内地区域的视频 API,请配置一条 `target_url` 指向该区域原生 Model Studio 地址的透传路由。 * **Chat 的 `api_base` 会原样复用。** AISIX 会去掉一个 `/compatible-mode/v1`、`/api/v1` 或 `/v1` 后缀,从中派生服务商根地址,并在其下组成 DashScope 的原生任务路径。已经为 Qwen Chat 流量配置的服务提供方密钥无需更改即可用于视频路由,异步提交所需的请求头也由网关自动补上。 * **`size` 对应的是较早的 Wan 协议。** `seconds` 会作为整数 `parameters.duration` 转发,`size` 则会以服务提供方使用的 `WIDTH*HEIGHT` 写法作为 `parameters.size` 转发。该参数属于 Wan 2.6 及更早版本;Wan 2.7 模型已改用 `resolution` 和 `ratio` 档位,而 AISIX 不会判断别名指向哪个系列,只会原样转发你发送的值。因此 Wan 2.7 别名请像上面的示例一样自行省略 `size`,由服务提供方使用默认值。 * **HappyHorse 文生视频走同一条路由。** `happyhorse-1.1-t2v` 和 `happyhorse-1.0-t2v` 与 Wan 使用相同的提交端点、轮询端点和任务状态,输出尺寸同样用 `resolution` 和 `ratio` 档位表达——因此与 Wan 2.7 一样,请省略 `size`,由服务提供方使用默认值。图生视频(`happyhorse-1.1-i2v`)、参考生视频和视频编辑属于 Model Studio 的另外几个 API,其参考素材输入不在建模路由的承载范围内,请像下面的其他原生字段一样通过透传路由访问。Runway 平台上也托管了 HappyHorse 模型,那条集成路径参见 [RunwayML](https://docs.apiseven.com/ai-gateway/providers/runwayml.md)。 * **服务提供方原生视频字段需要透传路由。** 标准化请求只建模 `prompt`、`seconds` 和 `size`;其他字段会被忽略。若要发送 `negative_prompt`、`seed`,或 Wan 2.7 的 `resolution` 和 `ratio` 等原生字段,请使用一条指向 DashScope 原生根地址的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),该根地址与本页 `/passthrough/alibaba` 示例假定的 OpenAI 兼容根地址不同。若一条透传路由认领 `/passthrough/alibaba-video` 前缀、并将 `target_url` 设为 `https://dashscope-intl.aliyuncs.com/api/v1`,则提交路径为 `/passthrough/alibaba-video/services/aigc/video-generation/video-synthesis`,轮询路径为 `/passthrough/alibaba-video/tasks/{id}`。请发送原生正文和准确的上游模型 ID,并自行设置服务提供方要求的异步提交请求头。透传不会返回统一的 AISIX 视频对象或网关编码的任务 ID。 * **已完成的视频通过重定向交付。** `GET /v1/videos/{id}/content` 返回 `302`,并在 `Location` 响应头中提供指向服务提供方签名下载 URL 的地址。字节数据会从 Model Studio 存储直接传输到客户端,不会经过网关,因此下载时请跟随重定向,例如使用 `curl` 的 `-L` 参数。 完整的提交、轮询和下载工作流(包括状态语义和轮询时的限流行为)请参阅[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ## 端点覆盖[​](#endpoint-coverage "端点覆盖的直接链接") Qwen 服务提供方密钥使用 `openai` 适配器,但路由支持还取决于 AISIX 服务提供方规则,以及配置的 Model Studio 基础地址上可用的 API: | 路由 | 使用 Qwen 模型别名时的行为 | | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持缓冲和流式传输。 | | `/v1/messages` | 通过转换为 Chat Completions 支持。原生格式请使用上文所述的区域 Messages 透传路由。由于 Model Studio 未提供该路由的文档,请将 `/v1/messages/count_tokens` 视为不可用。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送到阿里云[原生 Responses API](https://www.alibabacloud.com/help/en/model-studio/qwen-api-via-openai-responses)。如果没有此声明,AISIX 会使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/embeddings` | 别名指向同一区域可用的[文本嵌入模型](https://www.alibabacloud.com/help/en/model-studio/embedding)(例如 `text-embedding-v4`)时支持。AISIX 会将 `/embeddings` 追加到配置的 OpenAI 兼容基础地址。 | | `/v1/videos` 及其状态和内容路由 | 仅当模型服务提供方值恰好为 `alibaba` 时支持;`alibaba-cn` 不在视频路由允许列表中。AISIX 会将请求映射到 DashScope 异步[文生视频 API](https://www.alibabacloud.com/help/zh/model-studio/text-to-video-api-reference),该 API 同时服务 Wan 和 HappyHorse 文生视频模型。对于当前 Wan 2.7 和 HappyHorse 模型,请省略 `size`,因为 AISIX 的 `size` 映射面向较早的 Wan API。参见[使用 Wan 和 HappyHorse 生成视频](#generate-videos-with-wan)。需要原生 `resolution`、`ratio` 或多模态字段时请使用透传路由;对于 `alibaba-cn`,这要求一条以 Model Studio 原生基础地址为目标的路由。 | | `/v1/audio/*` | 本页配置的 OpenAI 兼容基础地址不支持。Model Studio 音频 API 使用服务提供方原生路由和请求结构。 | | `/v1/images/generations` | 不支持。该路由只接受配置的服务提供方为 `openai` 的模型;Model Studio 图片 API 需要透传路由。 | | `/v1/rerank` | 不支持。该路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值;Model Studio 重排模型使用服务提供方原生 API。 | | `/passthrough/alibaba/*rest` 和 `/passthrough/alibaba-cn/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 OpenAI 兼容根地址下 AISIX 尚未建模的原生 Model Studio API。透传路由不会重写请求体中面向调用方的别名,并会增量中继上游 SSE。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。原生 Messages 和视频 API 使用不同根地址,因此使用单独前缀。 | `/passthrough/alibaba` 和 `/passthrough/alibaba-cn` 前缀假定目标为对应的 OpenAI 兼容 Model Studio 根地址;`/passthrough/alibaba-messages` 和 `/passthrough/alibaba-cn-messages` 前缀假定目标为对应区域的 `/apps/anthropic` 根地址,而 `/passthrough/alibaba-video` 假定目标为上文所述的 DashScope 视频根地址。请分别配置每条路由,并在调用方 Key 的 `allowed_routes` 上授予其名称。 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你已将 AISIX 连接到 Qwen,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Qwen 区域之间,或在 Qwen 与其他服务提供方之间进行故障转移。 * [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md):按照提交、轮询和下载工作流使用受支持的 Wan 文本生成视频模型。 * [服务提供方专属覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看受支持的代理端点和服务提供方专属边界。 --- # RunwayML [RunwayML](https://docs.dev.runwayml.com/) 提供使用 Runway Gen 和 Runway 托管模型生成视频的接口。AISIX 让应用可通过网关的视频 API 提交并管理这些任务,同时管理 Runway 凭证、调用方访问权限、限流和用量核算。 本指南介绍如何为 AISIX [视频生成 API](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md) 配置 RunwayML。Runway 不提供 Chat Completions API,因此由 Runway 支持的模型别名只能用于视频任务。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一个从 [Runway 开发者门户](https://dev.runwayml.com/)获取的 Runway API Key。 * `curl` 和 `jq`。 开发者门户与 `runwayml.com` Web 应用相互独立。API Key 仅存在于该门户中,API Credits 与 Web 应用 Credits 也是两个独立的额度池;Web 应用订阅无法为 API 调用提供额度。请参阅 [Runway API 常见问题](https://help.runwayml.com/hc/en-us/articles/21668552945171-Runway-API-FAQs)。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 Runway 支持的视频路由创建服务提供方密钥、模型别名和调用方 API Key。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于保存 Runway 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export RUNWAY_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "runwayml-prod", "provider": "runwayml", "api_key": "'"${RUNWAY_API_KEY}"'", "api_base": "https://api.dev.runwayml.com", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `runwayml`,这是 AISIX 视频路由能够识别的服务提供方值。AISIX Cloud Admin API 会为此服务提供方派生 `openai` 适配器;`adapter` 字段仅适用于 BYO 服务提供方密钥。派生的适配器只适用于 Runway 并不提供的 Chat 类路由。 ❷ `api_key` 保存 Runway API Key,并在上游调用中作为 Bearer Token 发送。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 是裸主机。Runway 文档中的 API Base 不含版本片段;`/v1` 属于端点路径,因此 AISIX 会按原样在此 Root 上组合 `/v1/text_to_video` 和 `/v1/tasks/{id}`。对于此服务提供方,该字段可选;省略时,AISIX Cloud Admin API 会填入相同值。请显式设置该字段,让上游 Root 在资源中清晰可见。不要追加 `/v1`:AISIX 不会从此服务提供方的 Base 中移除版本后缀,因此 `https://api.dev.runwayml.com/v1` 会构造 `/v1/v1/…` 路径并在上游失败。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Runway 的文生视频端点(即网关提交任务的端点)目前提供 `gen4.5`、`veo3.1`、`veo3.1_fast`、`veo3`、`happyhorse_1_0`、`seedance2`、`seedance2_fast`、`seedance2_mini` 和 `gemini_omni_flash`。该端点会拒绝其他 Runway 模型 ID,例如图生视频模型 `gen4_turbo`,因此指向这些模型的别名会在提交时失败。创建模型别名前,请在 [Runway API 参考](https://docs.dev.runwayml.com/api/#text-to-video)中查看当前目录以及各模型接受的参数。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "runway-video-prod", "model_name": "gen4.5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Runway 模型 ID,例如 `gen4.5` 或 `veo3.1`。 ❸ `provider_key_id` 将该别名关联到 RunwayML 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且只在响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "runwayml-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID,使该密钥只能访问已创建的别名。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export RUNWAY_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "runwayml-prod" provider: "runwayml" adapter: "openai" api_key: ${RUNWAY_API_KEY} api_base: "https://api.dev.runwayml.com" models: - display_name: "runway-video-prod" provider: "runwayml" model_name: "gen4.5" provider_key: "runwayml-prod" api_keys: - display_name: "runwayml-caller" key_env: CALLER_API_KEY allowed_models: - "runway-video-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#verify-the-provider-connection "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 由于此服务提供方不提供 Chat 接口,请使用视频任务验证连接。通过 AISIX 代理提交任务: ``` curl -sS -X POST "$AISIX_PROXY/v1/videos" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "runway-video-prod", "prompt": "A lighthouse beam sweeps across a foggy harbor at night.", "seconds": 5, "size": "1280x720" }' ``` 网关返回一个视频任务对象,其中 `status` 为 `queued`(Runway 的创建响应仅确认任务已被接受),`id` 则是网关颁发、供后续调用使用的视频 ID。轮询任务直至完成,然后下载结果: ``` curl -sS "$AISIX_PROXY/v1/videos/YOUR_VIDEO_ID" \ -H "Authorization: Bearer ${AISIX_API_KEY}" curl -sS -L -o video.mp4 \ "$AISIX_PROXY/v1/videos/YOUR_VIDEO_ID/content" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 如果提交失败,请检查服务提供方密钥的 `api_key`、采用裸主机的 `api_base`,以及 `model_name` 中的 Runway 模型 ID。在围绕此路由编写脚本前,需要了解以下四种服务提供方特定行为: * **网关会自行发送必需的 API 版本请求头。** Runway 要求每次 API 调用都带有 `X-Runway-Version` 请求头,并拒绝不含该请求头的请求。AISIX 会在提交和轮询调用中设置 `X-Runway-Version: 2024-11-06`,这是其请求和响应处理所依据的 [API 版本](https://docs.dev.runwayml.com/api-details/versions/2024-11-06/)。该请求头不可由运维人员配置,也不会出现在网关配置中。 * **`size` 会映射到 Runway 的 `ratio`,且实际使用中为必填。** AISIX 通过替换分隔符,将统一的 `WIDTHxHEIGHT` 值转换为 Runway 的 `WIDTH:HEIGHT` 分辨率字符串,因此 `1280x720` 会以 `"1280:720"` 到达 Runway。Runway 会根据各模型支持的像素分辨率列表验证结果,而且其文生视频端点要求 `ratio`,因此缺少 `size` 的请求会被服务提供方拒绝,而不是由网关填入默认值。`seconds` 会作为服务提供方的整数 `duration` 转发;可接受的时长也因模型而异。请在 [Runway API 文档](https://docs.dev.runwayml.com/)的相应模型条目中查看这两个列表。 * **标准化路由只建模通用的文生视频字段。** AISIX 会发送上游模型 ID、`promptText`,以及上述可选的 `ratio` 和 `duration` 映射。其他 JSON 字段会被忽略,包括负面提示词、生成音频选项和参考媒体等 Runway 专用控制项。若要使用这些字段,请通过 `/passthrough/runwayml/v1/text_to_video` 发送 Runway 原生请求体、准确的上游模型 ID,以及必需的 `X-Runway-Version: 2024-11-06` 请求头。本页的 `/passthrough/runwayml` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 Runway 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。 * **`THROTTLED` 属于排队状态。** AISIX 将 Runway 的 `PENDING` 和 `THROTTLED` 任务状态映射为 `queued`,两者都表示任务已接受但尚未运行;`RUNNING` 报告为 `in_progress`,`SUCCEEDED` 报告为 `completed`,`FAILED` 或 `CANCELLED` 报告为 `failed`。失败任务会在统一的 `error` 对象中携带 Runway 机器可读的 `failureCode` 和人类可读的 `failure` 文本。 * **完成的视频通过重定向交付。** 已完成的 Runway 任务会将输出报告为签名链接列表,而 `GET /v1/videos/{id}/content` 返回 `302`,其 `Location` 响应头指向列表中的第一个链接。视频字节会直接从 Runway 存储传输到客户端,不经过网关,因此下载时请使用 `curl -L`。 完整的提交、轮询和下载工作流(包括状态语义和轮询时的限流行为)请参阅[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ## 模型 ID 和成本元数据[​](#模型-id-和成本元数据 "模型 ID 和成本元数据的直接链接") AISIX Cloud 从公开目录 models.dev 获取模型建议和定价,而 RunwayML 未列入该目录。这会给此服务提供方带来两个影响: * Dashboard 不会建议模型 ID。请从 [Runway API 文档](https://docs.dev.runwayml.com/)获取 ID,并直接填入 `model_name`。 * 定价目录不包含 Runway 模型的价格,因此用量报告或预算检查中使用的任何成本数据都需由运维人员在模型别名上提供,这与自带端点的处理方式相同。请参阅[成本元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 视频流量还受视频接口自身核算行为的限制:每次提交都会在用量日志中记录为零 Token 事件,基于时长的视频任务成本核算尚未应用于 AISIX Cloud 预算。请参阅[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md#endpoint-behavior)。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") RunwayML 服务提供方密钥用于视频路由。所有 Chat 格式路由都会解析到同一裸主机下的 URL,但 Runway 不提供其中任何路由: | 路由 | 使用 `runwayml` 模型别名时的行为 | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/videos` 及其状态和内容路由 | 支持。这是该服务提供方唯一提供的已建模路由。请参阅[验证服务提供方连接](#verify-the-provider-connection)。 | | `/v1/chat/completions` | 在上游失败。Runway 未发布 Chat Completions API;AISIX 会向服务提供方密钥 Base 追加 `/chat/completions`,但生成的路径在上游不存在。 | | `/v1/embeddings` | 在上游失败。Runway 未发布 Embeddings API。 | | `/v1/responses` | 在上游失败。Responses 桥接会发起 Chat Completions 调用,而 Runway 不提供该调用。 | | `/v1/images/generations` | 不支持。该路由仅接受所配置服务提供方为 `openai` 的模型。请改为通过透传访问 Runway 图像端点。 | | `/v1/rerank` | 不支持。该路由仅接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/passthrough/runwayml/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于网关尚未建模的 Runway API 和字段,包括图生视频和服务提供方专用的文生视频控制项。路由会转发调用方请求头,并且只注入凭证,因此调用方必须自行设置 `X-Runway-Version`;AISIX 只会在已建模的视频路由上添加该请求头。 | 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 RunwayML,并通过视频任务验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md):完成完整的提交、轮询和下载工作流。 * [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md):访问网关尚未建模的 Runway 接口。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # SiliconFlow [SiliconFlow](https://docs.siliconflow.com/) 托管来自多个模型组织的模型并提供推理服务。AISIX 将服务提供方凭证保留在网关中,同时为应用提供覆盖该目录的稳定别名。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 SiliconFlow 控制台获取的 SiliconFlow API Key。 * `curl` 和 `jq`。 ## 选择 SiliconFlow 平台[​](#选择-siliconflow-平台 "选择 SiliconFlow 平台的直接链接") SiliconFlow 运营两个平台,模型目录为每个平台提供一个服务提供方 ID: | 目录服务提供方 ID | API Root | 适用场景 | | ----------------- | -------------------------------- | --------------------------------------- | | `siliconflow` | `https://api.siliconflow.com/v1` | API Key 由 `siliconflow.com` 平台签发。 | | `siliconflow-cn` | `https://api.siliconflow.cn/v1` | API Key 由 `siliconflow.cn` 平台签发。 | 目录将两个平台建模为独立服务提供方,并分别使用凭证变量 `SILICONFLOW_API_KEY` 和 `SILICONFLOW_CN_API_KEY`。因此,请将它们视为独立账户,并选择与密钥签发平台匹配的服务提供方 ID。以下示例使用 `siliconflow`。如果你的账户位于另一个平台,请在全文中将其替换为 `siliconflow-cn` 和 `https://api.siliconflow.cn/v1`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为 SiliconFlow 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 SiliconFlow 是使用 OpenAI 兼容 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,使用 Bearer Token 对上游请求进行身份认证,并将 SiliconFlow API Root 用作 `api_base`。AISIX 不会注册 SiliconFlow 特有的请求或响应重写规则。 控制台将该服务提供方标记为传输格式未经验证的社区条目。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 SiliconFlow 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export SILICONFLOW_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "siliconflow-prod", "provider": "siliconflow", "api_key": "'"${SILICONFLOW_API_KEY}"'", "api_base": "https://api.siliconflow.com/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `siliconflow`。AISIX Cloud Admin API 接受该值,是因为此 ID 存在于其缓存的 models.dev 目录中,并且它会从目录推导适配器。不要发送 `adapter` 字段:仅当 `provider` 为 `byo` 哨兵值时才接受该字段;在目录服务提供方密钥中发送它会返回 400 错误。 ❷ `api_key` 存储 SiliconFlow API Key。SiliconFlow 使用 HTTP Bearer 身份认证,`openai` 适配器已经会发送该认证信息,因此无需额外配置请求头。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 为 `https://api.siliconflow.com/v1`。SiliconFlow 文档中的完整聊天端点是 `POST https://api.siliconflow.com/v1/chat/completions`,因此 Root 已包含 `/v1`,AISIX 会在其后追加 `/chat/completions` 等端点路径。对于 `siliconflow`,此字段可选:models.dev 会将同一值发布为服务提供方的 API 字段,省略时 AISIX Cloud Admin API 会自动填充。仍建议显式设置该字段,以便在配置中清楚显示每个密钥所指向的 Root,并避免密钥依赖可能早于服务商 URL 变更的目录快照。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") SiliconFlow 模型 ID 带有组织命名空间。ID 由模型组织、斜杠和模型名称组成,且前后两部分均区分大小写。当前示例包括 `deepseek-ai/DeepSeek-V3.2`、`zai-org/GLM-5.2`、`Qwen/Qwen3.6-27B`、`moonshotai/Kimi-K2.6` 和 `openai/gpt-oss-120b`。创建别名前,请在 [SiliconFlow 模型目录](https://cloud.siliconflow.com/models)中查看当前列表,因为托管模型集合会随着模型新增和退役而变化。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "siliconflow-deepseek-prod", "model_name": "deepseek-ai/DeepSeek-V3.2", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是包含组织前缀的 SiliconFlow 模型 ID。该前缀表示模型组织,而不是上游服务提供方。SiliconFlow 上 `openai/gpt-oss-120b` 的别名仍以 `siliconflow` 作为服务提供方值,网关的逐路由服务提供方规则会对此值进行判断。 ❸ `provider_key_id` 将别名关联到 SiliconFlow 服务提供方密钥。 models.dev 目录为其收录的 SiliconFlow Chat 模型提供每 Token 价格,因此这些别名无需额外配置即可进行用量和预算核算。该目录未收录 SiliconFlow Embedding 或音频模型,因此请为 Embedding 或转录别名添加价格覆盖项。 对于按时长计费的转录模型,请配置其**每分钟音频**费率。语音请求会显示为零 Token 用量事件,但 AISIX 不会应用按字符计费的文本转语音定价。请参阅[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)和[成本元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "siliconflow-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export SILICONFLOW_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "siliconflow-prod" provider: "siliconflow" adapter: "openai" api_key: ${SILICONFLOW_API_KEY} api_base: "https://api.siliconflow.com/v1" models: - display_name: "siliconflow-deepseek-prod" provider: "siliconflow" model_name: "deepseek-ai/DeepSeek-V3.2" provider_key: "siliconflow-prod" api_keys: - display_name: "siliconflow-caller" key_env: CALLER_API_KEY allowed_models: - "siliconflow-deepseek-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "siliconflow-deepseek-prod", "messages": [ { "role": "user", "content": "Say hello from SiliconFlow." } ] }' ``` 网关返回 OpenAI 兼容响应,并回显调用方可见的别名 `siliconflow-deepseek-prod`。 以下两种失败模式可以区分凭证问题和 URL 问题: * 上游身份认证错误通常指向 `api_key`,或表示密钥的签发平台与配置的服务提供方 ID 不匹配。 * 上游返回 404 通常指向 `api_base`。AISIX 会从 `api_base` 中移除粘贴的 `/chat/completions` 等端点后缀和末尾斜杠,但不会为非 OpenAI 主机补充缺失的 `/v1` 路径段。因此,`https://api.siliconflow.com` 会解析为 `https://api.siliconflow.com/chat/completions`,而这并不是 SiliconFlow 路由。 如果请求因模型不存在而被拒绝,请将 `model_name` 与 SiliconFlow 目录进行对照,并检查 ID 前后两部分的大小写。 ## 透传推理控制参数[​](#透传推理控制参数 "透传推理控制参数的直接链接") SiliconFlow 将推理控制参数放在 Chat Completions 请求体顶层,而不是嵌套对象中: | 参数 | 类型 | 作用 | | ----------------- | ------- | ---------------------------------------------------------------------- | | `enable_thinking` | boolean | 在思考模式和非思考模式之间切换混合推理模型。 | | `thinking_budget` | integer | 限制思维链消耗的 Token 数量。SiliconFlow 文档规定范围为 128 到 32768。 | AISIX 仅对一组固定的聊天参数建模,例如 `temperature`、`top_p`、`max_tokens` 和 `stream`。其他所有顶层参数都会原样转发到上游,因此这两个控制参数会原封不动地到达 SiliconFlow: ``` { "model": "siliconflow-deepseek-prod", "messages": [ { "role": "user", "content": "Plan a three-step migration." } ], "enable_thinking": true, "thinking_budget": 4096 } ``` 这些参数的支持情况取决于模型,而不是服务提供方。一个由 SiliconFlow 托管的模型接受的值可能会被另一个模型拒绝,因此请在 [SiliconFlow Chat Completions 参考](https://docs.siliconflow.com/en/api-reference/chat-completions/chat-completions)中确认所配置模型支持的控制参数。 在响应侧,SiliconFlow 通过 `reasoning_content` 返回思维链,该字段已是 AISIX 对流式和非流式响应采用的规范字段。使用该字段的模型无需配置响应覆盖项。如果某个特定模型通过其他 `delta` 路径流式返回推理内容,请在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 配置传输格式覆盖项[​](#配置传输格式覆盖项 "配置传输格式覆盖项的直接链接") 由于 SiliconFlow 没有 AISIX 精选适配器映射,AISIX 不会为其注册服务提供方特定的请求或响应重写规则。网关使用标准 OpenAI 兼容 Chat 形态。当 SiliconFlow 重命名参数,或某个托管模型偏离该形态时,需要在服务提供方密钥上配置相应调整。 服务提供方密钥覆盖项会由引用该密钥的每个模型继承。在 AISIX Cloud 中,就地更新现有服务提供方密钥。在开源 AISIX 网关中,更新声明式资源文件中的对应条目。 Admin API 会整体替换提供的每个 `request` 或 `response` 块。前面创建的服务提供方密钥没有覆盖项,因此下面的 `request` 块是完整的。如果要更新已经包含覆盖项的密钥,请先获取其详情,并在提供的每个块中包含所有希望保留的设置。省略整个块会保持该块不变,提供空对象则会清除它。 无论通过 AISIX Cloud 还是资源文件更新,覆盖项都会影响引用该服务提供方密钥的每个模型别名。如果该密钥承载生产流量,请先在仅供非生产别名使用的单独服务提供方密钥上验证相同覆盖项,并在受控变更窗口内更新共享密钥。 ``` curl -sS -X PATCH "$AISIX_CP/provider_keys/$PROVIDER_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "request": { "param_renames": { "max_completion_tokens": "max_tokens" } } }' ``` 该请求省略了 `response` 和凭证字段,因此这些设置保持不变,模型也会继续引用同一个服务提供方密钥。 对于开源 AISIX 网关,请在 `provider_keys` 中现有的 `siliconflow-prod` 条目上添加下面的 `request.param_renames` 映射。保留该条目的所有其他字段以及其他条目和集合,不要创建第二个顶层 `provider_keys` 键: resources.yaml(服务提供方密钥) ``` provider_keys: - display_name: "siliconflow-prod" provider: "siliconflow" adapter: "openai" api_key: ${SILICONFLOW_API_KEY} api_base: "https://api.siliconflow.com/v1" request: param_renames: max_completion_tokens: max_tokens ``` 按照上述说明验证声明式资源文件,然后重新加载或重启网关。 `request.param_renames` 会在请求发往上游时重命名顶层参数。当客户端发送当前 OpenAI 参数名而上游需要旧名称,或情况相反时,请使用此配置。如果请求同时携带两个名称,AISIX 会保留原始调用方参数名对应的值。 `response.reasoning_field` 会将非标准流式 `delta` 路径中的推理内容提升到规范的 `delta.reasoning_content`。仅当模型确实存在差异时才设置此项;SiliconFlow 文档中的字段已是规范字段。 有关完整字段目录,请参阅[服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") SiliconFlow 提供多种 OpenAI 形态的推理路由,但 `siliconflow` 服务提供方值不在部分代理路由执行的允许列表中。下表说明 SiliconFlow 支持的别名可以和不可以提供哪些功能。 | 路由 | 使用 SiliconFlow 别名时的行为 | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持,包括 `stream: true`。 | | `/v1/responses` | 通过聊天适配器路径上的 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持。没有对应 Chat 语义的 OpenAI Responses 专用字段会被忽略。 | | `/v1/messages` | 通过转换到 Chat Completions 支持 Anthropic 形态的调用方,而不会调用 SiliconFlow 原生 `/messages` 路由。当原生 Messages 请求或响应契约很重要时,请通过 `/passthrough/siliconflow/messages` 发送准确的上游模型 ID。`/v1/messages/count_tokens` 的 Token 计数要求使用 Anthropic 支持的模型。 | | `/v1/embeddings` | 当别名指向 SiliconFlow 嵌入模型时支持。`openai` 适配器会将 OpenAI 请求格式转发到 `{api_base}/embeddings`,SiliconFlow 在同一 API Root 上提供该端点。请参阅[嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/audio/transcriptions` | 当别名指向 `FunAudioLLM/SenseVoiceSmall` 或 `TeleAI/TeleSpeechASR` 等 [SiliconFlow 转录模型](https://docs.siliconflow.com/en/api-reference/audio/create-audio-transcriptions)时受支持。AISIX 会把 multipart `model` 字段重写为上游模型 ID,并把文件转发到 `{api_base}/audio/transcriptions`。 | | `/v1/audio/speech` | 当别名指向 `FunAudioLLM/CosyVoice2-0.5B` 等 [SiliconFlow 文本转语音模型](https://docs.siliconflow.com/en/api-reference/audio/create-speech)时受支持。AISIX 会重写 JSON `model` 字段,并返回服务提供方的二进制音频响应。`gain`、`sample_rate` 和 `references` 等 SiliconFlow 专用字段会原样透传。 | | `/v1/audio/translations` | 在上游失败。SiliconFlow 未在此 API Base 上提供音频翻译路由。 | | `/v1/rerank` | 拒绝。该路由仅接受 `openai`、`cohere` 和 `jina` 服务提供方值,因此即使 SiliconFlow 托管重排序模型,也会拒绝 `siliconflow` 别名。请改用透传路由访问 SiliconFlow 重排序服务。请参阅[重排序](https://docs.apiseven.com/ai-gateway/endpoints/rerank.md)。 | | `/v1/images/generations` | 拒绝。该路由只接受服务提供方为 `openai` 的模型。 | | `/v1/videos` | 返回 `501 not_implemented` 并拒绝请求。该路由根据自身的服务提供方允许列表进行分发,其中不包含 `siliconflow`。 | | `/passthrough/siliconflow/*` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于服务提供方原生路由,网关标准化有限。授权来自调用方 Key 的 `allowed_routes`,而不是其模型允许列表。 | 本页的 `/passthrough/siliconflow` 路径假定一条透传路由认领该前缀,`target_url` 设为 SiliconFlow 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。对于原生 Messages 和 Rerank 等没有标准化网关接口的 SiliconFlow 功能,透传是实用的访问方式。由于路由的 `target_url` 已以 `/v1` 结尾,AISIX 会移除透传路径开头重复的 `/v1`,因此 `/passthrough/siliconflow/rerank` 和 `/passthrough/siliconflow/v1/rerank` 都会解析到同一个上游 URL。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 SiliconFlow,并验证了模型别名。请继续阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 SiliconFlow 和第二个服务提供方之间进行故障转移,或按成本或延迟对目标进行排序。 * [语音和音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md):通过标准化音频路由调用 SiliconFlow 转录或文本转语音别名。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Snowflake Cortex [Snowflake Cortex](https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-rest-api) 将托管基础模型引入 Snowflake 账户,并通过 REST API 公开这些模型。AISIX 为应用提供一个 OpenAI 兼容 API,用于访问你账户中可用的模型。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * Snowflake 账户标识符和编程访问 Token(PAT)。 * 允许使用 Cortex 的 Snowflake 角色。Snowflake 文档说明了 `SNOWFLAKE.CORTEX_USER` 数据库角色和 REST API 用户角色要求。 * 在你的 Snowflake 区域中访问所选模型的权限。 * `curl` 和 `jq`。 导出 Snowflake 连接信息: ``` export SNOWFLAKE_ACCOUNT="example-account" export SNOWFLAKE_API_BASE="https://${SNOWFLAKE_ACCOUNT}.snowflakecomputing.com/api/v2/cortex/v1" export SNOWFLAKE_PAT="YOUR_SNOWFLAKE_PROGRAMMATIC_ACCESS_TOKEN" ``` 使用 Snowflake 连接信息中的账户主机名。`SNOWFLAKE_ACCOUNT` 中不要包含 `https://` 或其他路径。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` Snowflake 是提供 OpenAI 兼容 Cortex 端点的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,使用 Bearer Token 对上游请求进行身份认证,并将账户专用主机名用作 `api_base`。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "snowflake-cortex-prod", "provider": "snowflake-cortex", "api_key": "'"${SNOWFLAKE_PAT}"'", "api_base": "'"${SNOWFLAKE_API_BASE}"'", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` `snowflake-cortex` 是准确的目录 ID。`snowflake` 不是它的别名。AISIX 会推导出 `openai` 适配器,因此请省略 `adapter` 字段。 实际使用时必须提供账户专用的 `api_base`,因为 AISIX 无法推断哪个 Snowflake 账户应接收请求。AISIX 会在此 Root 后追加 `/chat/completions`。 `AISIX_TOKEN` 是 AISIX 管理 Token。`SNOWFLAKE_PAT` 是存储在服务提供方密钥中的上游凭证。尽管二者都可能被称为 PAT,但它们是互不相关的 Token 类型。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 为账户中可用的 Cortex 模型创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "snowflake-claude-prod", "model_name": "claude-sonnet-4-5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` Snowflake 支持的模型列表因区域和版本而异。只能将 `claude-sonnet-4-5` 替换为你账户可用的 ID,并从当前的 [Cortex 模型可用性参考](https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions#availability)中复制其准确拼写。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "snowflake-cortex-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export SNOWFLAKE_PAT="YOUR_SNOWFLAKE_PROGRAMMATIC_ACCESS_TOKEN" export SNOWFLAKE_ACCOUNT="YOUR_SNOWFLAKE_ACCOUNT" export SNOWFLAKE_API_BASE="https://${SNOWFLAKE_ACCOUNT}.snowflakecomputing.com/api/v2/cortex/v1" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "snowflake-cortex-prod" provider: "snowflake-cortex" adapter: "openai" api_key: ${SNOWFLAKE_PAT} api_base: "${SNOWFLAKE_API_BASE}" models: - display_name: "snowflake-claude-prod" provider: "snowflake-cortex" model_name: "claude-sonnet-4-5" provider_key: "snowflake-cortex-prod" api_keys: - display_name: "snowflake-cortex-caller" key_env: CALLER_API_KEY allowed_models: - "snowflake-claude-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "snowflake-claude-prod", "messages": [ { "role": "user", "content": "Say hello from Snowflake Cortex." } ] }' ``` AISIX 会转发 Snowflake 模型 ID,并使用 `Authorization: Bearer <SNOWFLAKE_PAT>` 进行身份认证。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Snowflake 同时提供 OpenAI 兼容的 Chat Completions 和仅支持 Claude 的 Anthropic Messages API。`snowflake-cortex` 目录条目使用 `openai` 适配器,因此标准化路由行为不同于 Snowflake 原生界面: | 路由 | 使用 Snowflake Cortex 别名时的行为 | | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 通过 Snowflake OpenAI 兼容 Chat 路由提供支持,包括缓冲和流式传输。 | | `/v1/responses` | 通过 AISIX [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持。Snowflake 不提供原生 Responses 端点;没有对应 Chat Completions 语义的字段会被忽略。 | | `/v1/messages` | 通过转换到 Chat Completions 提供支持,而不是使用 Snowflake 原生 Messages 路由。需要 Snowflake 原生 Anthropic 契约或 Beta 功能的 Claude 别名,应通过 `/passthrough/snowflake-cortex/messages` 调用,并发送准确的上游模型 ID 和必需的 `anthropic-version: 2023-06-01` 请求头。 | | `/v1/messages/count_tokens` | 不支持。Token 计数仅限适配器配置为 Anthropic 的模型。 | | `/v1/embeddings` | 与 Snowflake 的 [Vector Embed REST API](https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-rest-api/embed-api) 不兼容。Snowflake 使用 `POST /api/v2/cortex/inference:embed` 和原生请求体。请通过一条独立的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)访问:其 `target_url` 设为 `https://<account>.snowflakecomputing.com/api/v2/cortex`——路由只中继到一个固定基础地址,因此给这条路由独立的路径前缀——然后在该前缀下调用原生 `inference:embed` 路径;也可以改用其他 Embedding 服务提供方。 | | `/v1/images/generations`、`/v1/videos`、`/v1/rerank` | 不支持。这些路由不接受 `snowflake-cortex` 服务提供方值。 | | `/passthrough/snowflake-cortex/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 Snowflake 原生路由,网关标准化有限。当原生 API 需要不同 Base URL 时,请在独立前缀下另建一条路由。 | 本页的 `/passthrough/snowflake-cortex` 路径假定一条透传路由认领该前缀,`target_url` 设为本指南的 `api_base`;在调用方 Key 的 `allowed_routes` 上授予路由名称。 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 故障排查[​](#故障排查 "故障排查的直接链接") | 现象 | 检查项 | | ------------------------------ | ------------------------------------------------------------------------------ | | DNS 错误或上游返回 `404` | 确认 `SNOWFLAKE_ACCOUNT` 生成的主机名与 Snowflake 连接信息中显示的主机名相同。 | | 上游返回 `401` | 轮换 Snowflake PAT 并更新服务提供方密钥。 | | 上游返回 `403` | 确认该 Token 对应的用户和角色具有 Cortex 权限及模型访问权限。 | | 模型不可用 | 选择 Snowflake 账户所在区域支持的模型。 | | 创建服务提供方密钥时返回 `400` | 使用 `provider: "snowflake-cortex"` 并省略 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Snowflake Cortex,并验证了模型别名。请继续阅读以下指南: * [服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md):管理账户专用凭证和密钥轮换。 * [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md):访问 AISIX 未标准化的 Snowflake 原生路由。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Together AI [Together AI](https://docs.together.ai/) 为开放模型和合作伙伴模型提供托管推理。应用通过稳定的 AISIX 别名调用所选模型,网关负责保管 Together API Key。 ## 准备工作[​](#prerequisites "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Together 控制台](https://api.together.ai/settings/api-keys)获取的 Together API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#configure-with-aisix-cloud "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由 Together 提供支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 由于 Together AI 提供 OpenAI 兼容 API,AISIX 通过 `openai` 适配器连接,并使用 Together API 根地址作为 `api_base`。 ### 创建服务提供方密钥[​](#create-a-provider-key "创建服务提供方密钥的直接链接") 创建用于存储 Together 凭证和 API 根地址的服务提供方密钥,并允许其在该环境中使用: ``` # 请替换为实际值 export TOGETHER_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "together-prod", "provider": "togetherai", "api_key": "'"${TOGETHER_API_KEY}"'", "api_base": "https://api.together.ai/v1", "allowed_environments": ["'"$ENV_ID"'"] }' | jq -r '.provider_key.id') ``` ❶ `provider` 为目录服务提供方 ID `togetherai`。 ❷ `api_key` 存储 Together API Key。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `api_base` 已包含 `/v1` 路径。AISIX 会将 `/chat/completions` 追加到该地址。Together 当前记录的地址是 `https://api.together.ai/v1`;省略该字段时,AISIX Cloud 仍会填入等价的 `https://api.together.xyz/v1` 根地址。请显式设置官方根地址,使目标在资源中保持可见,且不依赖该回退值。 该命令会将返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#create-a-model "创建模型的直接链接") Together 目录经常变化。创建模型别名前,请在 [Together 模型列表](https://docs.together.ai/docs/serverless/models)中查找准确的 `<publisher>/<model>` ID。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "together-gptoss-prod", "model_name": "openai/gpt-oss-120b", "provider_key_id": "'"$PROVIDER_KEY_ID"'" }' | jq -r '.model.id') ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 `<publisher>/<model>` 形式的 Together 模型 ID。`gpt-4o` 等不含命名空间的 OpenAI 风格名称会导致 Together 返回 404。 ❸ `provider_key_id` 将别名关联到 Together 服务提供方密钥。 ### 创建调用方 API Key[​](#create-a-caller-api-key "创建调用方 API Key的直接链接") 创建可访问模型别名的调用方 API Key。API 会生成密钥值,并仅返回一次明文: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "together-caller", "allowed_models": ["'"$MODEL_ID"'"] }' | jq -r '.plaintext') ``` `allowed_models` 值通过 ID 引用模型。明文密钥仅在此响应中返回,因此请妥善保存。 新资源会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#configure-with-the-open-source-aisix-gateway "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export TOGETHER_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "together-prod" provider: "togetherai" adapter: "openai" api_key: ${TOGETHER_API_KEY} api_base: "https://api.together.ai/v1" models: - display_name: "together-gptoss-prod" provider: "togetherai" model_name: "openai/gpt-oss-120b" provider_key: "together-prod" api_keys: - display_name: "together-caller" key_env: CALLER_API_KEY allowed_models: - "together-gptoss-prod" ``` 如果 AISIX 安装在本地,请在加载文件前进行验证: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#verify-the-provider-connection "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "together-gptoss-prod", "messages": [ { "role": "user", "content": "Say hello from Together AI." } ] }' ``` 网关会返回 OpenAI 兼容响应,其中回显面向调用方的别名 `together-gptoss-prod`。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 `<publisher>/<model>` ID。 ## 端点覆盖[​](#endpoint-coverage "端点覆盖的直接链接") Together 在同一基础地址上提供多个 OpenAI 格式 API,但规范化路由支持也取决于模型的 `togetherai` 服务提供方值: | 路由 | 使用 Together AI 别名时的行为 | | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 所选模型实现该路由时支持,包括缓冲和流式传输。 | | `/v1/completions` | 所选模型实现该路由时支持缓冲响应。该路由不支持流式传输——需要流式请改用 `/v1/chat/completions`。 | | `/v1/responses` | 通过 AISIX [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)支持。Together [没有实现原生 Responses API](https://docs.together.ai/docs/inference/openai-compatibility),没有 Chat Completions 等价项的字段会被忽略。 | | `/v1/messages` | 通过转换为 Chat Completions 支持。`/v1/messages/count_tokens` 仅限 Anthropic 后端模型。 | | `/v1/embeddings` | 别名指向 [Together 嵌入模型](https://docs.together.ai/docs/inference/embeddings/embeddings)时支持。AISIX 会重写面向调用方的别名,并将 OpenAI 格式请求转发到 `{api_base}/embeddings`。 | | `/v1/audio/transcriptions`、`/v1/audio/translations` 和 `/v1/audio/speech` | 别名指向所选音频路由对应的 Together 模型时支持。AISIX 会在重写模型别名的同时保留 OpenAI 请求和响应结构。 | | `/v1/images/generations` | 不支持。即使 Together 原生提供相同路径,规范化路由只接受配置的服务提供方为 `openai` 的模型。请改用 `/passthrough/togetherai/images/generations`。 | | `/v1/videos` | 不支持。视频路由允许列表不包含 `togetherai`;请通过透传路由使用 Together 原生视频协议。 | | `/v1/rerank` | 不支持。规范化路由只接受 `openai`、`cohere` 和 `jina` 服务提供方值。请通过 `/passthrough/togetherai/rerank` 使用 Together 重排模型和原生请求体。 | | `/passthrough/togetherai/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 Together 原生路由,网关规范化有限。透传不会重写请求体中面向调用方的别名,并会增量中继上游 SSE。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 | 本页的 `/passthrough/togetherai` 路径假定一条透传路由认领该前缀,`target_url` 设为 Together 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。 完整端点与服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 后续步骤[​](#next-steps "后续步骤的直接链接") 你已将 AISIX 连接到 Together AI,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Together 与另一个服务提供方之间进行故障转移。 * [语音和音频](https://docs.apiseven.com/ai-gateway/endpoints/audio.md):通过规范化音频路由调用 Together 转录、翻译或文本转语音模型。 * [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md):访问 Together 图片、视频、重排和其他原生路由。 * [服务提供方专属覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看受支持的代理端点和服务提供方专属边界。 --- # vLLM [vLLM](https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/) 是一个开源推理服务器,可为你运行的模型提供 OpenAI 和 Anthropic 兼容 API。vLLM 继续提供推理服务,AISIX 则为其添加调用方身份认证、稳定的模型别名、用量报告和流量控制。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一台已安装 vLLM 0.10.0 或更高版本,并且拥有足够算力和存储空间来运行所选模型的主机。该版本开始提供本指南使用的原生 Responses 路由。 * AISIX 网关与 vLLM 之间网络连通。 * `curl` 和 `jq`。 ## 准备推理服务器[​](#准备推理服务器 "准备推理服务器的直接链接") 启动官方示例模型,并启用 API Key 检查: ``` vllm serve NousResearch/Meta-Llama-3-8B-Instruct \ --dtype auto \ --api-key token-abc123 ``` 导出上游密钥,以及可从 AISIX 网关访问的 API 根地址: ``` export VLLM_API_KEY="token-abc123" export VLLM_API_BASE="http://vllm.internal:8000/v1" ``` 请将 `vllm.internal` 替换为可解析的主机名或服务名称。如果使用 Docker Desktop 且 vLLM 位于主机上,通常可使用 `http://host.docker.internal:8000/v1`。如果两个服务共享 Docker 或 Kubernetes 网络,请使用 vLLM 服务的 DNS 名称。 警告 vLLM 文档说明,`--api-key` 保护的是其 OpenAI 兼容 API 路由,而不是服务器可能公开的所有端点。请将 vLLM 服务保留在私有网络中;如果管理或诊断路由需要保护,请应用网络策略或带身份验证的反向代理。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` vLLM 是私有端点,而不是 AISIX 目录服务提供方。请使用 `byo` 服务提供方值进行配置,并显式选择 `openai` 适配器。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "vllm-local", "provider": "byo", "adapter": "openai", "api_key": "'"${VLLM_API_KEY}"'", "api_base": "'"${VLLM_API_BASE}"'", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` BYO 密钥要求提供 `provider: "byo"`、非空的 `api_key` 和 `api_base`。本指南显式设置 `adapter: "openai"`;省略时,AISIX 会默认让 BYO 密钥使用 OpenAI 兼容适配器。AISIX 将 `VLLM_API_KEY` 作为 `Authorization: Bearer <key>` 发送,与传给 `vllm serve` 的密钥一致。 `apis.responses` 声明会把 Responses 请求发送至 vLLM 原生端点,而不是通过 Chat Completions 转换。 如果有意在不设置 `--api-key` 的情况下运行 vLLM,AISIX 的服务提供方密钥 schema 仍要求提供非空占位值。只要流量可能来自严格受控的本地网络之外,就应优先使用需要身份验证的 vLLM 端点。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 使用 vLLM 提供的模型名称: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "vllm-llama-prod", "model_name": "NousResearch/Meta-Llama-3-8B-Instruct", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` `model_name` 必须与 vLLM 从 `/v1/models` 公开的名称匹配。如果启动 vLLM 时覆盖了所提供的模型名称,请使用该覆盖值,而不是模型仓库路径。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "vllm-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export VLLM_API_KEY="token-abc123" export VLLM_API_BASE="http://vllm.internal:8000/v1" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "vllm-local" provider: "vllm" adapter: "openai" api_key: ${VLLM_API_KEY} api_base: "${VLLM_API_BASE}" apis: responses: {} models: - display_name: "vllm-llama-prod" provider: "vllm" model_name: "NousResearch/Meta-Llama-3-8B-Instruct" provider_key: "vllm-local" api_keys: - display_name: "vllm-caller" key_env: CALLER_API_KEY allowed_models: - "vllm-llama-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "vllm-llama-prod", "input": "Say hello from vLLM." }' ``` AISIX 会使用已配置的 vLLM Bearer Key,将所提供的模型名称发送到 vLLM 原生 `POST /v1/responses` 端点,然后在响应中恢复 AISIX 别名。 ## 通过透传使用原生 Messages[​](#通过透传使用原生-messages "通过透传使用原生 Messages的直接链接") 当前 vLLM 版本提供 Anthropic 兼容的 `/v1/messages` 和 `/v1/messages/count_tokens` 路由。本指南配置的已认证服务器要求 Bearer 身份认证,而 AISIX 会在声明的原生 Messages 协议面上发送 `x-api-key`。不要向此服务提供方密钥添加 `apis.messages`。 配置一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),然后调用 `/passthrough/byo/messages` 或 `/passthrough/vllm/messages` 访问原生 Messages。将 `/messages/count_tokens` 追加到同一路由前缀即可访问 Count Tokens。透传会保留配置的 Bearer 凭证以及 vLLM 请求和响应协议。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") 当前 vLLM [在线服务器](https://docs.vllm.ai/en/latest/serving/online_serving/)提供 OpenAI 兼容的生成、Responses、Embedding 和语音转文本 API,以及 rerank 和 score 等池化模型 API。具体可用性仍取决于 vLLM 服务器启动时选择的模型和任务。 | 路由 | 使用本指南 vLLM 别名时的行为 | | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持使用带 Chat 模板的文本生成模型。 | | `/v1/completions` | 支持文本生成模型。vLLM 不支持 OpenAI `suffix` 参数。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送至 vLLM 原生 Responses API。对于低于 0.10.0 的服务器,请省略此声明,让 AISIX 使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)。 | | `/v1/messages` | 通过 AISIX 转换到 Chat Completions 提供支持,而不是使用原生 Anthropic 兼容 vLLM 路由。需要 vLLM 原生契约时,请使用 `/passthrough/byo/messages` 或 `/passthrough/vllm/messages`。 | | `/v1/messages/count_tokens` | 配置的服务提供方密钥未声明 Messages 协议面,因此 AISIX 会拒绝此规范化路由。当前 vLLM 版本实现了 Count Tokens;请在透传路由前缀后追加 `/messages/count_tokens`。 | | `/v1/embeddings` | 当别名指向运行 Embedding 模型的 vLLM 服务器时受支持。 | | `/v1/audio/transcriptions`、`/v1/audio/translations` | 当别名指向运行兼容自动语音识别模型且安装了 vLLM 音频依赖的服务器时受支持。翻译支持取决于模型。 | | `/v1/audio/speech` | 不支持,因为 vLLM 未提供 OpenAI 兼容的文本转语音路由。 | | `/v1/realtime` | 当 vLLM 提供支持 Realtime 的自动语音识别模型且安装了音频依赖时受支持。AISIX 会通过标准化 Realtime 路由中继 OpenAI 形态的 vLLM WebSocket 协议。vLLM 当前支持流式语音转文本,而不是部分 OpenAI Realtime 模型提供的双向语音生成。 | | `/v1/rerank` | 拒绝,因为 `byo` 和 `vllm` 都不在标准化路由的服务提供方允许列表中。运行评分模型的 vLLM 服务器会提供 `/v1/rerank`;请通过 `/passthrough/byo/rerank` 或 `/passthrough/vllm/rerank` 访问。 | | `/v1/chat/completions/batch`、`/v1/score` | AISIX 没有对应的标准化路由。请在你的透传路由前缀后追加 `/chat/completions/batch` 或 `/score`。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名,而不是 vLLM 提供的模型。请通过 `/passthrough/byo/models` 或 `/passthrough/vllm/models` 获取 vLLM 原生列表。 | | `/v1/images/generations`、`/v1/videos` | 拒绝,因为这两个服务提供方值均不在对应标准化路由允许列表中。vLLM 也未提供匹配的生成 API。 | 每个生成、Embedding 或语音转文本模型都应使用单独的模型别名,通常还应使用单独的服务提供方密钥和服务进程。通过透传路由访问 Rerank 模型时也适用同一要求。 上述 `/passthrough/byo` 和 `/passthrough/vllm` 前缀假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 vLLM 服务器根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。透传路由会原样中继请求体,因此应使用 vLLM 公开的模型标识符,而不是 AISIX 别名。它会增量中继包括 SSE 在内的上游响应。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。一条路由绑定一个固定 `target_url`,因此请为每台 vLLM 服务器各建一条路由,而不是依赖模型访问权限挑选端点。 vLLM 还提供 `/pooling` 和 `/classify` 等 Root 级 API。它们位于本指南配置的 `/v1` API Base 之外,且没有标准化 AISIX 路由。要通过透传路由访问这些 API,需要 `target_url` 指向 vLLM 服务器 Root;不能假定以上述 `/v1` Base 为目标的路由可以到达它们。 ## 故障排除[​](#troubleshooting "故障排除的直接链接") | 现象 | 检查项 | | ------------------------------ | ------------------------------------------------------------------------------- | | 连接被拒绝或超时 | 从 AISIX 网关容器中解析并调用 `VLLM_API_BASE`。 | | 上游返回 `401` | 为 `--api-key` 和 AISIX 服务提供方密钥的 `api_key` 使用相同的值。 | | 找不到模型 | 将 `model_name` 与 `GET $VLLM_API_BASE/models` 的结果进行比较。 | | Chat 模板错误 | 提供具有有效 Chat 模板的 Chat 模型,或在 vLLM 中配置模板。 | | 创建服务提供方密钥时返回 `400` | 请包含 `provider: "byo"`、`adapter: "openai"`、非空的 `api_key` 和 `api_base`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 vLLM,并验证了模型别名。接下来可阅读以下指南: * [自带端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md):查看适用于私有 OpenAI 兼容服务器的可复用配置和自定义定价选项。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Volcengine Ark (Doubao) [Volcengine Ark](https://www.volcengine.com/docs/82379/1298459) 是字节跳动用于提供豆包及其他模型的平台。AISIX 允许应用通过网关的 OpenAI 兼容 API 调用这些模型,同时管理 Ark 凭证、调用方访问权限、速率限制和用量核算。 一个 Ark 服务提供方密钥可以同时处理 OpenAI 兼容的豆包 Chat、原生 Responses、原生 Messages 和 Count Tokens,以及 Seedance 视频任务。本指南先验证文本 API,然后复用该服务提供方密钥进行[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从 [Volcengine Ark 控制台](https://console.volcengine.com/ark)获取的 Ark API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为豆包文本请求创建服务提供方密钥、模型别名和调用方 API Key。后续视频工作流会复用服务提供方密钥和调用方 Key。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Ark 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export ARK_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "volcengine-prod", "provider": "volcengine", "api_key": "'"${ARK_API_KEY}"'", "api_base": "https://ark.cn-beijing.volces.com/api/v3", "apis": { "responses": {}, "messages": { "base": "https://ark.cn-beijing.volces.com/api/compatible" } }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `volcengine`,这是网关视频路由用于分发的服务提供方 ID。Volcengine Ark 未收录在 models.dev 中,但它并非社区目录条目:网关原生实现了 Ark 视频传输格式,AISIX Cloud Admin API 会直接接受该 ID,并为聊天流量推导出 `openai` 适配器。`adapter` 字段仅适用于 BYO 服务提供方密钥。 ❷ `api_key` 存储 Ark API Key。AISIX 会在 OpenAI 兼容、Responses 和视频路由中将其作为 Bearer Token 发送,并在原生 Messages 和 Count Tokens 中将其作为 `x-api-key` 发送。它遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 是 Ark 的 OpenAI 兼容 Base,其版本路径段为 `/api/v3`。AISIX 会将端点路径原样追加到 `api_base`,因此该值会生成 `https://ark.cn-beijing.volces.com/api/v3/chat/completions`。对于此服务提供方,该字段可选;省略时,AISIX Cloud Admin API 会填入同一规范值。但示例仍显式设置此字段,以便在配置中清楚显示每个密钥指向的上游 Root。 ❹ `apis` 启用 Ark 的[原生 Responses](https://www.volcengine.com/docs/82379/1958524?lang=zh)、[Messages](https://docs.volcengine.com/docs/82379/2655179?lang=zh) 和 [Count Tokens](https://docs.volcengine.com/docs/82379/2655180?lang=zh) 路由。Responses 使用 `api_base`;Messages 和 Count Tokens 使用单独的 `/api/compatible` Base。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 示例使用中国北京主机 `https://ark.cn-beijing.volces.com/api/v3`。字节跳动还运营该平台的国际版本 BytePlus ModelArk,其亚太区地址为 `https://ark.ap-southeast.bytepluses.com/api/v3`,欧洲区地址为 `https://ark.eu-west.bytepluses.com/api/v3`。API Key 和模型可用性因平台及区域而异,因此请使用账户实际预配的主机和模型 ID。任何以 `/api/v3` 结尾的 Ark Base 都可直接用于视频路由,因为网关会根据该后缀推导服务商 Root。 BytePlus 也在其 OpenAI 兼容根地址上提供[原生 Responses API](https://docs.byteplus.com/en/docs/ModelArk/Responses_API)。将此示例改用于 BytePlus 时,请保留 `apis.responses`,但省略 `apis.messages`。`/api/compatible` Messages Base 是 Volcengine 专用的,BytePlus 当前没有对应 Messages 和 Count Tokens 路由的文档。 下文使用的 `doubao-*` 模型 ID 属于 Volcengine Ark。BytePlus 的对应模型使用不同 ID,因此仅更改 `api_base` 并不足够。使用 BytePlus 账户时,请在 [BytePlus ModelArk 文档](https://docs.byteplus.com/en/docs/modelark/1099455)中选择适用于所在区域的模型 ID。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Ark 模型 ID 由系列名称、版本数字和发布日期后缀组成,各部分用连字符分隔。示例使用 `doubao-seed-2-1-pro-260628`,Volcengine 文档说明该模型支持 Responses、Messages 和 Count Tokens。Ark 还会预配 ID 以 `ep-` 开头的自定义推理端点。`model_name` 接受这两种形式,因为网关会将该值作为上游 `model` 原样转发。创建模型别名前,请在 [Ark 模型列表](https://www.volcengine.com/docs/82379/1330310)中查看当前目录和协议支持情况。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "doubao-flagship-prod", "model_name": "doubao-seed-2-1-pro-260628", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Ark 模型 ID,或你在 Ark 控制台中预配的推理端点 ID;后者以 `ep-` 开头。 ❸ `provider_key_id` 将别名关联到 Ark 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且只在响应中返回一次,因此请立即保存: ``` CALLER_KEY_RESPONSE=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "volcengine-caller", "allowed_models": ["'"${MODEL_ID}"'"] }') export AISIX_API_KEY=$(printf '%s' "$CALLER_KEY_RESPONSE" | jq -r '.plaintext') CALLER_API_KEY_ID=$(printf '%s' "$CALLER_KEY_RESPONSE" | jq -r '.api_key.id') ``` `allowed_models` 值必须引用上一步保存的模型 ID,因此该密钥只能访问你创建的别名。这些命令还会保留调用方密钥的资源 ID,以便后续添加视频模型。写入后,配置会自动投射到关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export ARK_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用此完整资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "volcengine-prod" provider: "volcengine" adapter: "openai" api_key: ${ARK_API_KEY} api_base: "https://ark.cn-beijing.volces.com/api/v3" apis: responses: {} messages: base: "https://ark.cn-beijing.volces.com/api/compatible" models: - display_name: "doubao-flagship-prod" provider: "volcengine" model_name: "doubao-seed-2-1-pro-260628" provider_key: "volcengine-prod" api_keys: - display_name: "volcengine-caller" key_env: CALLER_API_KEY allowed_models: - "doubao-flagship-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-flagship-prod", "messages": [ { "role": "user", "content": "Say hello from Doubao." } ] }' ``` 网关返回 OpenAI 兼容响应,并回显调用方可见的别名 `doubao-flagship-prod`。如果请求失败,请检查服务提供方密钥中的 `api_key`、`api_base` 和 `model_name` 中的 Ark 模型 ID。Ark 按平台和区域提供模型,因此上游返回找不到模型的错误,也可能表示你的账户无法在 `api_base` 指向的主机上使用该模型。 使用同一别名验证原生 Responses 转发: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-flagship-prod", "input": "Say hello from the Ark Responses API." }' ``` 响应采用 Ark 原生 Responses 格式,而不是 AISIX Chat 桥接格式。 使用 Count Tokens 请求验证单独的 Messages Base;该请求不会生成模型响应: ``` curl -sS -X POST "$AISIX_PROXY/v1/messages/count_tokens" \ -H "x-api-key: ${AISIX_API_KEY}" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-flagship-prod", "messages": [ { "role": "user", "content": "Count this Ark prompt." } ] }' ``` 成功响应包含 `input_tokens`。如果 Chat Completions 正常而其中一个请求失败,请确认模型支持所请求的协议,并检查对应的 `apis` 声明。 ## 提供成本元数据[​](#supply-cost-metadata "提供成本元数据的直接链接") models.dev 不提供 Volcengine Ark 模型的定价,因此 AISIX Cloud 定价目录中没有 `volcengine` 服务提供方的每 Token 费率,创建该服务提供方的别名时,控制台也不会建议模型 ID。[预算](https://docs.apiseven.com/ai-gateway/traffic-controls/budgets.md)和用量报告所需的成本元数据由运维人员在模型别名上提供,这与 [BYO 端点](https://docs.apiseven.com/ai-gateway/providers/bring-your-own-endpoint.md)的处理方式相同。在设置费率之前,这些别名的用量不包含成本信号,因此基于支出的控制功能无法识别这部分流量。 在 AISIX Cloud 部署中通过[模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md)设置费率,或在开源 AISIX 网关的 `resources.yaml` 中使用模型的 `cost` 字段设置费率,详见[成本元数据](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#cost-metadata)。此外,视频提交会记录为零 Token,AISIX Cloud 预算尚未对视频任务应用基于时长的成本核算。 ## 使用 Seedance 生成视频[​](#generate-videos-with-seedance "使用 Seedance 生成视频的直接链接") 同一服务提供方密钥可以驱动网关已建模的视频路由。创建第二个指向当前 Ark 视频模型(例如 Doubao Seedance 2.0)的别名。由于带日期的模型 ID 会随版本在目录中的变化而更新,请在创建别名前查看 [Ark 模型列表](https://www.volcengine.com/docs/82379/1330310): 在 AISIX Cloud 中创建视频别名: ``` VIDEO_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "doubao-video-prod", "model_name": "doubao-seedance-2-0-260128", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$VIDEO_MODEL_ID" ``` 将新模型 ID 添加到调用方密钥的 `allowed_models`。该字段是替换列表,因此也要包含现有聊天模型 ID: ``` curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/api_keys/$CALLER_API_KEY_ID" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "allowed_models": ["'"${MODEL_ID}"'", "'"${VIDEO_MODEL_ID}"'"] }' ``` 对于开源 AISIX 网关,请将 `doubao-video-prod` 添加到现有 `models` 集合。将现有 `volcengine-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(视频模型访问) ``` models: - display_name: "doubao-video-prod" provider: "volcengine" model_name: "doubao-seedance-2-0-260128" provider_key: "volcengine-prod" api_keys: - display_name: "volcengine-caller" key_env: CALLER_API_KEY allowed_models: - "doubao-flagship-prod" - "doubao-video-prod" ``` 按照上述说明验证声明式资源文件,然后重新加载或重启网关。 提交视频任务: ``` curl -sS -X POST "$AISIX_PROXY/v1/videos" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-video-prod", "prompt": "A paper boat drifts down a rain-soaked street at dusk.", "seconds": 5 }' ``` 在围绕此路由编写脚本前,需要了解以下五种服务提供方特有行为: * **聊天 `api_base` 会原样复用。** AISIX 会识别 `/api/v3` 后缀,据此推导服务商 Root,并在其下组合 Ark 原生任务路径:任务提交到 `POST {root}/api/v3/contents/generations/tasks`,并通过 `GET {root}/api/v3/contents/generations/tasks/{id}` 轮询。已为豆包聊天流量配置的服务提供方密钥无需修改即可用于视频路由。 * **`seconds` 映射到 `duration`;`size` 不会转发。** `seconds` 会作为服务提供方的整数 `duration` 转发。Ark 使用分辨率和宽高比质量等级表达输出尺寸,而不是像素 `WIDTHxHEIGHT` 值。因此,提供的 `size` 会进行格式验证,格式错误的值会在联系服务提供方前以 `400` 失败,但不会包含在上游请求中,最终采用服务提供方的默认输出设置。 * **服务提供方原生视频字段需要透传路由。** 标准化请求只建模 `prompt`、`seconds` 和 `size`;其他字段会被忽略。若要发送参考 `content`、`resolution`、`ratio`、`generate_audio` 或 `watermark` 等 Ark 字段,请通过 `/passthrough/volcengine/contents/generations/tasks` 发送 Ark 原生正文和准确的模型 ID,并通过 `/passthrough/volcengine/contents/generations/tasks/{id}` 轮询任务。透传不会返回统一的 AISIX 视频对象或网关编码的任务 ID。本页的 `/passthrough/volcengine` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 Ark 的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。 * **报告完整的四状态生命周期。** AISIX 将 Ark 任务状态映射到统一枚举:`queued` 报告为 `queued`,`running` 报告为 `in_progress`,`succeeded` 报告为 `completed`;`failed`、`cancelled` 和 `expired` 则都报告为 `failed`,并在可用时包含服务提供方的错误码和消息。任务完成后,轮询响应还会通过 `seconds` 报告实际视频时长。 * **已完成视频通过重定向交付。** `GET /v1/videos/{id}/content` 返回 `302`,其 `Location` 响应头指向服务提供方签名的下载 URL。视频字节会从 Ark 存储直接传输到客户端,不经过网关,因此下载时请使用 `curl -L`。 有关完整的提交、轮询和下载工作流,包括状态语义及轮询时的速率限制行为,请参阅[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Volcengine Ark 服务提供方密钥会解析到 `openai` 适配器,因此路由支持情况由该适配器和各路由自身的服务提供方规则共同决定: | 路由 | 使用 `volcengine` 模型别名时的行为 | | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持缓冲和流式响应。 | | `/v1/embeddings` | 当别名指向 Ark 嵌入模型(例如 `doubao-embedding-text-240515`)时支持。AISIX 会将 `/embeddings` 追加到 `api_base`,从而访问服务提供方的文本向量化端点。 | | `/v1/responses` | 由于本指南声明了 `apis.responses`,请求会发送到 Ark 原生 Responses API。如果没有此声明,AISIX 会通过 Chat Completions 桥接 Responses。请使用 Ark 文档中支持 Responses 的模型。 | | `/v1/messages` 和 `/v1/messages/count_tokens` | 由于本指南声明了 `apis.messages`,请求会发送到 Volcengine 原生 Anthropic 兼容路由。如果没有此声明,Messages 会转换为 Chat Completions,而 Count Tokens 不可用。BytePlus 没有此配置的文档。 | | `/v1/videos` 及其状态和内容路由 | 支持。请参阅[使用 Seedance 生成视频](#generate-videos-with-seedance)。 | | `/v1/images/generations` | 标准化路由不受支持,因为它只接受配置的服务提供方为 `openai` 的模型。Ark 为图像模型提供相同路径;请通过 `/passthrough/volcengine/images/generations` 发送原生请求体和准确的 Ark 模型 ID。 | | `/v1/rerank` | 不支持。此路由仅接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名,而不是 Ark 目录。请查阅上文链接的 Ark 控制台或模型列表,确认可用的服务提供方模型 ID。 | | `/passthrough/volcengine/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于 AISIX 尚未建模的服务提供方原生 API。透传不会重写 AISIX 别名,并会增量中继 SSE。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 | 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 Volcengine Ark,并验证了模型别名。请继续阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [模型定价](https://docs.apiseven.com/ai-gateway/cloud/model-pricing.md):设置该服务提供方的预算和用量报告所需、由运维人员提供的每 Token 费率。 * [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md):按照完整的提交、轮询和下载工作流处理 Seedance 任务。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Weights & Biases Inference [Weights & Biases Inference](https://docs.wandb.ai/inference/api-reference) 通过 W\&B 平台为开放模型提供托管推理服务。AISIX 将这些模型映射到稳定的别名,并在网关处控制调用方访问权限。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一个已获 Inference 授权的 W\&B API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` W\&B Inference 是使用 OpenAI 兼容 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,并使用 Bearer Token 对上游请求进行身份认证。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") ``` export WANDB_API_KEY="YOUR_WANDB_API_KEY" PROVIDER_KEY_ID=$( curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "wandb-prod", "provider": "wandb", "api_key": "'"${WANDB_API_KEY}"'", "api_base": "https://api.inference.wandb.ai/v1", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -er '.provider_key.id' ) echo "$PROVIDER_KEY_ID" ``` AISIX 服务提供方 ID 是 `wandb`,而不是 `weights-and-biases`。不要添加 `adapter`;AISIX 会为目录服务提供方推导出 `openai` 适配器。 显式 API Base 中包含 `/v1`。AISIX 发送上游请求时会追加 `/chat/completions`。 如果未指定项目,W\&B 会将请求归因到默认 Entity 和 `inference` 项目。若要使用其他 W\&B 团队和项目,请在服务提供方密钥的 `request.default_headers` 中添加 `OpenAI-Project` 值。请参阅[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#request-context-header-values)。 ### 创建模型[​](#创建模型 "创建模型的直接链接") 使用完整的 W\&B 模型 ID 创建别名: ``` MODEL_ID=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "wandb-llama-prod", "model_name": "meta-llama/Llama-3.1-8B-Instruct", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -er '.model.id' ) echo "$MODEL_ID" ``` 替换为 W\&B Inference 目录中的其他模型时,请保留发布方命名空间和大小写。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") ``` AISIX_API_KEY=$( curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "wandb-inference-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -er '.plaintext' ) echo "$AISIX_API_KEY" ``` ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export WANDB_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用这份完整的资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "wandb-prod" provider: "wandb" adapter: "openai" api_key: ${WANDB_API_KEY} api_base: "https://api.inference.wandb.ai/v1" models: - display_name: "wandb-llama-prod" provider: "wandb" model_name: "meta-llama/Llama-3.1-8B-Instruct" provider_key: "wandb-prod" api_keys: - display_name: "wandb-inference-caller" key_env: CALLER_API_KEY allowed_models: - "wandb-llama-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer $AISIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "wandb-llama-prod", "messages": [ { "role": "user", "content": "Say hello from W&B Inference." } ] }' ``` AISIX 将上游模型 ID 转发到 `POST /v1/chat/completions`,并在 Bearer 请求头中携带 W\&B API Key。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") W\&B Serverless Inference 当前提供 OpenAI 兼容的 Chat Completions 和模型列表。AISIX 会增加基于 Chat 的协议桥接,但无法增加 W\&B 未提供的上游能力: | 路由 | 使用 `wandb` 模型别名时的行为 | | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持缓冲和流式传输。 | | `/v1/responses` | 通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持。没有对应 Chat Completions 语义的字段会被忽略。 | | `/v1/messages` | 通过 AISIX 转换到 Chat Completions 提供支持。`/v1/messages/count_tokens` 不受支持,因为该模型并非由 Anthropic 提供支持。 | | `/v1/embeddings` | 不支持。W\&B Serverless Inference 未在此 API Root 上提供 Embedding 端点。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名,而不是 W\&B 目录。调用 `GET /passthrough/wandb/models` 可使用已配置的服务提供方凭证访问 W\&B 原生模型列表端点。 | | `/v1/images/generations`、`/v1/videos`、`/v1/rerank` | 不支持。W\&B 未提供这些 API,且 `wandb` 服务提供方值不在标准化路由允许列表中。 | | `/passthrough/wandb/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用:路由认领此前缀,`target_url` 设为 W\&B API 根地址;在调用方 Key 的 `allowed_routes` 上授予该路由。透传不会重写 AISIX 别名,并会增量中继 SSE 响应。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 | 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 故障排查[​](#故障排查 "故障排查的直接链接") | 现象 | 检查项 | | ------------------------------ | ------------------------------------------------ | | 上游返回 `401` 或 `403` | 确认 W\&B API Key 具有 Inference 访问权限。 | | 上游返回 `404` | 在 API Base 中保留 `/v1`,并验证模型 ID。 | | 找不到模型 | 保留发布方命名空间和大小写。 | | 创建服务提供方密钥时返回 `400` | 使用 `provider: "wandb"`,且不要添加 `adapter`。 | ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 W\&B Inference,并验证了模型别名。请继续阅读以下指南: * [服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md):管理服务提供方密钥轮换和环境访问权限。 * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 W\&B Inference 和其他服务提供方之间进行故障转移。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # xAI (Grok) [xAI](https://docs.x.ai/) 通过其 API 提供 Grok 系列模型。xAI 建议新集成使用 Responses API,同时为现有应用继续提供 Chat Completions。AISIX 可以通过稳定的模型别名转发原生 Responses 请求,同时确保 xAI 凭证不会出现在客户端代码中。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 一个 xAI API Key。按照 [xAI 快速入门](https://docs.x.ai/developers/quickstart)创建密钥。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为原生 Responses 和 Chat Completions 请求创建服务提供方密钥、模型别名和调用方 API Key。 xAI 是使用 OpenAI 兼容 API 的社区目录服务提供方。AISIX 通过 `openai` 适配器连接,使用 Bearer Token 对上游请求进行身份认证,并将 xAI API Root 用作 `api_base`。AISIX 不会注册 xAI 特有的请求或响应重写规则,因此以下章节将介绍必须配置的服务提供方特定值。 服务提供方目录将 xAI 作为社区条目返回,而不是精选服务提供方。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 xAI 凭证和 API Root 的服务提供方密钥: ``` # 请替换为实际值 export XAI_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "xai-prod", "provider": "xai", "api_key": "'"${XAI_API_KEY}"'", "api_base": "https://api.x.ai/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `xai`。AISIX Cloud Admin API 会根据目录服务提供方推导适配器,因此 `xai` 会通过目录的默认规则解析到 `openai` 适配器。`adapter` 字段仅适用于 BYO 服务提供方密钥,在目录服务提供方密钥中会被拒绝。 ❷ `api_key` 存储 xAI API Key。xAI 使用 HTTP Bearer 身份认证,`openai` 适配器已经会发送该认证信息。该值遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理行为。 ❸ `api_base` 对于 `xai` 是**必需的**。精选服务提供方条目会包含默认 API Root,社区目录服务提供方则回退到 models.dev 发布的 `api` 字段。models.dev 中的 `xai` 条目未发布 `api` 字段,因此没有可用的回退值。省略 `api_base` 会返回 `400`,并显示消息 `models.dev does not publish a default api_base for this provider — set api_base explicitly, or switch to the "byo" provider sentinel`。 请使用 `https://api.x.ai/v1`。AISIX 会将所选端点路径追加到 `api_base`,因此该值必须同时是 `/chat/completions` 和 `/responses` 的 Root。xAI 文档将其说明为 OpenAI 客户端库的 Base URL。 警告 不要将 `api_base` 设置为不含路径的主机 `https://api.x.ai`,也不要把完整端点 URL 粘贴到该字段。这两种错误会分别破坏不同的接口,因此只有带版本的 Root 才能同时安全用于两者。 不含路径的主机可用于 Responses——AISIX 会为不含路径的任意 `api_base` 追加 `/v1`——但 Chat Completions 只会为规范 OpenAI 主机补充缺失的路径段,因此 `https://api.x.ai` 会生成 xAI 不提供的 `https://api.x.ai/chat/completions`。 完整端点 URL 则会导致另一种故障。Responses 会移除末尾的 `/responses`,但 Chat Completions 只会移除自身的端点后缀,因此 `https://api.x.ai/v1/responses` 会变成 `https://api.x.ai/v1/responses/chat/completions`,并在没有明显提示的情况下失败。 ❹ `apis.responses` 声明此服务提供方密钥原生提供 Responses API。由于未单独设置 `base`,AISIX 会将 Responses 请求发送到已配置的 xAI API Root。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Grok 模型 ID 是不带服务商前缀的纯小写 Slug。小版本发布带有点号分隔的次版本号,例如 `grok-4.5` 和 `grok-4.3`;面向 Agent 的模型使用自己的系列名称,例如 `grok-build-0.1`;按日期发布的快照则追加发布日期和行为后缀,例如 `grok-4.20-0309-reasoning`。不要沿用聚合器中的 `xai/grok-4.5` 等带前缀形式。 创建别名前,请在 [xAI 模型列表](https://docs.x.ai/developers/models)中查看当前 Slug。xAI 会按照公布的计划退役较旧的 Grok Slug,并将对已退役 Slug 的请求重定向到当前模型。因此,仍固定到已退役 Slug 的别名会继续工作,但会在不提示的情况下实际使用另一个模型。当你使用的 Slug 退役时,请重新指定 `model_name`。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "grok-prod", "model_name": "grok-4.5", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 xAI 模型 ID,例如 `grok-4.5`、`grok-4.3` 或 `grok-build-0.1`。 ❸ `provider_key_id` 将别名关联到 xAI 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建能够访问该模型别名的调用方 API Key。明文密钥由服务器生成,并只在创建响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "xai-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export XAI_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用这份完整的资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "xai-prod" provider: "xai" adapter: "openai" api_key: ${XAI_API_KEY} api_base: "https://api.x.ai/v1" apis: responses: {} models: - display_name: "grok-prod" provider: "xai" model_name: "grok-4.5" provider_key: "xai-prod" api_keys: - display_name: "xai-caller" key_env: CALLER_API_KEY allowed_models: - "grok-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Responses 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/responses" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-prod", "input": "Say hello from Grok." }' ``` AISIX 将请求发送到 xAI 原生 Responses 端点,在上游把 `grok-prod` 替换为已配置的 xAI 模型 ID,并在响应中恢复调用方可见的别名。如果请求失败,请检查服务提供方密钥凭证,确认 API Root 以 `/v1` 结尾,并确认模型配置中的 xAI 模型 ID。 ## 选择原生或桥接 Responses[​](#选择原生或桥接-responses "选择原生或桥接 Responses的直接链接") `apis.responses` 声明只应用于 Responses 请求。Chat Completions 继续使用同一个服务提供方密钥和 API Root,因此现有调用方无需单独的模型别名。 如果省略该声明,AISIX 会通过 xAI Chat Completions 桥接 `/v1/responses`。桥接会转换可移植的输入、函数工具、采样字段、推理强度、输出 Token 上限和流式传输;但不会保留托管工具、服务器端状态或存储,也不会保留 `text` 等 Responses 输出控制项。新建 xAI 集成以及依赖 xAI Responses 语义的应用应使用原生声明。 ## 在 xAI 变更传输格式时进行适配[​](#在-xai-变更传输格式时进行适配 "在 xAI 变更传输格式时进行适配的直接链接") AISIX 目录中的精选服务提供方可以携带请求和响应重写规则,例如参数重命名、默认请求头或非标准推理流式路径。社区目录路径不会为 `xai` 注册这些规则。 服务提供方密钥上的请求覆盖项会应用于原生 Responses 和 Chat Completions。它们会影响引用该密钥的所有模型,因此请先使用非生产别名进行测试。有关完整字段目录,请参阅[服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides)。 当 xAI 要求的名称与客户端发送的名称不同时,重命名顶层请求参数: ``` { "request": { "param_renames": { "max_completion_tokens": "max_tokens" } } } ``` 对于流式 Chat Completions,将非标准 `delta` 路径中的推理内容映射到规范的 `delta.reasoning_content` 字段: ``` { "response": { "reasoning_field": "delta.thinking" } } ``` AISIX 不会移除 Chat Completions 路径上无法识别的顶层参数,因此新的 xAI 特有参数无需任何覆盖项就能到达上游。只有在请求发出时必须更改名称,或在响应返回时必须移动字段位置,才需要使用覆盖项。 ## 控制推理强度[​](#控制推理强度 "控制推理强度的直接链接") 在原生 Responses 路径上,请在请求的 `reasoning` 对象中设置推理强度: ``` { "model": "grok-prod", "input": "Plan a three-step migration.", "reasoning": { "effort": "low" } } ``` 对于 Chat Completions,请改为在顶层 `reasoning_effort` 字段中发送相同的值。AISIX 会原样转发该字段。 不同模型和 API 形态接受的值不同。例如,`grok-4.5` 接受 `low`、`medium` 和 `high`,后续模型可能增加其他值。请在 [xAI 模型列表](https://docs.x.ai/developers/models)中相应模型的页面确认支持的值。状态化对话、托管工具、结构化输出以及其他 Responses 功能是否可用,也可能因模型、账户和区域而异。 ## 指定区域端点[​](#指定区域端点 "指定区域端点的直接链接") xAI 通过 `https://<region>.api.x.ai` 提供区域端点,以处理必须在特定区域执行的请求;其文档将欧洲区域的 OpenAI 客户端 Base URL 写为 `https://eu-west-1.api.x.ai/v1`。同样需要遵循 `/v1` Root 规则:将 `api_base` 设置为区域主机加 `/v1`。 请为区域路由创建第二个服务提供方密钥,而不是编辑现有密钥,以便两个 Root 在用量记录中保持独立归因。 在 AISIX Cloud 中创建区域服务提供方密钥、模型别名和调用方密钥: ``` EU_PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "xai-eu", "provider": "xai", "api_key": "'"${XAI_API_KEY}"'", "api_base": "https://eu-west-1.api.x.ai/v1", "apis": { "responses": {} }, "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') EU_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "grok-eu-prod", "model_name": "grok-4.5", "provider_key_id": "'"${EU_PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') XAI_EU_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "xai-eu-caller", "allowed_models": ["'"${EU_MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 请使用 `XAI_EU_API_KEY` 调用 `grok-eu-prod` 别名。 对于开源 AISIX 网关,请将 `xai-eu` 添加到 `provider_keys`,并将 `grok-eu-prod` 添加到 `models`。将现有 `xai-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(欧盟区域资源) ``` provider_keys: - display_name: "xai-eu" provider: "xai" adapter: "openai" api_key: ${XAI_API_KEY} api_base: "https://eu-west-1.api.x.ai/v1" apis: responses: {} models: - display_name: "grok-eu-prod" provider: "xai" model_name: "grok-4.5" provider_key: "xai-eu" api_keys: - display_name: "xai-caller" key_env: CALLER_API_KEY allowed_models: - "grok-prod" - "grok-eu-prod" ``` 按照上述说明验证声明式资源文件,然后重新加载或重启网关。调用方通过选择别名来选择区域,网关会在用量事件中分别记录每个别名。将生产流量路由到某个区域前,请向 xAI 确认账户可用的区域:如果 xAI 无法在请求的区域中提供服务,请求会失败,而不会回退到其他区域。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") 社区目录路径会为 xAI 分配 `openai` 适配器。上述服务提供方密钥声明会把 Responses 请求原生发送到 xAI;标准化 Chat 形态路由使用 AISIX OpenAI 适配器。未建模的 xAI 原生 HTTP 路由仍可通过透传访问。本页的 `/passthrough/xai` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为 xAI API 根地址 `https://api.x.ai/v1`;在调用方 Key 的 `allowed_routes` 上授予该路由。 | 路由 | 使用 xAI 别名时的行为 | | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/chat/completions` | 支持,包括 `stream: true`。xAI 现已将 Chat Completions 标记为弃用,但 AISIX 中的标准化 xAI 路由仍将其作为上游 Chat 界面。 | | `/v1/responses` | 当服务提供方密钥声明 `apis.responses` 时,转发到 xAI 原生 Responses API;AISIX 会重写模型别名,并保留原生请求和响应格式。没有该声明时,AISIX 会通过 Chat Completions 使用 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md),并丢弃没有 Chat 等价项的字段。对于 AISIX 未建模的 xAI HTTP Responses 操作(例如检索或删除已存储的响应),请使用透传。 | | `/v1/messages` | 通过 AISIX 转换到 Chat Completions 支持现有 Anthropic 形态的调用方。xAI 已将其原生 Anthropic 兼容 Messages API 标记为完全弃用;如果现有应用仍需要该精确路由,可通过 `/passthrough/xai/messages` 访问。`/v1/messages/count_tokens` 不受支持,因为该模型并非由 Anthropic 提供支持。 | | `/v1/embeddings` | 不可用。xAI 目录条目未发布嵌入模型,因此请将嵌入请求路由到其他服务提供方。请参阅[嵌入](https://docs.apiseven.com/ai-gateway/endpoints/embeddings.md)。 | | `/v1/images/generations` | 返回 `400`,因为该路由只接受服务提供方为 `openai` 的模型。请通过 `/passthrough/xai/images/generations` 发送原生正文和准确的 Grok Imagine 模型 ID;图像编辑可通过 `/passthrough/xai/images/edits` 访问。 | | `/v1/videos` | 返回 `501`,因为 `xai` 不在该路由的服务提供方允许列表中。请通过 `/passthrough/xai/videos/generations` 使用原生异步 API,并通过 `/passthrough/xai/videos/{request_id}` 轮询。原生编辑和扩展路由位于同一透传前缀下。 | | `/v1/audio/transcriptions`、`/v1/audio/translations`、`/v1/audio/speech` | 与 xAI 原生语音路径不兼容。请通过 `/passthrough/xai/stt` 使用 REST 语音转文本,并通过 `/passthrough/xai/tts` 使用 REST 文本转语音。xAI 未提供音频翻译路由。 | | `/v1/realtime` | 支持直接 xAI 模型别名。AISIX 会把 OpenAI 兼容 WebSocket 传输中继到 `wss://api.x.ai/v1/realtime`,并将别名重写为配置的 xAI 模型 ID。 | | `/v1/rerank` | 返回 `400` 并拒绝请求。该路由仅接受 `openai`、`cohere` 和 `jina` 服务提供方值。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名,而不是 xAI 目录。请通过 `GET /passthrough/xai/models` 获取 xAI 原生模型列表。 | | `/passthrough/xai/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于服务提供方原生 HTTP 路由,网关标准化有限。它适用于 AISIX 未建模的路由,而不是普通的原生 Responses 创建。路由不会重写 AISIX 别名,并会增量中继 SSE 响应。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 | ### 通过透传访问服务提供方原生路由[​](#通过透传访问服务提供方原生路由 "通过透传访问服务提供方原生路由的直接链接") 透传路由会保留请求体,但不会保留所有请求头。在 inject 模式路由上,AISIX 会移除逐跳请求头以及服务提供方密钥的 `strip_headers` 值(默认 `authorization`、`cookie`、`set-cookie` 和 `x-api-key`);将绑定服务提供方密钥的 xAI 凭证注入为 `Authorization: Bearer ...`;并添加 `x-aisix-request-id`。路由的 `target_url` 固定上游 Root。对于网关未建模的 xAI 路由,例如延迟 Chat Completions、图像生成,以及已存储响应的检索或删除,请使用透传路由。 由于路由的 `target_url` 以 `/v1` 结尾,AISIX 会从剩余路径中移除开头重复的 `v1` 路径段,因此 `/passthrough/xai/v1/chat/deferred-completion/<request_id>` 和 `/passthrough/xai/chat/deferred-completion/<request_id>` 都会解析到同一个上游 URL: ``` curl -sS "$AISIX_PROXY/passthrough/xai/chat/deferred-completion/YOUR_REQUEST_ID" \ -H "Authorization: Bearer ${AISIX_API_KEY}" ``` 透传请求使用调用方 API Key 进行身份认证,网关按路由而不是按模型授权:密钥必须在其 `allowed_routes` Glob 列表中授予路由名称,密钥的模型允许列表在此不起作用。安全护栏通过 `passthrough_route` 作用域挂载到路由上,与调用方 Key、团队和环境作用域并存——不涉及任何模型别名。网关不会重写 `model` 字段,因此请发送准确的 xAI 模型 ID。AISIX 会检测 Chat、Completions 和 Responses 信封,并记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。请将透传路由视为访问网关未建模路由的逃生通道。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 现在,你已将 AISIX 连接到 xAI,并验证了模型别名。请继续阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由和故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 xAI 和第二个服务提供方之间进行故障转移。 * [服务提供方特定覆盖项](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides):当上游 API 与其适配器不同时,调整请求和响应形态。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # Zhipu AI (GLM) [Zhipu AI](https://docs.bigmodel.cn/cn/api/introduction) 通过托管 API 提供 GLM 语言模型和 CogVideoX 视频生成能力。应用使用 AISIX 调用方密钥和模型别名访问这两项能力,上游凭证则由网关保存。 本指南介绍如何通过一个 Zhipu AI 服务提供方密钥处理 GLM Chat 流量和 CogVideoX 视频任务。 ## 准备工作[​](#准备工作 "准备工作的直接链接") 开始前,请准备以下内容: * 一套 AISIX 环境: <!-- --> * 对于 AISIX Cloud,需要一个已关联网关的环境和具有写入作用域的 Admin Token。对于 On-Premises,请按照 [AISIX Cloud 快速入门](https://docs.apiseven.com/ai-gateway/getting-started/aisix-cloud-quickstart.md)操作。如需申请 Hybrid Cloud 访问权限,请[联系 API7](https://api7.ai/contact)。 * 对于开源 AISIX 网关,请准备本地 AISIX 安装,或使用[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的 Docker 环境。配置网关以加载声明式资源文件。 * 从[智谱 AI 开放平台](https://open.bigmodel.cn/)获取的 Zhipu AI API Key。 * `curl` 和 `jq`。 ## 使用 AISIX Cloud 配置[​](#使用-aisix-cloud-配置 "使用 AISIX Cloud 配置的直接链接") 导出 AISIX Cloud 连接信息: ``` # AISIX_CP 是 Admin API 基础 URL;应包含 /api,且不含尾部斜杠 # 本地私有化部署快速入门使用 http://localhost:8080/api export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL" export AISIX_TOKEN="YOUR_ADMIN_TOKEN" export ENV_ID="YOUR_ENVIRONMENT_ID" ``` 为由 GLM 支持的 Chat Completions 路由创建服务提供方密钥、模型别名和调用方 API Key。 由于 Zhipu AI 提供 OpenAI 兼容 API,AISIX 会通过 `openai` 适配器进行连接,并使用 Zhipu AI API 根地址作为 `api_base`。同一个服务提供方密钥也可用于网关的[视频生成路由](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ### 创建服务提供方密钥[​](#创建服务提供方密钥 "创建服务提供方密钥的直接链接") 创建用于存储 Zhipu AI 凭证和 API 根地址的服务提供方密钥: ``` # 请替换为实际值 export ZHIPU_API_KEY="YOUR_PROVIDER_API_KEY" PROVIDER_KEY_ID=$(curl -sS -X POST "$AISIX_CP/provider_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "zhipuai-prod", "provider": "zhipuai", "api_key": "'"${ZHIPU_API_KEY}"'", "api_base": "https://open.bigmodel.cn/api/paas/v4", "allowed_environments": ["'"${ENV_ID}"'"] }' | jq -r '.provider_key.id') echo "$PROVIDER_KEY_ID" ``` ❶ `provider` 为 `zhipuai`,即智谱 AI 开放平台的目录服务提供方 ID。AISIX Cloud Admin API 会从目录服务提供方派生适配器;`adapter` 字段仅在 BYO 服务提供方密钥上被接受。 ❷ `api_key` 存储 Zhipu AI API Key,并在上游调用中作为 Bearer Token 发送。其行为遵循[服务提供方密钥](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#credential-handling)中的凭证处理方式。 ❸ `api_base` 使用一种特殊的路径格式:版本路径段为 `v4`,位于 `/api/paas` 下,而不是大多数 OpenAI 兼容服务商使用的 `/v1` 根地址。AISIX 会将端点路径原样追加到 `api_base`,因此此值会生成 `https://open.bigmodel.cn/api/paas/v4/chat/completions`。对此服务提供方,该字段为可选字段;省略时,AISIX Cloud Admin API 会填入相同的规范值。当密钥指向其他 Zhipu AI 部署时,请显式设置该字段。 该命令会把返回的服务提供方密钥 ID 保存到 `PROVIDER_KEY_ID`。 Zhipu AI 运营两个使用不同目录服务提供方 ID 的平台。对于位于 `open.bigmodel.cn` 的中国大陆平台,请使用 `zhipuai`;对于 API 根地址为 `https://api.z.ai/api/paas/v4` 的国际 Z.ai 平台,请使用 `zai`。这两个 ID 不能互换。已建模的视频路由只会分发 `zhipuai`(以及简写 `zhipu`),因此 `zai` 服务提供方密钥可以处理 Chat 流量,但在 `/v1/videos` 上会返回未实现错误。 与部分其他 OpenAI 兼容目录条目不同,`zhipuai` 条目不需要请求或响应覆盖项。Zhipu AI 接受标准字段名称,并且已经在规范字段上返回推理文本,因此 AISIX 会原样发送 OpenAI 请求格式,不会重命名任何参数。请参阅[控制思考模式](#control-thinking-mode)。 ### 创建模型[​](#创建模型 "创建模型的直接链接") Zhipu AI 模型 ID 遵循 `glm-<version>` 格式。`glm-5.2` 等不带后缀的版本表示该代旗舰文本模型;`-flash`、`-flashx` 或 `-air` 后缀表示更轻量、更经济的服务级别;末尾的 `v`(例如 `glm-5v-turbo`)表示视觉模型。创建模型别名前,请在 [Zhipu AI 模型概览](https://docs.bigmodel.cn/cn/guide/start/model-overview)中确认当前目录。 创建调用方将在请求中发送的模型别名: ``` MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "glm-flagship-prod", "model_name": "glm-5.2", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$MODEL_ID" ``` ❶ `display_name` 是调用方在 `model` 中发送的别名。 ❷ `model_name` 是 Zhipu AI 模型 ID,例如 `glm-5.2`、`glm-5` 或 `glm-4.7`。 ❸ `provider_key_id` 将别名关联到 Zhipu AI 服务提供方密钥。 ### 创建调用方 API Key[​](#创建调用方-api-key "创建调用方 API Key的直接链接") 创建可访问该模型别名的调用方 API Key。明文密钥由服务器生成,并且只在响应中返回一次,因此请立即保存: ``` AISIX_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "zhipuai-caller", "allowed_models": ["'"${MODEL_ID}"'"] }' | jq -r '.plaintext') echo "$AISIX_API_KEY" ``` `allowed_models` 值必须引用上一步保存的模型 ID,使该密钥只能访问已创建的别名。写入后,配置会自动投射到已关联的网关。 ## 使用开源 AISIX 网关配置[​](#使用开源-aisix-网关配置 "使用开源 AISIX 网关配置的直接链接") 导出上游凭证,并选择应用将发送给网关的调用方 API Key: ``` export ZHIPU_API_KEY="YOUR_PROVIDER_API_KEY" export CALLER_API_KEY="YOUR_CALLER_API_KEY" ``` 对于新网关,请使用这份完整的资源文件。对于现有网关,请将这些条目合并到其[当前文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#apply-resource-examples-safely)中,并保留其他资源: resources.yaml ``` _format_version: "1" provider_keys: - display_name: "zhipuai-prod" provider: "zhipuai" adapter: "openai" api_key: ${ZHIPU_API_KEY} api_base: "https://open.bigmodel.cn/api/paas/v4" models: - display_name: "glm-flagship-prod" provider: "zhipuai" model_name: "glm-5.2" provider_key: "zhipuai-prod" api_keys: - display_name: "zhipuai-caller" key_env: CALLER_API_KEY allowed_models: - "glm-flagship-prod" ``` 如果 AISIX 安装在本地,请在加载前验证文件: ``` aisix validate --resources resources.yaml ``` 验证后,在网关进程环境中提供文件引用的环境变量,再启动网关。仅当这些变量已经可供进程使用时,才重新加载现有网关;否则,请使用更新后的环境重启网关。 如果使用 Docker,请调整[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中的验证和启动命令。挂载此 `resources.yaml` 文件,并在两条命令中使用 `-e` 传入它引用的每个环境变量。资源加载后,准备下文共用的验证请求: ``` export AISIX_API_KEY="$CALLER_API_KEY" ``` ## 验证服务提供方连接[​](#验证服务提供方连接 "验证服务提供方连接的直接链接") 导出 AISIX 网关 Origin: ``` # AISIX_PROXY 不含尾部斜杠或端点路径 # 本地快速入门使用 http://127.0.0.1:3000 export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL" ``` 通过 AISIX 代理发送 Chat Completions 请求: ``` curl -sS -X POST "$AISIX_PROXY/v1/chat/completions" \ -H "Authorization: Bearer ${AISIX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-flagship-prod", "messages": [ { "role": "user", "content": "Say hello from GLM." } ] }' ``` 网关会返回 OpenAI 兼容响应,其中回显面向调用方的别名 `glm-flagship-prod`。由于模型默认进行推理,助手消息除了 `content` 外还会携带 `reasoning_content` 字段。如果请求失败,请检查服务提供方密钥的 `api_key`、`api_base`,以及 `model_name` 中的 Zhipu AI 模型 ID。 ## 控制思考模式[​](#control-thinking-mode "控制思考模式的直接链接") GLM 推理模型默认启用思考。如需对单个请求关闭思考,请在 Chat Completions 请求体中添加服务提供方的 `thinking` 对象: ``` { "thinking": { "type": "disabled" } } ``` AISIX 会将其本身不解析的字段原样转发到上游,因此该控制项会按写入内容到达 Zhipu AI。可接受的值为 `enabled` 和 `disabled`。GLM-5.2 还支持在思考开启时通过 `reasoning_effort` 控制推理深度。当前各模型的行为和可接受的强度值请参阅[深度思考](https://docs.bigmodel.cn/cn/guide/capabilities/thinking)。 Zhipu AI 在 `reasoning_content` 上返回思考文本:非流式响应使用 `message.reasoning_content`,流式响应使用 `delta.reasoning_content`。这是 AISIX 保留的规范字段,因此该服务提供方不需要在服务提供方密钥上设置 [`response.reasoning_field`](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#configure-provider-specific-overrides) 覆盖项。 ## 使用 CogVideoX 生成视频[​](#generate-videos-with-cogvideox "使用 CogVideoX 生成视频的直接链接") 同一个服务提供方密钥可驱动网关的已建模视频路由。请创建第二个别名,指向 Zhipu AI 视频模型,例如 [CogVideoX-3](https://docs.bigmodel.cn/cn/guide/models/video-generation/cogvideox-3): 在 AISIX Cloud 中,创建视频别名和仅限该别名的调用方密钥: ``` VIDEO_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "glm-video-prod", "model_name": "cogvideox-3", "provider_key_id": "'"${PROVIDER_KEY_ID}"'" }' | jq -r '.model.id') echo "$VIDEO_MODEL_ID" VIDEO_API_KEY=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "zhipuai-video-caller", "allowed_models": ["'"${VIDEO_MODEL_ID}"'"] }' | jq -r '.plaintext') ``` 对于开源 AISIX 网关,请将 `glm-video-prod` 添加到现有 `models` 集合。将现有 `zhipuai-caller` 条目替换为下面更新后的条目,使其允许两个模型别名。保留无关条目和集合: resources.yaml(视频模型访问) ``` models: - display_name: "glm-video-prod" provider: "zhipuai" model_name: "cogvideox-3" provider_key: "zhipuai-prod" api_keys: - display_name: "zhipuai-caller" key_env: CALLER_API_KEY allowed_models: - "glm-flagship-prod" - "glm-video-prod" ``` 按照上文说明验证并重新加载或重启声明式资源文件,然后使用现有调用方密钥发送视频请求: ``` export VIDEO_API_KEY="$CALLER_API_KEY" ``` 提交任务: ``` curl -sS -X POST "$AISIX_PROXY/v1/videos" \ -H "Authorization: Bearer ${VIDEO_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-video-prod", "prompt": "A paper boat drifts down a rain-soaked street at dusk.", "seconds": 5, "size": "1920x1080" }' ``` 在为此路由编写脚本前,需要了解以下五项服务提供方特定行为: * **Chat 的 `api_base` 会原样复用。** AISIX 会识别 `/api/paas/v4` 后缀,从中派生服务商根地址,并在其下组成服务提供方的原生任务路径。已经为 GLM Chat 流量配置的服务提供方密钥无需更改即可用于视频路由。 * **参数直接映射。** `seconds` 会作为服务提供方的整数 `duration` 转发,`size` 则会原样传递,因为 Zhipu AI 文档使用的 `WIDTHxHEIGHT` 写法与统一请求相同。AISIX 会在联系服务提供方前验证格式。 * **服务提供方原生视频字段需要透传路由。** 标准化请求只建模 `prompt`、`seconds` 和 `size`;其他字段会被忽略。若要发送 `image_url`、`quality`、`with_audio` 或 `fps` 等 CogVideoX 字段,请通过 `/passthrough/zhipuai/videos/generations` 发送原生正文和准确的模型 ID,并通过 `/passthrough/zhipuai/async-result/{id}` 轮询任务。透传不会返回统一的 AISIX 视频对象或网关编码的任务 ID。本页的 `/passthrough/zhipuai` 路径假定一条[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)认领该前缀,`target_url` 设为该服务提供方的 API 根地址;在调用方 Key 的 `allowed_routes` 上授予路由名称。 * **不存在排队状态。** Zhipu AI 从接受任务起就将其报告为处理中,因此统一状态会直接变为 `in_progress`,永远不会报告 `queued`。请轮询 `GET /v1/videos/{id}`,直到其报告 `completed`。 * **已完成的视频通过重定向交付。** `GET /v1/videos/{id}/content` 返回 `302`,并在 `Location` 请求头中提供指向服务提供方签名下载 URL 的地址。字节数据会从 Zhipu AI 存储直接传输到客户端,不会经过网关,因此下载时请使用 `curl -L`。 完整的提交、轮询和下载工作流(包括状态语义和轮询时的限流行为)请参阅[视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md)。 ## 端点覆盖范围[​](#端点覆盖范围 "端点覆盖范围的直接链接") Zhipu AI 服务提供方密钥会解析到 `openai` 适配器,因此路由支持情况取决于该适配器以及各路由自身的服务提供方规则: | 路由 | 使用 `zhipuai` 模型别名时的行为 | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/chat/completions` | 支持非流式和流式传输。 | | `/v1/embeddings` | 当别名指向 Zhipu AI Embedding 模型(例如 `embedding-3`)时支持。AISIX 会将 `/embeddings` 追加到 `api_base`,到达服务提供方的文本 Embedding 端点。 | | `/v1/responses` | 对于 Chat 适配器路径可以表达的字段,通过 [Responses 桥接](https://docs.apiseven.com/ai-gateway/endpoints/responses-api.md)提供支持。没有对应 Chat 语义的 OpenAI Responses 专用字段会被忽略。 | | `/v1/messages` | 默认转换到 Chat Completions。Zhipu AI 还在 `https://open.bigmodel.cn/api/anthropic` 提供 Claude 兼容 Messages API,但其文档没有定义 AISIX 与 `apis.messages` 绑定的 Token 计数路由。原生 Messages 请使用经过身份认证的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md),不要声明 `apis.messages`,否则 `/v1/messages/count_tokens` 也会被路由到上游。 | | `/v1/videos` 及其状态和内容路由 | 支持。请参阅[使用 CogVideoX 生成视频](#generate-videos-with-cogvideox)。 | | `/v1/images/generations` | 标准化路由不受支持,因为它只接受配置的服务提供方为 `openai` 的模型。请通过 `/passthrough/zhipuai/images/generations` 发送原生正文和准确的图像模型 ID。 | | `/v1/audio/transcriptions` | 当别名指向 `glm-asr-2512` 等 Zhipu AI 语音转文本模型时受支持。上游路径和 multipart 请求形态与 AISIX 路由一致。服务提供方的流式响应会先被缓冲,再由 AISIX 返回。 | | `/v1/audio/speech` | 当别名指向 `glm-tts` 时受支持。非流式音频会原样返回;启用原生 `stream` 字段时,AISIX 会缓冲服务提供方响应。 | | `/v1/audio/translations` | 不支持,因为 Zhipu AI 未提供对应的上游路由。 | | `/v1/realtime` | 直接 GLM-Realtime 别名可以使用 WebSocket 中继。AISIX 会携带配置的上游模型作为查询参数连接 `wss://open.bigmodel.cn/api/paas/v4/realtime`,并在不转换事件的情况下进行中继。如果客户端还设置 `session.model`,请发送准确的 Zhipu AI 模型 ID,因为 AISIX 不会重写 WebSocket 帧正文。 | | `/v1/rerank` | 标准化路由不受支持,因为它只接受 `openai`、`cohere` 和 `jina` 服务提供方值。请通过 `/passthrough/zhipuai/rerank` 发送原生正文和准确的 `rerank` 模型 ID。 | | `/v1/models` | 返回调用方可访问的 AISIX 别名,而不是 Zhipu AI 目录。服务提供方模型 ID 请查阅上文链接的模型概述。 | | `/passthrough/zhipuai/*rest` | 通过已配置的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)可用于服务提供方原生 HTTP 路由。透传不会重写 AISIX 别名,并会增量中继 SSE。可识别的 Chat、Completions 和 Responses 信封会记录受支持的用量字段。没有可识别载体字段的请求保持不透明:缓冲响应记录零 Token,而不透明 SSE 仍可记录顶层受支持的 `usage` 字段。 | 完整端点和服务提供方矩阵请参阅[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 ## 后续步骤[​](#后续步骤 "后续步骤的直接链接") 你已将 AISIX 连接到 Zhipu AI,并验证了模型别名。接下来可阅读以下指南: * [模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md):为此别名配置路由、重试行为或成本元数据。 * [路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md):在 Zhipu AI 和另一个服务提供方之间进行故障转移。 * [视频生成](https://docs.apiseven.com/ai-gateway/endpoints/video-generation.md):按照完整的提交、轮询和下载工作流处理 CogVideoX 任务。 * [服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md):查看支持的代理端点和服务提供方特定边界。 --- # CLI 参考 `aisix` 二进制文件用于运行 AISIX 网关,并提供处理开源 AISIX 网关配置的命令。使用 `validate` 检查声明式 [`resources.yaml`](https://docs.apiseven.com/ai-gateway/reference/resources-file.md) 文件,使用 `export` 将现有 etcd 存储中的资源转换为该格式。这两个命令都不会启动网关监听器。 ``` Usage: aisix --config <CONFIG> aisix <COMMAND> ``` | 命令 | 用途 | | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `aisix --config <CONFIG>` | 使用指定的启动配置文件启动网关。请参阅[启动配置参考](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md)。 | | `aisix validate --resources <FILE>` | 在不启动网关的情况下检查资源文件。 | | `aisix export --etcd <ENDPOINT> [-o <FILE>]` | 将开源 AISIX 网关 etcd 存储中的资源导出为可加载的资源文件。 | 运行官方容器镜像时,请直接调用二进制文件: ``` docker run --rm --entrypoint /usr/local/bin/aisix ghcr.io/api7/aisix:1.2.0 --help ``` ## 验证资源文件[​](#validate-a-resources-file "验证资源文件的直接链接") `aisix validate` 会运行网关加载资源文件时使用的相同流水线——读取、`${VAR}` 插值、名称引用解析、规范 Schema 验证和交叉引用检查——但不会启动任何监听器。可以在启动或重新加载前将其用作预检查,也可以将其用作配置变更的 CI 门禁。 ``` aisix validate --resources resources.yaml ``` | 选项 | 必填 | 说明 | | -------------------- | ---- | ---------------------- | | `--resources <FILE>` | 是 | 要验证的资源文件路径。 | 文件中的 `${VAR}` 引用会根据 `validate` 进程自身的环境进行解析。请使用网关将收到的相同变量运行该命令,否则验证会因无法解析引用而失败。 文件加载通过之后,`validate` 会报告两类仅凭「加载成功」看不出来的安全护栏问题。 第一类是没有任何 Attachment 的安全护栏。它会被加载、会计入资源总数,但不检查任何流量,因为安全护栏的作用范围完全由 Attachment 决定。这是合法状态而非错误——它原本挂靠的模型或路由可能已从文件中移除——因此 `validate` 会在标准错误中列出这些条目,退出码仍为 `0`。 第二类是无法运行的行。`validate` 会构建每一条已启用的安全护栏,并报出其中构建不出来的行。配置能解析但构建不出来的安全护栏——非法正则、未知的检测器、语法有误的 `custom` 脚本——会在网关启动时被丢弃,网关随后在没有这项检查的情况下继续提供服务。由于加载本身是成功的,其他地方都不会报告问题:这项检查正是这类行唯一会暴露的地方。 ### 退出码[​](#退出码 "退出码的直接链接") | 退出码 | 含义 | | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `0` | 文件加载成功,且每一条已启用的安全护栏都能运行,并将摘要打印到标准输出;如果有已启用但没有任何 Attachment 的安全护栏,还会在标准错误中列出它们。 | | 非零 | 文件加载失败,或某条安全护栏能加载但无法运行,并将报告打印到标准错误。 | 成功时: ``` OK: resources.yaml loaded 3 resource(s) ``` 没有任何 Attachment 的安全护栏会被报告出来,但不影响退出码: ``` resources file resources.yaml: 1 enabled guardrail(s) have no attachment and inspect no traffic: - guardrails ("no-secrets"): add a guardrail_attachments entry to put it in force OK: resources.yaml loaded 4 resource(s) ``` 失败时,会统一报告整个文件中的所有问题,并指出资源类型、条目和字段: ``` resources file resources.yaml: 3 error(s): - provider_keys[0]: field `api_key`: environment variable `OPENAI_API_KEY` is unset or empty - models[0] ("gpt-4o-mini"): `provider_key` references unknown provider key "openai-main" (no provider_keys are defined in this file) - api_keys[0] ("quickstart-caller"): `key_env` environment variable `CALLER_API_KEY` is unset or empty ``` 能加载但无法运行的安全护栏也以同样方式报告,并给出该行会被丢弃的原因。`custom` 脚本的错误会带上引擎自己给出的行号和列号: ``` resources file resources.yaml: 1 guardrail(s) load but cannot run: - guardrails ("screen-with-my-service"): custom guardrail script does not compile: Error: unsupported keyword: export at guardrail.js:12:3 ``` ### 使用容器镜像进行验证[​](#使用容器镜像进行验证 "使用容器镜像进行验证的直接链接") 如果本地没有二进制文件,请通过 Docker 运行相同检查。挂载文件并传入该文件引用的环境变量: ``` docker run --rm \ -v "$(pwd)/resources.yaml:/etc/aisix/resources.yaml:ro" \ -e OPENAI_API_KEY \ -e CALLER_API_KEY \ --entrypoint /usr/local/bin/aisix \ ghcr.io/api7/aisix:1.2.0 \ validate --resources /etc/aisix/resources.yaml ``` ## 从 etcd 导出资源[​](#export-resources-from-etcd "从 etcd 导出资源的直接链接") `aisix export` 读取开源 AISIX 网关 etcd 前缀下的资源,并将其写入声明式资源文件。可以使用该命令将以 etcd 为后端的网关迁移到资源文件,包括资源由早期版本的网关 Admin API 创建的网关。该命令还可以为网关能够加载的资源创建便于审查的备份。 ``` aisix export \ --etcd "http://127.0.0.1:2379" \ --output resources.yaml ``` | 选项 | 必填 | 说明 | | ----------------------- | ---- | ------------------------------------------------------------------------------------------ | | `--etcd <ENDPOINT>` | 是 | 要读取的 etcd 端点。多个端点可以重复提供该选项,或使用逗号分隔的列表。 | | `--prefix <PREFIX>` | 否 | 包含资源的 Key 前缀。默认为 `/aisix`,即网关默认的 `etcd.prefix`。 | | `-o`、`--output <FILE>` | 否 | 将 YAML 文档写入文件,而不是标准输出。在 Unix 上,AISIX 会以 `0600` 模式创建或重置该文件。 | | `--reveal-secrets` | 否 | 内联写出存储的凭证,不使用环境变量占位符替换。生成的输出包含有效机密。 | 导出使用与运行中网关相同的 etcd 解码路径。它会把资源引用转换回显示名称,并省略生成的 ID,使输出文档符合资源文件格式。 默认情况下,存储的凭证会替换为 `${VAR}` 占位符。AISIX 会将占位符名称及其来源字段打印到标准错误。加载导出的文件之前,请在网关环境中设置这些变量。 警告 只有在受控迁移确实需要把明文凭证保留在文件中时才使用 `--reveal-secrets`。请勿提交、发布该输出,也不要将其复制到不安全的位置。 该命令会报告无法解码的 etcd 条目和资源关系警告,并仍然写出结果供检查。如果命名冲突或悬空引用导致文件无法加载,它会以非零状态退出。切换网关使用该文件之前,请验证完成后的文件: ``` aisix validate --resources resources.yaml ``` --- # AISIX Cloud Admin API 参考 AISIX Cloud Admin API 是面向组织范围自动化的公开契约:环境、模型、调用方 API Key、模型服务提供方 Key、安全护栏、限流策略、预算、团队、用量读取等操作都通过它完成。控制台能做的事,基本都能用它做。 完整的接口参考由控制面的 OpenAPI 源自动生成,**按发布版本逐版发布在英文文档站**,因此它始终与某个具体版本严格对应,不会出现文档描述的接口在你运行的版本里不存在的情况。 ## 接口参考[​](#接口参考 "接口参考的直接链接") * [AISIX Cloud Admin API 参考(最新发布版本)](https://docs.api7.ai/ai-gateway/reference/cloud-admin-api) ## 版本变更与历史版本[​](#版本变更与历史版本 "版本变更与历史版本的直接链接") 升级前需要评估影响时,请查看变更对照页。它列出相邻两个发布版本之间的全部接口差异——新增和删除的端点、请求与响应字段、枚举值、必填项——并把会影响调用方的变更标记为 **Breaking**。同一页面顶部还列出了每个历史版本的完整参考入口。 * [Cloud Admin API 版本变更对照](https://docs.api7.ai/ai-gateway/reference/cloud-admin-api-changelog) 每个版本的具体变更说明也会写在该版本的[发布说明](https://docs.apiseven.com/ai-gateway/release-notes.md)的「API 变化」一节中。 备注 接口参考的字段说明目前仅提供英文版本。端点路径、字段名和枚举值在两种语言下完全一致,因此可以直接对照本站的中文指南使用。 ## 认证[​](#认证 "认证的直接链接") Admin API 使用 Admin Token 认证,读操作需要有效 Token,写操作需要具备写权限的 Token。创建和管理 Token 的方法参见 [Admin Token](https://docs.apiseven.com/ai-gateway/cloud/admin-tokens.md)。 --- # 配置状态 AISIX 网关通过状态端点和 Prometheus 指标报告配置是否生效,并在未生效时说明原因。这些界面共同回答运维人员的核心问题:“网关是否正在使用我预期的配置提供服务?”它们覆盖所有资源来源:[`resources.yaml` 文件](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)、自行管理的 etcd 配置存储或 AISIX Cloud 控制面。 这些端点与 `GET /metrics` 一起由专用指标监听器 `observability.metrics.prometheus.addr`(默认 `0.0.0.0:9090`)提供。与指标端点一样,它们按设计不需要身份认证;请确保该监听器仅对监控网络开放。 | 端点 | 用途 | | -------------------- | ------------------------------------------------------------------------------------------------ | | `GET /status/config` | 完整配置加载状态:派生状态、来源与已应用哈希、资源数量、重新加载结果、被拒绝条目及部分兼容资源。 | | `GET /status/ready` | 就绪门禁:应用第一个有效配置前返回 `503`,之后返回 `200 ok`。 | | `GET /status/models` | 按模型统计的运行时健康状态:每个已配置模型一行,并包含其路由状态。 | ## GET `/status/config`[​](#get-statusconfig "get-statusconfig的直接链接") 返回描述最近一次观察到和最近一次应用配置的 JSON 文档: ``` curl -sS "http://127.0.0.1:9090/status/config" ``` ``` { "state": "synced", "source": { "type": "file", "source_hash": "1dc0ee8d06edcde3ecbf23672858622a83f266910846f514ccb909cf41046653", "observed_at": "YYYY-MM-DDTHH:MM:SSZ" }, "applied": { "config_hash": "1dc0ee8d06edcde3ecbf23672858622a83f266910846f514ccb909cf41046653", "apply_seq": 1, "applied_at": "YYYY-MM-DDTHH:MM:SSZ", "resource_counts": { "api_keys": 1, "models": 1, "provider_keys": 1 } }, "last_reload": { "successful": true, "at": "YYYY-MM-DDTHH:MM:SSZ" }, "last_failure": null, "rejected": [], "partially_compatible": [] } ``` ### 配置状态[​](#配置状态 "配置状态的直接链接") `state` 由网关根据最近一次观察到和已应用的快照派生: | 状态 | 含义 | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `synced` | 已应用配置与来源中观察到的最新快照一致,并且没有资源被拒绝。检查 `partially_compatible`,确认网关是否忽略了无法识别的字段。 | | `degraded` | 网关仍在提供服务,但最新快照中有部分条目被拒绝。已接受的资源和最后一个已知良好值仍会提供服务;`rejected` 数组会说明每个被拒绝的条目。 | | `out_of_sync` | 最近一次观察到的快照被整体拒绝。网关会继续使用最后一个有效配置提供服务。 | | `empty` | 已应用有效配置,但其中不包含资源。 | | `never_loaded` | 进程启动后尚未应用任何有效配置。 | 从资源文件加载配置的网关会以全有或全无的方式应用文件,因此文件重新加载失败时会报告 `out_of_sync`,而不是 `degraded`。当来源逐个投递资源且仅部分资源无效时,会出现 `degraded`。 从 etcd 读取配置具有向前兼容性。如果文档包含无法识别的字段,网关会使用可识别的字段提供服务,并在 `partially_compatible` 中报告被忽略的字段。仅出现这种情况不会使 `state` 从 `synced` 变为其他状态。资源文件验证仍然严格,因此资源文件中的未知字段会导致整个重新加载被拒绝。 对于使用 etcd 或 AISIX Cloud 的网关,`never_loaded` 是它首次连接配置来源期间所处的状态。处于该状态时它不会绑定代理监听器,因此该端点和 `GET /status/ready` 就是观察它的地方,参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。如果来源可以连上但其中没有资源,网关会应用一份空配置并报告 `empty`,而不是 `never_loaded`。 ### 响应字段[​](#响应字段 "响应字段的直接链接") 顶层字段: | 字段 | 类型 | 说明 | | ---------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `state` | string | 派生的配置状态,为 `synced`、`degraded`、`out_of_sync`、`empty` 或 `never_loaded`。 | | `source` | object | 从配置来源观察到的最新快照。 | | `applied` | object | 最近一次实际应用并用于提供服务的配置。`state` 为 `never_loaded` 时省略。 | | `last_reload` | object | 最近一次加载的结果。首次加载完成前省略。 | | `last_failure` | object 或 null | 进程启动后最近一次加载失败。该字段具有粘性:后续重新加载成功后仍保留,直到进程重启。 | | `rejected` | array | 网关从最新快照中拒绝的条目。所有内容均加载成功时为空。 | | `partially_compatible` | array | 包含当前网关版本无法识别字段、但仍在提供服务的 etcd 资源,按资源类型和字段聚合。所有用于提供服务的文档均符合网关 Schema 时为空。 | `source` 字段: | 字段 | 类型 | 说明 | | ------------------- | ------- | --------------------------------------------------------------------------- | | `type` | string | 配置读取位置:`file` 或 `etcd`。 | | `connected` | boolean | 配置存储是否可达。仅当 `type` 为 `etcd` 时存在。 | | `observed_revision` | number | 最近一次观察到的快照对应的存储修订版本。仅当 `type` 为 `etcd` 时存在。 | | `source_hash` | string | 最近一次观察到的快照的 SHA-256 哈希。对于文件来源,这是原始文件字节的哈希。 | | `observed_at` | string | 最近一次观察的 RFC 3339 UTC 时间戳。 | `applied` 字段: | 字段 | 类型 | 说明 | | ------------------ | ------ | ------------------------------------------------------------------------------- | | `applied_revision` | number | 已应用配置反映的存储修订版本。仅当 `source.type` 为 `etcd` 时存在。 | | `config_hash` | string | 已接受并用于提供服务的配置的 SHA-256 哈希。没有资源被拒绝时等于 `source_hash`。 | | `apply_seq` | number | 每次已应用配置发生变化时递增的计数器。内容未变化时不会递增。 | | `applied_at` | string | 最近一次应用变更的 RFC 3339 UTC 时间戳。 | | `resource_counts` | object | 按资源类型统计的服务中资源数量,例如 `{"models": 2}`。 | `last_reload` 和 `last_failure` 字段: | 字段 | 类型 | 说明 | | ------------------------------ | ------- | -------------------------------------------- | | `last_reload.successful` | boolean | 最近一次加载是否在没有拒绝资源的情况下完成。 | | `last_reload.at` | string | 最近一次加载的 RFC 3339 UTC 时间戳。 | | `last_failure.at` | string | 最近一次失败发生的时间。 | | `last_failure.last_error_kind` | string | 最近一次失败的故障类型。 | | `last_failure.last_error` | string | 最近一次失败的可读消息。 | `rejected` 中的每个条目: | 字段 | 类型 | 说明 | | --------------------------- | ------ | -------------------------------------------------------------------------------------------------------- | | `resource_kind` | string | 复数形式的资源类型,例如 `models` 或 `provider_keys`。无法确定来源条目类型时为空。 | | `resource_id` | string | 资源 ID。来源条目无法解析到足以识别资源时为空。 | | `last_error_kind` | string | 故障类型:`bad_key`、`non_json`、`schema_failed`、`parse_failed` 或 `unknown_kind`。 | | `last_error` | string | 可读错误消息。Schema 消息会遮蔽凭证值。 | | `first_seen_at` | string | 进程启动后首次观察到此拒绝的时间。重复加载同一无效条目时保持稳定。 | | `last_seen_at` | string | 最近一次观察到此拒绝的时间。 | | `serving_stale_since` | string | 网关从何时起继续使用该资源最后一个已知良好值提供服务的 RFC 3339 时间戳。没有以前的值仍在提供服务时省略。 | | `serving_stale_age_seconds` | number | 从 `serving_stale_since` 开始经过的秒数,在读取状态时重新计算。与 `serving_stale_since` 一同省略。 | `partially_compatible` 中的每个条目: | 字段 | 类型 | 说明 | | --------------- | ------ | ------------------------------------------------------------------------------ | | `resource_kind` | string | 复数形式的资源类型,例如 `api_keys` 或 `models`。 | | `field` | string | 被忽略的字段路径。数组索引会规范化为 `[]`,例如 `routing.targets[].priority`。 | | `count` | number | 包含该被忽略字段且仍在提供服务的此类资源数量。 | 使用 `config_hash` 确认特定变更已落地:该哈希是确定性的,因此知道所发布内容的部署流水线可以比较哈希,无需对资源执行差异比较。对于文件来源,`source_hash` 是文件字节的 SHA-256(`sha256sum resources.yaml`)。对于 etcd 来源,哈希相同并不表示所有字段都已执行;需要精确 Schema 兼容时,还应要求 `partially_compatible` 为空。 ## GET `/status/ready`[​](#get-statusready "get-statusready的直接链接") 仅针对配置来源的就绪门禁: ``` curl -sSi "http://127.0.0.1:9090/status/ready" ``` | 条件 | 状态 | 响应体 | | ---------------- | ------------------------- | ---------------------------- | | 尚未应用有效配置 | `503 Service Unavailable` | `no configuration available` | | 已应用有效配置 | `200 OK` | `ok` | 将其用作启动或就绪探针,可避免网关在能够提供已配置路由前接收流量。应用第一个配置后,该端点会保持返回 `200`;后续重新加载失败且网关使用最后一个有效配置提供服务时也是如此。 代理监听器上的 `/livez` 和 `/readyz` 回答的是进程级问题——存活状态和排空状态——而不是重复这一项。对于使用 etcd 或 AISIX Cloud 的网关,该监听器在应用第一个配置之前不会绑定,因此在这个端点返回 `503` 期间,它们两个都不会有任何响应。请参阅[健康检查](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 ## GET `/status/models`[​](#get-statusmodels "get-statusmodels的直接链接") 按模型统计的运行时健康视图,每个已配置模型对应一行: ``` curl -sS "http://127.0.0.1:9090/status/models" ``` ``` [ { "id": "9a3f2c67-52b8-4b1e-9f4e-1f2f3a4b5c6d", "display_name": "gpt-4o-prod", "kind": "direct", "status": "healthy" }, { "id": "5b17e9d2-8a44-4c05-b7a1-0c9d8e7f6a5b", "display_name": "claude-prod", "kind": "direct", "status": "cooldown", "status_reason": "upstream_auth_failure", "cooldown_until": { "secs_since_epoch": 1784708130, "nanos_since_epoch": 0 } } ] ``` | 状态 | 含义 | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `healthy` | 模型处于路由轮转中。 | | `cooldown` | 最近的上游失败使模型退出路由,直到 `cooldown_until`;`status_reason` 指出故障类别,例如 `upstream_auth_failure` 或 `upstream_rate_limited`。只有 `cooldown` 块中设置了 `enabled: true` 的模型才会进入该状态。 | | `unhealthy` | 最近的后台模型检查失败,路由会避开该模型。`last_check_status` 包含最近一次检查的 HTTP 状态。 | | `not_applicable` | 该行是多目标或其他虚拟模型;其可用性由目标模型的对应行决定。 | 时间戳(`cooldown_until`,以及经过后台检查的模型上的 `last_checked_at`)是如上所示的秒/纳秒 Epoch 对象,而不是 RFC 3339 字符串。与其他状态端点一样,`/status/models` 无需身份认证并反映已应用配置,因此适用于所有网关部署。 ## 配置加载指标[​](#配置加载指标 "配置加载指标的直接链接") 同一监听器上的 `GET /metrics` 端点会以 Prometheus 序列暴露配置加载状态。这些值在抓取时根据与 `GET /status/config` 相同的底层状态刷新。 | 指标 | 类型 | 标签 | 说明 | | ---------------------------------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `aisix_config_last_reload_successful` | gauge | 无 | 最近一次加载没有拒绝资源时为 `1`,否则为 `0`。 | | `aisix_config_last_reload_success_timestamp_seconds` | gauge | 无 | 最近一次成功加载的 Unix 时间戳。 | | `aisix_config_reloads_total` | counter | 无 | 进程启动后的配置加载次数,包括启动加载、文件重新加载和来自配置存储的完整同步。 | | `aisix_config_reload_failures_total` | counter | `reason` | 未完全成功的加载次数,按 `reason` 分类:`fetch`(来源不可达或不可读)、`parse`(无法解析来源内容)或 `validate`(资源 Schema、形状或引用验证失败)。 | | `aisix_config_rejected_resources` | gauge | `kind` | 当前按资源类型统计的被拒绝条目数。修复有问题的条目后为 `0`。 | | `aisix_config_partially_compatible_resources` | gauge | `kind` | 包含至少一个被忽略字段、但仍在提供服务的资源,按资源类型分组。包含多个被忽略字段的资源只计一次。 | | `aisix_config_stale_served_resources` | gauge | `kind` | 来源中的最新值被拒绝、但最后一个已知良好值仍在提供服务的资源,按资源类型分组。 | | `aisix_config_hash_info` | gauge | `hash` | Info 风格序列:只有一个值为 `1` 的活动样本,其 `hash` 标签为已应用的 `config_hash`。 | | `aisix_config_observed_revision` | gauge | 无 | 最近一次观察到的快照对应的存储修订版本。仅为 `etcd` 来源发出。 | | `aisix_config_applied_revision` | gauge | 无 | 已应用配置对应的存储修订版本。仅为 `etcd` 来源发出。 | | `aisix_config_source_connected` | gauge | 无 | 配置存储可达时为 `1`。仅为 `etcd` 来源发出。 | 完整指标目录请参阅[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md)。 ### 告警示例[​](#告警示例 "告警示例的直接链接") 网关拒绝任何已配置资源时发出告警。网关会继续提供服务,但运维人员写入的部分内容没有生效: ``` - alert: AisixConfigRejectedResources expr: sum by (instance) (aisix_config_rejected_resources) > 0 for: 5m labels: severity: warning annotations: summary: "AISIX gateway is rejecting configured resources" description: "Check GET /status/config on {{ $labels.instance }}: the rejected array names each entry and its error." ``` 配置持续重新加载失败时发出告警。网关正使用最后一个有效配置运行,新变更没有生效: ``` - alert: AisixConfigReloadFailing expr: aisix_config_last_reload_successful == 0 for: 10m labels: severity: warning annotations: summary: "AISIX gateway configuration reloads are failing" description: "The last configuration load on {{ $labels.instance }} did not fully succeed. Check last_failure and rejected in GET /status/config." ``` --- # 启动配置参考 本参考介绍用于定义监听器、资源来源连接、TLS、可观测性、缓存和限流后端以及 AISIX Cloud 连接等进程级设置的启动配置文件。 模型、调用方 API Key、服务提供方密钥、安全护栏、缓存策略和可观测性导出器不在启动配置中定义。对于开源 AISIX 网关,这些资源由 [`resources.yaml` 文件](#resource-source)或 etcd 提供;对于连接到 AISIX Cloud 的网关,则由控制面提供。 AISIX 接受 YAML、TOML 或 JSON 格式的启动配置文件。常见文件包括: * [`config.yaml`](#select-a-configuration-file):AISIX 加载的本地启动配置文件。 * [`config.example.yaml`](https://github.com/api7/aisix/blob/v1.2.0/config.example.yaml):不使用控制面、以配置存储为后端的完整网关示例,可复制或挂载为实际加载的 `config.yaml`。 * [`config.managed.yaml`](https://github.com/api7/aisix/blob/v1.2.0/config.managed.yaml):AISIX Cloud 在运行时提供资源时使用的网关引导配置。 下列示例使用 YAML,因为打包的示例配置采用 YAML。TOML 和 JSON 文件也可以定义相同的启动字段。面向任务的设置流程请参见[启动配置](https://docs.apiseven.com/ai-gateway/deployment/startup-configuration.md)。 ## 配置模式[​](#configuration-models "配置模式的直接链接") 每台 AISIX 网关都使用启动配置文件。管理模式决定动态资源来自何处,以及哪些设置由运维人员直接管理。 | 网关配置 | 资源来源 | 选择方式 | 变更到达方式 | | -------------------------------- | -------------------- | ---------------------------------------- | ---------------------------------------------- | | 使用资源文件的开源 AISIX 网关 | 声明式文件 | `resources_file` | 启动时加载,并在收到 `SIGHUP` 时重新加载。 | | 使用配置存储的开源 AISIX 网关 | 自行管理的 etcd 集群 | `etcd` | 首次同步后持续接收 etcd Watch 事件。 | | 连接到 AISIX Cloud 的 AISIX 网关 | AISIX Cloud 控制面 | `managed.enabled: true` 和生成的连接设置 | 网关通过托管的 etcd 连接接收控制面投影的资源。 | 无论使用哪种模式,代理、下游、上游、缓存、限流后端和本地可观测性设置仍属于网关启动设置。AISIX Cloud 提供模型、Key、策略和导出器等动态资源,但不会替换这些进程级设置。 对于开源 AISIX 网关,`admin.enabled` 默认为 `true`,但默认的 `admin.addr` 值 `127.0.0.1:0` 无法用作监听地址。要公开[只读 Admin API](https://docs.apiseven.com/ai-gateway/reference/admin-api),请将 `admin.addr` 设置为私有地址或回环地址,并至少配置一个 `admin.admin_keys` 值。将 `admin.enabled` 设置为 `false` 可禁用监听器。请通过[资源文件](#resources-file)或直接写入 [etcd](#etcd-configuration-store) 来配置资源。连接到 AISIX Cloud 的网关绝不会绑定网关 Admin API。 ## 常用启动配置[​](#常用启动配置 "常用启动配置的直接链接") 以下示例展示使用 etcd 的开源 AISIX 网关以及常见启动设置。网关也可以改为通过 `resources_file` 加载动态资源;请参阅[资源来源](#resource-source)。 config.yaml ``` etcd: endpoints: # 用于存储动态网关资源的 etcd 端点。 - "http://127.0.0.1:2379" prefix: "/aisix" # AISIX 在 etcd 中使用的 Key 前缀。 # env_id: "ENVIRONMENT_ID" # etcd 中网关资源的可选环境范围。 # user: "aisix" # 可选的 etcd 用户名。 # password_env: "AISIX_ETCD_PASSWORD" # 包含 etcd 密码的环境变量。 # dial_timeout_ms: 5000 # 可选,限制与 etcd 建立连接的整个过程——TCP 连接、TLS 握手和认证 # 交互。不设置和 0 都表示不施加超时。 # request_timeout_ms: 5000 # 可选,限制单次 etcd 请求-响应调用(含配置读取)的时间。不设置 # 和 0 都表示不施加超时。设置前请先阅读「etcd 配置存储」。 # tls: # mTLS 设置;三个证书字段必须同时提供。 # ca_cert_file: "/etc/aisix/mtls/ca.crt" # client_cert_file: "/etc/aisix/mtls/client.crt" # client_key_file: "/etc/aisix/mtls/client.key" # domain_name: "etcd.example.com" # 可选的 SNI 和证书名称覆盖项。 proxy: addr: "0.0.0.0:3000" # 面向调用方的代理 API 地址。 # request_body_limit_bytes: 0 # 请求体大小上限。默认值 0 表示不限制。 # 设置字节数可限制单请求内存。拒绝行为请参阅下文 # “限制请求体大小”。 # thread_per_core: true # 使用各自拥有监听器和上游连接池的独立 Worker 提供服务。 # 省略时,在 Linux 上启用,在其他平台关闭。设为 false 可使用 # 单个共享运行时。启动时应用,更改后需要重启。 # 请参阅“部署 > 每核一线程 Worker”。 # workers: 4 # 任一服务模式下的代理 Worker 线程数。省略时会跟随进程 # 可用的并行度,因此容器 CPU limit 或 taskset CPU 亲和性 # 掩码都可以确定其大小。最小值为 1。启动时应用。 # tls: # 代理监听器的 HTTPS 证书和密钥。 # cert_file: "/etc/aisix/tls/proxy.crt" # key_file: "/etc/aisix/tls/proxy.key" # real_ip: # AISIX 在可信代理后运行时解析调用方 IP。 # trusted_proxies: # - "10.0.0.0/8" # recursive: true # header: "x-forwarded-for" # url_rewrites: # 路由前在入口级重写路径(第一条匹配规则生效)。 # - name: per-server-mcp-compat # 网关日志中使用的可选标签。 # match: "^/mcp-servers/([^/]+)/mcp$" # 针对原始请求路径的正则表达式。 # rewrite: "/mcp/$1" # 替换匹配部分;规则错误会导致启动失败。 # # 完整语义请参阅“部署 > URL 重写”。 admin: enabled: false observability: service_name: "aisix" # 遥测数据中使用的服务名称。 log_level: "info" # 进程日志级别。 metrics: prometheus: enabled: true # 是否暴露 Prometheus 指标。 path: "/metrics" # 指标端点路径。 addr: "0.0.0.0:9090" # 专用指标/状态监听地址。 # managed: # 网关使用 AISIX Cloud 控制面时启用。 # enabled: true # cache: # 选择 Redis 的缓存策略所使用的 Redis 连接。 # redis: # mode: "single" # url: "redis://127.0.0.1:6379" # # nodes: ["redis://10.0.0.1:6379"] # Cluster 模式的种子节点。 # # sentinels: ["redis://10.0.0.1:26379"] # Sentinel 模式的节点。 # # master_name: "mymaster" # Sentinel 模式的主节点组。 # # username: "default" # Cluster 或 Sentinel 数据节点的 ACL 用户。 # # password: "replace-me" # Cluster 或 Sentinel 数据节点的 ACL 密码。 # # database: 0 # Sentinel 主节点的数据库索引。 # # timeout_secs: 5 # 限制一次 Redis 往返和一次连接尝试,最小值为 1。 # # single 模式下,请将凭证放在 Redis URL 中。 ratelimit: backend: "memory" # 限流计数器后端;跨副本共享计数器时使用 redis。 # redis: # mode: "single" # url: "redis://127.0.0.1:6379" # # nodes: ["redis://10.0.0.1:6379"] # Cluster 模式的种子节点。 # # sentinels: ["redis://10.0.0.1:26379"] # Sentinel 模式的节点。 # # master_name: "mymaster" # Sentinel 模式的主节点组。 # # username: "default" # Cluster 或 Sentinel 数据节点的 ACL 用户。 # # password: "replace-me" # Cluster 或 Sentinel 数据节点的 ACL 密码。 # # database: 0 # Sentinel 主节点的数据库索引。 # # timeout_secs: 5 # 限制一次 Redis 往返和一次连接尝试,最小值为 1。 # # single 模式下,请将凭证放在 Redis URL 中。 # concurrency_ttl_secs: 300 # 仅适用于 Redis 后端,用于回收过期的并发槽位。 upstream: # 向服务提供方发起出站调用。以下为默认值。 pool_idle_timeout_secs: 30 # 应低于网关与服务提供方之间最短的空闲超时。 # timeout_ms: 6000000 # 模型及其组/路由器均未设置 timeout 时的默认请求截止时间(6000 秒)。0 表示禁用兜底值。 # stream_timeout_ms: 0 # 默认流式分块间隔截止时间。0 表示回退到 timeout_ms。 # retries: 2 # 模型及其组/路由器均未设置 retries 时,可重试失败后的尝试次数。0 表示禁用重试。 # connect_timeout_ms: 5000 # DNS、TCP 和 TLS 的时间预算。0 表示禁用。 # tcp_keepalive_secs: 60 # 首次 Keepalive 探测前的空闲时间。0 表示禁用。 # tcp_keepalive_interval_secs: 30 # Keepalive 探测间隔。 # tcp_keepalive_retries: 5 # 丢弃连接前允许的未确认探测次数。 # pool_max_idle_per_host: 32 # 每个上游主机的空闲连接上限。未设置表示不限制。 # 对 Worker 本地连接池的每个 Worker 分别生效。 # tls: # 网关执行出站调用时信任的证书。 # ca_file: "/etc/aisix/tls/private-ca.pem" # 除平台自身 CA 外额外信任的 CA。 # client_cert_file: "/etc/aisix/tls/client.crt" # 用于要求 mTLS 且受支持的 HTTP 上游。 # client_key_file: "/etc/aisix/tls/client.key" # 必须与 client_cert_file 一起提供。 # verify: true # false 表示在受支持的位置禁用验证,仅用于测试环境。 downstream: # 接收客户端入站调用的连接层。以下为默认值。 idle_timeout_secs: 0 # 关闭两次请求间空闲的连接。0 表示从不关闭。 # sse_keepalive_interval_secs: 15 # 静默流式响应的心跳间隔。0 表示禁用。 # 可选的部署级 AWS Bedrock 安全护栏流量覆盖项。 # bedrock_endpoint_url: "https://bedrock-runtime.us-east-1.amazonaws.com" ``` 启动配置的更改会在网关重启后生效。 ### 限制请求体大小[​](#limit-request-body-size "限制请求体大小的直接链接") `proxy.request_body_limit_bytes` 默认为 `0`,表示网关侧不设上限。服务提供方接受的请求可能大于任何单一固定默认值,因此设置上限可能会拒绝原本可由所选服务提供方处理的请求。早期 AISIX 版本的默认值为 `10485760` 字节(10 MiB)。 如果网关直接接受来自不受信任客户端的请求,并且必须限制单请求内存,请设置一个字节数。也可以在网关前的负载均衡器或 Ingress 上实施请求体大小限制。 AISIX 会以 `413 Content Too Large` 拒绝超限请求,但不保证调用方一定能收到该响应。对于声明了超限 `Content-Length` 的请求,AISIX 会先排空请求体,以便在同一连接上返回 `413`。排空操作受字节数和时间限制;如果调用方未能在限制内发送完毕,网关会停止读取,此时调用方通常看到连接关闭或重置。分块请求体会在处理程序读取时被拒绝,不使用同一排空路径。 在 Content-Length 路径上,`aisix::body_limit` 日志条目和 [`aisix_proxy_request_body_limit_rejections_total`](https://docs.apiseven.com/ai-gateway/reference/metrics.md#request-metrics) 可区分排空完成、达到上限、超时或客户端读取错误。有关字段与关联分析流程,请参阅[指标与日志](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#collect-access-logs)。 ### 调整上游连接层[​](#tune-the-upstream-connection-layer "调整上游连接层的直接链接") `upstream` 配置块控制网关如何打开并复用到模型服务提供方的连接。默认值适合直接通过互联网访问服务提供方的网关。当网关位于负载均衡器、NAT 网关、企业代理或服务网格之后时,请调整这些设置。 应首先检查 `pool_idle_timeout_secs`。网关会复用池化连接,因此该值必须**低于**到模型服务提供方的路径上任何位置的最短空闲超时。如果中间跳点先于网关关闭空闲连接,连接池最终会分配一个已被远端关闭的连接,使访问健康模型服务提供方的请求也发生传输错误。 当较慢的模型尚未生成首 Token 时,TCP Keepalive 可让相同中间跳点继续感知该连接。否则,NAT 或负载均衡器的空闲计时器可能清除正在合法等待长耗时请求的连接。 在 Linux 上默认启用的每核一线程服务模式中,普通代理调度使用 Worker 本地连接池,`pool_max_idle_per_host` 对每个 Worker 分别生效。因此,一个进程到单个主机的空闲连接数最多可达到该上限乘以 `proxy.workers`。使用专用客户端的请求路径(例如配置了自定义 TLS 的服务提供方密钥)会保留独立的进程级连接池,不计入该倍数。有关服务模式及其容量规划影响,请参阅[每核一线程 Worker](https://docs.apiseven.com/ai-gateway/deployment/thread-per-core-workers.md)。 `timeout_ms` 和 `stream_timeout_ms` 是每个模型 `timeout` 和 `stream_timeout` 字段的部署级默认值。请求会使用第一个已设置值:目标模型、请求所经由的路由模型或语义路由器、最后是这些默认值。6000 秒默认值是防止请求永久挂起的兜底值,并非响应速度目标;它确保已经接受连接却永久静默的上游不能无限占用请求,同时不会截断合法的长耗时请求(深度推理调用可能超过十分钟;如需更严格限制,请设置每个模型的 `timeout`)。模型可通过 `timeout: 0` 跳过兜底值;设置 `timeout_ms: 0` 会移除部署级默认值。 值为零时的行为因字段而异。`upstream.timeout_ms: 0` 会移除部署级请求截止时间,模型上的 `timeout: 0` 会停止该请求超时的回退链。相比之下,`upstream.stream_timeout_ms: 0` 会回退到 `upstream.timeout_ms`,而模型上的 `stream_timeout: 0` 会继续回退到剩余的流超时和请求超时链。因此,流超时值为零时仍可能存在有效的流式截止时间。 `upstream.tls` 提供出站连接的部署级 TLS 设置。`ca_file` 适用于 HTTP 请求路径、Realtime WebSocket、Amazon Bedrock 和对象存储导出;客户端证书和验证设置支持的传输范围更窄。 如果上游证书由私有或企业 CA 签发,请设置 `ca_file`。这些 CA 会在平台自身 CA 之外额外受信任,因此公共服务提供方仍可访问。有关支持矩阵、各端点的信任、mTLS 和 Redis 后端设置,请参见 [TLS 与 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md#trust-an-upstream-behind-a-private-certificate-authority)。 ### 调整下游连接层[​](#调整下游连接层 "调整下游连接层的直接链接") `downstream` 配置块与 `upstream` 对称,用于控制网关接受的客户端连接,或接受来自其前方网关的连接。 `idle_timeout_secs` 会关闭在两次请求**之间**处于空闲状态的连接,即响应已完整写入且下一请求尚未开始。进行中的请求无论模型耗时多久都不会中断,流式响应也不会。相同的截止时间还会限制新连接在发送第一个请求行和请求头前可以等待多久,因此应显著高于最慢客户端的往返时延。 默认值为 `0`,表示永不关闭空闲连接,而将决定权交给对端。该默认值是有意设置的。网关前方的组件会维护自己的连接池;先关闭连接的节点会使对端仍将该连接视为可用,这与出站方向中 `pool_idle_timeout_secs` 所避免的故障相同。如果设置 `idle_timeout_secs`,请让它**高于**前方节点的连接池空闲超时,并仅在需要回收空闲连接时设置。 `sse_keepalive_interval_secs` 会在模型尚未产生任何内容时,向流式响应发送 SSE 注释。如果没有此心跳,首 Token 较慢的模型会被客户端与网关之间的代理误认为连接已放弃。所有符合规范的 SSE 客户端都会忽略该注释,此设置适用于所有流式端点。 这两个设置都适用于代理监听器。`idle_timeout_secs` 适用于 HTTP/1.1 连接。 ### 各超时设置之间的关系[​](#how-the-timeouts-relate "各超时设置之间的关系的直接链接") 以下每项设置限制请求的不同阶段,不能互相替代。 | 设置 | 位置 | 限制的阶段 | | --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `upstream.connect_timeout_ms` | 启动配置 | 发送请求前,与服务提供方之间的 DNS、TCP 和 TLS。 | | `upstream.timeout_ms` | 启动配置 | 模型与其所经由的路由模型/语义路由器均未设置 `timeout` 时的默认值。 | | `upstream.stream_timeout_ms` | 启动配置 | `stream_timeout` 的默认值;`0` 表示回退到 `upstream.timeout_ms`。 | | `upstream.pool_idle_timeout_secs` | 启动配置 | 响应完成后,到服务提供方的未使用连接在池中保留多久。 | | `downstream.idle_timeout_secs` | 启动配置 | 已接受的客户端连接在没有请求时保持打开多久。 | | `timeout` | 模型 | 从发送到最后一个字节的完整上游调用,依次从模型、路由模型/语义路由器、`upstream.timeout_ms` 解析;模型上的 `0` 表示禁用。 | | `stream_timeout` | 模型 | 流式响应两个分块之间的间隔,包括等待第一个分块和之后的每次间隔;每个分块都会重置计时器。它不是流总时长上限。值为 `0` 或未设置时,依次回退到组/路由器级的 `stream_timeout`、`timeout`,再到部署默认值。 | 两个连接池设置管理连接*复用*;模型设置限制*正在处理*的请求。TCP keepalive 是网络层活性探测,不会限制请求层的任何阶段。 通用代理用户通常会寻找 connect/send(write)/read 三种超时。对应关系如下:`connect_timeout_ms` 是连接超时;`stream_timeout` 是流式响应的读取超时(同样采用分块间隔语义),非流式响应则使用更严格的端到端 `timeout`。系统没有单独的发送超时,因为停滞的请求上传已经受相同的端到端或流式预算限制,未确认的发送还会更早在 TCP 层中断。通用代理需要三个设置,是因为它没有每请求截止时间概念;网关具备该概念,因此可以用更少的设置覆盖同一需求。 对于网关链路,每一跳都遵循同一规则:一个节点的客户端侧空闲超时必须留有余量地低于下一节点的服务器侧空闲超时。违反这一顺序会导致健康路径偶发传输错误。 ## 资源来源[​](#resource-source "资源来源的直接链接") 请只配置一个资源来源。来源选择会影响资源的加载方式,但不会改变面向调用方的[代理 API](https://docs.apiseven.com/ai-gateway/reference/proxy-api.md)。 ### 资源文件[​](#resources-file "资源文件的��直接链接") 开源 AISIX 网关只会从一个来源读取动态资源。设置 `resources_file` 可从声明式资源文件加载这些资源: config.yaml ``` resources_file: /etc/aisix/resources.yaml ``` `resources_file` 与 `etcd` 配置互斥,同时配置会导致启动失败。`resources_file` 也不能与 `managed.enabled: true` 组合使用,因为连接到 AISIX Cloud 的网关会从控制面接收资源。 设置 `resources_file` 后,网关会在启动时加载该文件,并在收到 `SIGHUP` 时重新加载。所有资源类型和字段请参见[资源文件参考](https://docs.apiseven.com/ai-gateway/reference/resources-file.md)。操作流程请参见[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md),验证或 etcd 导出请参见 [CLI 参考](https://docs.apiseven.com/ai-gateway/reference/cli.md)。[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)会显示运行中的网关加载了哪些内容。 ### etcd 配置存储[​](#etcd-configuration-store "etcd 配置存储的直接链接") 当配置自动化直接向 etcd 写入资源时,请设置 `etcd.endpoints`: config.yaml ``` etcd: endpoints: - "https://etcd.example.com:2379" prefix: "/aisix" tls: ca_cert_file: "/etc/aisix/mtls/ca.crt" client_cert_file: "/etc/aisix/mtls/client.crt" client_key_file: "/etc/aisix/mtls/client.key" domain_name: "etcd.example.com" ``` | 字段 | 必填 | 说明 | | ------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `etcd.endpoints` | 是 | 一个或多个 etcd 端点。未设置 `resources_file` 时,开源 AISIX 网关必须配置此字段。 | | `etcd.prefix` | 否 | 包含 AISIX 资源的 Key 前缀。默认为 `/aisix`;共享资源的网关必须使用相同前缀。 | | `etcd.env_id` | 否 | 写入方使用环境范围 Key 时,Key 布局中包含的环境范围。 | | `etcd.user` | 否 | etcd 用户名。 | | `etcd.password_env` | 否 | 包含 etcd 密码的环境变量名称。 | | `etcd.dial_timeout_ms` | 否 | 可选,限制与某个 etcd 端点建立连接的整个过程,单位毫秒:TCP 连接、叠加在其上的 TLS 握手,以及设置了 `etcd.user` 时进行的认证交互。默认不设置;不设置和 `0` 都不施加任何超时。 | | `etcd.request_timeout_ms` | 否 | 可选,限制单次 etcd 请求-响应调用的时间,单位毫秒。默认不设置;不设置和 `0` 都不施加任何超时。设置前请先阅读下面的说明。 | | `etcd.tls` | 否 | mTLS 连接的客户端 CA、证书、密钥以及可选的服务器名称覆盖项。三个证书文件字段必须同时提供。 | 两个 etcd 超时设置都是可选的,默认不设置。不写某个键,就表示对它所覆盖的调用不施加任何超时;把它设为 `0` 含义完全相同。这里的 `0` 表示「不设上限」而不是「回退到更外层的设置」,是因为这两个键是扁平的单层启动设置,没有可以回退的外层——这一点与模型的 `stream_timeout` 不同,后者的 `0` 会回退到其解析链的下一层。 `dial_timeout_ms` 限制的是建立连接的整个过程,而不只是 TCP 连接本身:叠加在连接器之上的 TLS 握手,以及设置了 `etcd.user` 时客户端所做的认证交互,都在它的覆盖范围之内。`request_timeout_ms` 限制单次请求-响应调用:网关在启动时以及每次重连时发起的全前缀配置读取、建立配置 watch 的握手、Admin API 自身的读取,以及这些调用在所需连接尚未建立时各自发起的那一次连接。 建立 watch 和消费 watch 受不受限制,是有意区分开的。建立 watch 是一次请求-响应交互——网关发出创建请求,等待 etcd 确认——因此设置了 `request_timeout_ms` 时它会被限制。随之返回的长连接流则永远不受它约束,因为任何这类上限都会在一段安静到没有产生事件的时间里到期,让网关不断重连而不是持续 watch。给建立过程加上上限,堵住的是一种原本无从察觉的故障:etcd 能正常响应配置读取、却始终不确认 watch 时,网关会一直提供它拿到的第一份快照,对之后的每一次变更都视而不见,而 `/status/config` 仍然报告来源已连接。 上面提到的、已经建立起来的 watch 流,是这两个键都不加约束的唯一一处交互,而这是有意为之。网关对 etcd 做的其他一切都落在其中某个键之下,建立连接时的认证交互也不例外:启动阶段由 `dial_timeout_ms` 覆盖,之后某次调用需要自行建立连接时由 `request_timeout_ms` 覆盖。 建立连接超时算作「没能连上 etcd」,而不是「etcd 拒绝了网关」,因此 `dial_timeout_ms` 到期会进入重试路径,而不会结束启动。哪些 etcd 故障会被一直等待、哪一种会终止启动,参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 除非你确实希望缓慢的 etcd 快速失败,否则请保持 `request_timeout_ms` 不设置。配置读取的耗时会随资源规模增长,因此一个读取无法在其中完成的上限会让每次尝试都被中断,网关会无限重试同一次读取。自建 etcd 的网关在未显式设置 `managed.snapshot_cache_path` 时不保留快照缓存,这种情况下代理监听器根本不会被绑定。而在启用了快照缓存的部署中,实例会基于[恢复出来的快照](https://docs.apiseven.com/ai-gateway/cloud/offline-resilience.md#restart-from-cached-configuration)完成绑定,并在该上限持续中断读取期间一直提供这份快照,于是它的流量看起来是健康的,配置却已悄悄不再跟随存储变化。参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 因此 `request_timeout_ms` 不只是一个启动期的开关。它所限制的全前缀读取会在每一次 watch 重连时再次执行,而那时代理监听器早已绑定,所以取值过小会以两种完全不同的方式出问题。在没有快照缓存的网关上,启动阶段代理端口根本不会打开,这很难被忽略。而在那之后,流量层面毫无变化——网关继续提供已经应用的那份配置,没有任何请求失败——与此同时每一次重连读取都被中断,已应用的配置离存储越来越远。真正点名这个配置键的是网关日志:其中的告警会带上 `range read exceeded etcd.request_timeout_ms`。在 `/status/config` 上,`source.connected` 会变为 `false`,`last_failure.last_error_kind` 为 `fetch`,但 `state` 仍然是 `synced`——该字段反映的是已经应用了什么,而不是它有多新。适合用来告警的计数器是指标监听器上的 `aisix_config_reload_failures_total{reason="fetch"}`。除非确有需要,否则请保持该键不设置。 设置了 `etcd.user` 时,网关在建立连接的过程中认证一次,此后这条连接终其一生都携带那次交互返回的 Token。即便 Token 背后的凭据完全有效,etcd 也可能不再接受这个 Token。面向部署的成因是认证存储的 revision 发生了变化:在签发 JWT Token 的集群上,**任何人**对认证存储做的**任何**改动——新增用户、授予角色、修改权限——都会让此前签发的每一个 Token 失效,其中也包括这个网关持有的那一个。Token 走到 `--auth-token-ttl` 的尽头也会到达同样的状态。 网关会自行恢复。当 etcd 以「拒绝这条连接所携带的 Token」来响应某次调用时——通常报为 `invalid auth token`,另外 `revision of auth store is old` 和 `user name is empty` 这两种应答也被识别为同一件事——网关会丢弃该连接、建立一条新连接(由此重新完成认证),并把该调用重试一次。在此之前,它会一直持有被拒绝的 Token 直到进程被重启,期间读不到任何配置。etcd 确实拒绝了凭据(`authentication failed, invalid user ID or password`)则有意不在这个列表中,仍然在第一次响应时就失败;再怎么重试也不会把错误的密码变成正确的密码。如果在刚刚完成认证的连接上 Token 仍然被拒绝,网关会把它作为「Token 被拒绝」而不是「凭据被拒绝」报出,以免这两件事被当作同一回事来排查。 这对健康的连接不产生任何代价,但它改变了设置 `request_timeout_ms` 之后的最坏情况:一次尝试会分别限制它的建立连接和调用,而重试拿到的是一个完整的新窗口,而不是上一次剩下的部分,因此走过这条恢复路径的一次配置读取最长可达所配置取值的四倍。两个超时键默认都不设置,因此默认部署不受影响;如果要设置一个很紧的取值,请把这个倍数考虑进去。 从现有配置存储迁移到资源文件时,请使用 [`aisix export`](https://docs.apiseven.com/ai-gateway/reference/cli.md#export-resources-from-etcd)。 ### AISIX Cloud[​](#aisix-cloud "AISIX Cloud的直接链接") 网关从 AISIX Cloud 接收资源时,请将 `managed.enabled` 设置为 `true`。请使用生成的网关安装代码片段,不要手动组合引导值;它会为所选环境提供正确的控制面端点和证书材料。 config.yaml ``` managed: enabled: true cp_base_url: "https://aisix.example.com" cp_etcd_endpoint: "aisix.example.com:443" mtls_dir: "/var/lib/aisix/mtls" dp_id_file: "/var/lib/aisix/dp_id" snapshot_cache_path: "/var/lib/aisix/config_cache.json" heartbeat_interval_secs: 15 ``` 连接证书、私钥和 CA 可以作为一组完整的内联字段(`cp_cert_pem`、`cp_key_pem` 和 `cp_ca_pem`)提供,也可以作为一组完整的文件路径字段(`cp_cert_file`、`cp_key_file` 和 `cp_ca_file`)提供。请勿在同一组凭证中混用内联和文件形式。请将凭证材料保存在环境变量或挂载的 Secret 文件中,不要提交到启动配置。 | 字段 | 必填 | 说明 | | --------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------- | | `managed.enabled` | 是 | 启用 AISIX Cloud 连接并禁用网关 Admin API 监听器。 | | `managed.cp_base_url` | 是 | 用于心跳、遥测、证书轮换和预算检查的 AISIX Cloud 控制面 Origin。 | | `managed.cp_etcd_endpoint` | 否 | 采用 `host:port` 形式的显式托管 etcd 端点。省略时,AISIX 会从 `cp_base_url` 派生。 | | `managed.cp_ca_cert_file` | 否 | 控制面 HTTP 和 etcd TLS 连接使用的额外 CA 证书包,本地部署控制面使用私有 CA 时通常需要。 | | `managed.mtls_dir` | 否 | AISIX 用于持久化生成的 mTLS 证书包的目录。默认为 `/var/lib/aisix/mtls`。 | | `managed.dp_id_file` | 否 | AISIX 持久化网关 ID 的文件。默认为 `/var/lib/aisix/dp_id`。 | | `managed.snapshot_cache_path` | 否 | 控制面中断和重启期间使用的最后已知配置缓存。连接到 AISIX Cloud 时默认为 `/var/lib/aisix/config_cache.json`;设置为空字符串可禁用。 | | `managed.heartbeat_interval_secs` | 否 | 心跳间隔秒数。默认为 `15`,并限制在 `5`–`300` 范围内。 | 托管连接在[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)中显示为 `source.type: "etcd"`,因为网关会通过托管配置存储连接使用控制面投影的资源。有关证书签发和安装流程,请参阅[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。这些字段的环境变量形式请参阅 [AISIX Cloud 连接变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md#aisix-cloud-connection-variables)。 ## 选择配置文件[​](#select-a-configuration-file "选择配置文件的直接链接") 直接运行二进制文件时,可通过 `--config` 或 `AISIX_CONFIG` 提供配置路径。 ``` aisix --config config.yaml ``` 运行官方容器镜像时,可以将配置文件挂载到 `/etc/aisix/config.yaml`,或将 `AISIX_CONFIG_PATH` 设置为容器内其它路径。 以下示例挂载生产配置文件,并让入口程序加载该文件: ``` docker run \ -v "$(pwd)/config.prod.yaml:/etc/aisix/config.prod.yaml:ro" \ -e AISIX_CONFIG_PATH="/etc/aisix/config.prod.yaml" \ ghcr.io/api7/aisix:1.2.0 ``` 如果未设置 `AISIX_CONFIG_PATH`,入口程序会使用 `/etc/aisix/config.yaml`。 ## 加载顺序[​](#加载顺序 "加载顺序的直接链接") AISIX 按以下顺序加载启动配置: 1. 内置默认值。 2. `--config` 或 `AISIX_CONFIG` 所选路径中的文件内容。 3. 以 `AISIX_` 为前缀的环境变量覆盖项。 环境变量覆盖项只作用于启动配置字段。覆盖语法和 AISIX Cloud 连接变量请参见[环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 --- # 环境变量 AISIX AI 网关使用环境变量选择启动配置文件、覆盖启动配置字段,并提供 AISIX 网关证书材料等部署相关值。 大多数运行时网关资源不直接通过环境变量配置。对于开源 AISIX 网关,请在 [`resources.yaml` 文件](https://docs.apiseven.com/ai-gateway/reference/resources-file.md)中声明模型、调用方 API Key、服务提供方密钥、安全护栏、缓存策略和可观测性导出器。该文件支持对 `${OPENAI_API_KEY}` 等值进行[环境变量插值](https://docs.apiseven.com/ai-gateway/reference/resources-file.md#environment-interpolation)。 对于连接到 AISIX Cloud 的 AISIX 网关,这些资源由控制面下发。 ## 保留环境变量[​](#保留环境变量 "保留环境变量的直接链接") AISIX 保留以下环境变量: | 变量 | 说明 | | ----------------------------------- | ------------------------------------------------------------------------------------------------ | | `AISIX_CONFIG` | AISIX 二进制文件使用的配置文件路径,等同于传入 `--config`。 | | `AISIX_CONFIG_PATH` | 官方容器入口使用的配置文件路径,默认值为 `/etc/aisix/config.yaml`。 | | `RUST_LOG` | 进程日志指令。未设置时,AISIX 使用 `observability.log_level`。 | | `AISIX_DP_BUDGET_STALE_MAX_SECONDS` | 正常缓存 TTL 过期后,连接到 AISIX Cloud 的网关可继续复用过期预算决策的最长秒数,默认值为 `600`。 | 使用这些变量时,请在启动 AISIX 前赋值。 直接运行二进制文件时,可以使用 `AISIX_CONFIG`: ``` export AISIX_CONFIG="/etc/aisix/config.yaml" aisix ``` 使用官方容器入口时,可以使用 `AISIX_CONFIG_PATH`: ``` docker run \ -v "$(pwd)/config.prod.yaml:/etc/aisix/config.prod.yaml:ro" \ -e AISIX_CONFIG_PATH="/etc/aisix/config.prod.yaml" \ ghcr.io/api7/aisix:1.2.0 ``` 容器入口会在启动二进制文件前清除 `AISIX_CONFIG_PATH`,因为它是入口变量,不是启动配置字段。 ## 启动配置覆盖[​](#启动配置覆盖 "启动配置覆盖的直接链接") AISIX 加载配置文件后,会应用以 `AISIX_` 为前缀的环境变量覆盖项。前缀后使用单下划线,嵌套字段之间使用双下划线。 以下示例覆盖代理监听地址: ``` export AISIX_PROXY__ADDR="0.0.0.0:3000" ``` 常见覆盖变量包括: | 变量 | 覆盖字段 | | --------------------------------------- | -------------------------------- | | `AISIX_PROXY__ADDR` | `proxy.addr` | | `AISIX_PROXY__THREAD_PER_CORE` | `proxy.thread_per_core` | | `AISIX_PROXY__WORKERS` | `proxy.workers` | | `AISIX_ETCD__ENDPOINTS` | `etcd.endpoints` | | `AISIX_ETCD__PREFIX` | `etcd.prefix` | | `AISIX_OBSERVABILITY__LOG_LEVEL` | `observability.log_level` | | `AISIX_CACHE__REDIS__MODE` | `cache.redis.mode` | | `AISIX_CACHE__REDIS__URL` | `cache.redis.url` | | `AISIX_CACHE__REDIS__MASTER_NAME` | `cache.redis.master_name` | | `AISIX_CACHE__REDIS__USERNAME` | `cache.redis.username` | | `AISIX_CACHE__REDIS__PASSWORD` | `cache.redis.password` | | `AISIX_CACHE__REDIS__DATABASE` | `cache.redis.database` | | `AISIX_CACHE__REDIS__TIMEOUT_SECS` | `cache.redis.timeout_secs` | | `AISIX_RATELIMIT__BACKEND` | `ratelimit.backend` | | `AISIX_RATELIMIT__REDIS__MODE` | `ratelimit.redis.mode` | | `AISIX_RATELIMIT__REDIS__URL` | `ratelimit.redis.url` | | `AISIX_RATELIMIT__REDIS__MASTER_NAME` | `ratelimit.redis.master_name` | | `AISIX_RATELIMIT__REDIS__USERNAME` | `ratelimit.redis.username` | | `AISIX_RATELIMIT__REDIS__PASSWORD` | `ratelimit.redis.password` | | `AISIX_RATELIMIT__REDIS__DATABASE` | `ratelimit.redis.database` | | `AISIX_RATELIMIT__REDIS__TIMEOUT_SECS` | `ratelimit.redis.timeout_secs` | | `AISIX_RATELIMIT__CONCURRENCY_TTL_SECS` | `ratelimit.concurrency_ttl_secs` | | `AISIX_BEDROCK_ENDPOINT_URL` | 顶层 `bedrock_endpoint_url`。 | `etcd.endpoints` 在环境变量中接受逗号分隔列表。 对于 Redis Cluster 和 Sentinel 节点列表,请在启动配置文件中配置 `cache.redis.nodes`、`cache.redis.sentinels`、`ratelimit.redis.nodes` 或 `ratelimit.redis.sentinels`。 配置文件字段请参见[启动配置参考](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md)。 ## AISIX Cloud 连接变量[​](#aisix-cloud-connection-variables "AISIX Cloud 连接变量的直接链接") AISIX 网关同样使用 `AISIX_` 覆盖机制设置 `managed.*` 启动配置。 | 变量 | 说明 | | ---------------------------------------- | --------------------------------------------------------------------------- | | `AISIX_MANAGED__ENABLED` | 设置为 `true` 时将网关连接到 AISIX Cloud。 | | `AISIX_MANAGED__CP_BASE_URL` | AISIX Cloud 控制面源地址,用于心跳、遥测、证书轮换和预算检查。 | | `AISIX_MANAGED__CP_ETCD_ENDPOINT` | 网关启动时使用的控制面 etcd 端点。 | | `AISIX_MANAGED__CP_CA_CERT_FILE` | 可选 CA bundle 文件,用于信任控制面和 etcd 的 TLS 连接。 | | `AISIX_MANAGED__CP_CERT_PEM` | 用于与 AISIX Cloud 控制面建立 mTLS 的内联客户端证书 PEM。 | | `AISIX_MANAGED__CP_KEY_PEM` | 与客户端证书配对的内联私钥 PEM。 | | `AISIX_MANAGED__CP_CA_PEM` | 作为信任锚的内联 CA 证书 PEM。 | | `AISIX_MANAGED__CP_CERT_FILE` | 客户端证书 PEM 文件路径。 | | `AISIX_MANAGED__CP_KEY_FILE` | 私钥 PEM 文件路径。 | | `AISIX_MANAGED__CP_CA_FILE` | CA 证书 PEM 文件路径。 | | `AISIX_MANAGED__MTLS_DIR` | 网关持久化已生成 mTLS bundle 的目录。 | | `AISIX_MANAGED__DP_ID_FILE` | 网关持久化 AISIX 网关 ID 的文件。 | | `AISIX_MANAGED__SNAPSHOT_CACHE_PATH` | 控制面故障期间使用的磁盘快照缓存文件路径。 | | `AISIX_MANAGED__HEARTBEAT_INTERVAL_SECS` | AISIX 网关心跳间隔(秒)。默认值为 `15`;取值会被限制在 `5` 到 `300` 之间。 | 证书、私钥和 CA bundle 应选择内联 PEM 变量或文件路径变量之一。同一个 bundle 不要混用内联和文件形式。 AISIX Cloud 连接设置请参见[连接 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md)。 --- # 响应头与错误码 AISIX 会通过多种面向调用方的 API 格式返回响应。失败的 Chat Completions 请求、Anthropic 风格 Messages 请求和透传路由请求使用的错误信封并不完全相同。 本参考帮助你理解响应头、重试提示、状态码和错误字段。排查时应先确认请求的 URL 路径,再查看对应错误格式,然后判断失败来自调用方、网关侧还是上游服务提供方。 ## 错误响应格式[​](#错误响应格式 "错误响应格式的直接链接") 请根据请求的 URL 路径识别适用的错误信封。 | 响应来源 | 错误信封 | 阅读 | | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------- | | OpenAI 兼容代理路由,例如 `/v1/chat/completions`、`/v1/completions`、`/v1/embeddings`、`/v1/responses`、音频、图像和 rerank | `{"error": {...}}` | [OpenAI 风格代理错误](#openai-style-proxy-errors) | | Anthropic 风格代理路由,例如 `/v1/messages` 和 `/v1/messages/count_tokens` | `{"type":"error","error": {...}}` | [Anthropic 风格代理错误](#anthropic-style-proxy-errors) | | `/mcp` 和 `/mcp/{server}` 下的 MCP 路由 | JSON-RPC 错误信封 | [MCP 错误](#mcp-errors) | | `/a2a/{agent}` 下的 A2A 调用 | 上游 JSON-RPC 响应;转发前失败使用 HTTP 错误;上游分发失败使用 JSON-RPC 错误 | [A2A 错误](#a2a-errors) | | `/a2a/{agent}/.well-known/agent-card.json` 下的 A2A Agent Card | 成功时使用 Agent Card JSON;网关或上游失败时使用 HTTP 错误响应 | [A2A 错误](#a2a-errors) | | 已配置的透传路由 | 转发上游状态码和响应体;AISIX 生成的失败使用 `{"error": {...}}` | [透传错误](#passthrough-errors) | ## 代理响应头[​](#proxy-response-headers "代理响应头的直接链接") 运行时响应头会因端点而异,不应假设每个响应头都适用于所有 `/v1/*` 路由。 | 响应头 | 使用场景 | | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-aisix-call-id` | 出现在 Chat Completions 响应中,用于关联一次网关调用。 | | `x-aisix-request-id` | 出现在每个代理响应中,用于将响应与该请求产生的任何访问日志和用量事件关联起来。一些 MCP 失败发生在用量核算之前;请参阅[用量事件](https://docs.apiseven.com/ai-gateway/mcp-gateway/observability.md#usage-events)。该请求头默认在请求上同样被接受:发送你自己的 ID,AISIX 会全程使用该值而不再自行生成。从哪些请求头读取 ID 可配置,因此具体部署可以扩展或关闭该行为。参见[复用自己的请求 ID](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#reuse-your-own-request-id)。 | | `x-aisix-served-by` | 出现在成功的 Chat Completions 路由响应中,用于识别实际处理请求的目标模型。 | | `x-aisix-cache` | 出现在缓存策略覆盖的聊天请求上:`hit`、`miss` 或 `bypass`。只有 `Cache-Control: no-cache` 会产生 `bypass`;`no-store` 仍会执行缓存查询,因此报告 `hit` 或 `miss`。用于确认响应是否由网关缓存返回。 | | `x-aisix-cache-layer` | 出现在缓存命中时:完全相同请求的匹配为 `exact`,向量相似度匹配为 `semantic`。用于区分命中来自哪个匹配层。 | | `x-aisix-cache-similarity` | 出现在语义缓存命中时。匹配条目的余弦相似度,取值 `0`–`1`。用于校准策略的相似度阈值。 | | `x-ratelimit-*` | 按维度拆分的一组响应头,名称以 `-requests`、`-tokens`、`-concurrent` 结尾。当调用方 API Key 配置了限流时,会出现在成功的 Chat Completions 响应中,用于查看请求、Token 和并发限制状态。 | | `X-RateLimit-Limit`<br />`X-RateLimit-Remaining`<br />`X-RateLimit-Reset`<br />`X-RateLimit-Scope` | 仅出现在 AISIX 自身限流器产生的 `429` 上,用于判断触发的是哪条限制以及何时可以重试。参见[限流拒绝响应头](#rate-limit-rejection-headers)。 | | `Retry-After` | 当网关能够给出重试提示时,会出现在限流、AISIX Cloud 预算和所有候选不可用的拒绝响应中;当 AISIX 能解析上游 429 的重试提示时,也会透出该响应头。调用方可据此判断重试时间。 | ### 限流拒绝响应头[​](#rate-limit-rejection-headers "限流拒绝响应头的直接链接") 当 AISIX 自身的限流器拒绝一个请求时,返回的 `429` 会描述拒绝该请求的那一条限制,OpenAI 风格和 Anthropic 风格两种错误信封都是如此。 | 响应头 | 取值 | | ----------------------- | ------------------------------------------------------------------------------------------------- | | `X-RateLimit-Limit` | 拒绝该请求的那条限制的配置上限。 | | `X-RateLimit-Remaining` | 该上限之下的剩余额度。触发拒绝时为 `0`。 | | `X-RateLimit-Reset` | 该限制重新放行请求所需的秒数。 | | `Retry-After` | 与上一行相同的秒数,客户端可以按自己已支持的那个响应头退避。 | | `X-RateLimit-Scope` | AISIX 扩展,标明是哪条限制拒绝了请求:`rps`、`rpm`、`rph`、`rpd`、`tpm`、`tpd` 或 `concurrency`。 | `X-RateLimit-Reset` 是**以秒为单位的时长**,不是时间戳,因此客户端不需要与网关对时。对于有窗口的限制,它向当前固定窗口的结束时刻倒数。它永远不会为 `0`,最小值是 `1`。 一个调用方 API Key、一个模型或一条限流策略都可以同时配置多条限制。对于某一个请求,只有其中一条会拒绝它——AISIX 最先发现耗尽的那一条——响应头描述的就是这一条。`X-RateLimit-Scope` 让这些数字不再含糊,因为各维度的单位并不相同:`x-ratelimit-limit: 1000` 在 `rpm` 下是 1000 次请求,在 `tpm` 下是 1000 个 Token,在 `concurrency` 下是 1000 个在途请求。 有两种情况不适用上面的读法: * **路由模型或语义路由。** 分发会跳过每一个超出自身限制的目标并尝试下一个;当所有目标都用尽时,响应头描述的是**最后一个拒绝的目标**,那是配置在该目标上的限制,而不是配置在请求所寻址的别名上的。应当把它理解为"请求为什么无法被投递",而不是调用方自身的配额。 * **合议模型。** 合议成员或评审模型超出自身限制时,请求会以 `429` 失败,但该响应不携带这些响应头,也不携带 `Retry-After`。 并发拒绝是唯一没有固定窗口的情况。并发槽位在某个在途请求结束时释放,而网关无法预测这个时刻,因此 `X-RateLimit-Reset` 和 `Retry-After` 都固定返回 `60`。 一个原始的拒绝响应如下: ``` HTTP/1.1 429 Too Many Requests content-type: application/json retry-after: 43 x-ratelimit-limit: 100 x-ratelimit-remaining: 0 x-ratelimit-reset: 43 x-ratelimit-scope: rpm x-aisix-request-id: 018f3c1f-... {"error":{"message":"request limit exceeded (requests)","type":"rate_limit_exceeded"}} ``` HTTP 响应头名称不区分大小写,AISIX 在网络上以小写形式写出。读取 `X-RateLimit-Limit` 和读取 `x-ratelimit-limit` 的客户端都能匹配到。 `X-RateLimit-*` 系列响应头**只**在 AISIX 自身拒绝请求时出现。以下情况不会出现: * **成功响应。** `200` 响应携带的是按维度拆分的 `x-ratelimit-*` 系列:`x-ratelimit-limit-requests`、`x-ratelimit-limit-tokens`、`x-ratelimit-limit-concurrent` 以及各自对应的 `remaining` 和 `reset`。这一系列只报告调用方 API Key 自身的 `rpm`、`tpm` 和 `concurrency` 状态,不包含模型限制、限流策略,也不包含按秒、按小时、按天的窗口。 * **上游返回的 `429`。** AISIX 能解析出服务提供方的 `Retry-After` 时会透传,但服务提供方的配额状态并非 AISIX 所知,因此不会给出自己的这几个值。 * **AISIX Cloud 预算拒绝。** 预算限制的是消费金额,而不是请求数或 Token 数。它同样返回 `429`,在错误体中带上结构化的预算字段;只有当控制面给出了重置时间时才携带 `Retry-After`。 因此,`X-RateLimit-*` 是否出现,就是调用方判断"拒绝来自 AISIX 自身限流器"的依据。仅凭 `Retry-After` 无法判断——如上面两种情况所示,其他拒绝也会带上它。 ## 代理状态码[​](#代理状态码 "代理状态码的直接链接") 当错误信封包含错误类型时,应优先查看它。状态码给出大类,错误类型通常能标识更精确的网关状态。 | 状态码 | 含义 | | ------ | ----------------------------------------------------------------------------------------------------------------------------------- | | `400` | 请求无效。 | | `401` | 调用方认证缺失或无效。 | | `403` | 调用方已通过身份认证,但已配置的访问控制不允许该请求。 | | `404` | 请求的资源未找到。网关生成的示例包括未知模型别名、MCP 服务器或 A2A Agent。上游服务也可能返回 `404`;AISIX 会保留上游 `4xx` 状态码。 | | `413` | 请求体超过代理请求体大小限制。 | | `422` | 内容被安全护栏拦截,可能是策略命中,也可能是关闭式失败的安全护栏无法评估该内容。参见[安全护栏拒绝](#guardrail-refusals)。 | | `429` | 请求触发限流或 AISIX Cloud 预算拒绝。 | | `501` | 解析出的服务提供方适配器未实现该端点。 | | `502` | 上游服务提供方返回服务端失败,或适配器将上游失败映射为代理错误格式。 | | `503` | 身份认证依赖项或服务提供方适配器不可用,或所有路由候选都被运行时状态过滤。 | | `504` | 上游请求超时。 | ## OpenAI 风格代理错误[​](#openai-style-proxy-errors "OpenAI 风格代理错误的直接链接") AISIX 的 OpenAI 兼容代理错误使用如下信封: ``` { "error": { "message": "...", "type": "invalid_request_error" } } ``` 当 AISIX 没有对应值时,会省略 `param` 和 `code` 字段。AISIX Cloud 预算拒绝会在 `error` 对象中包含结构化预算字段,例如 `scope`、`limit_usd`、`spent_usd`、`period` 和 `retry_after_seconds`。 常见的 AISIX `error.type` 取值如下: | 错误类型 | 常见状态码 | 含义 | | ---------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid_api_key` | `401` | 调用方认证缺失或无效。无效、已过期或未映射的 JWT 也使用此类型;具体情况请检查 `error.code`。 | | `permission_denied` | `403` | 调用方 API Key 无权使用请求的模型、调用方客户端 IP 不在模型的 `allowed_cidrs` 范围内,或已验证的 JWT 不满足必需 Scope 或 Claim。 | | `model_not_found` | `404` | 请求的模型别名未配置。 | | `invalid_request_error` | `400` 或 `413` | 请求体或端点使用方式无效。过大的 OpenAI 风格请求会返回该错误类型和 `413` 状态码。 | | `provider_unavailable` | `503` | 选中的上游服务提供方适配器无法完成请求。 | | `all_candidates_unavailable` | `503` | 所有路由候选都被过滤或不可用。 | | `api_error` | `503` | AISIX 无法完成内部依赖操作,例如获取用于 JWT 身份认证的签名密钥。 | | `content_filter` | `422` | 请求或响应被安全护栏拦截。安全护栏无法评估内容时 `error.code` 为 `guardrail_unavailable`;策略命中时该字段不存在。参见[安全护栏拒绝](#guardrail-refusals)。 | | `billing_error` | `429` | AISIX Cloud 预算执行拒绝了请求,原因是具有阻断动作的预算已超限,或预算的故障处理策略在控制面不可用时拒绝了请求。 | | `rate_limit_exceeded` | `429` | 请求超过已配置的限流规则。 | | `not_implemented` | `501` | 解析出的服务提供方适配器未实现该端点。 | | `timeout` | `504` | 上游请求超时。 | | `upstream_error` | 不固定,上游服务端失败通常为 `502` | 上游服务提供方返回错误,AISIX 将其渲染为代理错误格式。 | ### 身份认证错误码[​](#authentication-error-codes "身份认证错误码的直接链接") OpenAI 风格代理错误可能包含以下用于调用方身份认证的稳定 `error.code` 值。Anthropic 风格代理错误会省略 `code`;请改用其 HTTP 状态码和按状态映射的 `error.type`。 这并不是 `error.code` 的全部取值。部分 OpenAI 风格路由会在安全护栏无法评估内容而拒绝请求时携带 `guardrail_unavailable`;具体接口差异请参见[安全护栏拒绝](#guardrail-refusals)。来源 IP 拒绝携带 `ip_restricted`,预算拒绝携带 `budget_exceeded`。 | `error.code` | 状态码 | 含义 | | ----------------------- | ------ | ---------------------------------------------------------------------------------------- | | `api_key_expired` | `401` | 调用方 API Key 的到期时间已过。 | | `api_key_disabled` | `401` | 调用方 API Key 已被管理员禁用。 | | `jwt_invalid` | `401` | JWT 格式错误,或未通过签发者、签名、签名算法、受众、必需 Claim 或生效时间验证。 | | `jwt_expired` | `401` | JWT 的 `exp` 到期时间已过。 | | `jwt_claims_rejected` | `403` | JWT 有效,但不满足信任提供方要求的 Scope 或绑定 Claim。 | | `jwt_identity_unmapped` | `401` | 缺少已配置的身份 Claim,或该 Claim 未映射到绑定此 OIDC 提供方的调用方 API Key。 | | `jwks_unavailable` | `503` | AISIX 无法解析或获取信任提供方的签名密钥。请检查 OIDC Discovery 或 JWKS 端点,然后重试。 | 有关 JWT 信任提供方配置和拒绝行为,请参阅 [JWT 身份认证](https://docs.apiseven.com/ai-gateway/traffic-controls/jwt-authentication.md#rejection-reasons)。 ### 上游服务提供方错误[​](#上游服务提供方错误 "上游服务提供方错误的直接链接") OpenAI 风格路由会通过同一错误信封渲染上游服务提供方失败,但 AISIX 不一定原样返回上游响应。 上游 `4xx` 响应会保留客户端可见的 HTTP 类别。原生 OpenAI 上游错误可以保留 OpenAI 风格字段。跨服务提供方上游错误会使用 `upstream_error`,并可能包含更具体的 `error.code`,例如限流、权限或模型未找到代码。 上游 `5xx` 响应通常会返回 `502`。AISIX 不暴露上游 `5xx` 响应体,因为其中可能包含服务提供方账号、基础设施或私有诊断信息。 ## Anthropic 风格代理错误[​](#anthropic-style-proxy-errors "Anthropic 风格代理错误的直接链接") `POST /v1/messages` 和 `POST /v1/messages/count_tokens` 使用 Anthropic 风格错误信封: ``` { "type": "error", "error": { "type": "invalid_request_error", "message": "..." } } ``` Anthropic 信封会省略 OpenAI 信封可能携带的 `param` 和 `code` 字段。因此这些路由上的安全护栏因无法评估内容而拒绝请求时,不会带上部分 OpenAI 风格路由会携带的 `guardrail_unavailable`;失败标记仍然会写在消息里。参见[安全护栏拒绝](#guardrail-refusals)。 嵌套的 `error.type` 遵循与 Anthropic SDK 兼容的状态映射: | 状态码 | Anthropic `error.type` | | -------------- | ----------------------- | | `400` 或 `422` | `invalid_request_error` | | `401` | `authentication_error` | | `403` | `permission_error` | | `404` | `not_found_error` | | `408` | `timeout_error` | | `413` | `request_too_large` | | `429` | `rate_limit_error` | | `503` | `overloaded_error` | | 其它状态码 | `api_error` | AISIX 保留 `408` 映射以兼容 Anthropic SDK。网关侧产生的超时通常会通过服务提供方错误处理暴露,而不是作为原生 `408` 响应返回。 示例参见 [Anthropic 风格 Messages API](https://docs.apiseven.com/ai-gateway/endpoints/anthropic-messages.md#handle-errors)。 ## MCP 错误[​](#mcp-errors "MCP 错误的直接链接") `ANY /mcp` 和 `ANY /mcp/{server}` 使用 MCP Streamable HTTP 和 JSON-RPC 响应结构。身份认证失败或请求体过大等错误仍可能在 MCP 处理程序运行前使用 `401` 或 `413` 等 HTTP 状态码。 当安全护栏阻断工具调用或工具结果时,AISIX 会返回 HTTP 200,并在响应体中返回标记了 `isError` 的工具结果。MCP 把 JSON-RPC 协议错误保留给不合法的请求;策略拒绝属于工具执行失败,因此调用方 Agent 会把它当作工具输出读取并据此调整: ``` { "jsonrpc": "2.0", "id": 42, "result": { "content": [{ "type": "text", "text": "tool call blocked by content policy (guardrail 'block-secrets')" }], "isError": true } } ``` 这与 OpenAI 兼容路由不同,后者的安全护栏拦截使用 HTTP 422 和 OpenAI 风格错误信封。 被拒绝或不存在的工具则仍然是协议错误——HTTP 200 且 `error.code` 为 `-32602`——因为此时请求本身指定了调用方无权调用的对象。 消息措辞和失败标记词表参见[安全护栏拒绝](#guardrail-refusals)。 ## A2A 错误[​](#a2a-errors "A2A 错误的直接链接") `POST /a2a/{agent}` 会原样返回成功的上游 JSON-RPC 响应。网关识别 Agent 并进入 A2A 分发后,如果上游连接失败或返回非成功响应,则会返回 HTTP `502` 和 JSON-RPC 错误信封: ``` { "jsonrpc": "2.0", "id": 42, "error": { "code": -32000, "message": "..." } } ``` 安全护栏拒绝使用同一个 JSON-RPC 错误信封,HTTP 状态码为 `422`;其 `code` 是 JSON-RPC 的 `-32000`,不是网关错误码。参见[安全护栏拒绝](#guardrail-refusals)。 部分失败发生在 AISIX 转发 A2A 请求之前,因此不使用 JSON-RPC 错误。调用方身份认证缺失或无效时返回 `401`;调用方 Key 无权访问已注册 Agent 时返回 `403`;Agent 未知或已禁用时返回 `404`。限流或 AISIX Cloud 预算拒绝返回 `429`。 Agent Card 发现使用普通 HTTP 状态码,而不是 JSON-RPC 信封。调用方身份认证缺失或无效时返回 `401`,Agent 访问被拒绝时返回 `403`,Agent 未知或已禁用时返回 `404`。如果网关无法从上游 Agent 获取可用的 Agent Card,则返回 `502`。如果网关无法从请求中确定自身的对外地址,则返回 `500`,而不是返回一份仍然公布上游 Agent 地址的 Agent Card。 流式方法(`message/stream`、`tasks/resubscribe`)只在流建立之前遵循上述规则。响应一旦开始,状态行已经发出,之后的上游失败便无法再变成 `502`:网关会把 JSON-RPC 错误信封作为流的最后一个事件转发,并在用量事件中记录该失败。如果上游对流式调用返回的是普通 JSON-RPC 响应而非流,该响应会作为单个事件转发。 ## 透传错误[​](#passthrough-errors "透传错误的直接链接") 当 AISIX 收到上游 HTTP 响应且没有网关策略替换该响应时,命中的[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)会原样转发上游的状态码和响应体。 AISIX 生成的失败会使用 [OpenAI 风格代理错误](#openai-style-proxy-errors)信封,包括调用方身份认证拒绝、缺少 `allowed_routes` 授权或来源不在路由 `source_cidrs` 内(`403`,来源拒绝携带 `error.code: ip_restricted`)、护栏阻断,以及上游传输、超时或响应解码失败。护栏阻断是一次 `422`,流式响应上则是一个终止性 SSE `error` 事件。参见[安全护栏拒绝](#guardrail-refusals)。 未被任何显式路由认领的 `/passthrough/*` 路径会按普通流程返回响应体为空的 `404`。创建一条透传路由即可认领该路径。 ## 安全护栏拒绝[​](#guardrail-refusals "安全护栏拒绝的直接链接") 安全护栏停止流量有两种原因,两者对调用方的含义并不相同。 **策略命中**指安全护栏读到了内容并拒绝了它。**关闭式失败的可用性故障**指安全护栏根本无法评估内容,而它的配置规定「检查不了的就不放行」。 两者都属于安全护栏拒绝。两者都会遵循所请求端点自身的错误约定,也都会被记为安全护栏阻断。 标识第二种情况的有两样东西,很容易混淆: * `error.code` 在携带它的那些接口面上是一个固定取值,而不是逐类故障的取值。在 OpenAI 风格信封上它是 `guardrail_unavailable`,只在安全护栏无法评估时出现,策略命中时该字段不存在。有两个接口面不遵循这条规则:桥接的 `/v1/responses` 流始终发送 `content_filter`,`/v1/realtime` 始终发送 `content_filtered`——无论是策略命中还是可用性故障都一样。 * **失败标记**(`lakera_timeout`、`unscannable_body` 等)来自由代码定义、取值范围有限的集合,写在拒绝消息文本的括号中。消息所在字段取决于接口协议,例如 OpenAI、Anthropic 和 A2A 错误的 `error.message`、桥接 Responses 流的顶层 `message`,或 MCP 工具结果的 `result.content[].text`。标记不是 `error.code` 的取值,也没有专门的信封字段承载它。 消息按固定形态构造: ``` <side> rejected: guardrail '<name>' could not evaluate it (<tag>) <side> rejected: a guardrail could not evaluate it (<tag>) ``` 当无法指名某一条具体的安全护栏时使用第二种形态。网关代表整条护栏链、而不是基于某个成员的判定发起的拒绝,都属于这种情况。`<side>` 为 `request` 或 `response`;在 `/mcp` 上则是 `tool call` 或 `tool result`。 策略命中使用同样的形态,但不带标记: ``` <side> blocked by content policy (guardrail '<name>') <side> blocked by content policy ``` 在 OpenAI 风格路由上,`error.code` 是否存在本身就是信号,因此按它做分支。在桥接的 `/v1/responses` 流和 `/v1/realtime` 上,`code` 是常量,无法区分策略命中与可用性故障——只有消息括号里的标记能区分。请把标记词表当作一个已知取值集合,而不是字符串中的固定位置。 ### 各接口面的拒绝信封[​](#refusal-envelopes-by-surface "各接口面的拒绝信封的直接链接") 每个接口面都保留自己协议的错误形态,因此 `guardrail_unavailable` 并不会送达所有调用方。Anthropic 风格路由根本没有 `code` 字段,`/mcp` 以工具结果在带内应答,`/a2a` 以 JSON-RPC 应答。 | 接口面 | HTTP | 响应体 | `code` | | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | | OpenAI 兼容路由,非流式——包括 `/v1/chat/completions`、`/v1/embeddings`、`/v1/audio/transcriptions`、`/v1/audio/translations`,以及 Batch 和 Fine-tuning 路由 | `422` | `{"error":{"message":...,"type":"content_filter","code":"guardrail_unavailable"}}` | `guardrail_unavailable` | | `/v1/chat/completions`,流式 | `200`,随后一个终止性 SSE `error` 事件 | `{"error":{"message":...,"type":"content_filter"}}` | 无 | | `/v1/responses`,上游原生提供 Responses API 时 | `422` | 同上述非流式 OpenAI 信封 | `guardrail_unavailable` | | `/v1/responses`,AISIX 为不原生提供 Responses API 的服务提供方做桥接时 | `200`,随后一个终止性 SSE `error` 事件 | 扁平结构,与 Responses 错误事件一致:`{"type":"error","code":"content_filter","message":...,"param":null,"sequence_number":N}` | `content_filter` | | `/v1/messages` 和 `/v1/messages/count_tokens`,非流式 | `422` | `{"type":"error","error":{"type":"invalid_request_error","message":...}}` | Anthropic 信封没有 `code` 字段 | | `/v1/messages`,流式 | `200`,随后一个终止性 SSE `error` 事件 | `{"type":"error","error":{"type":"invalid_request_error","message":...}}` | Anthropic 信封没有 `code` 字段 | | 透传路由,非流式 | `422` | 同上述非流式 OpenAI 信封 | `guardrail_unavailable` | | 透传路由,流式 | `200`,随后一个终止性 SSE `error` 事件 | `{"error":{"type":"content_filter","message":...}}` | 无 | | `/mcp` 和 `/mcp/{server}` | `200` | 一个标记了 `isError` 的工具结果,文本即拒绝消息。参见 [MCP 错误](#mcp-errors)。 | 不适用 | | `/a2a/{agent}` | `422` | `{"jsonrpc":"2.0","id":...,"error":{"code":-32000,"message":...}}` | `code` 是 JSON-RPC 的 `-32000`,不是网关错误码 | | `/v1/realtime` | 没有状态码——会话已经建立 | 一个 WebSocket 文本帧 `{"type":"error","error":{"type":"invalid_request_error","code":"content_filtered","message":...}}`,随后是关闭帧,关闭码为 `1011`、原因为 `content policy` | `content_filtered` | 有两点需要提前规划。Anthropic 风格路由上的 SDK 无法基于 `error.code` 分支,因为该信封没有这个字段——请改用 HTTP 状态码和消息。以及,在大多数流式接口面上,拒绝都发生在一个已经返回 `200` 的响应上,因此只检查状态码的客户端看到的是一次成功但被截断的流。 ### 网关发起的失败标记[​](#failure-tags-raised-by-the-gateway "网关发起的失败标记的直接链接") 以下三个来自代理自身、代表整条护栏链发起,此时没有任何安全护栏产生可携带标记的判定,因此它们不会指名某条安全护栏。 | 标记 | 方向 | 出现位置 | | ------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `unscannable_body` | 请求侧和响应侧 | 部分内容无法按送达形态完成评估。请求侧可能是扫描器无法解析的 `/v1/messages` 或 `/v1/messages/count_tokens` 正文。响应侧可能是被保留的流最终没有任何可扫描内容、无法解析的 `/mcp` 工具结果,或 AISIX 无法在不替换非法字节序列的情况下解码的非流式音频转录或翻译响应。参见 [AISIX 无法扫描的帧](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#frames-aisix-cannot-scan)和 [AISIX 解码不出来的转录文本](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#transcripts-aisix-could-not-decode)。 | | `output_buffer_exceeded` | 仅响应侧 | 流式响应在被扫描之前就超出了保留缓冲区上限。出现在 `/v1/chat/completions`、`/v1/messages`、`/v1/responses` 和透传路由上。这里只有 `/v1/chat/completions` 和透传路由会遵循 `on_buffer_exceeded`;`/v1/messages` 和 `/v1/responses` 在溢出时一律关闭式失败。 | | `mask_writeback_failed` | 请求侧和响应侧 | 掩码判定无法写回正文,因此内容被拒绝,而不是不经掩码就转发。仅出现在 `/mcp` 上,`tools/call` 参数和工具结果两侧都有。 | 对于无法读取的 Anthropic 请求、MCP 工具结果或纯文本音频转录,只有当至少一条作用域内的安全护栏读取该交换方向且在该方向采用 fail-closed 时,`unscannable_body` 才会触发拒绝。如果该方向的所有读取器都 fail-open,AISIX 会中继内容,并把 `unscannable_body` 记录到 `guardrail_bypassed_reason`;对于音频,AISIX 仍会扫描尽力解码得到的文本,因此只有被替换的字节序列逃过检查。安全护栏链若不读取该方向,则既不拒绝,也不记录绕过。被保留的流最终没有可扫描内容则不同:一旦执行型输出安全护栏已经扣住该流,AISIX 就会拒绝,不受 `fail_open` 影响。 `output_buffer_exceeded` 通常**不是**一次状态码拒绝。在大多数路由上流都已经返回了 `200`,因此拒绝以终止性 SSE `error` 事件送达,被扣住的帧则被丢弃。 唯一的例外是 `/v1/responses` 且上游原生提供 Responses API:此时尚未交付任何内容,请求会以 `422` 被拒绝。当 AISIX 为不提供该 API 的服务提供方做桥接时,同样的溢出则以终止性 SSE `error` 事件送达。 ### 各安全护栏类型发起的失败标记[​](#failure-tags-raised-by-a-guardrail-kind "各安全护栏类型发起的失败标记的直接链接") 每种远程安全护栏都会把自己后端的故障归入一个有限集合。无论该条目怎么配置,用的都是同一个标记。fail-open 时它是 `Bypass` 的原因,fail-closed 时它是拒绝的标记,因此同一次故障两种配置读起来是一样的。 | 安全护栏类型 | 失败标记 | | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `lakera` | `lakera_timeout`、`lakera_throttled`、`lakera_5xx`、`lakera_too_large`、`lakera_config_error` | | `presidio` | `presidio_timeout`、`presidio_throttled`、`presidio_5xx`、`presidio_too_large`、`presidio_config_error` | | `openai_moderation` | `openai_moderation_timeout`、`openai_moderation_throttled`、`openai_moderation_5xx`、`openai_moderation_too_large`、`openai_moderation_config_error` | | `azure_content_safety` 和 `azure_content_safety_text_moderation` | `azure_cs_timeout`、`azure_cs_throttled`、`azure_cs_5xx`、`azure_cs_config_error` | | `bedrock` | `bedrock_timeout`、`bedrock_throttled`、`bedrock_too_large`、`bedrock_5xx` | | `aliyun_text_moderation` 和 `aliyun_ai_guardrail` | `aliyun_timeout`、`aliyun_throttled`、`aliyun_5xx`、`aliyun_bad_response`、`aliyun_config_error` | | `custom` | `custom_timeout`、`custom_script_error`、`custom_engine_error`、`custom_no_verdict`、`custom_bad_verdict`、`custom_unknown_action` | | `semantic` | `semantic_embed_unresolved`、`semantic_embed_timeout`、`semantic_embed_upstream` | 两种 Azure 类型共用一套词表,因为它们调用的是同一个服务;两种阿里云类型同理。请把标记理解为在指认后端,而不是在指认某条安全护栏条目——后者请看消息中的安全护栏名称。 标记的含义与名称一致。`_timeout` 是配置的等待时间耗尽,`_throttled` 是后端返回 `429`。`_5xx` 是服务端或传输层故障。`_config_error` 是非 `429` 的 `4xx`,例如凭证被拒或端点填错。`_too_large` 是后端因体积拒绝了载荷。 `aliyun_bad_response` 指 `2xx` 但响应体不是文档描述的结构。它与 `aliyun_5xx` 分开,因为两者的修复方式不同。 `custom_*` 一组区分脚本超时、抛异常、引擎无法启动。它同时覆盖脚本什么都没返回、返回的结构不是判定,以及返回了词表之外的动作。 内置的 [`keyword`](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/keyword.md) 和 [`pii`](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/pii.md) 安全护栏在网关内部运行、不调用任何后端,因此没有失败标记。这两者的阻断完全不携带 `error.code`。 ### 你还会在哪里遇到这些标记[​](#where-else-you-meet-these-tags "你还会在哪里遇到这些标记的直接链接") 各安全护栏类型自身的标记会出现在四个面向运维的位置,因此从调用方错误消息里读到的标记可以直接拿去检索: * **用量记录中的审计命中。** 关闭式失败的拒绝记为 `action` = `blocked_unavailable`,标记写入 `error_type`。普通策略命中记为 `action` = `blocked`,`error_type` 为空。监控模式下评估失败的观察会把标记记在它的 `would_block` 摘要中。 * **`aisix_guardrail_latency_seconds` Prometheus 直方图。** 关闭式失败的 `blocked`、`bypassed`,以及监控模式下失败的 `would_block`,其 `error_type` 标签都会携带该标记。普通策略命中使用 `none`。`result` 标签在关闭式失败的拒绝上仍然是 `blocked`,不会另起取值,因此既有的 `result="blocked"` 告警仍会统计到它。参见[指标参考](https://docs.apiseven.com/ai-gateway/reference/metrics.md#measure-guardrail-latency-and-outcomes)。 * **`aisix_guardrail_bypasses_total` Prometheus 计数器。** 失败开放的执行会在 `reason` 标签下使用同一个标记递增该计数器。它统计的是绕过事件而不是请求,并且没有安全护栏、类型或阶段标签。 * **用量事件上的 `guardrail_bypassed_reason`。** 安全护栏 fail-**open** 时不会拒绝任何内容,调用方也收不到任何消息,但同一个标记会记录在这里。每条代理路由的用量事件都会携带该字段;追溯批处理归因事件除外,因为这些事件没有解析安全护栏链。 网关自己发起的那三个标记是例外。它们不是安全护栏执行,因此不会出现在审计命中或安全护栏执行直方图的 `error_type` 中。失败关闭的拒绝会记录 `guardrail_blocked`,并在调用方消息和网关日志中写入该标记。当适用的失败开放策略放行 `unscannable_body` 时,用量事件会把该标记记录到 `guardrail_bypassed_reason`。`aisix_guardrail_bypasses_total` 计数器仍会递增,但由于没有安全护栏真正执行,因此不会发出延迟直方图观测值。 --- # 指标标签与变量 通过 `observability.metrics.labels` 配置每个 Prometheus 指标族的完整标签列表,既可以添加可用变量,也可以删除默认标签。1.1.0 及更早版本的网关不支持此配置项。 ## 配置标签[​](#configure-labels "配置标签的直接链接") config.yaml ``` observability: metrics: labels: aisix_request_ttft_seconds: - env_id - endpoint - model - provider - status_class - streaming - provider_key_name aisix_proxy_requests_total: - endpoint - status aisix_requests_total: [] ``` 此示例为 TTFT 添加所选提供商凭据的名称。详细请求计数器仅保留入口和状态码。旧版请求计数器的全部业务标签被删除。 * 未配置的指标保留现有默认标签。`labels: {}` 保持所有指标的默认输出。 * 每个列表都会**替换**对应指标的默认列表。如果该指标没有必须保留的身份标签,空列表会删除全部业务标签。 * 使用指标族名称,例如 `aisix_request_ttft_seconds`,不要添加 `_bucket`、`_sum` 或 `_count` 后缀。直方图的各个组成部分始终使用相同的标签;Prometheus 自动添加的 `le` 和摘要的 `quantile` 不受此配置影响。 * 指标名未知、变量不适用于该指标、变量重复或删除必要身份标签时,网关会报告配置错误并拒绝启动。 * 标签在启动时确定,修改后需要重启网关。Prometheus 已存储的序列按其保留策略继续存在;依赖已删除标签的查询和告警也需要相应调整。 通过环境变量配置时,用一个 JSON 对象设置整个映射: ``` export AISIX_OBSERVABILITY__METRICS__LABELS='{"aisix_request_ttft_seconds":["model","provider_key_name"]}' ``` 在 AISIX Cloud 的**数据平面**安装卡片中展开**指标标签**,即可选择指标和标签。生成的 Docker、Compose、Helm 和 systemd 安装指令会包含此启动配置。请将配置应用到支持此功能的网关版本。 ## 聚合与时间序列数量[​](#aggregation-and-cardinality "聚合与时间序列数量的直接链接") 删除标签会在累计观测值之前合并计数器和直方图分布。例如,删除 `model` 后会合并不同模型的请求,而不是保留某个模型的最后一个样本。标签配置不会改变指标原本统计的请求或尝试范围。 Gauge 表示当前状态,例如某个凭据的剩余额度或某个部署的健康状态。下表列出的必要身份标签必须保留,避免不同对象的值互相覆盖。其他 gauge 标签仍可增减。 每组不同的标签值都会产生独立时间序列。凭据名称、API 密钥 ID 和成员身份可能显著增加序列数量。传统直方图针对每组标签值,分别为有限边界桶、`+Inf` 桶、`_sum` 和 `_count` 创建序列。请只选择查询所需的维度。 删除分类标签也会合并其各个类别。例如,`token_type="total"` 已包含输入与输出;删除 `token_type` 会累加三个类别,不能再把结果解释成原来的 Token 总量。 ## 大规模部署[​](#large-deployments "大规模部署的直接链接") 除非显式配置替换列表,默认标签始终保留。API Key 或成员数量较多时,应根据实际查询和告警需求选择维度。如果不需要在 Prometheus 中按成员查询,可通过请求日志或导出的用量事件调查单次调用。 可以从以下选择开始: * 保留服务级查询所需的 `model`、`provider`、协议、状态及结果维度。需要区分故障转移后恢复的请求时,保留 `is_fallback`。保留 `token_type` 等分类标签;删除它们会改变求和的含义。 * 如果不按调用者查询,从请求、耗时、Token 和用量事件指标中移除 `api_key_id`、`user_id`、`user_name`。仅在需要按团队监控的指标族中保留 `team_id`。 * 监控凭据健康状态时,优先使用 `provider_key_id` 而非凭据显示名称。名称作为标签时,改名会产生新序列。如果部署和查询需要区分环境,可添加 `env_id`。 * 保留预算、剩余配额、部署状态及其他 gauge 的必需身份标签。这些指标表示各个对象的当前值,删除身份会使一个对象的值覆盖另一个对象,因此网关会拒绝此类配置。 以下示例按模型及提供商凭据聚合详细流量指标,移除调用者身份和显示名称。将这些条目加入现有的 `observability.metrics.labels` 映射,保留其他指标族的设置。每行会替换对应指标族的完整标签列表,因此应先根据仪表盘需求调整,再重启网关。 config.yaml(可观测性配置片段) ``` observability: metrics: labels: aisix_proxy_requests_total: [endpoint, upstream_protocol, provider, model, provider_key_id, inbound_protocol, stream, is_fallback, status, outcome] aisix_proxy_failed_requests_total: [endpoint, upstream_protocol, provider, model, provider_key_id, inbound_protocol, stream, is_fallback, status, outcome] aisix_llm_requests_total: [endpoint, upstream_protocol, provider, model, provider_key_id, inbound_protocol, stream, is_fallback, status, outcome] aisix_proxy_request_duration_seconds: [endpoint, upstream_protocol, provider, model, provider_key_id, inbound_protocol, stream, status, outcome] aisix_llm_request_duration_seconds: [endpoint, upstream_protocol, provider, model, provider_key_id, inbound_protocol, stream, status, outcome] aisix_llm_time_to_first_token_seconds: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_spend_micro_usd_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_input_tokens_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_output_tokens_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_total_tokens_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_cached_input_tokens_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_cache_read_input_tokens_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_llm_cache_creation_input_tokens_total: [endpoint, upstream_protocol, provider, model, provider_key_id] aisix_usage_events_emitted_total: [handler, status_code, status, inbound_protocol, upstream_protocol, model, provider_key_id] aisix_usage_event_drops_total: [reason, model, provider_key_id, upstream_protocol] ``` 此示例保留 SLO 延迟直方图的默认标签,也不修改预算和配额 gauge;这些逐对象序列仍会影响总规模。未列出的指标继续使用全部默认标签,因此还需结合实际流量检查下表中的其他指标族。 容量应按**实际观测过的标签组合**估算,而非只看配置数量或当前请求速率。大量不同调用者访问后,即使业务暂时空闲,累计指标序列仍然存在。每个默认耗时 summary 输出七个分位值及 sum、count:两个此类指标族各有 50,000 组标签时,仅它们就产生 900,000 行样本,尚未包括 counter 和其他指标。包含 N 个有限桶边界的 histogram,每组标签产生 N + 3 条序列。在记录前裁减标签,可以减少网关存储、维护、序列化和传输成本。Prometheus 的 `metric_relabel_configs` 在网关生成响应后才执行,不能消除网关侧的这些工作;在那里删除标签也不会聚合样本。 直接抓取每个网关实例,避免通过负载均衡服务轮流读取多个实例的独立计数器。可从 30 秒抓取间隔、10 秒超时开始,在预期的峰值基数下测量,包括预热后的首次抓取。超时应短于抓取间隔,间隔则应满足告警时效要求。仅增大超时不会减少序列数量或 CPU 消耗。 同时检查 `scrape_duration_seconds`、`scrape_samples_scraped`、`up`、网关 CPU、RSS 和请求延迟。例如,查找已入库的 AISIX 指标中序列最多的指标族: ``` topk(10, count by (__name__) ({job="aisix", __name__=~"aisix_.+"})) ``` 将 `job="aisix"` 替换为实际抓取任务名称。修改标签后,验证新的抓取结果,更新受影响的仪表盘和告警,并等待 Prometheus 按保留策略淘汰旧序列。 ## 支持的变量[​](#supported-variables "支持的变量的直接链接") 变量名就是输出的标签名。变量是否可用取决于指标;下表分别列出默认标签和额外支持的变量。请求归属缺失时使用 `unknown`;已有指标明确约定的其他缺省类别保持不变。没有请求上下文的后台指标不能使用请求变量。不支持任意请求头或表达式。 | 变量 | 含义 | | ------------------- | ---------------------------------------------------------------------------------------- | | `env_id` | 网关所属的 AISIX Cloud 环境 ID;未连接控制面时为 unknown。所有指标均可使用。 | | `endpoint` | 匹配到的路由模板,不含调用方传入的动态路径参数。 | | `inbound_protocol` | 调用方使用的协议,由匹配的入口确定。 | | `upstream_protocol` | 所选提供商凭据对应的上游协议;尚未选择上游或非 LLM 请求时为 unknown。 | | `provider` | 本次观测归属的提供商类型;集成模型没有唯一提供商时为 ensemble。 | | `model` | 指标归属的网关模型配置标识。通配符请求使用配置中的模式;请求或尝试的归属范围见指标参考。 | | `upstream_model` | 上游模型标识。通配符请求使用配置中的模式,避免调用方生成无限多种标签值。 | | `provider_key_id` | 所选提供商凭据的 ID,不包含密钥内容。 | | `provider_key_name` | 同一提供商凭据的显示名称;重命名后会产生新的时间序列。 | | `api_key_id` | 用于认证的网关 API 密钥 ID,不包含明文密钥。 | | `team_id` | 认证所用 API 密钥关联的团队。 | | `user_id` | 认证所用 API 密钥关联的成员。 | | `user_name` | API 密钥配置快照中的成员显示名称。 | | `stream` | 是否请求流式响应,取值 true 或 false;用于详细请求指标。 | | `streaming` | 是否为流式请求,取值 true 或 false;用于请求延迟直方图。 | | `is_fallback` | 请求归属是否为回退尝试,取值 true 或 false。 | | `status` | 请求和使用事件指标中的 HTTP 状态码;A2A 指标中表示状态码类别。 | | `status_class` | HTTP 状态码类别:2xx、3xx、4xx、5xx 或 other。 | | `status_code` | 使用事件指标中的 HTTP 状态码类别;同类指标的 status 标签保留具体状态码。 | | `outcome` | 指标定义的结果,例如请求结果、缓存决策或请求体大小限制结果。 | | `client_type` | 由内置规则或 client\_type\_rules 识别的客户端名称,不使用原始 User-Agent。 | | `token_type` | Token 类别:input、output 或 total;total 已包含 input 和 output。 | | `fallback_model` | 路由回退归属的模型配置名称。 | | `scope` | 限流决策的作用域。 | | `layer` | 限流决策的层级。 | | `policy_id` | 限流策略 ID,或该指标约定的缺省策略值。 | | `reason` | 认证、安全防护、配置或导出器指标定义的有限原因代码。 | | `method` | 凭据认证所使用的方法。 | | `result` | 指标定义的认证或安全防护执行结果。 | | `guardrail` | 安全防护配置的名称。 | | `kind` | 安全防护指标中的防护类型,或配置指标中的资源类型。 | | `phase` | 安全防护执行阶段。 | | `error_type` | 有限的安全防护错误类别;无错误时为 none。 | | `handler` | 使用事件的处理入口族,例如 `chat`、`messages`、`embeddings` 或 `mcp`。 | | `policy` | 缓存策略配置的名称。 | | `cause` | 语义缓存向量化失败的有限原因类别。 | | `op` | 语义缓存的存储操作。 | | `operation` | 指标定义的 Redis 操作或 A2A 操作。 | | `exporter` | 可观测性导出器配置的名称。 | | `agent` | 已注册的 A2A 智能体名称。 | | `state` | 上游智能体报告的 A2A 任务状态。 | | `hash` | 网关已应用资源配置的哈希值。 | ## 各指标可用的变量[​](#variables-available-per-metric "各指标可用的变量的直接链接") 所有指标均可添加 `env_id`。所有默认标签都属于可选变量。额外变量列表示默认标签以外可以添加的变量;短横线表示没有。配置替换列表时必须包含必要身份标签。 | 指标族 | 默认标签 | 额外变量 | 必要身份标签 | | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | `aisix_requests_total` | `provider`, `model`, `status`, `outcome` | `env_id` | — | | `aisix_request_duration_seconds` | `provider`, `model`, `status` | `env_id` | — | | `aisix_ratelimit_rejections_total` | `scope`, `layer`, `policy_id` | `env_id` | — | | `aisix_tokens_consumed_total` | `provider`, `model` | `env_id` | — | | `aisix_llm_spend_micro_usd_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_input_tokens_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_output_tokens_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_total_tokens_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_cached_input_tokens_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_cache_read_input_tokens_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_cache_creation_input_tokens_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_requests_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `is_fallback`, `status`, `outcome` | `env_id` | — | | `aisix_llm_request_duration_seconds` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `status`, `outcome` | `is_fallback`, `env_id` | — | | `aisix_llm_time_to_first_token_seconds` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | — | | `aisix_llm_tokens_by_client_total` | `client_type`, `model`, `token_type` | `env_id` | — | | `aisix_proxy_in_flight_requests` | `endpoint`, `inbound_protocol` | `env_id` | `endpoint` | | `aisix_proxy_requests_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `is_fallback`, `status`, `outcome` | `env_id` | — | | `aisix_proxy_failed_requests_total` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `is_fallback`, `status`, `outcome` | `env_id` | — | | `aisix_proxy_request_duration_seconds` | `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `status`, `outcome` | `is_fallback`, `env_id` | — | | `aisix_proxy_client_cancelled_requests_total` | `endpoint`, `model`, `provider_key_id`, `provider_key_name` | `env_id` | — | | `aisix_proxy_request_body_limit_rejections_total` | `endpoint`, `inbound_protocol`, `outcome` | `env_id` | — | | `aisix_deployment_requests_total` | `provider`, `model`, `upstream_model`, `provider_key_id` | `env_id` | — | | `aisix_deployment_success_responses_total` | `provider`, `model`, `upstream_model`, `provider_key_id` | `env_id` | — | | `aisix_deployment_failure_responses_total` | `provider`, `model`, `upstream_model`, `provider_key_id` | `env_id` | — | | `aisix_deployment_state` | `provider`, `model`, `upstream_model`, `provider_key_id` | `env_id` | `provider`, `model`, `upstream_model`, `provider_key_id` | | `aisix_deployment_cooled_down_total` | `provider`, `model`, `upstream_model`, `provider_key_id` | `env_id` | — | | `aisix_routing_successful_fallbacks_total` | `model`, `fallback_model` | `env_id` | — | | `aisix_routing_failed_fallbacks_total` | `model`, `fallback_model` | `env_id` | — | | `aisix_ratelimit_remaining_requests` | `api_key_id`, `model` | `env_id` | `api_key_id`, `model` | | `aisix_ratelimit_remaining_tokens` | `api_key_id`, `model` | `env_id` | `api_key_id`, `model` | | `aisix_budget_limit_usd` | `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | `api_key_id`, `team_id`, `user_id`, `user_name` | | `aisix_budget_spent_usd` | `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | `api_key_id`, `team_id`, `user_id`, `user_name` | | `aisix_budget_remaining_usd` | `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | `api_key_id`, `team_id`, `user_id`, `user_name` | | `aisix_budget_reset_seconds` | `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | `api_key_id`, `team_id`, `user_id`, `user_name` | | `aisix_budget_details_present` | `api_key_id`, `team_id`, `user_id`, `user_name` | `env_id` | `api_key_id`, `team_id`, `user_id`, `user_name` | | `aisix_redis_failures_total` | `operation` | `env_id` | — | | `aisix_usage_event_drops_total` | `reason`, `model`, `provider_key_id`, `provider_key_name`, `user_id`, `user_name`, `upstream_protocol` | `env_id` | — | | `aisix_guardrail_blocks_total` | — | `env_id` | — | | `aisix_guardrail_bypasses_total` | `reason` | `env_id` | — | | `aisix_auth_decisions_total` | `method`, `result`, `reason` | `env_id` | — | | `aisix_guardrail_latency_seconds` | `env_id`, `guardrail`, `kind`, `phase`, `result`, `error_type` | — | — | | `aisix_usage_events_emitted_total` | `handler`, `status_code`, `status`, `inbound_protocol`, `upstream_protocol`, `model`, `provider_key_id`, `provider_key_name`, `user_id`, `user_name` | `env_id` | — | | `aisix_cache_requests_total` | `policy`, `outcome` | `env_id` | — | | `aisix_cache_semantic_embedding_seconds` | `policy` | `env_id` | — | | `aisix_cache_semantic_embedding_failures_total` | `policy`, `cause` | `env_id` | — | | `aisix_cache_semantic_store_failures_total` | `policy`, `op` | `env_id` | — | | `aisix_otlp_fanout_drops_total` | `exporter`, `reason` | `env_id` | — | | `aisix_otlp_fanout_failures_total` | `exporter` | `env_id` | — | | `aisix_request_e2e_latency_seconds` | `env_id`, `endpoint`, `model`, `provider`, `status_class`, `streaming` | `inbound_protocol`, `upstream_protocol`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | — | | `aisix_request_ttft_seconds` | `env_id`, `endpoint`, `model`, `provider`, `status_class`, `streaming` | `inbound_protocol`, `upstream_protocol`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` | — | | `aisix_a2a_requests_total` | `agent`, `operation`, `status` | `env_id` | — | | `aisix_a2a_ttfb_seconds` | `agent`, `operation` | `env_id` | — | | `aisix_a2a_stream_events_total` | `agent`, `operation` | `env_id` | — | | `aisix_a2a_task_state_total` | `agent`, `state` | `env_id` | — | | `aisix_config_last_reload_successful` | — | `env_id` | — | | `aisix_config_last_reload_success_timestamp_seconds` | — | `env_id` | — | | `aisix_config_reloads_total` | — | `env_id` | — | | `aisix_config_reload_failures_total` | `reason` | `env_id` | — | | `aisix_config_rejected_resources` | `kind` | `env_id` | `kind` | | `aisix_config_partially_compatible_resources` | `kind` | `env_id` | `kind` | | `aisix_config_stale_served_resources` | `kind` | `env_id` | `kind` | | `aisix_config_observed_revision` | — | `env_id` | — | | `aisix_config_applied_revision` | — | `env_id` | — | | `aisix_config_hash_info` | `hash` | `env_id` | `hash` | | `aisix_config_source_connected` | — | `env_id` | — | --- # 指标参考 AISIX 以 Prometheus 文本格式公开运行指标。Prometheus 服务器或其他兼容采集器可抓取这些指标,用于仪表盘、告警和 PromQL 查询。 默认在专用监听器上启用 Prometheus 指标。默认启动配置如下: config.yaml ``` observability: metrics: prometheus: enabled: true addr: 0.0.0.0:9090 path: /metrics ``` Prometheus 从此监听器抓取 `GET /metrics`。 指标端点按设计不需要认证。请确保该监听器仅对监控网络开放。 每次抓取端点时,AISIX 都会公开配置状态。其他指标系列会在 AISIX 首次记录相应活动时注册,因此流量指标可能不会在启动后立即出现。请通过代理发送请求,然后再次抓取,即可看到相应序列。 下方目录列出默认标签。有关按指标增减标签的配置及所有支持的变量,参见[指标标签与变量](https://docs.apiseven.com/ai-gateway/reference/metric-labels.md)。 如需开箱即用的运维概览,请参见[导入 Grafana 概览仪表板](https://docs.apiseven.com/ai-gateway/observability/metrics-and-logs.md#import-the-grafana-overview-dashboard)。 ## 指标目录 搜索指标名称、描述、标签和值,或按指标系列和类型筛选目录。 * 指标 65 * 系列 10 查询行为 ### 指标类型 counter 持续累加并在进程重启前只增不减的值,例如请求总数或 Token 总数。使用 `rate()` 计算其变化速率。 gauge 可增可减的当前值,例如活跃请求数或剩余配额。 histogram 按可配置分桶统计的观测值。计算百分位数前,可以聚合 `_bucket`、`_sum` 和 `_count` 序列。 summary 由各网关实例计算分位数的观测值。摘要也公开 `_sum` 和 `_count`,但其分位数无法跨实例聚合。 ### 请求指标 跟踪请求结果以及代理当前正在处理的工作。 详细请求标签 本族的每个计数器都是每次客户端请求采样一次,其 `status` 是调用方实际收到的状态码。第一个目标失败、随后由回退目标成功处理的请求,在这里只是一个 `status="200"` 样本;它所恢复的那次失败在本族中完全没有体现。统计上游尝试请使用[部署指标](#deployment-metrics),查看单次尝试请使用用量日志。 对于三个详细请求计数器,`stream` 记录客户端是否请求流式响应。`is_fallback` 记录请求是否由回退目标处理,并且不会出现在延迟指标中。 `provider_key_name` 和 `user_name` 是对应 ID 的可读名称。每个名称与其 ID 一一对应,因此不会增加新的序列维度。在控制平面提供名称前,`user_name` 为 `unknown`。 失败请求与成功请求携带相同的 `provider`、`upstream_model` 和 Provider Key 标签,因此仅凭本族指标即可计算按 Provider 或按 Provider Key 的失败率。这些上游标签记录请求最后选定的目标:在重试或回退场景下,即调用方最终收到其错误的那次尝试。只有当请求从未选定任何目标时它们才为 `unknown`,例如模型不存在、被输入护栏拦截、被预算拒绝,或请求体在派发前即被拒绝。 `inbound_protocol` 是由标准化端点推导出的有界协议类型集合。Anthropic 协议端点报告 `anthropic`;`/mcp`、`/a2a`、`/v1/realtime` 和 `/passthrough_route` 分别报告 `mcp`、`a2a`、`realtime` 和 `passthrough`;其余网关端点报告 `openai`。在途请求仪表使用相同的值。 `upstream_protocol` 是该协议对的另一半:AISIX 与实际处理该请求的上游通信时所使用的协议。它按照与请求转发相同的规则从所选目标的 Provider Key 解析得出,因此报告的是请求实际被转换成的传输格式——`openai`、`anthropic`、`bedrock`、`vertex` 或 `azure-openai`;当请求完全没有选中上游时报告 `unknown`。同时按两个标签分组即可区分原生流量与跨协议转换流量,参见[区分跨协议转换流量](#separate-cross-protocol-conversion-traffic)。 请勿用 `provider` 代替 `upstream_protocol`。`provider` 是开放的厂商字符串,同一厂商可以通过不同的 adapter 接入,因此从厂商名到协议的 PromQL 映射需要手工维护,并且会对所有自定义厂商和 OpenAI 兼容厂商给出错误结果。 `endpoint` 始终是标准化的路由模板,而不是原始请求路径。带路径参数的路由会合并为一条序列,例如 `/v1/batches/:id`、`/v1/videos/:id` 和 `/mcp/{server}`;`/passthrough/` 下的路径使用 `/passthrough_route`,无法识别的路径报告为 `other`。 ### `aisix_requests_total` 兼容性序列中的代理请求结果,覆盖的端点范围最广。 Type: counter. ##### 标签 `provider`, `model`, `status`, `outcome` ##### `outcome` 的值 `success`, `client_error`, `rate_limited`, `upstream_error` `success` 表示 HTTP 200–399;`client_error` 表示除 429 外的 HTTP 400–499;`rate_limited` 表示 HTTP 429;其他所有状态均映射为 `upstream_error`。 ##### 行为 A2A 智能体调用使用 `provider="a2a"` 和 `model="a2a"`。 ##### PromQL 示例 ``` sum(rate(aisix_requests_total[5m])) by (outcome) ``` ### `aisix_llm_requests_total` 模型推理请求的结果,包括成功和失败的请求。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `is_fallback`, `status`, `outcome` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### `stream` 的值 `false`, `true` ##### `is_fallback` 的值 `false`, `true` ##### `outcome` 的值 `success`, `client_error`, `rate_limited`, `upstream_error` `success` 表示 HTTP 200–399;`client_error` 表示除 429 外的 HTTP 400–499;`rate_limited` 表示 HTTP 429;其他所有状态均映射为 `upstream_error`。 ##### 行为 覆盖调用模型的端点:聊天补全、补全、消息、Token 计数、响应、向量嵌入、重排序、音频、图像生成、视频和 realtime 会话。未调用模型的请求只计入 `aisix_proxy_requests_total`,包括 MCP 工具调用、A2A Agent 调用、服务提供方透传,以及文件、批处理和微调管理路由。 在分发前被拒绝的请求(例如请求体过大)会计入其目标端点,因此端点成功率的分母包括这些失败。 ### `aisix_proxy_requests_total` 所有代理流量(包括模型推理和其他流量)的详细请求结果。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `is_fallback`, `status`, `outcome` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `mcp`, `a2a`, `realtime`, `passthrough` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### `stream` 的值 `false`, `true` ##### `is_fallback` 的值 `false`, `true` ##### `outcome` 的值 `success`, `client_error`, `rate_limited`, `upstream_error` `success` 表示 HTTP 200–399;`client_error` 表示除 429 外的 HTTP 400–499;`rate_limited` 表示 HTTP 429;其他所有状态均映射为 `upstream_error`。 ##### 行为 每次客户端请求采样一次,携带调用方实际收到的状态码。请求内部的重试和故障转移不会增加样本,因此这个计数器回答的是「调用方发起了多少请求、各自如何结束」,而不是「网关向上游发起了多少次调用」。 ### `aisix_proxy_failed_requests_total` 结果不为 `success` 的代理请求子集。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `is_fallback`, `status`, `outcome` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `mcp`, `a2a`, `realtime`, `passthrough` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### `stream` 的值 `false`, `true` ##### `is_fallback` 的值 `false`, `true` ##### `outcome` 的值 `client_error`, `rate_limited`, `upstream_error` `client_error` 表示除 429 外的 HTTP 400–499;`rate_limited` 表示 HTTP 429;其他所有状态均映射为 `upstream_error`。 ### `aisix_proxy_in_flight_requests` 代理当前正在处理的请求,按标准化端点和入站协议分组。 Type: gauge. ##### 标签 `endpoint`, `inbound_protocol` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `mcp`, `a2a`, `realtime`, `passthrough` ##### 行为 MCP 请求使用 `inbound_protocol="mcp"`;聚合网关使用 `endpoint="/mcp"`,按服务器划分的端点使用 `endpoint="/mcp/{server}"`。A2A 调用使用 `endpoint="/a2a"` 和 `inbound_protocol="a2a"`。 标准化为 `endpoint="/passthrough_route"` 的请求使用 `inbound_protocol="passthrough"`。 ##### PromQL 示例 ``` sum(aisix_proxy_in_flight_requests) by (endpoint, inbound_protocol) ``` ### `aisix_proxy_client_cancelled_requests_total` 调用方在网关发送响应头前断开连接的请求。 Type: counter. ##### 标签 `endpoint`, `model`, `provider_key_id`, `provider_key_name` ##### 行为 这些请求不会产生正常结果,因此不会出现在其他请求计数器中。网关会在此处记录它们,并在访问日志中以状态码 `499` 记录。 该指标速率上升通常意味着调用方在等待首个 Token 时放弃。可按 `model` 拆分该序列,并与同一模型的 `aisix_llm_time_to_first_token_seconds` 对比。 `model` 是调用方请求的模型,Provider Key 标签标识请求当时正在等待的目标。若调用方在网关解析出它们之前就断开连接(例如仍在上传请求体时),这三个标签均为 `unknown`。 本指标刻意不包含其他请求计数器的调用方身份、状态码和结果标签。被取消的请求没有状态码,通常也没有团队或用户信息,这些维度在每个样本上都会是 `unknown`。 调用方在响应头发送后断开连接的情况不计入此处。该请求已经产生正常结果和用量事件。 ##### PromQL 示例 ``` sum(rate(aisix_proxy_client_cancelled_requests_total[5m])) by (endpoint, model) ``` ### `aisix_proxy_request_body_limit_rejections_total` 因超过 `proxy.request_body_limit_bytes` 而被拒绝的请求,按网关结束读取被拒绝请求体的方式分组。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `outcome` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `mcp`, `a2a`, `realtime`, `passthrough` ##### `outcome` 的值 `completed`, `cap_reached`, `timeout`, `client_read_error` `completed` 表示调用方发送了声明的完整请求体,因此可以读取 `413` 响应。`cap_reached` 和 `timeout` 表示网关先停止接收请求体;`client_read_error` 表示调用方在发送请求体时断开连接。这三种情况下,调用方通常会看到连接关闭,而不是收到响应。 ##### 行为 网关会读取并丢弃被拒绝请求的请求体,以便调用方在同一连接上接收 `413`。该读取操作有上限,`outcome` 用于报告其结束方式。 除 `completed` 外,任何结果的占比上升都表示调用方看到的是连接关闭,而不是 `413` 响应。匹配的 `aisix::body_limit` 日志条目会记录同一 `request_id` 的声明大小、配置上限和已读取字节数。 这里只统计声明的 `Content-Length` 超过上限的请求。采用分块传输且超过上限的请求会在读取时被拒绝,没有可比的 outcome,并以状态码 `413` 出现在 `aisix_requests_total` 中。 ##### PromQL 示例 ``` sum(rate(aisix_proxy_request_body_limit_rejections_total[5m])) by (endpoint, inbound_protocol, outcome) ``` ### `aisix_auth_decisions_total` API Key、JWT 和缺少凭证路径上的调用方身份认证决策。 Type: counter. ##### 标签 `method`, `result`, `reason` ##### `method` 的值 `api_key`, `jwt`, `none` ##### `result` 的值 `allowed`, `denied` ##### 行为 允许请求的 `reason` 为 `none`。被拒绝请求使用有限集合中的原因,例如 `missing_credentials`、`unknown_key`、`key_expired`、`jwt_bad_signature`、`jwt_untrusted_issuer` 或 `jwt_identity_unmapped`。 ##### PromQL 示例 ``` sum(rate(aisix_auth_decisions_total{result="denied"}[5m])) by (method, reason) ``` ### 延迟指标 检查单个网关的延迟,或跨网关实例聚合直方图分桶。 延迟聚合与标签 跨网关实例的服务级仪表盘和告警应使用直方图,因为可在调用 `histogram_quantile()` 前聚合其 `_bucket`、`_sum` 和 `_count` 序列。摘要用于检查单个网关实例预先计算的分位数。摘要分位数无法跨实例聚合,因此不要对其取平均值。 每个直方图都有自己的分桶边界,因为两种分布不同:端到端延迟从毫秒级开始,而首个 Token 时间不可能快于生成 Token 的上游。两组边界均可配置。`env_id` 标识连接到 AISIX Cloud 的 AISIX 网关所服务的环境;AISIX 网关未连接 AISIX Cloud 时其值为 `unknown`。`status_class` 为 `2xx`、`3xx`、`4xx`、`5xx` 或 `other`。为控制分桶序列数量,不包含按密钥和按用户的标签;这些维度请使用用量分析。 ### `aisix_request_duration_seconds` 兼容性序列中各代理端点的请求持续时间。HTTP 流式请求记录到响应开始的时间;realtime �记录 WebSocket 会话关闭前的完整持续时间。 Type: summary. ##### 标签 `provider`, `model`, `status` ##### 行为 摘要分位数由各 AISIX 实例计算,无法跨实例聚合。 ### `aisix_llm_request_duration_seconds` 模型推理端点的详细请求持续时间。HTTP 流式请求记录到响应开始的时间;realtime 记录 WebSocket 会话关闭前的完整持续时间。 Type: summary. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `status`, `outcome` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### `stream` 的值 `false`, `true` ##### `outcome` 的值 `success`, `client_error`, `rate_limited`, `upstream_error` `success` 表示 HTTP 200–399;`client_error` 表示除 429 外的 HTTP 400–499;`rate_limited` 表示 HTTP 429;其他所有状态均映射为 `upstream_error`。 ### `aisix_proxy_request_duration_seconds` 所有代理流量的详细请求持续时间。HTTP 流式请求记录到响应开始的时间;realtime 记录 WebSocket 会话关闭前的完整持续时间。 Type: summary. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name`, `stream`, `status`, `outcome` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `mcp`, `a2a`, `realtime`, `passthrough` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### `stream` 的值 `false`, `true` ##### `outcome` 的值 `success`, `client_error`, `rate_limited`, `upstream_error` `success` 表示 HTTP 200–399;`client_error` 表示除 429 外的 HTTP 400–499;`rate_limited` 表示 HTTP 429;其他所有状态均映射为 `upstream_error`。 ### `aisix_llm_time_to_first_token_seconds` 流式聊天补全、消息和响应请求中,从上游尝试开始到首个流式帧的时间。 Type: summary. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ### `aisix_request_e2e_latency_seconds` 客户端感知的聊天补全、消息和响应延迟,以及 A2A 的 Agent 调用延迟,包括完整的流式传输时长。 Type: histogram. ##### 标签 `env_id`, `endpoint`, `model`, `provider`, `status_class`, `streaming` ##### `status_class` 的值 `2xx`, `3xx`, `4xx`, `5xx`, `other` ##### `streaming` 的值 `false`, `true` ##### 行为 默认分桶范围为 5 毫秒到 600 秒,可通过 `observability.metrics.buckets.request_e2e_latency` 配置。较低边界用于记录缓存命中和分发前被拒绝的请求等快速响应。跨网关实例计算百分位数前,请先聚合 `_bucket` 序列。 每个纳入该指标的模型推理请求只观测一次。非流式请求和失败请求在处理程序返回时记录。流式请求在流结束时记录,包括客户端取消的情况;取消的模型流保留已提交的状态,并记录截至取消时的时长。 A2A 调用使用 `endpoint="/a2a"`。已下发的调用记录 Agent 调用的完整时长,包含完整的流。已进入 A2A 统计、但在下发之前被拒绝的调用记录为零时长,被放弃的 A2A 流在 `4xx` 状态类中记录为 `499`。在进入 A2A 统计之前就被拒绝的调用不会出现在该直方图中。 ##### PromQL 示例 ``` histogram_quantile( 0.90, sum by (le) (rate(aisix_request_e2e_latency_seconds_bucket[5m])) ) ``` ### `aisix_request_ttft_seconds` 流式聊天补全、消息和响应请求中,从上游尝试开始到首个流式帧的时间。 Type: histogram. ##### 标签 `env_id`, `endpoint`, `model`, `provider`, `status_class`, `streaming` ##### `status_class` 的值 `2xx`, `3xx`, `4xx`, `5xx`, `other` ##### `streaming` 的值 `true` ##### 行为 即使首帧不携带任何可见的生成输出——例如仅包含角色的起始帧或 Anthropic 的 `message_start` 事件——它也会停止计时。内容帧、推理帧和工具调用帧同样会停止计时。 默认分桶范围为 50 毫秒到 300 秒,可通过 `observability.metrics.buckets.request_ttft` 配置。当附近的模型服务器可以在 50 毫秒内生成输出时,请降低起始边界。只使用托管服务提供方的部署可以提高下限,移除始终为空的分桶。 ##### PromQL 示例 ``` histogram_quantile( 0.90, sum by (le) (rate(aisix_request_ttft_seconds_bucket[5m])) ) ``` ### 用量与成本指标 测量 Token 用量、估算支出和标准化客户端用量。 哪些端点报告 Token 所有从上游接收 Token 数量的端点都会在此记录,包括聊天补全、补全、消息、响应、向量嵌入、重排序、音频转录路由、图像生成和 realtime 会话。 有两个模型推理端点不会报告 Token,因为其计费方式不同:`/v1/audio/speech` 按输入字符计费,`/v1/videos` 按视频计费。两者仍计为请求,因此只能在同一 `endpoint` 内用 Token 总数除以请求数,不能跨全部端点计算。 逐请求 Token 与支出序列(三个 `aisix_llm_*_tokens_total` 计数器和 `aisix_llm_spend_micro_usd_total`)使用与详细请求计数器相同的标签,因此查询可基于 `endpoint`、`model`、`provider` 和调用方身份标签关联 Token 用量与请求结果。另两个指标的标签不同:`aisix_tokens_consumed_total` 仅按 `provider` 和 `model` 标记;`aisix_llm_tokens_by_client_total` 仅按 `client_type`、`model` 和 `token_type` 标记。 另有三个计数器单独统计上游服务商用自身 Prompt Cache 提供的 Token。它们与上述 Token 计数器使用相同的标签,且仅在取值非零时才创建序列,因此不报告缓存明细的服务商不会产生任何序列。它们描述的是\*\*上游服务商\*\*的缓存,而不是 AISIX 响应缓存——后者是[缓存指标](#cache-metrics)中的 `aisix_cache_requests_total`,两者互不相关。 各服务商对缓存读取采用两种不同的计量口径,因此读取侧有两个计数器而非一个。`aisix_llm_cached_input_tokens_total` 对应 OpenAI 口径:缓存命中的 Token 本身就属于上报的 prompt Token,因此已经包含在 `aisix_llm_input_tokens_total` 之内。`aisix_llm_cache_read_input_tokens_total` 和 `aisix_llm_cache_creation_input_tokens_total` 对应 Anthropic 口径:它们与输入 Token 并列上报而非包含其中,因此位于 `aisix_llm_input_tokens_total` 之外、`aisix_llm_total_tokens_total` 之内。 把两种口径分开正是跨协议查询能够成立的原因:请求实际消耗的输入为 `aisix_llm_input_tokens_total + aisix_llm_cache_read_input_tokens_total + aisix_llm_cache_creation_input_tokens_total`,其中由缓存提供的部分为 `aisix_llm_cached_input_tokens_total + aisix_llm_cache_read_input_tokens_total`。这两个表达式对任一服务商口径都成立。参见[计算 Prompt Cache 命中率](#calculate-prompt-cache-hit-rate)。 ### `aisix_tokens_consumed_total` 所有报告 Token 用量的端点的 Token 总数,属于覆盖范围最广的兼容性序列。 Type: counter. ##### 标签 `provider`, `model` ### `aisix_llm_input_tokens_total` 上游在所有报告 Token 用量的端点中报告的输入 Token 数。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ### `aisix_llm_output_tokens_total` 上游在所有报告 Token 用量的端点中报告的输出 Token 数。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ### `aisix_llm_total_tokens_total` 上游在所有报告 Token 用量的端点中报告的 Token 总数。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ### `aisix_llm_cached_input_tokens_total` 上游用其 Prompt Cache 提供、并计入 prompt Token 数量的输入 Token。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### 行为 OpenAI 计量口径:OpenAI 及 OpenAI 兼容服务商的 `prompt_tokens_details.cached_tokens`、DeepSeek 的 `prompt_cache_hit_tokens`、Vertex AI 上 Gemini 的 `cachedContentTokenCount`。这些 Token 已计入 `aisix_llm_input_tokens_total`,两者相加会重复计算。 仅在上游报告该字段时记录。AISIX 不会依据响应耗时或提示词相似度推断缓存命中。 ### `aisix_llm_cache_read_input_tokens_total` 上游用其 Prompt Cache 提供、并与输入 Token 数量分开上报的输入 Token。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### 行为 Anthropic 计量口径:Anthropic 的 `cache_read_input_tokens` 和 Amazon Bedrock 的 `cacheReadInputTokens`。这些 Token \*\*不\*\*包含在 `aisix_llm_input_tokens_total` 中,但包含在 `aisix_llm_total_tokens_total` 中。 ### `aisix_llm_cache_creation_input_tokens_total` 写入上游 Prompt Cache 的输入 Token。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ##### 行为 对应 Anthropic 的 `cache_creation_input_tokens` 和 Amazon Bedrock 的 `cacheWriteInputTokens`。与同一口径下的缓存读取一样,这些 Token 位于 `aisix_llm_input_tokens_total` 之外、`aisix_llm_total_tokens_total` 之内。 各服务商对缓存写入的计费高于标准输入价格,对缓存读取的计费则远低于标准价格,因此写入远多于读取的工作负载反而比完全不用缓存更贵。将该计数器与 `aisix_llm_cache_read_input_tokens_total` 对比即可发现这种情况。 ### `aisix_llm_spend_micro_usd_total` 以微美元计的估算支出;1 美元等于 1,000,000 微美元。网关只要能够解析请求价格,就会记录该指标。 Type: counter. ##### 标签 `endpoint`, `inbound_protocol`, `upstream_protocol`, `provider`, `model`, `upstream_model`, `provider_key_id`, `provider_key_name`, `api_key_id`, `team_id`, `user_id`, `user_name` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `realtime` ##### `upstream_protocol` 的值 `openai`, `anthropic`, `bedrock`, `vertex`, `azure-openai`, `unknown` 网关与上游通信所使用的协议,与 `inbound_protocol` 相互独立。`unknown` 表示该请求没有选中任何上游——在转发前被拒绝,或是不调用模型的路由。 ### `aisix_llm_tokens_by_client_total` 所有报告 Token 用量的端点中的 Token 用量,按标准化客户端、请求模型和 Token 类型分组。 Type: counter. ##### 标签 `client_type`, `model`, `token_type` ##### `client_type` 的值 `openai-python`, `openai-node`, `anthropic-python`, `anthropic-typescript`, `claude-code`, `codex`, `cline`, `roo-code`, `kilocode`, `zoo-code`, `github-copilot`, `cursor`, `opencode`, `qwen-code`, `gemini-cli`, `crush`, `zed`, `aider`, `vercel-ai-sdk`, `langchain`, `llamaindex`, `litellm`, `curl`, `python-requests`, `httpx`, `aiohttp`, `okhttp`, `go-http-client`, `node`, `postman`, `browser`, `other`, `unknown` 无法识别的 `User-Agent` 映射为 `other`;缺少 `User-Agent` 时映射为 `unknown`。部署可通过管理员定义的映射规则(`observability.metrics.client_type_rules`)扩展此集合。完整的 User-Agent 字符串和版本仍会保留在请求日志和用量分析中。 ##### `token_type` 的值 `input`, `output`, `total` `total` 包含输入、输出以及 Anthropic 缓存创建和缓存读取 Token。 ##### 行为 `model` 是调用方请求的模型名称,与 `aisix_llm_*` Token 序列的 `model` 标签值相同。路由、语义、合议和故障转移分发会保留此别名,而不是报告所选直接模型。 有界的 `client_type` 白名单可防止客户端可控的 User-Agent 导致 Prometheus 基数无限增长。具体模型别名受已配置模型集合的限制,但通配符别名会记录通过该模式请求的每个具体模型名称。基数很重要时,请限制通配符访问并监控标签增长。 管理员定义的映射规则(`observability.metrics.client_type_rules`)可对更多客户端进行分类。规则在内置白名单之前匹配,并输出固定且经过验证的标签值,因此标签集合保持有界。 在相同端点范围内跨所有标签聚合后,包含缓存的 `total` 与 `aisix_llm_total_tokens_total` 一致。由于两个指标系列使用不同的标签集合,单条序列并不对应;专用客户端类型序列避免为按密钥统计的 Token 序列再增加一个标签维度。 Anthropic 将缓存 Token 与输入 Token 分开报告,因此 `total` 可能大于 `input` 与 `output` 之和。 ##### PromQL 示例 ``` sum by (client_type, model, token_type) ( rate(aisix_llm_tokens_by_client_total[5m]) ) ``` ### 限流与预算指标 监控每个标签集合的限流拒绝,以及最新配额或预算状态。 ### `aisix_ratelimit_rejections_total` 在各代理端点上被共享限流闸门拒绝的请求。 Type: counter. ##### 标签 `scope`, `layer`, `policy_id` ##### `scope` 的值 `requests`, `tokens` 并发限制拒绝使用 `requests`;运行时不会发出单独的 `concurrency` 值。 ##### `layer` 的值 `api_key`, `model`, `mcp`, `policy` ##### 行为 `policy_id` 在 `layer="policy"` 之外为空;在策略层上,该标签携带已配置的策略 ID。 限流器背后的共享 Redis 可能在不拒绝任何请求的情况下失败——限流器会静默回退为按副本计数。这类失败由[缓存指标](#cache-metrics)中的 `aisix_redis_failures_total` 统计。 ### `aisix_ratelimit_remaining_requests` 处理聊天补全请求时报告的剩余请求配额,按 API Key 和模型分组。 Type: gauge. ##### 标签 `api_key_id`, `model` ##### 行为 `model` 是请求解析到的已配置模型——通配符别名报告的是该行本身(例如 `openai/*`),而不是调用方发来的具体名称。 在 API Key 被删除、或被改绑到其他团队或成员之后的数秒内退休为 `NaN`。用 `NaN` 而不是 `0`,是因为 `0` 在这个仪表上本身就是一个有意义的读数;任何与 `NaN` 的比较都为假,因此挂在退休序列上的告警会停止触发。对含有退休序列的指标族做聚合,结果同样是 `NaN`。 ### `aisix_ratelimit_remaining_tokens` 处理聊天补全请求时报告的剩余 Token 配额,按 API Key 和模型分组。 Type: gauge. ##### 标签 `api_key_id`, `model` ##### 行为 `model` 是请求解析到的已配置模型——通配符别名报告的是该行本身(例如 `openai/*`),而不是调用方发来的具体名称。 在 API Key 被删除、或被改绑到其他团队或成员之后的数秒内退休为 `NaN`。用 `NaN` 而不是 `0`,是因为 `0` 在这个仪表上本身就是一个有意义的读数;任何与 `NaN` 的比较都为假,因此挂在退休序列上的告警会停止触发。对含有退休序列的指标族做聚合,结果同样是 `NaN`。 ### `aisix_budget_limit_usd` 预算上限(美元)。 Type: gauge. ##### 标签 `api_key_id`, `team_id`, `user_id`, `user_name` ##### 行为 删除某把 Key 的预算不会把这个仪表置零——它会保留最后一次的预算值,这正是查询需要加上 `aisix_budget_details_present == 1` 条件的原因。 在 API Key 被删除、或被改绑到其他团队或成员之后的数秒内退休为 `NaN`。用 `NaN` 而不是 `0`,是因为 `0` 在这个仪表上本身就是一个有意义的读数;任何与 `NaN` 的比较都为假,因此挂在退休序列上的告警会停止触发。对含有退休序列的指标族做聚合,结果同样是 `NaN`。 ### `aisix_budget_spent_usd` 已用预算(美元)。 Type: gauge. ##### 标签 `api_key_id`, `team_id`, `user_id`, `user_name` ##### 行为 删除某把 Key 的预算不会把这个仪表置零——它会保留最后一次的预算值,这正是查询需要加上 `aisix_budget_details_present == 1` 条件的原因。 在 API Key 被删除、或被改绑到其他团队或成员之后的数秒内退休为 `NaN`。用 `NaN` 而不是 `0`,是因为 `0` 在这个仪表上本身就是一个有意义的读数;任何与 `NaN` 的比较都为假,因此挂在退休序列上的告警会停止触发。对含有退休序列的指标族做聚合,结果同样是 `NaN`。 ### `aisix_budget_remaining_usd` 剩余预算(美元)。 Type: gauge. ##### 标签 `api_key_id`, `team_id`, `user_id`, `user_name` ##### 行为 删除某把 Key 的预算不会把这个仪表置零——它会保留最后一次的预算值,这正是查询需要加上 `aisix_budget_details_present == 1` 条件的原因。 在 API Key 被删除、或被改绑到其他团队或成员之后的数秒内退休为 `NaN`。用 `NaN` 而不是 `0`,是因为 `0` 在这个仪表上本身就是一个有意义的读数;任何与 `NaN` 的比较都为假,因此挂在退休序列上的告警会停止触发。对含有退休序列的指标族做聚合,结果同样是 `NaN`。 ### `aisix_budget_reset_seconds` 距离预算周期重置的秒数。 Type: gauge. ##### 标签 `api_key_id`, `team_id`, `user_id`, `user_name` ##### 行为 删除某把 Key 的预算不会把这个仪表置零——它会保留最后一次的预算值,这正是查询需要加上 `aisix_budget_details_present == 1` 条件的原因。 在 API Key 被删除、或被改绑到其他团队或成员之后的数秒内退休为 `NaN`。用 `NaN` 而不是 `0`,是因为 `0` 在这个仪表上本身就是一个有意义的读数;任何与 `NaN` 的比较都为假,因此挂在退休序列上的告警会停止触发。对含有退休序列的指标族做聚合,结果同样是 `NaN`。 ### `aisix_budget_details_present` 是否已填充预算详情。 Type: gauge. ##### 标签 `api_key_id`, `team_id`, `user_id`, `user_name` ##### `指标值` 的值 `0`, `1` `1` 表示存在预算详情;`0` 表示预算详情已清除。 ### 缓存指标 按策略衡量响应缓存的效果,并关注语义层的 embedding 与存储健康状况。 缓存命中率 每个被已启用缓存策略覆盖、且后端可用的请求都会记录一次 `aisix_cache_requests_total`。没有匹配策略或后端不可用的请求不计入——闸门从未打开——因此该系列衡量的是策略效果,而不是总流量。 按策略计算命中率:`sum by (policy) (rate(aisix_cache_requests_total{outcome=~"hit_exact|hit_semantic"}[5m])) / sum by (policy) (rate(aisix_cache_requests_total[5m]))`。按 `outcome` 拆分可以看出语义层在精确匹配之上贡献了多少。 语义层的失败会退化为普通未命中,仅凭结果计数器无法区分损坏的 embedding 模型或存储与健康的低命中率。对 `aisix_cache_semantic_embedding_failures_total` 和 `aisix_cache_semantic_store_failures_total` 设置告警来区分二者。 ### `aisix_cache_requests_total` 按策略名称和结果统计的缓存合格请求,当匹配的已启用策略与可用后端打开缓存闸门时,每个请求计数一次。 Type: counter. ##### 标签 `policy`, `outcome` ##### `outcome` 的值 `hit_exact`, `hit_semantic`, `miss`, `bypass` `bypass` 表示调用方发送了 `Cache-Control: no-cache`,跳过了读取路径。`no-store` 会保留读取路径,因此记录为普通的命中或未命中,并且只在未命中后禁止写入。 ### `aisix_cache_semantic_embedding_seconds` 语义层 embedding 调用的延迟,按策略统计。无固定桶的摘要系列。 Type: summary. ##### 标签 `policy` ### `aisix_cache_semantic_embedding_failures_total` 语义层的 embedding 失败。失败的请求不经缓存直接发往上游。 Type: counter. ##### 标签 `policy`, `cause` ##### `cause` 的值 `resolve`, `embed` `resolve`(embedding 模型缺失或不是 embedding 模型)按合格请求计数一次,包括随后命中精确层的请求;`embed`(服务提供方调用失败或超时)按 embedding 调用计数。 ### `aisix_cache_semantic_store_failures_total` 语义存储的操作失败,按操作统计。进程内存储不会失败;共享(Redis)存储可能失败。失败退化为普通未命中。 Type: counter. ##### 标签 `policy`, `op` ##### `op` 的值 `lookup`, `store` ### `aisix_redis_failures_total` 对 Redis 后端存储的失败操作,每次操作失��败计数一次。它覆盖所有以 Redis 为后端的子系统——共享限流器、精确响应缓存和语义缓存——因为一套部署通常把它们指向同一个 Redis。1.1.0 及更早版本不发射该指标。 Type: counter. ##### 标签 `operation` ##### `operation` 的值 `ratelimit_acquire`, `ratelimit_commit`, `ratelimit_peek`, `ratelimit_release`, `ratelimit_add_tokens`, `cache_get`, `cache_put`, `semantic_acquire`, `semantic_index`, `semantic_lookup`, `semantic_store` 取值同时标明子系统和具体调用,因此即使限流器与各类缓存共用一个 Redis,也能分辨出是哪个存储在退化。 ##### 行为 这些失败在设计上都是静默降级——共享限流器回退为按副本计数,缓存读取变成未命中——因此该计数器是唯一能反映这种降级的指标。其中大多数同时也会记录日志;只有分离出去的 `ratelimit_release` 和 `ratelimit_add_tokens` 操作没有日志,该计数器是它们唯一的痕迹。 ### 部署指标 监控每个目标模型的表现:上游尝试及其结果、目标之间的回退,以及目标是否仍参与轮转。 统计的是尝试而非请求 这些计数器每次上游\*\*尝试\*\*采样一次,且每个样本归属于被尝试的目标,而不是调用方指定的模型组。一次客户端请求若在三个目标之间故障转移,在这里是三个样本,在[请求指标](#request-metrics)中是一个样本。用本族回答「哪个目标在失败」,用请求族回答「调用方经历了什么」。 只统计真正到达上游的尝试。被网关自行拒绝的尝试——目标超出其自身限流,或其凭据、端点在发送任何内容之前就未通过校验——从未产生上游响应,因此不会出现在这里,但仍会出现在用量日志中。这样配置错误就不会被读成目标不健康。 由通过模型组下发的端点输出:`/v1/chat/completions`、`/v1/messages` 和 `/v1/responses`。其他端点每次请求只调用一个模型,请求指标已经完整描述了它们。 ### `aisix_deployment_requests_total` 下发到某个目标模型的上游尝试次数,不论结果如何。 Type: counter. ##### 标签 `provider`, `model`, `upstream_model`, `provider_key_id` ##### PromQL 示例 ``` sum(rate(aisix_deployment_requests_total[5m])) by (model) ``` ### `aisix_deployment_success_responses_total` 目标模型成功响应的上游尝试次数。 Type: counter. ##### 标签 `provider`, `model`, `upstream_model`, `provider_key_id` ##### 行为 对于流式响应,尝试在上游流建立时即计为成功。此后中断的流不会在这里重新归类。 ### `aisix_deployment_failure_responses_total` 在目标模型处失败的上游尝试次数,包含随后被回退救回的那些失败。 Type: counter. ##### 标签 `provider`, `model`, `upstream_model`, `provider_key_id` ##### PromQL 示例 ``` sum(rate(aisix_deployment_failure_responses_total[5m])) by (model) / sum(rate(aisix_deployment_requests_total[5m])) by (model) ``` ### `aisix_routing_successful_fallbacks_total` 在先前目标失败后,成功处理了该请求的回退尝试次数。 Type: counter. ##### 标签 `model`, `fallback_model` ##### 行为 `model` 是调用方所请求的名称,即模型组名称。`fallback_model` 是网关转向的目标。 ### `aisix_routing_failed_fallbacks_total` 同样失败的回退尝试次数。 Type: counter. ##### 标签 `model`, `fallback_model` ##### 行为 被第二个回退目标救回的请求,会在这里贡献一个样本,同时在成功回退族中贡献一个样本。 ### `aisix_deployment_state` 目标模型是否参与轮转。 Type: gauge. ##### 标签 `provider`, `model`, `upstream_model`, `provider_key_id` ##### `指标值` 的值 `0`, `2` `0` 表示健康。`2` 表示目标因正在冷却或后台健康检查失败而退出轮转。 ### `aisix_deployment_cooled_down_total` 目标模型进入冷却的次数。 Type: counter. ##### 标签 `provider`, `model`, `upstream_model`, `provider_key_id` ### 安全护栏指标 跟踪所有端点上各安全护栏的执行延迟和结果,以及聚合阻断和 fail-open 绕过。 安全护栏执行延迟 每次计时的安全护栏执行都会记录一条 `aisix_guardrail_latency_seconds` 观测。安全护栏通常在每个适用阶段执行一次;流式窗口扫描可以为一条响应记录多次输出执行。该直方图使用可配置的分桶,默认范围为 1 毫秒到 30 秒,因此可通过 `histogram_quantile` 计算各安全护栏的 P50/P95/P99。 `kind` 标签用于区分本地进程内检测(`keyword`、`pii`)和远程审核服务(其他所有种类);`result` 标签用于区分 fail-open 绕过(`bypassed`,失败标签位于 `error_type` 中)与策略决策。fail-closed 的远程故障会显示为 `blocked`,其延迟会集中在配置的服务提供方超时时间附近。 `_count` 序列同时也可用作各安全护栏的执行计数器:`sum by (guardrail, result) (rate(aisix_guardrail_latency_seconds_count[5m]))` 无需单独的计数器即可提供执行率和阻断率。 聚合阻断和绕过计数器与该直方图共用覆盖所有端点的执行路径。它们不包含安全护栏、种类和阶段标签;需要这些维度时,请使用直方图的 `_count` 序列。 ### `aisix_guardrail_latency_seconds` 所有端点中一次计时的安全护栏执行所经历的实际时间。`guardrail` 是配置的安全护栏名称。 Type: histogram. ##### 标签 `env_id`, `guardrail`, `kind`, `phase`, `result`, `error_type` ##### `kind` 的值 `keyword`, `pii`, `aliyun_ai_guardrail`, `aliyun_text_moderation`, `azure_content_safety`, `azure_content_safety_text_moderation`, `bedrock`, `lakera`, `openai_moderation`, `presidio` `keyword` 和 `pii` 在进程内运行(本地检测);其他种类均会调用远程审核服务。 ##### `phase` 的值 `input`, `output` ##### `result` 的值 `allowed`, `blocked`, `masked`, `bypassed`, `would_block`, `would_mask` `bypassed` 表示远程故障采用 fail-open;fail-closed 的远程故障记录为 `blocked`。`would_block`/`would_mask` 来自配置为 `enforcement_mode: monitor` 的安全护栏。 ##### `error_type` 的值 `none`, `aliyun_5xx`, `aliyun_config_error`, `aliyun_throttled`, `aliyun_timeout`, `azure_cs_5xx`, `azure_cs_config_error`, `azure_cs_throttled`, `azure_cs_timeout`, `bedrock_5xx`, `bedrock_throttled`, `bedrock_timeout`, `lakera_5xx`, `lakera_config_error`, `lakera_throttled`, `lakera_timeout`, `openai_moderation_5xx`, `openai_moderation_config_error`, `openai_moderation_throttled`, `openai_moderation_timeout`, `presidio_5xx`, `presidio_config_error`, `presidio_throttled`, `presidio_timeout` 当 `result="bypassed"` 时,设置为有界失败标签(与 `aisix_guardrail_bypasses_total{reason}` 的值相同);其他情况为 `none`。 ##### 行为 默认分桶:0.001、0.0025、0.005、0.01、0.025、0.05、0.1、0.25、0.5、1、2.5、5、10 和 30 秒,可通过 `observability.metrics.buckets.guardrail_latency` 配置。 监控模式执行会在请求继续处理的同时记录 `would_block` / `would_mask`,因此可以在实施策略前评估分阶段策略的规模。 通过同步逐字段操作执行的 PII 和关键词脱敏不会计入该序列;其进程内耗时以微秒计。 ### `aisix_guardrail_blocks_total` 在所有端点上被输入或输出安全护栏强制措施拒绝的请求数,包括安全护栏成员执行前因流式输出缓冲区溢出等原因触发的 fail-closed 路径。 Type: counter. ##### 标签 无。 ### `aisix_guardrail_bypasses_total` 在所有端点上,远程安全护栏不可达时,`fail_open` 允许请求继续处理的计时 fail-open 执行次数。 Type: counter. ##### 标签 `reason` ##### `reason` 的值 `aliyun_5xx`, `aliyun_config_error`, `aliyun_throttled`, `aliyun_timeout`, `azure_cs_5xx`, `azure_cs_config_error`, `azure_cs_throttled`, `azure_cs_timeout`, `bedrock_5xx`, `bedrock_throttled`, `bedrock_timeout`, `lakera_5xx`, `lakera_config_error`, `lakera_throttled`, `lakera_timeout`, `openai_moderation_5xx`, `openai_moderation_config_error`, `openai_moderation_throttled`, `openai_moderation_timeout`, `presidio_5xx`, `presidio_config_error`, `presidio_throttled`, `presidio_timeout` ### A2A 指标 按调用到的 Agent 和调用的操作来度量 Agent-to-Agent 流量。 Agent 与操作标签 `agent` 是已注册的 A2A Agent,`operation` 是调用方实际调用的规范化操作。A2A 0.3 和 1.0 会把同一个操作拼成两种写法,因此 AISIX 记录规范化形式;同时对接两个版本的部署仍然会聚合为同一条序列。无法识别的方法归为 `unknown`。 任务 ID、上下文 ID 和 JSON-RPC 请求 ID 有意不作为标签。正是它们让单次调用可追踪,也正因如此它们不能做标签值;请到用量事件和链路追踪中查找。 `aisix_a2a_requests_total` 与 `aisix_proxy_requests_total{endpoint="/a2a"}` 的数字并不一致,这是有意为之。在 Agent 解析出来之前就被拒绝的调用没有可归属的 Agent,只会计入 proxy 系列;被调用方中途放弃的流在这里是 `4xx`,在那里是 `2xx`,因为响应确实是以 200 开始的。看 Agent 健康度用这个系列,看路由流量用 proxy 系列。 对于流式 A2A,`aisix_proxy_request_duration_seconds` 记录到响应开始为止的时间。对于已下发的调用,`aisix_request_e2e_latency_seconds{endpoint="/a2a"}` 记录 Agent 调用的完整时长,包含完整的流。 ### `aisix_a2a_requests_total` 按调用到的 Agent、调用的规范化操作和状态类别统计的 A2A 调用数。 Type: counter. ##### 标签 `agent`, `operation`, `status` ##### 行为 与用量事件在同一处记录,因此被计入用量的调用一定也被计入指标。 ##### PromQL 示例 ``` sum by (agent, operation) ( rate(aisix_a2a_requests_total{status!="2xx"}[5m]) ) ``` ### `aisix_a2a_ttfb_seconds` 流式 A2A 调用中,上游 Agent 发出首个流式事件的耗时。 Type: histogram. ##### 标签 `agent`, `operation` ##### 行为 之所以按「事件」而非「Token」命名,是因为 Agent 流传输的是任务更新而不是 Token。默认分桶与 `aisix_request_ttft_seconds` 相同,可通过 `observability.metrics.buckets.a2a_ttfb` 配置。 仅在至少产生一个事件的流式操作上记录。 ##### PromQL 示例 ``` histogram_quantile( 0.90, sum by (le, agent) (rate(aisix_a2a_ttfb_seconds_bucket[5m])) ) ``` ### `aisix_a2a_stream_events_total` 流式 A2A 调用中向下游转发的事件数。 Type: counter. ##### 标签 `agent`, `operation` ##### 行为 除以流式操作上的 `aisix_a2a_requests_total`,即为每次调用的事件数——可以看出某个 Agent 有多「话密」,以及这一点是否发生了变化。`message/stream` 和 `tasks/resubscribe` 都是流式操作,分母要同时包含两者,否则比值会偏高。 ##### PromQL 示例 ``` sum by (agent) (rate(aisix_a2a_stream_events_total[5m])) / sum by (agent) ( rate(aisix_a2a_requests_total{operation=~"message/stream|tasks/resubscribe"}[5m]) ) ``` ### `aisix_a2a_task_state_total` 按 Agent 最后上报的任务状态统计的 A2A 调用数,已归一为规范定义的状态集合加 `unknown`。 Type: counter. ##### 标签 `agent`, `state` ##### 行为 这是按每次调用「结束时」的状态累加的计数器,因此应当按速率来读,而不是当作实时积压量:任务后续状态变化不会减少之前的样本,而用 `tasks/get` 轮询同一个任务时每次轮询都会再上报一次状态。上游从未应答的调用不会上报状态,也不计入此指标。 ##### PromQL 示例 ``` sum by (agent, state) (rate(aisix_a2a_task_state_total[5m])) ``` ### 用量事件指标 区分用量事件发送尝试与传递队列未接受的事件。 用量事件传递 每次发送尝试的事件要么被队列接受,要么计为丢弃。从发送尝试速率中减去丢弃速率,即可计算接受速率。 两个计数器携带相同的 `model`、`provider_key_id` 和 `provider_key_name` 标签,因此该减法在按模型、按 Provider Key 的粒度上同样成立。用它来判断哪些队列交接被拒绝了。丢弃速率集中在某个模型或某个 Provider Key 上,说明这部分流量的用量记录从未到达 worker。 被队列接受不等于已传递到存储。worker 接受事件之后,控制面上报仍可能失败(`telemetry batch failed (events dropped)`)。导出器链路则是另一条独立的腿——它由同一个发射点供给,而不是接在 worker 之后——同样可能在重试后丢弃。这两种情况都不会增加 `aisix_usage_event_drops_total`;导出器侧的丢失由 `aisix_otlp_fanout_drops_total` 统计。 `status_code` 标签为 `2xx`、`3xx`、`4xx`、`5xx` 或 `other`,`status` 则在其旁边携带原始 HTTP 状态码——`status` 用于定位单一故障模式,`status_code` 用于按状态族汇总,二者描述的是同一个事件。`handler` 示例值包括 `chat`、`embeddings`、`messages` 和 `mcp`。 `user_id` 是发起请求所用 API Key 所属的组织成员,`user_name` 是该成员的显示名称;API Key 未绑定成员时二者均为 `unknown`。两个计数器都携带这两个标签,因此 `发送尝试 = 已接受 + 已丢弃` 在按成员的粒度上依然成立。由于经 JWT 认证的请求会以其身份解析出的 API Key 运行,一个成员标签即可覆盖该成员使用的全部凭证。名称与 ID 一一对应,因此不会增加新的序列维度。它是控制平面上次投影该 API Key 时写入的名称,而非实时查询结果:此后成员改名,这些指标上仍会沿用旧名称,直到该 API Key 因其他原因被再次写入。 `model` 是调用方请求的模型,并会归一到已配置的模型名称。未能解析出模型的请求报告 `unresolved`;本身就没有模型的请求——MCP 工具调用、A2A 智能体调用、透传路由——报告 `unknown`。凡是未解析出上游 Provider Key 的情况,两个 Provider Key 标签同样为 `unknown`。 MCP 工具调用使用 `handler="mcp"` 和 `inbound_protocol="mcp"`。其用量事件负载会标识 MCP 服务器和工具;Token 与成本字段为零。 A2A 智能体调用使用 `handler="a2a"`。该指标将其有界的 `inbound_protocol` 标签映射为 `other`,而传递的事件使用 `inbound_protocol="a2a"`,并标识智能体名称和 JSON-RPC 方法。网关会根据消息文本估算输入和输出 Token 并置 `usage_estimated: true`,成本字段仍为零。 ### `aisix_usage_events_emitted_total` 用量事件发送尝试,在 AISIX 尝试将事件加入队列前计数,包括被队列接受的事件和被队列拒绝的事件。 Type: counter. ##### 标签 `handler`, `status_code`, `status`, `inbound_protocol`, `upstream_protocol`, `model`, `provider_key_id`, `provider_key_name`, `user_id`, `user_name` ##### `handler` 的值 `a2a`, `audio`, `batch`, `batches`, `chat`, `completions`, `count_tokens`, `embeddings`, `files`, `fine_tuning`, `images`, `mcp`, `messages`, `passthrough_route`, `realtime`, `rerank`, `responses`, `videos` ##### `status_code` 的值 `2xx`, `3xx`, `4xx`, `5xx`, `other` ##### `inbound_protocol` 的值 `openai`, `anthropic`, `mcp`, `other` `other` 包括 A2A、realtime、passthrough,以及三个具名协议分桶以外的所有其他值。 ### `aisix_usage_event_drops_total` 未被队列接受的用量事件。 Type: counter. ##### 标签 `reason`, `model`, `provider_key_id`, `provider_key_name`, `upstream_protocol`, `user_id`, `user_name` ##### `reason` 的值 `sink_disabled`, `sink_full`, `sink_closed` ##### PromQL 示例 ``` sum(rate(aisix_usage_event_drops_total[5m])) by (model, provider_key_name, reason) ``` ### `aisix_otlp_fanout_drops_total` 导出器扇出丢失的遥测记录,按导出器和原因统计。尽管指标名里带 OTLP,它覆盖所有可观测性导出器——OTLP/HTTP、阿里云 SLS、对象存储和 Datadog——因为它们都跑在同一条扇出链路上。按记录数而非批次数计数,因此可以与导出器实际投递的数量直接对比:一个失败的批次丢失多少条记录,取决于它携带了多少条。1.1.0 及更早版本不发射该指标。 Type: counter. ##### 标签 `exporter`, `reason` ##### `reason` 的值 `queue_full`, `worker_stopped`, `retries_exhausted`, `permanent_error` `queue_full` 和 `worker_stopped` 在入队时被拒绝,每次丢失一条记录。`retries_exhausted` 和 `permanent_error` 发生在导出尝试之后,会丢失整个批次。 ##### 行为 `exporter` 是可观测性导出器的配置名称——控制面里的资源,或独立网关资源文件中的对应行。 扇出与用量事件队列是同一发射点上两条互相独立的投递腿,而不是一前一后。两族计数器互不蕴含:同一条记录可能被两者都丢弃、只被其中一条丢弃,或都不丢弃。扇出丢弃不会增加 `aisix_usage_event_drops_total`。 ### `aisix_otlp_fanout_failures_total` 对某个可观测性导出器的失败导出尝试,每次尝试计数一次,包含重试。与丢弃计数器一样,它覆盖所有导出器类型,不只是 OTLP/HTTP。一个总是到第三次尝试才成功的导出器在这里可见,即使它从未丢失记录——这正是它与 `aisix_otlp_fanout_drops_total` 的区别。1.1.0 及更早版本不发射该指标。 Type: counter. ##### 标签 `exporter` ##### 行为 `exporter` 是可观测性导出器的配置名称——控制面里的资源,或独立网关资源文件中的对应行。 ### 配置指标 监控 AISIX 是否能从配置源加载并应用变更。 配置状态 AISIX 在这些指标以及指标和状态监听器的 `GET /status/config` 中反映相同的实时配置状态。 重新加载指标适用于文件和 etcd 配置源。仅当 AISIX 从 etcd 加载配置时,才会公开版本和配置源连接指标。 比较已观测和已应用的版本,以判断网关是否正在使用最新的 etcd 配置。 ### `aisix_config_last_reload_successful` 最近一次配置加载是否成功。 Type: gauge. ##### 标签 无。 ##### `指标值` 的值 `0`, `1` `1` 表示成功,`0` 表示失败。 ### `aisix_config_last_reload_success_timestamp_seconds` 最近一次成功加载配置的 Unix 时间戳(秒)。 Type: gauge. ##### 标签 无。 ##### 行为 在配置成功加载前不会公开该序列。 ### `aisix_config_reloads_total` 完整配置重新加载尝试,包括配置源获取失败。 Type: counter. ##### 标签 无。 ##### 行为 etcd 增量 watch 事件不会增加此计数器。 ### `aisix_config_reload_failures_total` 按原因分组的配置重新加载失败。 Type: counter. ##### 标签 `reason` ##### `reason` 的值 `fetch`, `parse`, `validate` `fetch` 表示无法读取配置源,`parse` 表示配置源数据无效,`validate` 表示资源无效。 ### `aisix_config_rejected_resources` 当前被拒绝的资源数,按资源类型分组。 Type: gauge. ##### 标签 `kind` ##### 行为 某类资源的所有拒绝均清除后,AISIX 会将其现有序列设为 `0`。 ### `aisix_config_partially_compatible_resources` 包含至少一个当前网关版本无法识别字段、但仍在提供服务的资源,按资源类型分组。 Type: gauge. ##### 标签 `kind` ##### 行为 包含多个被忽略字段的资源只计一次。请检查 `GET /status/config` 中的 `partially_compatible`,查看字段路径和各字段计数。 某类资源的所有部分兼容资源均清除后,AISIX 会将其现有序列设为 `0`。 ### `aisix_config_stale_served_resources` 来源中的最新值被拒绝、但最后一个已知良好值仍在提供服务的资源,按资源类型分组。 Type: gauge. ##### 标签 `kind` ##### 行为 请检查 `GET /status/config` 中的 `rejected`,确定每项资源及其开始使用陈旧值提供服务的时间。 某类资源不再使用陈旧值提供服务后,AISIX 会将其现有序列设为 `0`。 ### `aisix_config_observed_revision` 网关观测到的最新 etcd 版本。 Type: gauge. ##### 标签 无。 ### `aisix_config_applied_revision` 网关当前使用的配置所对应的 etcd 版本。 Type: gauge. ##### 标签 无。 ### `aisix_config_hash_info` 已应用配置的哈希值。 Type: gauge. ##### 标签 `hash` ##### `指标值` 的值 `0`, `1` 筛选值 `1` 可选择当前哈希。应用的配置变更后,AISIX 会保留值为 `0` 的旧哈希标签。 ### `aisix_config_source_connected` 网关是否已连接到 etcd 配置源。 Type: gauge. ##### 标签 无。 ##### `指标值` 的值 `0`, `1` `1` 表示已连接,`0` 表示未连接。 ## 使用 PromQL 分析指标[​](#analyze-metrics-with-promql "使用 PromQL 分析指标的直接链接") 配置 Prometheus 表达式浏览器或其他兼容监控界面抓取 AISIX 指标端点后,可使用以下 PromQL 示例。请根据要检查的流量和网关实例调整时间窗口、标签筛选条件和分组维度。 ### 计算成功率[​](#calculate-success-rate "计算成功率的直接链接") 用成功请求速率除以总请求速率可计算成功率。以下查询合并五分钟窗口内的所有模型推理流量: ``` sum(rate(aisix_llm_requests_total{outcome="success"}[5m])) / sum(rate(aisix_llm_requests_total[5m])) ``` 若要单独分析某个 API,请添加 `endpoint` 筛选条件或按 `endpoint` 分组。 若要包括不计为模型推理的流量(MCP 工具调用、A2A Agent 调用、透传路由——endpoint 标签为 `/passthrough_route`——以及文件、批处理和微调路由),请对 `aisix_proxy_requests_total` 运行相同查询。该指标包含所有代理请求。 若只测量主路由路径,请将分子和分母限制为未由回退目标处理的请求: ``` sum(rate(aisix_llm_requests_total{outcome="success", is_fallback="false"}[5m])) / sum(rate(aisix_llm_requests_total{is_fallback="false"}[5m])) ``` 是否将受限流的请求纳入总体取决于运维策略。若要从分母中排除已达到配额的客户端,请使用: ``` sum(rate(aisix_llm_requests_total{outcome="success"}[5m])) / sum(rate(aisix_llm_requests_total{outcome!="rate_limited"}[5m])) ``` ### 区分跨协议转换流量[​](#separate-cross-protocol-conversion-traffic "区分跨协议转换流量的直接链接") 所有详细请求、延迟和 Token 序列都带有两个协议标签:`inbound_protocol` 表示调用方与 AISIX 通信所使用的协议,`upstream_protocol` 表示 AISIX 与实际处理该请求的上游通信所使用的协议。同时按两者分组即可得到一张转换矩阵,其中对角线是原生流量,其余单元格都是 AISIX 转换过的流量: ``` sum by (inbound_protocol, upstream_protocol) (rate(aisix_llm_requests_total[5m])) ``` 协议转换在功能保真度上是有代价的——只存在于协议一侧的特性在另一侧没有对应表达——因此有必要了解有多少流量依赖它。若要单独观察某个方向,同时指定两端即可: ``` # Anthropic 协议调用方,由 OpenAI 形态的上游提供服务 sum(rate(aisix_llm_requests_total{inbound_protocol="anthropic", upstream_protocol="openai"}[5m])) ``` 比较不同上游协议的可靠性,可以区分服务商问题和协议转换问题。若调用方相同而某个协议的成功率明显偏离,说明差异出在上游一侧: ``` sum by (upstream_protocol) (rate(aisix_llm_requests_total{outcome="success"}[5m])) / sum by (upstream_protocol) (rate(aisix_llm_requests_total[5m])) ``` 当请求完全没有选中上游时,`upstream_protocol` 报告 `unknown`——例如模型不存在、被输入安全护栏拦截、被 AISIX Cloud 预算拒绝,或请求体在转发前被拒绝。这些都是真实的失败,因此在计算成功率时应保留在分母中;只有在专门比较各上游时才应排除它们。 请勿改用 `provider` 推导上游协议。`provider` 是开放的厂商字符串,同一厂商可以通过多个适配器接入,而通过 OpenAI 兼容端点接入的自定义厂商使用的是运维人员自行填写的名称。在 PromQL 中手工维护厂商到协议的映射,恰恰会对该标签所要描述的这部分流量给出错误结果。 ### 计算聚合延迟百分位数[​](#calculate-aggregate-latency-percentiles "计算聚合延迟百分位数的直接链接") 计算百分位数前,请跨网关实例合并直方图分桶。P90 表示 90% 的观测值小于或等于该值。请在 `sum by` 分组中保留 `le`;需要细分时,可添加 `model` 或 `provider` 等标签: ``` # 所有匹配网关实例的 P90 端到端延迟 histogram_quantile( 0.90, sum by (le) (rate(aisix_request_e2e_latency_seconds_bucket{status_class="2xx"}[5m])) ) # 各模型的 P90 端到端延迟 histogram_quantile( 0.90, sum by (le, model) (rate(aisix_request_e2e_latency_seconds_bucket{status_class="2xx"}[5m])) ) # 各服务提供方的 P90 首个流式帧延迟 histogram_quantile( 0.90, sum by (le, provider) (rate(aisix_request_ttft_seconds_bucket[5m])) ) ``` 流式端到端时间涵盖完整生成过程,因此流式和非流式请求具有不同的延迟分布。请使用 `streaming` 标签分别分析: ``` # 成功流式请求的 P90 端到端延迟 histogram_quantile( 0.90, sum by (le) (rate(aisix_request_e2e_latency_seconds_bucket{streaming="true", status_class="2xx"}[5m])) ) ``` ### 比较单实例流式延迟[​](#compare-single-instance-streaming-latency "比较单实例流式延迟的直接链接") 摘要序列为每个网关实例公开预先计算的 `quantile` 标签。请选择一个抓取目标以及要检查的模型或服务提供方: ``` # 流式 chat completions 的 P90 首个流式帧延迟 aisix_llm_time_to_first_token_seconds{endpoint="/v1/chat/completions", quantile="0.9"} # 同一批流量的 P90 响应开始延迟 aisix_llm_request_duration_seconds{endpoint="/v1/chat/completions", stream="true", quantile="0.9"} ``` 两条查询都固定了 `endpoint`,因为这两个序列默认覆盖的流量并不相同:首个流式帧延迟在流式 `/v1/chat/completions`、`/v1/messages` 和 `/v1/responses` 上记录,而持续时间序列覆盖所有模型推理端点。不加这个过滤条件,其他模型推理端点的流量可能会影响持续时间 P90,却不会计入 TTFT P90。 `aisix_llm_request_duration_seconds` 在网关把响应交给客户端时记录。流式请求在这一刻还没有读取任何帧,因此该值只覆盖到响应开始为止的处理,不包含整个生成过程。它不是流式流量的端到端指标,加上 `stream="true"` 过滤也不会变成端到端。`aisix_request_duration_seconds` 和 `aisix_proxy_request_duration_seconds` 在同一时刻记录,同样如此。非流式流量上这三者确实覆盖完整请求。 要获取流式请求的端到端延迟,请使用在流结束时记录的 `aisix_request_e2e_latency_seconds`。它是直方图而非摘要,因此请用上文的分位数查询读取,而不是按实例读取。 对于已下发的 A2A 调用,同一直方图使用 `endpoint="/a2a"`,记录 Agent 调用的完整时长。已进入 A2A 统计、但在下发之前被拒绝的调用记录为零时长。对于流式调用,`aisix_proxy_request_duration_seconds` 在响应开始时就停止计时,而该直方图会持续到流结束;被放弃的流在 `4xx` 状态类中记录为 `499`。 不要对跨实例的摘要分位数取平均值。请使用上述直方图查询计算跨网关实例的百分位数。 ### 测量安全护栏延迟和结果[​](#measure-guardrail-latency-and-outcomes "测量安全护栏延迟和结果的直接链接") `aisix_guardrail_latency_seconds` 会为每次计时的安全护栏执行记录一次观测,并使用安全护栏名称、种类、阶段和 `result` 作为标签。安全护栏通常在每个适用阶段执行一次;流式窗口扫描可以在一条响应中多次执行同一个输出安全护栏。同步的逐字段 PII 和关键词脱敏操作不计入该指标。计算各安全护栏执行延迟的 P95,以验证是否符合审核延迟预算: ``` histogram_quantile( 0.95, sum by (le, guardrail) (rate(aisix_guardrail_latency_seconds_bucket[5m])) ) ``` 安全护栏顺序执行,因此它们对请求延迟的总贡献等于该请求所有执行时间之和。计算每个安全护栏和阶段的平均执行时间,并与审核延迟预算比较: ``` sum by (guardrail, phase) (rate(aisix_guardrail_latency_seconds_sum[5m])) / sum by (guardrail, phase) (rate(aisix_guardrail_latency_seconds_count[5m])) ``` 使用 `kind` 标签比较各类安全护栏的执行延迟。`keyword` 和 `pii` 在进程内运行;远程审核类型还包含后端调用的耗时: ``` histogram_quantile( 0.95, sum by (le, kind) (rate(aisix_guardrail_latency_seconds_bucket[5m])) ) ``` `_count` 序列同时也可用作执行计数器。按安全护栏跟踪阻断率和 fail-open 绕过率,并在远程安全护栏开始 fail-open 时发出告警: ``` sum by (guardrail, result) (rate(aisix_guardrail_latency_seconds_count[5m])) # 按失败原因统计 fail-open 绕过 sum by (guardrail, error_type) (rate(aisix_guardrail_latency_seconds_count{result="bypassed"}[5m])) ``` ### 按客户端计算 Token 用量[​](#calculate-token-volume-by-client "按客户端计算 Token 用量的直接链接") 使用 `token_type="total"` 按标准化客户端类型计算包含缓存的 Token 用量: ``` sum by (client_type) (rate(aisix_llm_tokens_by_client_total{token_type="total"}[5m])) ``` 若要比较输入和输出用量,请同时选择两种 Token 类型,并在分组中包含 `token_type`: ``` sum by (client_type, token_type) (rate(aisix_llm_tokens_by_client_total{token_type=~"input|output"}[5m])) ``` ### 按客户端类型和模型细分 Token 用量[​](#break-down-token-volume-by-client-type-and-model "按客户端类型和模型细分 Token 用量的直接链接") `model` 标签记录客户端请求的模型名称,而不是 AISIX 选择的直接模型。按 `client_type` 和 `model` 分组,可以查看各标准化客户端类型如何在不同模型间分配 Token 用量: ``` sum by (client_type, model) (rate(aisix_llm_tokens_by_client_total{token_type="total"}[5m])) ``` 若要检查单个客户端类型,请按 `client_type` 筛选,并仅按模型分组: ``` sum by (model) (rate(aisix_llm_tokens_by_client_total{client_type="claude-code", token_type="total"}[5m])) ``` ### 计算提示词缓存命中率[​](#calculate-prompt-cache-hit-rate "计算提示词缓存命中率的直接链接") 上游服务商会缓存提示词前缀,并对命中缓存的输入按远低于标准价格计费,因此「输入中有多少来自缓存」是判断提示词缓存是否划算的唯一关键数字。AISIX 用三个计数器报告它,而它们之间的拆分正是让查询在不同服务商之间都成立的原因: | 计数器 | 上游的上报方式 | 与 `aisix_llm_input_tokens_total` 的关系 | | --------------------------------------------- | --------------------------- | ---------------------------------------- | | `aisix_llm_cached_input_tokens_total` | 计入提示词 Token 数量之内 | 已包含在其中 | | `aisix_llm_cache_read_input_tokens_total` | 与输入 Token 并列的独立计数 | 在其之外 | | `aisix_llm_cache_creation_input_tokens_total` | 与输入 Token 并列的独立计数 | 在其之外 | 因此请求实际消耗的输入是 `input + cache_read + cache_creation`,其中来自缓存的部分是 `cached + cache_read`。无论服务商采用哪种口径,这两个表达式都成立,因此该命中率在混合部署中也可以横向比较: ``` ( sum(rate(aisix_llm_cached_input_tokens_total[5m])) + sum(rate(aisix_llm_cache_read_input_tokens_total[5m])) ) / ( sum(rate(aisix_llm_input_tokens_total[5m])) + sum(rate(aisix_llm_cache_read_input_tokens_total[5m])) + sum(rate(aisix_llm_cache_creation_input_tokens_total[5m])) ) ``` 给每个 `sum` 都加上 `by (model)`,即可看出哪些工作负载真正受益。前缀稳定的提示词——较长的系统提示词、固定的工具结构、固定的文档——命中率应当稳定在较高水平;每次调用都改写开头的提示词则会一直接近零,是应当优先重构的对象。 缓存写入的单价高于普通输入 Token,缓存读取则低得多,因此写入远多于读取的工作负载是在为一个没人命中的缓存付溢价。对同时上报两者的服务商,可监控该比值: ``` sum by (model) (rate(aisix_llm_cache_creation_input_tokens_total{upstream_protocol=~"anthropic|bedrock"}[5m])) / sum by (model) (rate(aisix_llm_cache_read_input_tokens_total{upstream_protocol=~"anthropic|bedrock"}[5m])) ``` 若该比值在较长窗口内持续明显大于 1,说明缓存条目在被复用之前就已过期。可缩短共享同一前缀的调用之间的间隔,或者干脆不再缓存该提示词。 每个计数器只在取值非零后才创建,因此不报告缓存明细的服务商不会产生任何序列,此时对其求 `sum()` 得到的是空结果而不是 0。若告警需要在出现缓存流量之前就能求值,请用 `or vector(0)` 包裹查询。 这三个计数器描述的是**上游服务商**的提示词缓存。AISIX 响应缓存是另一套机制,由 `aisix_cache_requests_total` 度量,参见[测量响应缓存效果](#measure-response-cache-effectiveness)。 ### 计算支出与单请求成本[​](#calculate-spend-and-cost-per-request "计算支出与单请求成本的直接链接") `aisix_llm_spend_micro_usd_total` 以微美元计数,1 美元等于 1,000,000 微美元。除以 `1e6` 即可换算为美元: ``` # 按团队统计每小时美元支出 sum by (team_id) (rate(aisix_llm_spend_micro_usd_total[5m])) * 3600 / 1e6 # 按最近一天的速率预测 30 天支出 sum(rate(aisix_llm_spend_micro_usd_total[24h])) * 86400 * 30 / 1e6 ``` 由于支出计数器与请求计数器使用相同的标签,单请求平均成本可以直接相除。请对两侧使用相同的分组标签: ``` sum by (model) (rate(aisix_llm_spend_micro_usd_total[5m])) / 1e6 / sum by (model) (rate(aisix_llm_requests_total[5m])) ``` 只有在 AISIX 能解析出请求价格时才会记录支出,而请求计数器会统计所有请求。若部署中存在未配置成本的模型,其流量会计入分母,使平均值偏低。请将两侧都过滤到已配置价格的模型,或逐个模型分别比较,而不要直接读取一个全局数字。 ### 计算单请求 Token 数[​](#calculate-tokens-per-request "计算单请求 Token 数的直接链接") ``` sum by (endpoint, model) (rate(aisix_llm_total_tokens_total[5m])) / sum by (endpoint, model) (rate(aisix_llm_requests_total[5m])) ``` 分组中必须保留 `endpoint`。`/v1/audio/speech` 按输入字符计费,`/v1/videos` 按视频计费,两者都计为请求但不报告 Token;跨端点求和会按这部分流量的占比拉低平均值。 `aisix_llm_total_tokens_total` 是包含缓存的:它包含输入、输出,以及服务商与输入并列上报的缓存读取和缓存写入 Token。这使它成为单请求消耗量的正确分子,同时也是缓存命中率的错误分子——后者请使用[计算提示词缓存命中率](#calculate-prompt-cache-hit-rate)中的查询。 ### 排查用量最高的调用方[​](#rank-the-heaviest-consumers "排查用量最高的调用方的直接链接") Token 与支出计数器带有完整的调用方身份标签,因此用 `topk` 就能定位账单该找谁沟通: ``` # Token 速率最高的十个 API Key topk(10, sum by (api_key_id) (rate(aisix_llm_total_tokens_total[1h]))) # 支出速率最高的十个用户,单位为每小时美元 topk(10, sum by (user_id, user_name) (rate(aisix_llm_spend_micro_usd_total[1h])) * 3600 / 1e6) # 某个团队的支出分布在哪些模型上 sum by (model) (rate(aisix_llm_spend_micro_usd_total{team_id="team-platform"}[1h])) * 3600 / 1e6 ``` `user_name` 和 `provider_key_name` 与各自的 ID 一一对应,因此在分组中加入名称不会增加序列数量。在控制面提供之前,`user_name` 报告 `unknown`。 ### 测量响应缓存效果[​](#measure-response-cache-effectiveness "测量响应缓存效果的直接链接") `aisix_cache_requests_total` 统计的是命中了某个已启用、且后端可用的缓存策略的请求。没有匹配策略的请求完全不计入,因此该指标衡量的是已配置策略的效果,而不是全部流量中被缓存的比例: ``` sum by (policy) (rate(aisix_cache_requests_total{outcome=~"hit_exact|hit_semantic"}[5m])) / sum by (policy) (rate(aisix_cache_requests_total[5m])) ``` 按 `outcome` 拆分即可看出语义层相对精确匹配的额外收益,这也是它所付出的向量嵌入调用是否值得的依据: ``` sum by (policy, outcome) (rate(aisix_cache_requests_total[5m])) ``` 语义层失败会退化为普通未命中,因此向量嵌入模型或存储故障与「命中率本来就低」在结果计数器中完全一样。对失败计数器告警才能区分两者: ``` sum by (policy, cause) (rate(aisix_cache_semantic_embedding_failures_total[5m])) > 0 sum by (policy, op) (rate(aisix_cache_semantic_store_failures_total[5m])) > 0 ``` 该缓存与上游服务商的提示词缓存相互独立,但两者存在一个值得注意的单向影响:命中 AISIX 响应缓存的请求根本不会到达上游,因此不会为服务商缓存计数器贡献任何数据。响应缓存命中率上升会拉低提示词缓存的绝对 Token 速率,但这并不意味着提示词缓存的效果变差了。 ### 测量目标健康度与故障转移[​](#measure-target-health-and-fallback "测量目标健康度与故障转移的直接链接") 请求指标说明调用方经历了什么,部署指标说明是哪个目标造成的。一个成功率看起来很健康的模型组,可能正掩盖着某个持续失败、只是被故障转移一直救回来的目标。把两者放在一起看: ``` # 每个被尝试目标的失败率 sum by (model, upstream_model, provider_key_id) (rate(aisix_deployment_failure_responses_total[5m])) / sum by (model, upstream_model, provider_key_id) (rate(aisix_deployment_requests_total[5m])) # 由故障转移目标提供服务的客户端请求占比 sum(rate(aisix_llm_requests_total{is_fallback="true"}[5m])) / sum(rate(aisix_llm_requests_total[5m])) ``` 故障转移占比上升而成功率保持平稳,正是需要采取行动的信号:调用方仍然得到了服务,而主目标正在其背后劣化。 ``` # 当前已被移出轮转的目标数 count by (model) (aisix_deployment_state == 2) # 目标进入冷却的频率 sum by (model, upstream_model) (rate(aisix_deployment_cooled_down_total[15m])) ``` 部署计数器按每次上游**尝试**采样,因此一个跨三个目标故障转移的客户端请求在这里是三个样本,在请求指标中只有一个样本。不要用一个指标族去除以另一个。 ### 监控限流并诊断预算拒绝[​](#monitor-rate-limits-and-diagnose-budget-denials "监控限流并诊断预算拒绝的直接链接") 以下限流指标适用于所有 AISIX 网关。AISIX Cloud 预算 Gauge 指标描述预算拒绝,并不会持续提供当前支出数据。 被限流拒绝的请求占比来自请求指标族的 `outcome` 标签,它覆盖所有端点: ``` sum(rate(aisix_llm_requests_total{outcome="rate_limited"}[5m])) / sum(rate(aisix_llm_requests_total[5m])) ``` 若要区分请求数限流和 Token 限流,请使用专用计数器的 `scope` 标签: ``` sum by (scope) (rate(aisix_ratelimit_rejections_total[5m])) ``` 当 AISIX Cloud 因阻断型预算超限而拒绝请求时,预算 Gauge 指标会记录拒绝详情。它们使用相同的 `api_key_id`、`team_id`、`user_id` 和 `user_name` 标签,因此可以比较上报的支出与限额: ``` # 上报的支出相对于阻断请求的限额的比例 (aisix_budget_spent_usd / aisix_budget_limit_usd) and on (api_key_id, team_id, user_id) (aisix_budget_details_present == 1) ``` 请务必加上 `aisix_budget_details_present == 1` 这一条件。后续决策不包含预算详情时,**不会**把其他 Gauge 指标置零,它们仍保留上次拒绝时的金额,因此未加保护的比值可能显示陈旧数据。这个标志位用于区分两者。 这些 Gauge 指标无法在 AISIX Cloud 拒绝请求前发出预警,因为它们的值来自拒绝响应。请配置[预算告警与通知](https://docs.apiseven.com/ai-gateway/traffic-controls/budget-alerts.md),在阻断型预算开始拒绝流量前接收阈值通知。 #### 当一把 Key 消失之后[​](#when-a-key-goes-away "当一把 Key 消失之后的直接链接") `aisix_budget_*` 和 `aisix_ratelimit_remaining_*` 只在处理请求的过程中写入,而 Prometheus 序列一旦产生就不会被删除。因此 AISIX 会主动让它们退休:API Key 被删除、或被改绑到其他团队或成员(这会开出一条新序列并让旧的搁浅)之后的数秒内,陈旧的样本会被改写为 `NaN`,`aisix_budget_details_present` 则写为 `0`。 用 `NaN` 而不是 `0` 是有意的。`aisix_ratelimit_remaining_requests 0` 的含义是调用方配额已耗尽,`aisix_budget_remaining_usd 0` 的含义是预算已花完,所以把退休序列置零等于把一个陈旧的读数换成一个错误的读数。`NaN` 与阈值进行 `>`、`<`、`>=` 或 `<=` 比较时,结果都为假,因此使用这些比较运算符的告警不会继续被退休序列触发。有两点需要预先考虑: * 序列本身仍然存在,因此 `absent()` 不会把它报告为缺失。 * 对含有退休序列的指标族做聚合,结果也是 `NaN`——`sum(aisix_budget_spent_usd)` 返回 `NaN` 而不是当前总额。请按某个身份标签分组,或先用 `aisix_budget_details_present == 1` 过滤。上面那几条逐序列的查询不受影响。 `aisix_deployment_state` 不会退休。它只在部署的健康状态发生变化时才写入,所以清空它会让一个活着的模型在下次状态跳变之前完全没有状态可报。因此,一个在冷却期间被删除的模型,会一直被 `count by (model) (aisix_deployment_state == 2)` 计入,直到网关重启。 ### 测量并发与被放弃的请求[​](#measure-concurrency-and-abandoned-requests "测量并发与被放弃的请求的直接链接") `aisix_proxy_in_flight_requests` 是代理上的实时并发量,网关容量应按它来规划,而不是按请求速率: ``` sum by (endpoint, inbound_protocol) (aisix_proxy_in_flight_requests) ``` 在响应头发出之前就断开连接的调用方不会产生正常的请求结果,因此不会出现在请求计数器中;要计算放弃率,必须把它们重新加回分母: ``` sum(rate(aisix_proxy_client_cancelled_requests_total[5m])) / ( sum(rate(aisix_proxy_requests_total[5m])) + sum(rate(aisix_proxy_client_cancelled_requests_total[5m])) ) ``` 放弃通常意味着调用方在等待首个 Token 时失去了耐心。按 `model` 细分,并与同一模型的首 Token 时间对比: ``` sum by (model) (rate(aisix_proxy_client_cancelled_requests_total[5m])) ``` 认证被拒是另一种静默故障模式——密钥轮换或签发方配置错误,往往在有人报障之前很久就会在这里显现: ``` sum by (method, reason) (rate(aisix_auth_decisions_total{result="denied"}[5m])) ``` ### 验证用量事件投递[​](#verify-usage-event-delivery "验证用量事件投递的直接链接") 用量事件是计费和分析的数据来源,因此应单独对事件静默丢失的情况设置告警。每次发送尝试要么被投递队列接受,要么被计为丢弃: ``` sum(rate(aisix_usage_event_drops_total[5m])) / sum(rate(aisix_usage_events_emitted_total[5m])) ``` 两个计数器都带有 `model`、`provider_key_id` 和 `provider_key_name`,因此同样的除法在每个模型、每个 Provider Key 维度上也成立。丢弃率集中在其中某一项,就指明了哪部分流量的用量记录丢失了: ``` sum by (model, provider_key_name, reason) (rate(aisix_usage_event_drops_total[5m])) ``` 队列接受不等于成功写入存储。工作线程接受事件之后,控制面上报和导出器管道仍可能失败,而这两者都不会增加丢弃计数器——这类失败会记录在网关日志中。 ### 对配置问题告警[​](#alert-on-configuration-problems "对配置问题告警的直接链接") 无法加载配置的网关会继续使用上一份可用配置提供服务,因此其表现是「毫无反应」而不是报错。请直接对状态告警: ``` # 最近一次加载失败 aisix_config_last_reload_successful == 0 # 已连续五分钟没有成功加载 time() - aisix_config_last_reload_success_timestamp_seconds > 300 # 网关拒绝的资源,按类型分组 sum by (kind) (aisix_config_rejected_resources) > 0 # 正在提供服务的 etcd 修订版本落后于已观测到的修订版本 aisix_config_observed_revision - aisix_config_applied_revision > 0 ``` `aisix_config_partially_compatible_resources` 是升级顺序的信号:它统计的是携带了当前网关版本无法识别字段的资源,也就是控制面领先数据面一个版本时会产生的情况。它在升级窗口内出现属于预期,数据面升级完成后应当归零: ``` sum by (kind) (aisix_config_partially_compatible_resources) > 0 ``` 以上任一情况的具体资源和字段路径,可在指标监听器的 `GET /status/config` 中查看。 ## 配置指标[​](#configure-metrics "配置指标的直接链接") 在启动时配置自定义客户端分类和直方图分桶边界。变更会在网关重启后生效,并可能改变标签值或分桶序列,因此应同时协调仪表盘、告警和记录规则。 ### 将自定义客户端映射到客户端类型[​](#map-custom-clients-to-a-client-type "将自定义客户端映射到客户端类型的直接链接") AISIX 开箱即用地识别常见 AI 编程客户端和 SDK。若要对内部工具进行分类,或将被内置规则归入 `node` 等通用类别的客户端重新分类,请在网关配置中定义映射规则: config.yaml ``` observability: metrics: client_type_rules: - pattern: "^billing-batcher/" client: billing-batcher - pattern: "internal-eval-harness" client: eval-harness ``` 每条规则将正则表达式映射到固定的 `client` 值,AISIX 将其作为 `client_type` 标签公开。规则会在内置规则之前按顺序与原始 `User-Agent` 请求头匹配,首个匹配项生效。匹配不区分大小写且默认不锚定;需要前缀匹配时,请使用 `^` 锚定模式。 标签使用 `client` 值,而不是请求的 `User-Agent`,因此无论客户端发送什么内容,标签集合都保持有界。配置限制进一步保证这一点:最多 64 条规则,模式最长 512 字节,`client` 值最长 64 个字符且必须匹配 `[a-z0-9][a-z0-9._-]*`。AISIX 会在启动时验证规则,遇到无效规则时拒绝启动;变更在重启后生效。 `User-Agent` 为空的请求始终报告为 `unknown`;未匹配任何规则的请求会继续使用内置分类。 ### 自定义直方图分桶[​](#customize-histogram-buckets "自定义直方图分桶的直接链接") 以下四个指标是带有 `le` 分桶边界的 Prometheus 直方图。由于各自分布不同,每个指标都有自己的默认边界: | 指标 | 默认边界(秒) | | ----------------------------------- | --------------------------------------------------------------------------------- | | `aisix_request_e2e_latency_seconds` | 0.005、0.01、0.025、0.05、0.1、0.25、0.5、1、2、5、10、30、60、120、300、420、600 | | `aisix_request_ttft_seconds` | 0.05、0.1、0.25、0.5、1、2、5、10、30、60、120、300 | | `aisix_guardrail_latency_seconds` | 0.001、0.0025、0.005、0.01、0.025、0.05、0.1、0.25、0.5、1、2.5、5、10、30 | | `aisix_a2a_ttfb_seconds` | 0.05、0.1、0.25、0.5、1、2、5、10、30、60、120、300 | 端到端延迟包括缓存命中和分发前被拒绝的请求,因此需要毫秒级边界。首个 Token 时间(TTFT)在上游流式输出的首个帧到达时记录,无论帧内容为何;使用托管服务提供方时,低于 50 毫秒的分桶通常为空。安全护栏指标既需要覆盖快速的进程内检查,也需要覆盖远程审核服务,因此同时使用较低和较高的边界。A2A Agent 发出首个流式事件的耗时默认沿用 TTFT 的边界,但使用独立的 `a2a_ttfb` 覆盖项,因为 Agent 任务可能思考几分钟才开口。 如果流量具有不同的分布,可以分别覆盖每个指标的边界。例如,与网关位于同一节点的 vLLM 或 Ollama 模型服务器可能在几毫秒内生成首个输出: config.yaml ``` observability: metrics: buckets: request_ttft: [0.005, 0.01, 0.025, 0.05, 0.1, 0.5, 1, 5, 30] ``` 每个字段均为可选,并且只替换其对应指标的边界;未指定的指标保留默认值。提供的列表必须包含 1–64 个有限、正数且严格递增的边界。不要列出 `+Inf`,AISIX 会自行添加该分桶。AISIX 会在启动时验证配置,遇到无效列表时拒绝启动;变更会在重启后生效。 每个边界都会为每组标签组合增加一个 `_bucket` 时间序列,因此列表越长,采集器需要存储的序列就越多。 对于使用 AISIX Helm Chart 部署的网关,请通过 `extraEnvVars` 提供逗号分隔的列表: ``` extraEnvVars: - name: AISIX_OBSERVABILITY__METRICS__BUCKETS__REQUEST_TTFT value: "0.005,0.01,0.025,0.05,0.1,0.5,1,5,30" ``` 警告 修改边界会改变输出的 `_bucket` 序列。选择已移除 `le` 值的仪表盘或记录规则将不再匹配。不要比较变更前后由分桶计算的分位数。 有关 Helm 配置模式,请参阅[设置其他网关配置](https://docs.apiseven.com/ai-gateway/cloud/kubernetes.md#set-any-other-gateway-configuration)。 --- # On-Premises 配置 On-Premises 部署可通过 Docker Compose `.env` 文件或 Helm 配置值进行配置,具体取决于控制面的安装方式。 需要查看或自定义生成的部署配置时,请结合 [On-Premises 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md) 阅读本参考。 这些设置用于配置私有化控制面部署包,与 AISIX 网关运行时环境变量不同。网关运行时变量请参见[环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 ## Docker Compose 环境变量[​](#docker-compose-环境变量 "Docker Compose 环境变量的直接链接") Docker Compose 部署包会从 `./aisix-self-hosted/.env` 读取环境变量。快速开始脚本和离线包会在首次启动时生成该文件。请将它与数据库一同备份:其中包含数据库密码和主密钥,后续发布的部署包归档中不会包含该文件。 在常规的原地升级中,`run.sh` 会更新 `AISIX_VERSION`,使其与解压后的部署包一致。`.env` 中的其他设置和密钥会保留。 请在 `./aisix-self-hosted` 目录中运行本页的 Docker Compose 命令。 ### 镜像和发布版本[​](#镜像和发布版本 "镜像和发布版本的直接链接") | 变量 | 作用 | | ---------------------- | ------------------------------------------------------------------------------------------------------------- | | `AISIX_VERSION` | 部署包拥有的镜像发布版本标签;除非设置了单独的镜像覆盖项,否则各镜像使用此标签。`run.sh` 会在升级时更新该值。 | | `AISIX_API_IMAGE` | `cp-api` 的可选镜像覆盖项。 | | `AISIX_DPM_IMAGE` | `dp-manager` 的可选镜像覆盖项。 | | `AISIX_UI_IMAGE` | 控制台的可选镜像覆盖项。 | | `AISIX_CLOUD_DP_IMAGE` | 生成网关安装片段时使用的可选 AISIX 网关镜像覆盖项。 | 单独设置的镜像覆盖项会在部署包升级后继续生效。 ### 数据库[​](#数据库 "数据库的直接链接") | 变量 | 作用 | | ------------------- | ------------------------------------------------------------------------------------- | | `POSTGRES_USER` | 随包 PostgreSQL 使用的用户名。 | | `POSTGRES_PASSWORD` | 随包 PostgreSQL 使用的密码。请使用强且 URL 安全的值,因为它会嵌入 `postgres://` URL。 | | `POSTGRES_DB` | PostgreSQL 数据库名称。 | 这些变量仅配置随包提供的 PostgreSQL 服务。部署包不会在 `.env` 中提供外部数据库 URL 覆盖项。控制面必须连接外部 PostgreSQL 数据库时,请使用 [Helm 安装](https://docs.apiseven.com/ai-gateway/on-premises/deployment.md#helm-on-kubernetes)。 ### 密钥[​](#密钥 "密钥的直接链接") | 变量 | 作用 | | --------------------------- | ----------------------------------------------------------------------------- | | `AISIX_CLOUD_MASTER_KEY` | Base64 编码的 32 字节 AES 密钥,用于信封加密。`dp-manager` 也会使用同一个值。 | | `AISIX_CLOUD_MASTER_KEY_ID` | 与加密数据一起存储的标识,用于让控制面识别包装密钥。 | | `BETTER_AUTH_SECRET` | 控制台身份认证的会话签名密钥。 | 除非正在执行主密钥轮换流程,否则不要修改已有部署中的 `AISIX_CLOUD_MASTER_KEY`。如果修改时没有保留旧密钥,已加密数据可能无法读取。 ### 恢复缺失的 CA 根证书[​](#恢复缺失的-ca-根证书 "恢复缺失的 CA 根证书的直接链接") 警告 仅当 `cp-api` 或 `dp-manager` 因 `ca_root row missing but dp_certificates has rows` 错误而拒绝启动,并且已经确认控制面连接的是预期数据库时,才使用此恢复覆盖项。生成新的根 CA 会使所有现有网关 mTLS 链失效,无法恢复丢失的根证书。 如果无法从完整数据库备份中恢复缺失的根证书,并且确定要替换它,请将以下设置添加到 `.env`: ``` AISIX_CLOUD_ALLOW_FRESH_BOOTSTRAP=1 ``` 重新创建两个服务,使任一进程都能引导生成替代 CA: ``` docker compose up -d --wait api dpm ``` 两个服务都健康后,从 `.env` 中删除 `AISIX_CLOUD_ALLOW_FRESH_BOOTSTRAP`,再运行同一命令,以不带覆盖项的方式重新创建服务。两个服务再次恢复健康后,请[重新注册每个 AISIX 网关](https://docs.apiseven.com/ai-gateway/cloud/connect-a-gateway.md);由缺失根证书签发的证书将无法再通过身份验证。 ### 运行时 URL[​](#运行时-url "运行时 URL的直接链接") | 变量 | 作用 | | ----------------------------- | ------------------------------------------------------------------------------------------ | | `AISIX_CLOUD_PUBLIC_BASE_URL` | 面向浏览器的控制面源站,例如 `https://aisix.example.com`。登录时会根据该值校验会话签发方。 | | `AISIX_CLOUD_DPMGR_BASE_URL` | AISIX 网关主机可访问的 `dp-manager` mTLS 端点,可以是 DNS 名称或 IP 地址。 | | `AISIX_CLOUD_DASHBOARD_URL` | `cp-api` 使用的内部控制台 URL。Compose 默认指向 dashboard 服务。 | | `AISIX_TRUSTED_ORIGINS` | 允许登录的其他浏览器源站,以逗号分隔。公共基础 URL 及其回环对应地址会自动受信任。 | 在将部署暴露到本地主机或容器网络之外前,请设置 `AISIX_CLOUD_PUBLIC_BASE_URL` 和 `AISIX_CLOUD_DPMGR_BASE_URL`。 Compose 还会把 `AISIX_CLOUD_DPMGR_BASE_URL` 传递给 `dpm` 服务,因为 `dp-manager` 会为该主机签发 TLS 服务器证书。修改后请重新创建 `api` 和 `dpm`。 ### 价格目录[​](#pricing-catalog "价格目录的直接链接") 打包的 Docker Compose 文件默认以离线定价模式运行 `cp-api`。它在 `api` 服务上把 `AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH` 设置为 `cp-api` 镜像内置的快照,使控制面无需访问 `models.dev` 即可初始化模型价格。 部署包通过 `.env` 暴露定价模式: | 变量 | 作用 | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | `AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH` | 值为快照路径时选择离线模式。未设置该变量时,Compose 使用镜像内置快照;显式设置为空值时选择在线模式。 | | `AISIX_CLOUD_PRICESYNC_URL` | 在在线模式下覆盖 `models.dev` 目录 URL,例如改用内部镜像。值为空时,在线模式使用 `https://models.dev/api.json`。 | 如需使用在线定价,请在部署目录的 `.env` 中添加空的快照路径赋值。只有需要改用其他目录端点时才添加 URL: ``` AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH= ``` 修改任一设置后,重新创建 `cp-api`: ``` docker compose up -d api ``` 请将这些覆盖项保留在 `.env` 中,而不是写入 `docker-compose.yaml`,因为解压后续部署包时会替换 Compose 文件。 ### 私有网络访问[​](#私有网络访问 "私有网络访问的直接链接") 默认情况下,如果目标解析到私有、内部或回环地址,`cp-api` 会拒绝以下出站连接。仅为受信任且 `cp-api` 可以访问的网络中的服务启用必要权限。 | 变量 | 作用 | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AISIX_PLAYGROUND_ALLOW_PRIVATE_IPS` | 设置为 `1` 时,允许控制台 Playground 访问私有、内部或回环地址上的 LLM 端点。该项默认关闭,用作 SSRF 防护;仅在自托管模型位于内网时启用。参见 [Playground](https://docs.apiseven.com/ai-gateway/cloud/playground.md#reach-private-network-endpoints-on-premises)。 | | `AISIX_CLOUD_NOTIFY_ALLOW_PRIVATE_URLS` | 设置为 `true` 时,允许预算通知访问私有 Webhook 接收器或 Slack 代理。 | | `AISIX_CLOUD_MCP_SPEC_ALLOW_PRIVATE_URLS` | 设置为 `true` 时,允许控制面从私有 `spec_url` 获取 MCP 服务器的 OpenAPI 文档。如果文档位于私有 URL 且此设置保持关闭,请改为提供 `spec_content`。 | 在 `.env` 中设置所需变量,然后重新创建 `cp-api`: ``` docker compose up -d api ``` ### 控制台和端口[​](#控制台和端口 "控制台和端口的直接链接") | 变量 | 作用 | | ------------------------ | --------------------------------------------- | | `AISIX_DASHBOARD_LOCALE` | 部署使用的控制台语言。支持值为 `en` 和 `zh`。 | | `POSTGRES_HOST_PORT` | 随包 PostgreSQL 的宿主机端口绑定。 | | `API_HOST_PORT` | `cp-api` 和控制台反向代理的宿主机端口绑定。 | | `DPM_HOST_PORT` | `dp-manager` 的宿主机端口绑定。 | 如果某个服务只应绑定到回环地址,请在宿主机端口前添加 `127.0.0.1:`。 ## Helm 配置值[​](#helm-values "Helm 配置值的直接链接") `api7/aisix-cp` Chart 使用 Helm 配置值,而不是 Compose `.env` 文件。查看或安装 Chart 前,请先添加 API7 Helm 仓库: ``` helm repo add api7 https://charts.api7.ai helm repo update ``` 查看所有 Chart 配置值: ``` helm show values api7/aisix-cp --version 1.2.0 ``` Chart 源码和软件包发布在 [`aisix-cp-1.2.0` Helm Chart Release](https://github.com/api7/api7-helm-chart/releases/tag/aisix-cp-1.2.0) 中。 ### 镜像和服务[​](#镜像和服务 "镜像和服务的直接链接") | Helm 配置项 | 作用 | | -------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `api.image.repository`, `api.image.tag` | `cp-api` 镜像。 | | `dpm.image.repository`, `dpm.image.tag` | `dp-manager` 镜像。 | | `ui.image.repository`, `ui.image.tag` | 控制台镜像。 | | `api.replicaCount`, `dpm.replicaCount`, `ui.replicaCount` | 每个控制面组件的副本数。 | | `api.affinity`, `dpm.affinity`, `ui.affinity` | 用于将副本分散到不同节点或故障域的 Kubernetes 调度规则。 | | `api.nodeSelector`, `dpm.nodeSelector`, `ui.nodeSelector` | 每个控制面组件的节点标签约束。 | | `api.tolerations`, `dpm.tolerations`, `ui.tolerations` | 每个控制面组件的 Kubernetes 污点容忍配置。 | | `api.service.type`, `api.service.port`, `api.service.nodePort` | `cp-api` 的 Kubernetes Service 设置。直接通过 NodePort 连接时使用明文 HTTP。 | | `dpm.service.type`, `dpm.service.port`, `dpm.service.nodePort` | `dp-manager` mTLS 端点的 Kubernetes Service 设置。 | | `ui.service.type`, `ui.service.port`, `ui.service.nodePort` | 位于 `cp-api` 后方的控制台服务设置。直接通过 NodePort 连接时使用明文 HTTP。 | 只有对应 Service 类型为 `NodePort` 时,Chart 才会渲染已配置的 `nodePort`。将该值留空可让 Kubernetes 动态分配端口。对于其他 Service 类型,Chart 会忽略该值。 运维人员通常通过 `cp-api` 访问控制台,由 `cp-api` 将控制台流量代理到 UI Service。不要把 UI NodePort 用作独立的控制台入口。如果外部同源代理将其用作上游,请将控制台页面路由到 UI Service,并将 `/api/*` 请求路由到 `cp-api`。除非该代理仅在可信私有网络中运行,否则请在代理上终止 TLS。 ### 控制面 URL[​](#控制面-url "控制面 URL的直接链接") | Helm 配置项 | 作用 | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `api.publicBaseURL` | 面向浏览器的控制面源站。当 `cp-api` 使用 NodePort 时,请将其设为该端口上外部可访问的源站,或前置 TLS 反向代理的源站。 | | `api.dpmgrBaseURL` | AISIX 网关主机可访问的 `dp-manager` mTLS 端点,可以是 DNS 名称或 IP 地址。当 `dp-manager` 使用 NodePort 时,请将其设为外部可访问的 HTTPS 端点。Chart 也会把该值传递给 `dp-manager` Deployment,后者会为该主机签发 TLS 服务器证书。 | | `api.dpImage` | 生成 AISIX Cloud 网关安装片段时展示的 AISIX 网关镜像。 | ### Playground[​](#playground "Playground的直接链接") | Helm 配置项 | 作用 | | ------------------------------- | ----------------------------------------------------------------------------------------------- | | `api.playgroundAllowPrivateIPs` | 允许控制台 Playground 访问私有、内部或回环地址上的 LLM 端点。默认值为 `false`,用作 SSRF 防护。 | ### 通知目标[​](#通知目标 "通知目标的直接链接") | Helm 配置项 | 作用 | | ---------------------------- | ------------------------------------------------------------------------------------ | | `api.notifyAllowPrivateURLs` | 允许 `cp-api` 向私有、内部或回环地址发送预算通知。默认值为 `false`,用作 SSRF 防护。 | ### 密钥[​](#密钥-1 "密钥的直接链接") | Helm 配置项 | 作用 | | -------------------------- | ---------------------------------------------------- | | `secrets.masterKey` | Base64 编码的 32 字节 AES 密钥,用于信封加密。 | | `secrets.masterKeyID` | 与加密数据一起存储的标识,用于让控制面识别包装密钥。 | | `secrets.betterAuthSecret` | 控制台身份认证的会话签名密钥。 | 安装前请替换 Chart 中的占位密钥。Chart 会拒绝占位密钥值。 ### PostgreSQL[​](#postgresql "PostgreSQL的直接链接") | Helm 配置项 | 作用 | | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | `postgresql.builtin` | 设置为 `true` 时部署随包 PostgreSQL Chart。 | | `postgresql.auth.password` | 随包 Chart 所配置 PostgreSQL 用户的密码。即使应用使用 `postgres` 用户连接,Chart 也要求提供非占位值。 | | `postgresql.auth.postgresPassword` | PostgreSQL 超级用户密码。Chart 默认使用该密码建立控制面连接。 | | `postgresql.auth.usePostgresUserForAppConnections` | 控制面连接使用 `postgres` 用户,默认值为 `true`。 | | `postgresql.auth.existingSecret` | 用于随包 PostgreSQL 凭证的已有 Kubernetes Secret。 | | `externalDatabase.*` | 当 `postgresql.builtin=false` 时,用于已有 PostgreSQL 数据库的顶层配置值。 | 请使用 URL 安全的 PostgreSQL 密码,例如 `openssl rand -hex 24` 生成的值,因为 Chart 会根据配置的凭证构造 `postgres://` 连接 URL。 ### 控制台的私有 PostgreSQL CA[​](#private-postgresql-ca-for-the-dashboard "控制台的私有 PostgreSQL CA的直接链接") 从 `aisix-cp` chart **1.2.1**(应用版本 **1.2.0**)开始,可通过 `ui.extraVolumes` 和 `ui.extraVolumeMounts` 为控制台挂载私有数据库 CA。两者默认为空列表,配置的内容会追加到内置 Next.js 缓存卷和挂载之后。 如果外部 PostgreSQL 使用私有 CA,控制台的 Node.js 客户端必须信任该 CA。否则,即使控制台页面能够加载,注册和登录仍可能因 `SELF_SIGNED_CERT_IN_CHAIN` 而失败。 在控制台所在命名空间创建 ConfigMap,存放 PEM 格式的公开 CA 证书。以下示例的 release 和命名空间均为 `aisix-cp`,请替换为实际部署名称: ``` kubectl create configmap aisix-postgres-ca \ --namespace aisix-cp --from-file=ca.crt=./ca.crt ``` 将以下设置合并到现有 Helm values 文件中,保留数据库配置及三个 `ui` 列表中已有的条目: ``` ui: extraEnvVars: - name: NODE_EXTRA_CA_CERTS value: /etc/aisix/postgres-ca/ca.crt extraVolumes: - name: postgres-ca configMap: name: aisix-postgres-ca items: - key: ca.crt path: ca.crt extraVolumeMounts: - name: postgres-ca mountPath: /etc/aisix/postgres-ca readOnly: true ``` 使用 Secret 时,将 `configMap` 块替换为: ``` secret: secretName: aisix-postgres-ca items: - key: ca.crt path: ca.crt ``` 该 Secret 也必须位于同一命名空间。这里只需要公开 CA 证书,CA 私钥应保留在证书签发方。卷名和挂载路径必须唯一,内置缓存使用的 `next-cache` 和 `/app/.next/cache` 应予以保留。这些设置仅影响控制台;其他控制面组件的数据库 TLS 配置需按实际情况单独设置。 使用支持这些字段的 chart 版本应用 values,并保持 PostgreSQL TLS 证书验证开启。将证书资源和 values 纳入部署配置源,确保后续 GitOps 同步保留挂载。 更新或轮换 CA 后,需要重启控制台,让 Node.js 重新加载 `NODE_EXTRA_CA_CERTS`。外部 ConfigMap 或 Secret 变化时,chart 不会自动重启 Pod: ``` kubectl rollout restart deployment/aisix-cp-ui --namespace aisix-cp kubectl rollout status deployment/aisix-cp-ui --namespace aisix-cp ``` ### 控制台语言[​](#控制台语言 "控制台语言的直接链接") | Helm 配置项 | 作用 | | ------------------ | --------------------------------------------- | | `ui.defaultLocale` | 部署使用的控制台语言。支持值为 `en` 和 `zh`。 | --- # 端口参考 使用本参考为 AISIX 网关和 AISIX Cloud 控制面组件规划防火墙规则、安全组、Kubernetes Service 和负载均衡器。 下表会区分默认值、必填值和示例值。如果已部署的启动配置、Kubernetes Service 或生成的 AISIX Cloud 安装说明与示例不同,请以已部署环境中的值为准。 任何部署都应先查看网关端口。如果网关连接到 AISIX Cloud,还需要查看 [AISIX Cloud 网关连接](#aisix-cloud-gateway-connectivity)。对于本地部署,还需要查看[本地部署控制面端口](#on-premises-control-plane-ports)。 ## AISIX 网关端口[​](#aisix-gateway-ports "AISIX 网关端口的直接链接") 每个 AISIX 网关都通过代理监听器提供调用方流量。使用 etcd 或 AISIX Cloud 作为资源来源时,网关只有在应用第一个配置之后才会绑定该监听器,在那之前端口处于关闭状态,参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。开源 AISIX 网关还可以绑定 Admin 监听器;连接到 AISIX Cloud 的网关不会绑定该监听器。出站要求取决于网关的配置来源和已配置的运行时目标。 | 监听器或连接 | 配置 | 地址或端口行为 | 流量和作用 | 暴露范围 | | -------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | 代理监听器 | `proxy.addr` | 必填;示例配置使用 `0.0.0.0:3000`。使用 etcd 或 AISIX Cloud 作为资源来源时,网关应用第一个配置之前不会绑定。 | 面向调用方的 AI API,以及 `/livez` 和 `/readyz` 健康检查路由的入站流量。 | 仅暴露给预期调用方,或暴露给网关前置的入口层。 | | Admin 监听器 | `admin.addr` | 默认为无法使用的地址 `127.0.0.1:0`;示例配置使用 `127.0.0.1:3001`。 | 开源网关的入站流量,用于只读[网关 Admin API](https://docs.apiseven.com/ai-gateway/reference/admin-api)、其 OpenAPI 文档和 Scalar UI、Playground 以及健康检查路由。 | 保持私有或绑定到回环地址。经过身份认证的资源读取可能返回敏感配置,而健康检查和 OpenAPI 发现路由无需身份认证。连接到 AISIX Cloud 时不会绑定此监听器。 | | 指标和状态监听器 | `observability.metrics.prometheus.addr` | 启用 Prometheus 指标时,默认为 `0.0.0.0:9090`。 | 提供已配置 Prometheus 路径以及 `/status/config`、`/status/ready` 和 `/status/models` 的入站流量。 | 仅对 Prometheus 和运维系统开放。这些路由不需要应用身份认证。 | | etcd | `etcd.endpoints` | 无默认值;外部 etcd 通常使用客户端端口 `2379`。 | 从 etcd 加载动态资源的开源网关发出的出站流量。 | 仅对 AISIX 和管理网关配置的系统开放 etcd。使用资源文件时不使用此连接。 | | AISIX Cloud 管理连接 | `managed.cp_base_url` | 无默认值;未显式指定端口的 HTTPS URL 使用 `443`。 | 用于注册、心跳、遥测、预算检查和证书轮换的出站流量。 | 允许网关向配置的端点发起连接。控制面不会主动连接网关主机。 | | AISIX Cloud 配置存储 | `managed.cp_etcd_endpoint` | 未设置时,网关使用 `managed.cp_base_url` 中的主机和端口。 | 到可选独立 AISIX Cloud 配置存储的出站连接。 | 只有生成的安装配置提供该端点时才允许配置的端口。 | 运行时目标没有统一的默认端口。构建出站白名单时,请允许网关启动配置或资源配置中指定的每个端点,包括模型服务提供方、安全护栏服务、MCP 服务器、A2A Agent、OIDC 签发者、Redis 后端和遥测导出器。 ## 配置 AISIX 网关端口[​](#configure-listener-ports "配置 AISIX 网关端口的直接链接") 启动配置定义网关监听器端口;对于使用 etcd 的开源网关,还会定义外部 etcd 端点。连接到 AISIX Cloud 的网关应使用生成的安装说明中的管理端点;请参阅 [AISIX Cloud 网关连接](#aisix-cloud-gateway-connectivity)。 使用 `proxy.addr` 设置代理监听端口: ``` proxy: addr: "0.0.0.0:3000" ``` 启动配置必须包含代理监听地址。无论使用哪种资源来源,该地址都会在启动阶段检查——网关会先绑定一次该地址随即释放,并加载 `proxy.tls` 证书材料——因此此时端口已被占用,或证书文件不可读,都是启动失败,而不会推迟到后面某个时刻。等待期间网关并不持有该地址,因此如果端口在等待期间被别的程序占用,仍会在真正绑定时失败。监听器本身在使用资源文件时立即绑定,使用 etcd 或 AISIX Cloud 时则只有在应用第一个配置之后才绑定,参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 对于开源网关,`admin.enabled` 默认为 `true`。要公开只读网关 Admin API,请将无法使用的默认 `admin.addr` 值 `127.0.0.1:0` 替换为私有地址或回环地址,并至少配置一个 `admin.admin_keys` 值。将 `admin.enabled` 设置为 `false` 可禁用该监听器。无论这些设置为何,连接到 AISIX Cloud 的网关都不会绑定此监听器。 如需修改专用指标和状态监听器地址,请设置 `observability.metrics.prometheus.addr`。启用 Prometheus 指标时,该监听器会运行并默认使用 `0.0.0.0:9090`: ``` observability: metrics: prometheus: enabled: true path: "/metrics" addr: "0.0.0.0:9090" ``` 指标/状态监听器还会提供 `/status/config`、`/status/ready` 和 `/status/models`。这些运维路由无需认证。请将监听器绑定到私有接口,或通过网络策略或防火墙规则限制访问。 对于使用 etcd 的开源网关,请为每个端点配置实际客户端端口: ``` etcd: endpoints: - "https://etcd.internal.example:2379" ``` 当 etcd 连接跨越主机或网络信任边界时,请使用 mTLS。请参阅 [TLS 和 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md#configure-etcd-mtls)。 ## AISIX Cloud 网关连接[​](#aisix-cloud-gateway-connectivity "AISIX Cloud 网关连接的直接链接") 网关会主动发起到 AISIX Cloud 的所有管理连接。控制面不会主动连接网关主机,调用方的实时流量也不会经过控制面。 在混合云模式下,控制面由 API7 托管,因此运维人员无需部署控制面服务。请允许每个网关向生成的安装说明中指定的管理端点和配置存储端点建立出站 TCP 连接。不要创建从控制面到网关的入站防火墙规则。 在本地部署模式下,网关通过 mTLS 连接 `dp-manager` 端点。请确保每个网关主机或集群都能访问该端点。Docker Compose 使用 `AISIX_CLOUD_DPMGR_BASE_URL`,Helm 使用 `api.dpmgrBaseURL` 设置网关可访问的地址。控制面会把该地址写入生成的网关安装说明,并使用其主机名签发 `dp-manager` 服务器证书。 ## 本地部署控制面端口[​](#on-premises-control-plane-ports "本地部署控制面端口的直接链接") 在本地部署环境中,浏览器和 Admin API 流量使用的入口与网关管理流量不同。请将控制台内部流量和数据库流量保留在部署网络内。 | 默认端口 | 组件 | 作用 | 暴露范围 | | -------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | `8080` | `cp-api` | 面向浏览器的控制台入口和 AISIX Cloud Admin API。`cp-api` 会将控制台请求反向代理到内部控制台服务。 | 通过预期的控制面 Origin 暴露。生产环境使用终止 TLS 的反向代理或负载均衡器。 | | `7944` | `dp-manager` | 网关用于注册、配置投递、心跳、遥测和预算检查的 mTLS 端点。HTTPS API 和配置存储协议共享该端口。 | 仅暴露给运行 AISIX 网关的网络。保持到 `dp-manager` 的端到端 TLS。 | | `3000` | 控制台 | `cp-api` 访问的内部控制台服务。它与同样默认使用 `3000` 的网关代理监听器不同。 | 不要直接公开。 | | `5432` | PostgreSQL | `cp-api`、`dp-manager` 和控制台发往数据库的流量。 | 仅对控制面服务和数据库管理员开放。 | | `7946` | `dp-manager` 健康检查服务器 | 明文 HTTP `/healthz` 监听器。默认 Helm 部署将其用于 Kubernetes Probe;Docker Compose 不发布该端口。它不属于 `dp-manager` Service。 | 保留在 Pod 或容器网络内。不要暴露给网关或运维网络。 | ### 控制面出站流量[​](#control-plane-egress "控制面出站流量的直接链接") 部分控制面功能会从 `cp-api` 发起出站连接。端口来自已配置的目标 URL,而不是固定的 AISIX 默认值。 | 目标 | 何时需要 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------- | | 已配置的 LLM 端点 | 控制台 Playground 和语义路由测试请求。 | | 已配置的 Webhook 或 Slack 目标 | 投递预算通知。 | | `https://models.dev/api.json` 或 `AISIX_CLOUD_PRICESYNC_URL` | 在线模型价格同步。随包提供的 Docker Compose 部署默认使用离线快照,不需要此连接。 | 对于默认拒绝的出站策略,请允许每项已启用功能的目标端口。HTTP 和 HTTPS URL 未指定端口时分别使用 `80` 和 `443`。 ### Docker Compose 端口映射[​](#docker-compose-port-mappings "Docker Compose 端口映射的直接链接") Docker Compose 会在主机上发布以下容器端口。更改主机端口绑定不会改变相应的容器端口。 | 变量 | 默认主机绑定 | 容器端口 | | -------------------- | ---------------- | -------- | | `API_HOST_PORT` | `8080` | `8080` | | `DPM_HOST_PORT` | `7944` | `7944` | | `POSTGRES_HOST_PORT` | `127.0.0.1:5432` | `5432` | 默认的 `API_HOST_PORT` 和 `DPM_HOST_PORT` 值会绑定主机所有网络接口。要把仅本地使用的部署限制在回环地址,请为值添加 `127.0.0.1:` 前缀,例如 `127.0.0.1:8080`。当网关运行在其他主机或集群上时,请在 `AISIX_CLOUD_DPMGR_BASE_URL` 中设置的主机名和端口上暴露 `dp-manager` 端点。 控制台只在 Compose 网络内监听端口 `3000`。它没有主机端口,因为 `cp-api` 会通过端口 `8080` 提供控制台。 ### Helm Service 端口[​](#helm-service-ports "Helm Service 端口的直接链接") 默认 Helm Chart 创建 `ClusterIP` Service。只发布集群外客户端需要访问的 Service。 | Helm 配置项 | 默认值 | 使用方 | | -------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------- | | `api.service.type`, `api.service.port`, `api.service.nodePort` | `ClusterIP`, `8080`, 空 | 通过已配置控制面 Origin 访问的运维人员、浏览器和 Admin API 客户端 | | `dpm.service.type`, `dpm.service.port`, `dpm.service.nodePort` | `ClusterIP`, `7944`, 空 | AISIX 网关 | | `ui.service.type`, `ui.service.port`, `ui.service.nodePort` | `ClusterIP`, `3000`, 空 | 集群内的 `cp-api` | | `postgresql.primary.service.ports.postgresql` | `5432` | 集群内的控制面服务 | 对于 API、数据面管理器和 UI Service,只有 Service 类型为 `NodePort` 时,Chart 才会使用已配置的 `nodePort`。将该值留空可让 Kubernetes 动态分配端口。对于其他 Service 类型,Chart 会忽略该值。 直接连接 API 和 UI NodePort 时使用明文 HTTP。生产环境访问时,请在前方部署终止 TLS 的代理或负载均衡器。运维人员通常通过 `cp-api` 打开控制台,由 `cp-api` 将控制台流量代理到 UI Service。如果同源代理直接连接 UI NodePort,请将控制台页面路由到 UI Service,并将 `/api/*` 请求路由到 `cp-api`。 当 `cp-api` 使用 NodePort 时,请将 `api.publicBaseURL` 设为该端口上外部可访问的源站,或前置 TLS 反向代理的源站。如果网关在集群外运行,请提供通往 `dp-manager` Service 且能保留其 mTLS 连接的 TCP 路径,然后把 `api.dpmgrBaseURL` 设置为外部可访问的 HTTPS 端点。端口 `7946` 上的 `dp-manager` 健康检查监听器仍保留在 Pod 内部,不属于此 Service。 有关所有本地部署配置变量和 Helm 配置项,请参阅[本地部署配置参考](https://docs.apiseven.com/ai-gateway/reference/on-premises-configuration.md)。 --- # 代理 API 参考 代理 API 是 AISIX 在代理监听端口上暴露给调用方的 API 面。应用可以继续使用已有请求格式,AISIX 负责执行认证、模型解析、流量控制和服务提供方调度。 开源 AISIX 网关和连接到 AISIX Cloud 的 AISIX 网关使用相同的代理 API 面。运维人员配置资源的方式不同,但调用方使用的网关路由相同。AISIX Cloud 还提供预算等控制面功能。 本参考说明 AISIX 的路由行为、认证、模型发现、路由选择和端点约束。代理请求和响应体遵循各路由对应的 API 族;需要完整正文结构时,请参考对应上游 API 文档。 在 AISIX 中,面向客户端的路由路径由 AI API 形态决定,而不是为每个上游自定义路径。应用直接调用受支持的代理端点。请求中的 model 值会选择已配置的 AISIX 模型别名,进而决定请求背后的服务提供方密钥、上游模型、路由行为和流量控制。 ## 代理路由[​](#代理路由 "代理路由的直接链接") | 方法 | 路由 | 说明 | | --------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `GET` | `/v1/models` | 列出该调用方 API Key 可以请求的模型别名,包括虚拟别名。通配符别名不会展示。 | | `POST` | `/v1/chat/completions` | OpenAI 兼容 Chat Completions,支持的服务提供方范围最广。 | | `POST` | `/v1/completions` | OpenAI 兼容文本补全。 | | `POST` | `/v1/messages` | Anthropic 风格 Messages。Anthropic 上游使用原生格式,非 Anthropic 上游通过转换支持。 | | `POST` | `/v1/messages/count_tokens` | Anthropic 风格 Token 计数,仅支持 Anthropic 上游目标。 | | `POST` | `/v1/embeddings` | 向量嵌入,仅支持 OpenAI 协议族适配器。 | | `POST` | `/v1/responses` | OpenAI Responses API。OpenAI 上游直接转发,非 OpenAI 上游通过服务提供方适配器桥接。 | | `POST` | `/v1/images/generations` | 图像生成。解析出的模型必须配置为 `provider: "openai"`。 | | `POST` | `/v1/images/edits` | Multipart 图像编辑。解析出的模型必须配置为 `provider: "openai"`;不支持流式传输。 | | `POST` | `/v1/videos` | 提交异步视频生成任务。支持 `alibaba`、`zhipuai`(或 `zhipu`)、`volcengine`、`runwayml`(或 `runway`)和 `openai` 服务提供方标签。 | | `GET` | `/v1/videos/{video_id}` | 轮询视频生成任务。 | | `GET` | `/v1/videos/{video_id}/content` | 下载已完成的视频结果。 | | `POST` | `/v1/audio/transcriptions` | 语音转文本。转发到上游 OpenAI 风格音频路由。 | | `POST` | `/v1/audio/translations` | 语音翻译。转发到上游 OpenAI 风格音频路由。 | | `POST` | `/v1/audio/speech` | 文本转语音。转发到上游 OpenAI 风格音频路由。 | | `GET` | `/v1/realtime` | OpenAI Realtime WebSocket 中继。要求使用直接模型,并在升级连接前完成身份认证。 | | `POST` | `/v1/rerank` | 重排序。仅支持 `openai`、`cohere` 和 `jina` 服务提供方标签。 | | `POST`、`GET` | `/v1/files` | 上传文件或列出文件。 | | `GET`、`DELETE` | `/v1/files/{id}` | 获取或删除文件。 | | `GET` | `/v1/files/{id}/content` | 下载文件内容。 | | `POST`、`GET` | `/v1/batches` | 创建 Batch 或列出 Batch。 | | `GET` | `/v1/batches/{id}` | 获取 Batch。 | | `POST` | `/v1/batches/{id}/cancel` | 取消 Batch。 | | `POST`、`GET` | `/v1/fine_tuning/jobs` | 创建 Fine-tuning Job 或列出 Job。 | | `GET` | `/v1/fine_tuning/jobs/{id}` | 获取 Fine-tuning Job。 | | `POST` | `/v1/fine_tuning/jobs/{id}/cancel` | 取消 Fine-tuning Job。 | | `ANY` | 已配置的透传路由 | 在每条路由的路径前缀和/或入站 `Host` 白名单上做原生转发,包含网关认证和有限的网关标准化处理。未匹配任何类型端点或显式透传路由的请求会按普通流程返回响应体为空的 `404`。 | | `ANY` | `/mcp` 和 `/mcp/` | MCP 网关端点。认证调用方,列出允许访问的工具,并将工具调用路由到已注册的上游 MCP 服务器。 | | `ANY` | `/mcp/{server}` | 单服务器 MCP 端点。通常公开原始工具名称;需要避免命名冲突时保留当前服务器前缀。 | | `GET`、`HEAD` | `/.well-known/oauth-protected-resource` | MCP OAuth 受保护资源元数据。仅在 MCP OAuth 发现配置了至少一个启用的 OIDC 提供方时可用。 | | `GET`、`HEAD` | `/.well-known/oauth-protected-resource/mcp` | 同一 MCP OAuth 受保护资源元数据的路径插入形式。 | | `POST` | `/a2a/{agent}` | 一个已注册 Agent 的 A2A JSON-RPC 端点。转发前会执行调用方 Key 的 Agent 访问控制。 | | `GET` | `/a2a/{agent}/.well-known/agent-card.json` | 获取已注册 Agent 的 Agent Card,并把其服务 URL 重写为网关地址。要求调用方完成身份认证并具有 Agent 访问权限。 | | `GET` | `/livez` | 无需认证的存活探针,用于确认代理监听端口已启动。优雅关闭期间保持返回 200——正在排空的实例是健康的、不应被重启;检测排空状态请使用 `/readyz`。 | | `GET` | `/readyz` | 无需认证的就绪探针。实例正在排空时返回 503。对于使用 etcd 或 AISIX Cloud 的网关,首次应用配置之前整个代理监听器都未绑定,因此在那之前该路由是被拒绝而不是返回响应;参见[启动与第一个配置](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md#startup-and-the-first-configuration)。 | ## 认证[​](#认证 "认证的直接链接") 代理请求接受调用方 API Key,或由已配置的 OpenID Connect(OIDC)提供方签发的 JWT。两种方法都会将请求解析到调用方 API Key 资源。解析出的 Key 决定应用哪些模型和工具允许列表、限流,以及其他访问和流量控制;使用 AISIX Cloud 时,还会应用匹配的预算。 ### 调用方 API Key[​](#caller-api-key "调用方 API Key的直接链接") 通过 AISIX Cloud 控制面创建调用方 API Key,或在开源 AISIX 网关的 [`resources.yaml` 文件](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)中声明调用方 API Key。 推荐格式: ``` Authorization: Bearer <plaintext-caller-key> ``` 备用格式: ``` x-api-key: <plaintext-caller-key> ``` 调用方 API Key 是 AISIX 网关凭证,不是上游服务提供方密钥。 ### OIDC 签发的 JWT[​](#oidc-issued-jwt "OIDC 签发的 JWT的直接链接") 以 Bearer Token 形式发送 OIDC 签发的 JWT: ``` Authorization: Bearer <jwt> ``` 当环境启用了 OIDC 提供方时,AISIX 会验证 JWT 签名和声明,再将外部身份映射到与该信任提供方和主体绑定的调用方 API Key。AISIX 不会内省不透明的 OAuth Token。验证失败的 JWT 会被拒绝,不会被当作调用方 API Key。有关信任提供方配置、身份映射和支持的签名算法,请参阅 [JWT 身份认证](https://docs.apiseven.com/ai-gateway/traffic-controls/jwt-authentication.md)。 ## 模型发现[​](#model-discovery "模型发现的直接链接") `GET /v1/models` 会返回该调用方 API Key 允许请求的模型别名。直接模型和虚拟模型(多目标、语义和合议)都会展示,因为每一个都是调用方可在 `model` 中发送的名称。通配符别名不会展示:`provider/*` 是匹配模式,而不是调用方可以请求的名称。 列出的虚拟别名可以在支持虚拟分发的路由上解析。`/v1/realtime` 以及 Files、Batches 和 Fine-tuning 路由要求使用直接模型,并会拒绝虚拟别名。 列表遵循调用方 API Key 的模型允许列表。只允许某个多目标别名的 Key 会返回该别名,而不会返回其目标。请将此别名作为调用方发现的入口点,并将其目标保持为内部实现细节。 ## 路由行为[​](#路由行为 "路由行为的直接链接") 多目标别名会在请求时解析为一个或多个目标模型,适用于 `/v1/chat/completions`、`/v1/messages`、`/v1/messages/count_tokens` 和 `/v1/responses`。 流式请求会使用第一个被选中的可用目标,不会在流式传输过程中切换目标。非流式请求在遇到可重试的上游失败时,可以故障转移到下一个可用目标。 `/v1/responses` 可以解析多目标别名。OpenAI 上游目标会直接转发 Responses 请求,非 OpenAI 目标会使用 Responses 桥接。 `/v1/messages/count_tokens` 可以解析多目标别名,但只会使用 Anthropic 上游目标。如果没有可用的 Anthropic 目标,网关会拒绝该请求。 ## 端点约束[​](#端点约束 "端点约束的直接链接") 有些路由除了适配器协议族兼容性外,还会施加服务提供方专属约束。 | 路由 | 约束 | | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `/v1/responses` | 对 OpenAI 上游目标使用直接转发,对其它服务提供方目标使用桥接转换。 | | `/v1/images/generations` | 解析出的模型必须设置 `provider: "openai"`。 | | `/v1/images/edits` | 解析出的模型必须设置 `provider: "openai"`,且只接受非流式 multipart 请求。 | | `/v1/rerank` | 模型的 `provider` 标签必须为 `openai`、`cohere` 或 `jina`。 | | `/v1/embeddings` | 当解析出的适配器不支持 embeddings 时,返回 `501 not_implemented`。 | | `/v1/audio/*` | 转发 OpenAI 风格音频请求,不跨服务提供方协议族做转换。 | | `/v1/files`、`/v1/batches`、`/v1/fine_tuning/jobs` | 支持 OpenAI 兼容服务提供方和 Azure OpenAI。Vertex AI、AWS Bedrock 和 Anthropic 原生 batch 流程使用不同的传输格式和存储模型,因此不由这些路由提供。 | ## Files、Batches 和 Fine-Tuning[​](#filesbatches-和-fine-tuning "Files、Batches 和 Fine-Tuning的直接链接") Files、batches 和 fine-tuning jobs 使用 OpenAI 兼容路由形态。由于部分后续调用只引用 file 或 job ID,AISIX 会在它创建的 ID 中编码路由信息。网关创建的 ID 以 `aisix-` 开头,后续 file、batch 和 fine-tuning 调用无需再次提供模型提示即可完成路由。 上传文件时,请通过 `model` multipart 字段、`model` 查询参数或 `x-aisix-model` 请求头提供一次路由模型。仍可使用原始服务提供方 ID,但为了确定性路由,请显式传入 model 查询参数或请求头。 文件和 job 管理调用会记录零 Token 用量事件。当批处理查询首次发现批处理已完成时,AISIX 会下载批处理输出文件,按行聚合 Token 用量,并发出带 Token 计数的用量事件。完整工作流请参见 [Batch、Files 和 Fine-Tuning](https://docs.apiseven.com/ai-gateway/endpoints/batch-files-fine-tuning.md)。 ## 透传[​](#透传 "透传的直接链接") [透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md)会在完成网关认证和调用方 Key 的路由授权后转发原生请求。每条已配置路由服务于自己的路径前缀和/或入站 `Host` 白名单;host 命中的请求在网关自身的路径路由之前分发,路径前缀匹配则在所有一等路由之后运行。上游的状态码和响应体原样返回,`text/event-stream` 响应增量中继。与一等模型化路由相比,这些路由有意减少网关标准化处理。 已移除的隐式 `/passthrough/:provider/*rest` 通道不再解析。未被任何显式路由认领的 `/passthrough/*` 路径会按普通流程返回响应体为空的 `404`。 ## MCP 网关[​](#mcp-gateway "MCP 网关的直接链接") `ANY /mcp` 会让 AISIX 作为 MCP 服务器暴露给下游 Agent。网关会聚合已注册上游 MCP 服务器的工具,并以带服务器前缀的名称暴露每个工具。 MCP 请求使用与其它代理请求相同的调用方身份认证。只有当解析出的调用方 API Key 的工具访问权限允许请求的工具名称时,工具调用才会被允许。调用方 API Key 限流和安全护栏也可以治理工具调用。在 AISIX Cloud 中,覆盖该 Key 的预算也会生效。 握手和发现方法可以连接并列出调用方可用的工具。工具调用会产生包含 MCP 服务器和工具归因的用量事件,但不会携带 Token 用量。 启用 MCP OAuth 发现后,两个 `/.well-known/oauth-protected-resource` 路由会发布已配置的 `/mcp` 资源 URL、启用的 OIDC 签发方 URL、Bearer 请求头支持以及所需 Scope。这些路由无需身份认证,以便客户端发现登录方式。如果未配置 MCP 资源 URL,或没有启用的 OIDC 提供方,则两个路由均返回 `404`,MCP 身份认证失败也不会包含 OAuth 发现质询。配置方法和 `WWW-Authenticate` 行为参见 [MCP 客户端身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/client-authentication.md#oauth-sign-in)。 MCP 端点支持 `2025-03-26`、`2025-06-18`、`2025-11-25` 和 `2026-07-28` 协议修订版,并为每个客户端分别协商:`initialize` 握手会回显请求中受支持的修订版;如果请求的版本不受支持,则响应 `2025-11-25`;`2026-07-28` 客户端也可以直接从 `server/discover` 开始。所有协议代际都以无状态方式提供服务,不会发出 `Mcp-Session-Id`。MCP 协议消息使用 `POST`;身份认证和指定服务器解析会先执行,二者通过后,`GET` 和 `DELETE` 返回 `405`。`MCP-Protocol-Version` 请求头是可选的(缺少时表示 `2025-03-26`);如果请求头指定了不受支持的修订版,则返回 HTTP `400`,并在 JSON-RPC 错误信封中列出受支持的修订版。上游会话的修订版按已注册服务器选择,并且与客户端无关;请参阅[协议版本支持](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md#protocol-version-support)。 `ANY /mcp/{server}` 将网关限定到一台已注册服务器。它的工具列表通常保留上游服务器的原始名称,而不添加聚合端点使用的 `<server>__` 前缀。如果原始名称与已注册服务器前缀存在歧义,AISIX 会保留当前服务器前缀,确保公布的名称仍可调用。访问控制仍会评估规范的带前缀工具标识,因此在聚合端点和按服务器划分的端点之间切换客户端不会绕过授权。 ## A2A 网关[​](#a2a-gateway "A2A 网关的直接链接") `POST /a2a/{agent}` 会把 A2A JSON-RPC 请求转发到一台已注册的上游 Agent。AISIX 会验证调用方身份,确认调用方 API Key 允许访问该 Agent,对消息文本运行输入安全护栏,应用请求限流和并发限制,然后转发请求体,不会在不同 A2A 协议版本之间进行转换。网关连接到 AISIX Cloud 时还会应用预算。 `GET /a2a/{agent}/.well-known/agent-card.json` 会获取上游 Agent Card,并把其中公布的**每一个**服务 URL——顶层 `url` 以及 `supportedInterfaces` 和 `additionalInterfaces` 中的每一项——重写为网关上的 `/a2a/{agent}`。Agent Card 路由要求相同的调用方身份认证和 Agent 授权,但不受限流影响。 A2A 调用不会解析模型。其用量事件中的 Token 数由网关统计消息文本得出,并标记为 `usage_estimated`,成本为零。它们会发出带 A2A 归因的用量指标和请求指标。有关协议行为,请参阅 [Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/overview.md);有关官方 SDK 客户端示例,请参阅[配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)。 ## 请求头与错误[​](#请求头与错误 "请求头与错误的直接链接") 代理响应可能包含 AISIX 专属响应头,用于请求关联、路由、缓存状态、限流状态和重试时机。 错误信封取决于请求格式:OpenAI 兼容路由使用 OpenAI 风格错误信封,Anthropic 风格路由使用 Anthropic 风格信封。 MCP 路由使用 JSON-RPC 信封。A2A 调用会原样返回上游 JSON-RPC 响应,并在上游分发失败时使用 JSON-RPC 错误。身份认证、访问控制和流量控制失败可能会在 A2A 请求转发前返回普通网关 HTTP 错误。透传路由返回上游响应。 完整响应头列表、错误信封和状态码说明请参见[响应头与错误码](https://docs.apiseven.com/ai-gateway/reference/headers-and-error-codes.md)。按端点查看服务提供方支持情况,请参见[服务提供方兼容性](https://docs.apiseven.com/ai-gateway/providers/compatibility.md)。 --- # 资源文件参考 开源 AISIX 网关可以从声明式 `resources.yaml` 文件加载服务提供方凭证、模型、调用方凭证和运行时策略。本参考涵盖该文件的 YAML 规则、跨资源命名、环境变量插值和所有受支持的资源集合。 在启动配置中设置 [`resources_file`](https://docs.apiseven.com/ai-gateway/reference/configuration-files.md#resource-source) 以选择该文件。如需创建并加载可用配置,请从[开源 AISIX 网关快速入门](https://docs.apiseven.com/ai-gateway/getting-started/gateway-quickstart.md)开始。使用 [CLI 参考](https://docs.apiseven.com/ai-gateway/reference/cli.md#validate-a-resources-file)校验变更,并通过[配置状态](https://docs.apiseven.com/ai-gateway/reference/config-status.md)检查已启用或被拒绝的配置。 ## 文件格式[​](#文件格式 "文件格式的直接链接") AISIX 从一个资源文件中只加载一个 YAML 文档。文件名并不固定:本文档约定使用 `resources.yaml`,但 `resources_file` 可以指向任意可读文件路径。 该设置只接受一个路径。AISIX 不会加载目录、解析 include 或 import 指令,也不会合并多个资源文件。如果你以多个源文件片段维护配置,请在校验和加载前将它们组装成一个 YAML 文档。 ### 安全应用资源示例[​](#apply-resource-examples-safely "安全应用资源示例的直接链接") 保留完整的活动快照 AISIX 不会把资源文件与之前加载的配置合并。每次成功加载都会替换活动资源快照。新增或更改资源时,请从网关当前使用的完整文件开始;组装后的文件中省略的条目和集合将从活动配置中消失。 代码块标题用于区分完整文档与局部配置块: * 标题为 `resources.yaml` 的代码块是包含 `_format_version` 的自包含文档。请结合上下文判断它是新网关配置还是参考示例。 * `resources.yaml(OIDC 服务提供方)` 之类的标题表示不含 `_format_version` 的局部配置块。括号中的简短说明标识其内容;上下文会说明应添加、替换、更新还是仅检查该配置块。 应用局部配置块时,请从网关当前使用的完整文件开始。每个受影响的集合只更新或创建一次,保留无关条目和集合,不要重复创建已有的顶层集合键。 组装完所有局部配置块后,请验证完整文件,而不是单独验证局部配置块。 文档顶层是一个映射,其中必须包含 `_format_version`,并且最多包含十四个资源集合: resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-prod provider: openai api_key: ${OPENAI_API_KEY} models: - display_name: gpt-4o provider: openai model_name: gpt-4o-2024-11-20 provider_key: openai-prod api_keys: - display_name: ci-bot key_env: CI_BOT_KEY allowed_models: ["gpt-4o"] rate_limit_policies: - name: cap-gpt4o scope: model scope_ref: gpt-4o window: minute max_requests: 300 ``` | 集合 | 用途 | 标识字段 | | ----------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------ | | [`provider_keys`](#provider-keys) | 存储上游服务提供方凭证和连接设置。 | `display_name` | | [`models`](#models) | 定义面向调用方的模型别名和分发行为。 | `display_name` | | [`api_keys`](#caller-api-keys) | 对调用方进行身份认证,并控制其模型、MCP 工具和 A2A Agent 访问权限。 | `display_name` | | [`oidc_providers`](#oidc-providers) | 信任用于调用方身份认证的 JWT 签发者。 | `name` | | [`mcp_auth_settings`](#mcp-authentication-settings) | 配置 OAuth Discovery 以及 MCP 客户端可选的匿名访问。 | 单例;无标识字段 | | [`claim_mappings`](#claim-mappings) | 把验证通过的 JWT Claims 解析到调用方 API Key。 | `name` | | [`guardrails`](#guardrails) | 检查或转换请求和响应内容。 | `name` | | [`guardrail_attachments`](#guardrail-attachments) | 把安全护栏绑定到它要检查的流量。 | `guardrail_id` + `scope_type` + `scope_id` | | [`mcp_servers`](#mcp-servers) | 将 MCP 服务器或 OpenAPI 操作公开为工具。 | `name` 或 `display_name` | | [`a2a_agents`](#a2a-agents) | 为 A2A 调用方注册上游 Agent。 | `name` 或 `display_name` | | [`passthrough_routes`](#passthrough-routes) | 将匹配的 HTTP 流量在网关审计和策略下中继到服务提供方端点。 | `name` 或 `display_name` | | [`cache_policies`](#cache-policies) | 缓存匹配的非流式模型响应。 | `name` | | [`observability_exporters`](#observability-exporters) | 将请求遥测数据导出到外部系统。 | `name` | | [`rate_limit_policies`](#rate-limit-policies) | 应用条件式或单作用域的请求和 Token 限制。 | `name` | ### YAML 结构[​](#yaml-structure "YAML 结构的直接链接") `_format_version` 必须是字符串 `"1"`,需要加引号以确保 YAML 将其解析为字符串。缺少版本或版本无法识别会导致加载错误;未加引号的 `1` 会触发专用错误,提示你为它添加引号。 网关会应用以下 YAML 约束: * 文件必须只包含一个 YAML 文档。使用 `---` 分隔的多个文档会导致加载错误。 * 顶层映射和所有嵌套映射都必须使用字符串 Key。 * 每个存在的资源集合都必须是映射序列。不存在或值为 `null` 的集合按空集合加载。 * 未知顶层集合和资源中的未知字段都会导致加载错误。 * YAML 锚点和别名可以复用值。合并 Key(`<<`)不会展开,并会在 Schema 校验时被视为未知字段而失败。 ### 标识与派生 ID[​](#identity-and-derived-ids "标识与派生 ID的直接链接") 除 `mcp_auth_settings` 和 `guardrail_attachments` 外,每个条目的标识字段都必须是非空字符串,并且在集合中唯一;重复会导致加载错误,并指出两个冲突条目。对于 `mcp_servers`、`a2a_agents` 和 `passthrough_routes`,可以使用 `name` 或 `display_name` 作为标识;同时包含两种写法会导致加载错误,只能使用其中一种。`mcp_auth_settings` 采用固定的单例标识,因此文件在该集合中最多只能包含一个条目。`guardrail_attachments` 条目由 `guardrail_id` + `scope_type` + `scope_id` 三元组标识,因此把同一个安全护栏挂到同一个目标两次属于重复条目。 所有条目都不接受 `id` 字段。条目 ID 根据 `<kind>/<identity>`,在命名空间 `63e50ab2-677a-54d3-8d1e-c0cb29ceae94` 中以 UUIDv5 确定性派生,因此相同文件在重新加载和不同进程中始终生成相同 ID。例如,`api_keys/anonymous-mcp` 会派生出 `d6869ae7-741a-598e-8213-16672e922546`。由 ID 标识的引用和限流计数器因此可以跨 `SIGHUP` 重新加载保留。 ### 名称引用[​](#name-references "名称引用的直接链接") 条目通常通过名称选择关联资源。加载器会按以下方式检查每种关系: | 关系 | 使用的引用 | 校验行为 | | -------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | 模型到服务提供方凭证 | 服务提供方密钥的显示名称(推荐),或其确定性 ID | `provider_key` 会解析显示名称;名称未知时,错误会列出可用密钥。`provider_key_id` 必须匹配同一文件中已定义服务提供方密钥的派生 ID。两字段互斥。 | | 调用方或虚拟模型到目标模型 | 模型的显示名称 | 必须匹配文件中定义的模型。包含 `*` 的值是 Glob 模式,不检查是否精确匹配。 | | 限流策略到其主体 | 模型或调用方 API Key 的显示名称 | 对于 `model` 和 `api_key` 作用域,名称会解析为目标;对于其它作用域,该值原样传递。 | | 安全护栏绑定到安全护栏 | 安全护栏 `name` | 必须匹配已定义的安全护栏;未知名称会导致加载错误,并列出可用的安全护栏。 | | 安全护栏绑定到作用目标 | 目标集合各自的标识——模型的 `display_name`,MCP 服务器或透传路由的 `name`,调用方 API Key 的 `display_name` | 必须匹配该集合中的条目。`scope_type: team` 原样保留,因为文件中没有团队集合可供校验。 | | 调用方身份到 JWT 签发者 | OIDC 服务提供方名称 | 保留为名称,而不解析成派生 ID。 | | 透传路由到注入凭证 | 经 `provider_key` 引用的服务提供方密钥显示名称 | 必须匹配已定义的服务提供方密钥;未知名称会导致加载错误,并列出可用的密钥。与 `provider_key_id` 互斥。 | | 透传路由到匿名主体 | 经 `anonymous_key` 引用的调用方 Key 显示名称 | 必须匹配已定义的调用方 API Key。与 `anonymous_key_id` 互斥。 | | 调用方 Key 到透传路由 | 经 `allowed_routes` 引用的路由名称 | 条目是单 `*` Glob;不含 `*` 的条目必须匹配文件中定义的路由。 | ### 环境变量插值[​](#environment-interpolation "环境变量插值的直接链接") `${VAR}` 引用只会在字符串标量中根据网关进程环境解析。替换发生在已解析的 YAML 树中,因此环境变量值无法注入 YAML 结构,映射 Key 也不会被插值。 此插值用于用户自定义的进程变量。有关 AISIX 定义的启动和连接变量,请参见[环境变量](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 * 支持部分插值:`api_base: https://${UPSTREAM_HOST}/v1`。 * 变量未设置或值为空都会导致加载错误;错误只指出变量名,绝不会包含变量值。 * 不支持 `${VAR:-default}` 和 `${VAR:?message}` 等 Shell 风格的回退值和必填值表达式。 * `$$` 生成字面量 `$`;没有大括号的 `$VAR` 原样保留;未闭合的 `${` 或空的 `${}` 会导致错误。 * 整数、浮点数、布尔值和 `null` 等非字符串标量不会被插值。 ### 加载、错误与重新加载[​](#loading-errors-and-reload "加载、错误与重新加载的直接链接") 启动、`SIGHUP` 重新加载和 [`aisix validate`](https://docs.apiseven.com/ai-gateway/reference/cli.md) 使用相同的加载流程。网关会读取文件、解析 YAML、插值 `${VAR}` 引用、转换各条目、解析名称引用、执行 Schema 校验并检查交叉引用。所有配置来源使用相同的 Schema 校验。 错误会在整个文件范围内聚合,并定位到问题条目和字段,例如 `models[2] ("gpt-4o")`。加载为全有或全无:任何错误都会拒绝整个文件。 启动时,被拒绝的文件会使网关立即停止。`SIGHUP` 重新加载时,网关会继续提供上一个有效快照,记录聚合报告,并通过 [`GET /status/config`](https://docs.apiseven.com/ai-gateway/reference/config-status.md) 暴露被拒绝的加载。网关不会监视文件变化,必须显式重新加载。 ## 服务提供方密钥[​](#provider-keys "服务提供方密钥的直接链接") 服务提供方密钥保存上游凭证及该服务提供方使用的连接设置。模型通常通过 `display_name` 选择服务提供方密钥;直接模型也可以按照[直接模型](#direct-models)所述改用该密钥的确定性 ID。每个嵌套层级都会拒绝未知字段。 | 字段 | 类型 | 必填 | 说明 | | ------------------------------------------- | ---------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `display_name` | string | 是 | 条目标识,在 `provider_keys` 中唯一。这是推荐的模型引用;直接模型也可以改用该密钥的确定性 ID。 | | `api_key` | string | 视情况而定 | 上游服务提供方 API Key。请以 `${VAR}` 形式提供。也可以使用 `secret` 作为替代写法;两者必须且只能提供一个。部分服务提供方的凭证包含多个字段。对于这些服务提供方,请通过一个环境变量提供 JSON 凭证文档。有关凭证格式,请参见 [AWS Bedrock](https://docs.apiseven.com/ai-gateway/providers/aws-bedrock.md) 和[使用 Entra ID 的 Azure OpenAI](https://docs.apiseven.com/ai-gateway/providers/azure-openai.md)。 | | `provider` | string | 否 | 上游服务提供方标识符,例如 `openai` 或 `deepseek`。这是用于服务提供方专用分发的开放字符串,默认为空。 | | `adapter` | enum | 否 | 没有适用的服务提供方专用分发时所用的上游协议族:`openai`、`anthropic`、`bedrock`、`vertex` 或 `azure-openai`。参见[适配器协议族](https://docs.apiseven.com/ai-gateway/providers/adapters.md)。 | | `api_base` | string | 否 | 覆盖上游服务提供方的基础 URL。私有 OpenAI 兼容端点实际上必须设置此字段。支持部分插值,例如 `https://${UPSTREAM_HOST}/v1`。 | | `apis` | object | 否 | 该端点原生提供哪些 API 协议面、分别在哪个地址。写了 `apis` 但省略某个协议面,表示该协议面不是原生提供的,网关会改为转换成 chat completions。完全省略该块则从 `provider` 和 `adapter` 推导所有协议面,这是默认行为。`bedrock`、`vertex` 和 `azure-openai` 适配器不接受该字段。见[声明 API 协议面](https://docs.apiseven.com/ai-gateway/models/provider-keys.md#declare-the-api-surfaces)。 | | `apis.responses` | object | 否 | 该端点原生提供 `/v1/responses`。`apis` 一旦存在,此项即为权威依据:不写它就是在声明该端点没有这个接口。 | | `apis.messages` | object | 否 | 该端点原生提供 `/v1/messages` 和 `/v1/messages/count_tokens`。此项是叠加的——`adapter` 为 `anthropic` 的密钥无论是否列出都提供这两个接口;列出它是为了给适配器是其他协议的密钥补上这两条路由。 | | `apis.<surface>.base` | string | 否 | 该协议面的基础 URL,用于端点把它放在与 `api_base` 不同的路径上的情况。形式要求与 `api_base` 相同。该协议面就在 `api_base` 上时省略此字段。 | | `strip_headers` | 字符串数组 | 否 | 使用此密钥的 inject 模式[透传路由](#passthrough-routes)转发前删除的入站请求头。默认:`authorization`、`cookie`、`set-cookie`、`x-api-key`。条目会去除首尾空格、转成小写并去重。显式 `[]` 会禁用此列表,但 inject 模式恒剥离 `authorization` 和 `x-api-key`,确保调用方凭证绝不与注入凭证并排发送。这并不是绝对禁令:路由自己的 `forward_client_headers` 会覆盖它,对于既非凭证也非链路上下文的名称,`x-*` 这类通配符就足以把请求头放回传输上。 | | `tls` | object | 否 | HTTP 服务提供方分发使用的端点级 TLS 设置。Amazon Bedrock 和 Realtime 分发会忽略此配置块;请改用适用的部署级 `upstream.tls` 设置。 | | `tls.ca_cert` | string | 否 | 此 HTTP 端点额外信任为签发者的 PEM 编码 CA 证书。一个证书包可以包含多张证书。参见 [TLS 和 mTLS](https://docs.apiseven.com/ai-gateway/deployment/tls-and-mtls.md#trust-an-upstream-behind-a-private-certificate-authority)。 | | `tls.verify` | boolean | 否 | 是否验证此 HTTP 端点的证书。默认:`true`。设为 `false` 会接受任意证书,仅用于测试环境。 | | `telemetry_tags` | object | 否 | 通过该 Key 路由请求时发出的归因标签。 | | `telemetry_tags.kind` | enum | 否 | 归因类别:`catalog` 或 `byo`。 | | `telemetry_tags.featured` | boolean | 否 | 是否突出显示该服务提供方密钥。默认:`false`。 | | `telemetry_tags.branded_provider` | string | 否 | 目录条目的品牌服务提供方 Slug。 | | `telemetry_tags.pk_label` | string | 否 | 运维人员定义的服务提供方密钥标签,例如 `production`。 | | `telemetry_tags.byo_label` | string | 否 | 运维人员定义的自带服务提供方标签,例如团队名称。 | | `request` | object | 否 | 分发前应用的请求格式覆盖。 | | `request.param_renames` | 字符串到字符串的映射 | 否 | 分发前,把左侧指定的顶层请求体 Key 重命名为右侧 Key。 | | `request.param_constraints` | object | 否 | Chat Completions 请求体中 `temperature` 的截断边界。 | | `request.param_constraints.temperature_min` | number | 否 | 接受的最小 `temperature`。省略时不应用下限。 | | `request.param_constraints.temperature_max` | number | 否 | 接受的最大 `temperature`。省略时不应用上限。 | | `request.default_headers` | 字符串到字符串的映射 | 否 | 添加到出站请求的请求头。由于加载器会先从环境中解析 `${...}`,请求上下文引用需要写成 `$${...}`,例如 `$${request.api_key.team_id}` 加载后会变成 `${request.api_key.team_id}`,用于按请求渲染。某个请求中变量无值时,该请求头会被丢弃,而不是发送空值。除凭证槽位外,这些请求头的优先级高于 `forward_client_headers` 转发的请求头——在凭证槽位上转发值胜出;它们也不能替换网关自身设置的同名请求头。无论来自哪里,`host`、逐跳请求头和 `x-aisix-*` 都会被丢弃;保存服务提供方密钥时,AISIX Cloud 拒绝的也正是这些名称。凭证名称在两种路径下都被接受,且只有在服务提供方桥接留空该槽位时才会到达上游。`request` 块的这一半在 `/v1/realtime` 上并不生效,那里只有 `forward_client_headers` 起作用。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md)。 | | `request.forward_client_headers` | 字符串数组 | 否 | 中继给上游的入站客户端请求头,取值为精确名称或含一个 `*` 的通配符(例如 `x-trace-*`),匹配不区分大小写。为空(默认值)时不转发任何请求头。[凭证槽位](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#headers-that-must-be-named-exactly)以及链路上下文请求头 `traceparent`/`tracestate` 只有在模式精确点名时才会中继,通配符永远不会匹配到它们,`x-amz-*` 也不例外。中继的凭证会占用该密钥本会注入的槽位,而不是与之并存。`host`、逐跳请求头、`x-aisix-*`,以及网关会重新序列化的请求体与内容协商请求头(`content-type`、`content-length`、`accept`、`accept-encoding`、`content-encoding`、`expect`)、`set-cookie`、`anthropic-version` 和 `x-stainless-*` 绝不会被中继。在 Bedrock 形态的密钥上,SigV4 签名涉及的名称(`authorization`、`x-amz-date`、`x-amz-content-sha256`、`x-amz-security-token`、`x-amz-target`、`x-amzn-bedrock-accept`)会被丢弃而不是投递。在 `/v1/realtime` 上,该面拥有的握手槽位(`sec-websocket-accept`、`sec-websocket-extensions`、`sec-websocket-key`、`sec-websocket-protocol`、`sec-websocket-version`)即使被模式完整点名也会被拒绝。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md)。 | | `request.default_body_fields` | 字符串到 JSON 值的映射 | 否 | 调用方未设置时添加到出站请求的顶层请求体字段。 | | `response` | object | 否 | 由支持的服务提供方桥接器应用的响应格式覆盖。 | | `response.stream_done_marker` | enum | 否 | 上游 SSE 流是否应发出 `data: [DONE]`:`required`、`optional` 或 `none`。省略时两种情况均可接受。 | | `response.content_list_to_string` | boolean | 否 | 为 `true` 时,在分发前把 `messages[*].content` 文本块数组展平为一个字符串。默认 `false`。 | | `response.reasoning_field` | string | 否 | 从服务提供方响应中提取推理内容的路径,例如 `delta.reasoning_content`。 | | `response.error_envelope` | string | 否 | 为兼容控制面配置而保留的错误信封首选项;代理目前不会应用。 | 以下示例综合使用了这些设置。它定义一个 OpenAI 服务提供方密钥和一个私有 OpenAI 兼容端点。私有端点声明 `openai` 适配器,从环境变量构建基础 URL,并信任一个额外的 CA。 resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-prod provider: openai api_key: ${OPENAI_API_KEY} - display_name: internal-vllm provider: internal-vllm adapter: openai api_base: https://${UPSTREAM_HOST}/v1 api_key: ${INTERNAL_LLM_KEY} # 仅当此端点的证书由私有或企业 CA 签发时, # 才需要配置以下内容。 tls: ca_cert: | -----BEGIN CERTIFICATE----- MIIB... -----END CERTIFICATE----- ``` ## 模型[​](#models "模型的直接链接") 模型条目定义一个面向调用方的别名。直接、向量嵌入、路由、合议和语义别名都会出现在 `/v1/models` 中;通配符模式不会列出(参见[模型别名](https://docs.apiseven.com/ai-gateway/models/model-aliases.md))。每个条目只使用一种分发形态:直接、路由、合议或语义。在同一条目中混合不同形态会导致加载错误,每个嵌套层级也都会拒绝未知字段。 以下超时、重试、访问、成本和内联限额字段在各模型形态间共享,但每个字段只在网关会解析它的 kind 上被接受——**适用 kind** 列列出这些 kind;在不解析该字段的 kind 上设置它会作为加载错误被拒绝: | 字段 | 类型 | 适用 kind | 说明 | | ---------------- | ---------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `display_name` | string | 全部 | 条目标识,在 `models` 中唯一,也是面向调用方的别名。每种形态都必填。 | | `timeout` | 整数(ms) | direct、embedding、routing、semantic | 非流式上游调用的端到端截止时间。在路由模型或语义路由器上,这是应用于未自行设置该值的每个目标的组/路由器级槽位;缺省时依次回退到该槽位和部署级 `upstream.timeout_ms` 默认值(`6000000` ms,即 6000 s)。`0` 禁用超时。ensemble 不接受此字段——其每次调用的截止时间是 `ensemble.timeout_ms`。 | | `stream_timeout` | 整数(ms) | direct、embedding、routing、semantic | 上游流式分块之间的最长间隔。`0` 或缺省时依次回退到组/路由器的 `stream_timeout`、`timeout` 和部署默认值。ensemble 不接受此字段。 | | `retries` | integer | direct、embedding、semantic | 发生可重试的上游失败后,对此模型执行的重试次数。在语义路由器上这是路由器级槽位。`0` 禁用对同一目标的重试。**路由模型不接受顶层 `retries`**——其组级槽位是下文的 `routing.retries`;路由目标自身的 `retries` 会覆盖它。ensemble 不接受此字段。 | | `rate_limit` | object | 全部 | 按调用方所寻址的条目强制执行的请求、Token 和并发限制,见下文。 | | `allowed_cidrs` | 字符串数组 | 全部 | 采用 CIDR 表示法的客户端 IP 允许列表(支持 IPv4 和 IPv6)。空值或缺省允许所有客户端。配置限制后,缺少或格式错误的源 IP 会被拒绝。 | | `cost` | object | direct、embedding | 用于 `least_cost` 排序以及 Realtime 会话和已完成 Batch 作业的用量事件中 `cost_usd` 的每 Token 成本元数据:`input_per_1k` 和 `output_per_1k`,单位均为每 1,000 个 Token 的美元;存在该块时两者都必填。设置在组所分发到的 `direct` 或 `embedding` 模型上,而非组本身。 | `rate_limit` 中的每个字段均可选,省略时不限制: | 字段 | 限制 | | ------------------------ | ---------------------------------------- | | `rate_limit.rps` | 固定 1 秒窗口内的请求数。 | | `rate_limit.rpm` | 固定 60 秒窗口内的请求数。 | | `rate_limit.rph` | 固定 3,600 秒窗口内的请求数。 | | `rate_limit.rpd` | 固定 86,400 秒窗口内的请求数。 | | `rate_limit.tpm` | 固定 60 秒窗口内的 Token 数。 | | `rate_limit.tpd` | 固定 86,400 秒窗口内的 Token 数。 | | `rate_limit.concurrency` | 最大进行中请求数。它是信号量,不是窗口。 | ### 直接模型[​](#direct-models "直接模型的直接链接") 直接模型指定一个服务提供方密钥背后的一个上游模型: | 字段 | 类型 | 必填 | 说明 | | ------------------------ | ---------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `provider` | string | 是 | 服务提供方标识,例如 `openai` 或 `anthropic`。首字符必须为小写字母或数字;后续可使用 `.`、`_` 和 `-`;长度 1–64 个字符。 | | `model_name` | string | 是 | 在服务提供方请求中发送的上游模型标识,例如 `gpt-4o-2024-11-20`。 | | `provider_key` | string | 是\* | `provider_keys` 条目的名称。这是资源文件中的推荐引用。与 `provider_key_id` 互斥。 | | `provider_key_id` | string | 是\* | 同一文件中已定义 `provider_keys` 条目的确定性 ID。与 `provider_key` 互斥。ID 与同一文件中的任何服务提供方密钥都不匹配时会发生加载错误。 | | `embedding` | object | 否 | 将模型标记为支持向量嵌入:`dimensions`(必填,向量维度)和 `normalize`(默认 `true`,端点是否已经返回 L2 归一化向量)。随后该模型可以服务 `/v1/embeddings` 并支持语义路由器。 | | `background_model_check` | object | 否 | 后台健康检查,参见[健康检查](https://docs.apiseven.com/ai-gateway/deployment/health-checks.md)。存在该块时,子字段 `enabled`、`interval_seconds`(最小 5)、`timeout_seconds`、`prompt`、`max_tokens` 和 `stale_after_seconds` 必填;`ignore_statuses`(状态码数组)可选。 | | `cooldown` | object | 否 | 发生可重试上游失败后的请求路径冷却。冷却需要显式开启:省略该块,或不设置其中的 `enabled`,请求路径失败都不会让模型退出轮转。见下文。 | | `auto_prompt_caching` | object | 否 | 自动注入 Anthropic 提示词缓存标记。仅支持服务提供方为 `anthropic` 的直接模型。存在该对象时 `enabled` 必填;`ttl` 可设为 `5m`(默认)或 `1h`。参见 [Anthropic 提示词缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/prompt-caching.md)。 | | `effort_mapping` | 字符串对象 | 否 | 直接模型的精确请求力度改写。键是调用方取值,值是上游取值;最终目标选定后只查找一次。省略或设为空对象即关闭。参见[推理力度映射](https://docs.apiseven.com/ai-gateway/models/reasoning-effort-mapping.md)。 | 必须且只能设置 `provider_key` 与 `provider_key_id` 其中一个。 可选的 `cooldown` 对象接受以下设置。只有 `enabled: true` 才会开启冷却;其余设置是冷却开启后使用的参数,单独设置其中某一项并不会开启该功能: | 字段 | 默认值 | 行为 | | ------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `cooldown.enabled` | `false` | 启用请求路径冷却跟踪。省略 `cooldown` 块或不设置该字段的模型,无论上游如何失败都会留在轮转中。 | | `cooldown.default_seconds` | `30` | 没有可用 `Retry-After` 响应头时设置冷却 TTL。设为 `0` 不是把冷却时长设为零,而是彻底关闭该模型的冷却,包括走 `Retry-After` 的那条路径。 | | `cooldown.max_seconds` | `600` | 限制根据 `Retry-After` 得出的冷却时间。 | | `cooldown.honor_retry_after` | `true` | 存在有效的 `Retry-After` 值时使用该值。 | | `cooldown.trigger_statuses` | `[401, 408, 429, 500, 502, 503, 504]` | 触发冷却的状态码。设置该字段会替换完整默认列表。 | | `cooldown.trigger_on_timeout` | `true` | 上游超时后触发冷却。 | | `cooldown.trigger_on_transport` | `true` | 上游传输失败后触发冷却。 | 只有直接模型可以配置 `embedding`、`background_model_check`、`cooldown` 和 `auto_prompt_caching`。自动提示词缓存还要求服务提供方为 `anthropic`。 ### 路由模型[​](#routing-models "路由模型的直接链接") `routing` 条目会为每个请求选择一个目标,并通过该目标模型的上游配置分发: | 字段 | 类型 | 必填 | 说明 | | ------------------------------ | ---------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `routing.targets` | array | 是 | 有序目标集合,至少一个条目。每请求的路由标签和 `allowed_cidrs` 过滤器会先缩小该集合,再由配置的策略对保留目标排序。 | | `routing.targets[].model` | string | 是 | 可以接收路由流量的现有直接模型名称。 | | `routing.targets[].weight` | integer | 否 | 默认:`1`。在 `round_robin` 下设置轮转份额,在 `consistent_hash` 下设置哈希环份额,在 `least_busy` 下设置分数的分母 `max(weight, 1)`。运行时会把 `0` 视为 `1`。`failover`、`least_cost` 和 `least_latency` 接受但忽略此值。 | | `routing.targets[].priority` | integer | 否 | 默认:`0`。把符合条件的目标划分为层级,值越高越优先。更高层级没有可用目标后才尝试较低层级;使用 `-1` 可设置备用层级。 | | `routing.targets[].tags` | 字符串数组 | 否 | 用于按请求筛选资格的标签。如果所有目标都没有标签,则不启用标签筛选,所有目标均符合条件。否则,携带标签的请求会保留至少一个标签匹配的目标;没有匹配项时回退到带 `default` 标签的目标。未携带标签的请求优先选择 `default` 目标;不存在该类目标时,所有目标仍符合条件。 | | `routing.strategy` | enum | 否 | `round_robin`(平滑加权轮询)、`consistent_hash`、`failover`(默认)、`least_cost`、`least_latency` 或 `least_busy`。位置策略在每个优先级层内选择一个起始目标,并在失败时向后遍历;指标策略在每层内按最佳优先排序。 | | `routing.retries` | integer | 否 | 故障转移前每个目标的默认重试次数。目标模型的 [`retries`](https://docs.apiseven.com/ai-gateway/models/model-aliases.md#retry-budget) 会覆盖此值。如果两处都未设置,AISIX 会直接移至下一个符合条件的目标,并且仅对最后一个目标应用部署级默认值。 | | `routing.max_fallbacks` | integer | 否 | 初始目标失败后最多尝试的后续目标数。默认:所有后续目标。`0` 禁用故障转移。 | | `routing.retry_on_429` | boolean | 否 | 上游 `429` 是否参与重试和故障转移。默认 `false`。 | | `routing.fallback_on_statuses` | 整数数组 | 否 | 额外视为可重试的 4xx 状态码,适用于使用这些状态表示暂时性情况的服务提供方,例如 `[408, 409]`。5xx 已默认可重试。 | | `routing.when_all_unavailable` | enum | 否 | `fail`(默认):健康状态和冷却状态排除所有目标时返回 `503`;`try_anyway`:无论状态如何,都按声明顺序尝试所有目标。 | | `routing.hash_on` | array | 否 | 仅用于 `consistent_hash`:有序的哈希键来源链,取第一个非空值。每个条目形如 `{type, name?}`,`type` 为 `header`、`cookie`(两者通过 `name` 指定名称)、`api_key` 或 `client_ip` 之一。默认:`x-aisix-routing-key` 请求头,其次调用方 API Key。 | 配置、路由行为和可运行的故障测试请参见[多目标路由与故障转移](https://docs.apiseven.com/ai-gateway/routing/routing-and-failover.md)。 ### 合议模型[​](#ensemble-models "合议模型的直接链接") `ensemble` 条目会把每个请求并发分发给所有合议成员,再由评审模型合成一个答案: | 字段 | 类型 | 必填 | 说明 | | ------------------------ | ---------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ensemble.panel` | array | 是 | 合议成员,至少一个。`panel[].model` 指定直接模型;可选的 `panel[].temperature` 和 `panel[].seed` 覆盖每个成员的采样参数;`panel[].weight` 可以配置,但目前忽略。 | | `ensemble.judge` | object | 是 | `judge.model` 指定执行合成的直接模型;可选 `judge.synthesis_prompt` 覆盖内置合成提示词。 | | `ensemble.min_responses` | integer | 否 | 合成前要求的最少成功成员响应数。默认是 `2` 与成员数中的较小值,上限为成员数,下限为 `1`。 | | `ensemble.timeout_ms` | 整数(ms) | 否 | 每个合议成员调用和评审调用的截止时间。`0` 或缺省时禁用。 | 行为和响应格式请参见[合议模型](https://docs.apiseven.com/ai-gateway/routing/ensemble-models.md)。 ### 语义路由器[​](#semantic-routers "语义路由器的直接链接") `semantic` 条目会对最新用户消息进行向量嵌入,根据每条路由的示例向量计算分数,并分发到达到阈值的最佳路由;如果没有路由达到阈值,则分发到 `default`: | 字段 | 类型 | 必填 | 说明 | | ------------------------------- | -------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `semantic.embedding_model` | string | 是 | 支持向量嵌入的直接模型名称(即包含 `embedding` 块的模型)。 | | `semantic.routes` | array | 是 | 至少一条路由。每条路由必须包含 `name`(通过 `x-aisix-route` 响应头暴露)、`target`(直接模型名称)和 `examples`(至少一条示例话语;应用配置时计算并缓存向量);可选 `description`(仅用于文档)和 `threshold`(覆盖该路由的 `match.threshold`)。 | | `semantic.default` | string | 是 | 没有路由匹配时接收请求的直接模型。 | | `semantic.match` | object | 是 | 共享匹配参数:`threshold`(必填,0.0–1.0,越高越严格)、`distance_metric`(仅支持 `cosine`)和 `aggregation`(仅支持 `max`,路由分数取最匹配的示例)。 | | `semantic.embedding_timeout_ms` | 整数(ms) | 否 | 向量嵌入调用的截止时间。`0` 或缺省时禁用。 | | `semantic.on_embedding_failure` | enum 或 object | 否 | 向量嵌入调用失败时的处理方式:`default`(路由到 `default` 模型,也是默认行为)、`fail`(以 `503` 拒绝),或 `{ target: "<alias>" }`(路由到指定模型)。 | 行为和调优请参见[语义路由](https://docs.apiseven.com/ai-gateway/routing/semantic-routing.md)。 以下完整示例展示四种模型形态的关系。三个直接模型是可复用目标;其余条目将它们组合成会话绑定路由、合议模型和语义路由器。 resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-main provider: openai api_key: ${OPENAI_API_KEY} models: - display_name: gpt-4o provider: openai model_name: gpt-4o provider_key: openai-main timeout: 30000 rate_limit: rpm: 100 tpm: 100000 cost: input_per_1k: 0.0025 output_per_1k: 0.01 - display_name: gpt-4o-mini provider: openai model_name: gpt-4o-mini provider_key: openai-main - display_name: text-embed provider: openai model_name: text-embedding-3-small provider_key: openai-main embedding: dimensions: 1536 - display_name: balanced routing: strategy: consistent_hash targets: - model: gpt-4o weight: 90 - model: gpt-4o-mini weight: 10 retries: 1 retry_on_429: true - display_name: council ensemble: panel: - model: gpt-4o - model: gpt-4o-mini temperature: 0.2 judge: model: gpt-4o min_responses: 2 timeout_ms: 45000 - display_name: smart-router semantic: embedding_model: text-embed routes: - name: coding target: gpt-4o examples: - "Write a Python function that parses CSV" - "Debug this stack trace" threshold: 0.8 default: gpt-4o-mini match: threshold: 0.75 on_embedding_failure: default ``` ## 调用方 API Key[​](#caller-api-keys "调用方 API Key的直接链接") 调用方 API Key 条目用于认证调用网关的应用。文件绝不会保存明文 Key:请通过 `key_env` 提供,或预先哈希到 `key_hash`。 | 字段 | 类型 | 必填 | 说明 | | ----------------- | ---------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `display_name` | string | 是 | 条目标识,在 `api_keys` 中唯一。 | | `key_env` | string | 是\* | 保存明文调用方 Key 的环境变量**名称**,例如不带 `${VAR}` 的 `MY_APP_KEY`。加载时,网关会使用 SHA-256 哈希该值并丢弃明文;明文绝不会出现在已加载文档、错误或日志中。与 `key_hash` 互斥,两者必须且只能提供一个。变量名不要以 `AISIX_` 开头,该前缀保留给[启动配置覆盖](https://docs.apiseven.com/ai-gateway/reference/environment-variables.md)。 | | `key_hash` | string | 是\* | 明文 Key 的小写十六进制 SHA-256 哈希,原样传递。两个条目解析到相同凭证时会导致加载错误;错误只指出条目,绝不会包含哈希。 | | `allowed_models` | 字符串数组 | 是 | 此 Key 可以使用的模型。条目是单 `*` Glob:`"*"` 授予所有模型,`"team-a/*"` 授予匹配名称;不包含 `*` 的条目必须匹配同一文件中定义的模型 `display_name`。空数组拒绝所有模型。 | | `rate_limit` | object | 否 | 按 Key 设置限制,子字段与模型的 `rate_limit` 相同:`rps`、`rpm`、`rph`、`rpd`、`tpm`、`tpd`、`concurrency`。 | | `mcp_rate_limits` | object | 否 | 此 Key 按 MCP 服务器设置的请求和并发限制。Key 为已注册的 MCP 服务器名称,见下文。 | | `mcp_access` | object | 否 | 此 Key 可以调用的 MCP 工具:必填的 `allow` 列表和可选的 `deny` 列表,使用 `<server>__<tool>` 名称并按单 `*` Glob 匹配——`"github__*"` 覆盖某个服务器上的所有工具。省略该配置块表示此处无 MCP 工具访问权限,见下文。 | | `allowed_agents` | 字符串数组 | 否 | 此 Key 可以访问的 A2A Agent,按注册名称和单 `*` Glob 匹配。省略、`null` 或空值表示无 A2A Agent 访问权限。 | | `allowed_routes` | 字符串数组 | 否 | 此 Key 可以使用的[透传路由](#passthrough-routes),按路由名称和单 `*` Glob 匹配。省略、`null` 或空值表示无透传路由访问权限。 | | `jwt_subject` | string | 否 | 从已验证 JWT 中选择的外部身份。与 `jwt_provider` 一起设置;该组合在文件中必须唯一。 | | `jwt_provider` | string | 否 | 允许声明 `jwt_subject` 的 `oidc_providers` 条目名称。设置 `jwt_subject` 时必填。 | | `expires_at` | string | 否 | RFC 3339 时间戳;超过该时间后,Key 会停止认证并返回 `401`。省略表示永不过期。格式错误的时间戳会在加载时拒绝条目,而不是被静默视为永不过期。 | | `disabled` | boolean | 否 | 管理性禁用 Key:重新启用前,请求会返回 `401`。默认 `false`。 | | `team_id` | string | 否 | 团队归因,由 `scope: team` 的 `rate_limit_policies` 原样匹配。 | | `user_id` | string | 否 | 所属成员归因,由成员作用域策略原样匹配。 | | `user_name` | string | 否 | 仅用于遥测标签的可读所有者名称。 | ### MCP 工具访问权限和限额[​](#mcp-tool-access-and-limits "MCP 工具访问权限和限额的直接链接") 请通过 `mcp_access` 授予 MCP 工具访问权限。在 AISIX Cloud 中,该配置块是三层 ACL 中的一层,会与环境和团队的访问策略取交集;资源文件没有策略集合,因此这里该配置块是这把 Key 唯一的一层,没有该配置块的 Key 无法访问任何 MCP 工具。`allow` 为必填——不需要收窄、只依赖 `deny` 的 Key 请发送 `["*"]`,完全不允许调用的 Key 请发送 `[]`。 使用 `mcp_rate_limits` 为一个调用方 Key 分别设置每个已注册 MCP 服务器的限额。每个服务器条目支持以下字段: | 字段 | 限制 | | ------------- | ---------------------- | | `rps` | 每秒请求数。 | | `rpm` | 每分钟请求数。 | | `rph` | 每小时请求数。 | | `rpd` | 每日请求数。 | | `concurrency` | 最大进行中工具调用数。 | 这些限额与 Key 的常规 `rate_limit` 一起应用于 `tools/call` 请求;初始化和工具列表请求不计数。 以下示例允许一个调用方访问一个模型以及 `github` MCP 服务器公开的所有工具。常规 `rate_limit` 与工具限额同时生效,`mcp_rate_limits.github` 则进一步限制该服务器的工具调用。 resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-main provider: openai api_key: ${OPENAI_API_KEY} models: - display_name: gpt-4o provider: openai model_name: gpt-4o provider_key: openai-main mcp_servers: - name: github type: mcp url: https://api.example.com/mcp api_keys: # MY_APP_KEY 是保存明文调用方 Key 的环境变量名称; # 加载时会被哈希,且绝不会存储明文。 - display_name: my-app key_env: MY_APP_KEY allowed_models: ["gpt-4o"] mcp_access: allow: ["github__*"] rate_limit: rpm: 60 concurrency: 5 mcp_rate_limits: github: rpm: 30 concurrency: 2 ``` ## OIDC 服务提供方[​](#oidc-providers "OIDC 服务提供方的直接链接") OIDC 服务提供方条目定义网关在调用方认证中信任的外部签发者及其 JWT Token。已验证身份会映射到 `jwt_provider` 和 `jwt_subject` 字段分别与服务提供方和 Token 匹配的调用方 API Key。 | 字段 | 类型 | 必填 | 说明 | | ----------------- | ---------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | 是 | 条目标识,在 `oidc_providers` 中唯一。调用方 API Key 通过此名称引用服务提供方。 | | `issuer` | string | 是 | 预期的 JWT `iss` 声明,进行精确比较。每个已启用服务提供方必须使用不同签发者。 | | `audiences` | 字符串数组 | 是 | 接受的 JWT `aud` 值。Token 必须至少包含一个已配置值;列表至少包含一个条目。 | | `jwks_uri` | string | 否 | 获取签名 Key 的 JWKS 端点。省略时,AISIX 从 `<issuer>/.well-known/openid-configuration` 解析。 | | `identity_claim` | string | 否 | 其字符串值用于选择调用方 API Key `jwt_subject` 的声明。Key 中的点用于遍历嵌套对象。默认:`sub`。 | | `required_scopes` | 字符串数组 | 否 | 必须全部出现在 Token `scope` 声明中的作用域。该声明可以是空格分隔字符串或数组。默认:不要求作用域。 | | `bound_claims` | object | 否 | 必须全部满足的额外声明要求。Key 中的点用于遍历嵌套声明。每个值可以是字符串或非空数组;字符串声明必须等于某个接受值,数组声明必须包含一个接受值。 | | `leeway_secs` | integer | 否 | `exp` 和 `nbf` 的时钟偏差容许值,范围为 `0` 到 `300` 秒。默认 `0`。 | | `enabled` | boolean | 否 | 服务提供方是否参与身份认证。默认 `true`。 | `issuer` 和 `jwks_uri` 的用户信息或疑似凭证查询参数中不得包含嵌入凭证。AISIX 接受非对称 JWT 签名算法,并拒绝 HMAC 签名 Token。支持的算法、请求行为和 Key 轮换请参见 [JWT 认证](https://docs.apiseven.com/ai-gateway/traffic-controls/jwt-authentication.md)。 以下配置会信任 `corp-keycloak` 签发者,并将 JWT 主体 `agent-billing-01` 映射到 `billing-agent` 调用方条目。 即使启用 JWT 身份认证,每个调用方条目仍需要 `key_env` 或 `key_hash`。加载以下示例前,请在网关进程环境中设置 `BILLING_AGENT_KEY`。空的 `allowed_models` 列表会拒绝模型访问;当此身份需要调用模型端点时,请添加模型别名。 resources.yaml ``` _format_version: "1" oidc_providers: - name: corp-keycloak issuer: https://sso.example.com/realms/agents audiences: ["aisix-gateway"] required_scopes: ["ai.access"] bound_claims: department: ai-lab api_keys: - display_name: billing-agent key_env: BILLING_AGENT_KEY allowed_models: [] jwt_subject: agent-billing-01 jwt_provider: corp-keycloak ``` ## MCP 身份认证设置[​](#mcp-authentication-settings "MCP 身份认证设置的直接链接") 可选的 `mcp_auth_settings` 集合控制客户端如何在 `/mcp` 和 `/mcp/{server}` 上进行身份认证。它在每个环境中是单例,因此资源文件最多只能包含一个条目;第二个条目会导致加载错误。该条目包含两项互相独立的设置:同时启用 OIDC 服务提供方时,`resource_url` 会启用 OAuth Discovery;`anonymous` 则允许来自可信网络且未提供凭证的调用方访问所选 MCP 条目。 | 字段 | 类型 | 必填 | 说明 | | --------------------------- | ---------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `resource_url` | string | 否 | 网关 `/mcp` 端点的规范公共 URL。它必须是绝对 `http` 或 `https` URL,路径必须恰好为 `/mcp`,不得包含查询参数、片段或嵌入式凭证。该 URL 还必须出现在为 MCP 登录启用的 OIDC 服务提供方所接受的 Audience 中。 | | `anonymous` | object | 否 | 匿名访问设置。省略时,每个 MCP 请求都必须提供有效的网关 API Key 或可信 OAuth Access Token。 | | `anonymous.enabled` | boolean | 否 | 是否启用匿名访问。默认:`true`。设为 `false` 可在关闭匿名访问的同时保留设置。 | | `anonymous.api_key_id` | string | 是\* | 匿名请求以其身份运行的 `api_keys` 条目确定性 ID。该 Key 的 MCP 授权、限额、安全护栏和用量归因照常生效。设置 `anonymous` 时必填。 | | `anonymous.source_cidrs` | 字符串数组 | 是\* | 允许匿名进入的非空客户端来源 CIDR 列表。AISIX 会匹配通过 Real IP 配置解析出的客户端地址,而不是调用方提供的不可信请求头。设置 `anonymous` 时必填。 | | `anonymous.servers` | 字符串数组 | 是\* | 匿名调用方可以访问的非空 MCP 服务器名称列表。该列表也是此主体通过聚合 `/mcp` 端点访问内容的上限。设置 `anonymous` 时必填。 | | `anonymous.aggregate_entry` | boolean | 否 | 聚合 `/mcp` 端点是否也为匿名调用方提供服务。默认:`false`。启用后,不带凭证的客户端不会收到原本用于启动 OAuth Discovery 的 `401`。 | 以下示例会启用 OAuth Discovery,并允许一个可信网络匿名访问 `docs` 服务器。API Key ID 与根据显示名称 `anonymous-mcp` 派生的确定性 ID 一致: resources.yaml ``` _format_version: "1" oidc_providers: - name: corp-sso issuer: https://sso.example.com/realms/agents audiences: - https://gateway.example.com/mcp required_scopes: - mcp:tools api_keys: - display_name: anonymous-mcp key_env: ANONYMOUS_MCP_KEY allowed_models: [] mcp_access: allow: - docs__* mcp_servers: - name: docs type: mcp url: https://docs.example.com/mcp mcp_auth_settings: - resource_url: https://gateway.example.com/mcp anonymous: api_key_id: d6869ae7-741a-598e-8213-16672e922546 source_cidrs: - 10.0.0.0/8 servers: - docs aggregate_entry: false ``` 请在网关进程环境中设置 `ANONYMOUS_MCP_KEY`。有关身份认证流程和安全影响,请参阅[客户端身份认证](https://docs.apiseven.com/ai-gateway/mcp-gateway/client-authentication.md)。 ## Claim 映射[​](#claim-mappings "Claim 映射的直接链接") Claim 映射在没有 Key 直接绑定 Token Subject 时,把 JWT 中已验证的声明解析到一把既有的调用方 API Key。命中提供方的已启用映射按 `priority` 顺序求值(数值小者在前,同值按 `name` 排序);第一条条件全部成立的映射决定所用的 Key,未命中任何映射的 Token 会被拒绝。求值语义参见 [JWT Claim 映射](https://docs.apiseven.com/ai-gateway/traffic-controls/claim-mappings.md)。 | 字段 | 类型 | 必填 | 说明 | | -------------------- | ---------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | 是 | 条目标识,在 `claim_mappings` 中唯一。也是同优先级时的求值决胜依据。 | | `jwt_provider` | string | 是 | 此映射作用的 `oidc_providers` 条目名称。必须引用文件中已定义的提供方。 | | `priority` | integer | 否 | 在该提供方的映射中的求值顺序;数值小者先求值。默认:`0`。 | | `match` | array of objects | 是 | 声明条件,全部成立才算命中。每个条件包含 `claim`(点号遍历嵌套对象)、`op`(`exact` 匹配字符串声明,`contains` 匹配数组声明;非字符串数组元素被忽略)和 `values`(任一匹配即可的备选值)。列表至少一个条件。 | | `resolve.api_key` | string | 见下 | 命中请求所运行的调用方 API Key 的 `display_name`。加载时解析为对应条目。 | | `resolve.api_key_id` | string | 见下 | Key 引用的规范形式,用于按规范 schema 直接编写的文档。`resolve.api_key` / `resolve.api_key_id` 必须恰好设置一个。配置导出会像其他引用一样,把存储的 ID 转换回 Key 名称并输出 `resolve.api_key`。 | | `enabled` | boolean | 否 | 映射是否参与求值。默认:`true`。 | 引用的提供方和 API Key 必须定义在同一文件中;未知引用或空的 `match` 列表会导致加载失败。 resources.yaml ``` _format_version: "1" oidc_providers: - name: corp-keycloak issuer: https://sso.example.com/realms/agents audiences: ["aisix-gateway"] api_keys: - display_name: finance-policy-key key_env: FINANCE_POLICY_KEY allowed_models: [] claim_mappings: - name: finance-dept jwt_provider: corp-keycloak priority: 100 match: - claim: department op: exact values: ["finance"] resolve: api_key: finance-policy-key ``` ## 安全护栏[​](#guardrails "安全护栏的直接链接") 安全护栏条目用于检查请求或响应内容。它只在[绑定](#guardrail-attachments)指定的范围内运行——没有任何绑定的安全护栏会被加载、会计入资源总数,但不检查任何流量。`kind` 字段标识安全护栏类型,并决定条目还接受哪些字段。这些字段直接位于条目中,不存在嵌套 `config` 对象。所选类型的未知字段会被拒绝。 安全护栏条目的通用字段如下;除非特别说明,均与类型无关: | 字段 | 类型 | 必填 | 说明 | | ------------------ | ------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | 是 | 条目标识,在 `guardrails` 中唯一,并显示在指标标签和错误原因中。 | | `kind` | enum | 是 | 安全护栏类型,见下方类型表。 | | `enabled` | boolean | 否 | `false` 会暂存规则但不运行。默认 `true`。 | | `hook_point` | enum | 否 | 规则运行位置:`input`(请求负载,在上游调用前)、`output`(上游响应)或 `both`(默认)。 | | `direction` | string | 否 | 用于兼容基于挂载配置的字段。它不会选择资源文件安全护栏的运行位置;执行位置由 `hook_point` 控制。新资源文件应省略此字段。 | | `enforcement_mode` | string | 否 | `block`(默认)会执行判定;`monitor` 记录本应发生的结果,但不阻断或脱敏。 | | `fail_open` | boolean | 否 | 该安全护栏无法完成检查时的行为,对**所有**类型都生效。有两类原因会走到它:后端不响应,这只会发生在会调用外部服务的类型上;以及网关根本没有可扫描的内容,这对所有类型都会发生,`keyword` 和 `pii` 也不例外。`true` 允许该流量并记录绕过;`false`(默认)返回 `422` 阻断。它管输入钩子——在 `keyword` 和 `pii` 上还同时管输出钩子。参见[安全护栏行为](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/behavior.md#handle-remote-guardrail-failures)。 | | `output_fail_open` | boolean | 否 | 输出钩子的相同策略,适用于除 `keyword` 和 `pii` 外的所有类型。这两个类型没有 `output_fail_open` 并会拒绝该字段,它们的 `fail_open` 同时管两个钩子。默认 `false`。 | | `timeout_ms` | integer | 否 | 远程 API 和 `semantic` 类型的检查截止时间。对于 `custom`,它限制整个钩子调用。默认 `5000`。`keyword`、`pii` 和 `bedrock` 会拒绝此字段;Bedrock 使用 `latency_mode`。 | | `created_at` | string | 否 | RFC 3339 时间戳。存在时,安全护栏按最早时间优先求值;没有此字段的条目排在最后。 | 所选 `kind` 决定条目还接受哪些字段: | `kind` | 必填字段 | 重要选项 | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `keyword` | `patterns`:进程内求值的 `{kind: literal \| regex, value}` 阻断模式数组。空列表可以加载,但不会匹配任何内容。 | — | | `semantic` | `embedding_model`;`deny_examples` 非空时还需 `deny_threshold`,`allow_examples` 非空时还需 `allow_threshold` | 要执行检查,至少需要一个非空的 `deny_examples` 或 `allow_examples` 列表。两者都为空时,安全护栏可以加载,但保持不活动。两个阈值都没有默认值——余弦分数在不同向量嵌入模型之间不可比较,因此文件中列了示例却没有对应阈值会导致校验失败,且被拒绝的是整个文件而不是那一个条目。取值方式参见[校准语义筛查安全护栏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/semantic-screening-calibration.md)。其他选项:`text_source`(默认 `user_messages`,也可为 `all_messages`)、`max_screened_texts`(默认 `8`)、`timeout_ms`、`max_buffer_bytes`、`on_buffer_exceeded`、`output_fail_open`。同一钩子的候选消息会在一次批量请求中生成向量嵌入。 | | `custom` | `script`:非空 ES 模块 | 导出 `checkInput`、`checkOutput` 或两者来检查对应钩子;未导出的钩子会跳过。其他选项:`secrets`、`timeout_ms`(整个调用默认 `5000`)、`max_memory_bytes`(默认 `16777216`)、`stream_processing_mode`(默认 `window`,也可为 `buffer_full`)、`window_size`、`window_overlap_size`、`max_buffer_bytes`、`on_buffer_exceeded`、`output_fail_open`。 | | `pii` | — | `detectors`(内置检测器列表:`email`、`china_mobile`、`china_id_card`、`bank_card`、`us_ssn`、`ip_address`、`api_key`、`jwt`、`private_key`,每个检测器可选 `action`)、`custom_patterns`(运维人员正则表达式,包含 `name`、`regex`,另可选填每个模式各自的 `action` 与 `replacement`)、`default_action`(默认 `mask`,或 `block`)。脱敏片段变为 `[<DETECTOR>_REDACTED]`,除非该模式设置了 `replacement`——它按字面量使用(`$1` 不会展开),且正则带捕获组时只替换第 1 组(参见 [PII 脱敏](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/pii.md#choose-what-a-masked-span-becomes))。匹配值绝不会出现在日志或错误中。 | | `presidio` | `analyzer_url`、`anonymizer_url`:客户自行运行的 Presidio 容器基础 URL。 | `entities`(Presidio 实体类型,每个实体可选 `action`)、`default_action`、`operator`(默认 `replace`,也可为 `mask`、`hash`、`redact`)、`language`(默认 `en`)、`score_threshold`。 | | `openai_moderation` | `api_key` | `model`(默认 `omni-moderation-latest`)、`category_thresholds`(按类别配置分数;空值采用服务提供方的 `flagged` 判定)、`endpoint` 覆盖。仅检测,不会改写内容。 | | `lakera` | `api_key` | `project_id`,以及用于区域或自托管部署的 `endpoint` 覆盖。 | | `azure_content_safety` | `endpoint`、`api_key` | Cognitive Services 端点上的 Azure Prompt Shield。 | | `azure_content_safety_text_moderation` | `endpoint`、`api_key` | `categories`(默认包含 `Hate`、`Sexual`、`SelfHarm`、`Violence` 四项)、`severity_threshold`(默认 `2`)、`severity_threshold_by_category`、`output_type`、`blocklist_names`、`halt_on_blocklist_hit`、`text_source`(默认 `concatenate_user_content`,或 `concatenate_all_content`),以及下文的流式控制。`text_source` 只影响输入钩子。 | | `aliyun_text_moderation` | `region`、`access_key_id`、`access_key_secret` | `endpoint` 覆盖、`risk_level_threshold`(`low`、`medium`、`high`,默认 `high`),以及下文的流式控制。 | | `aliyun_ai_guardrail` | `region`、`access_key_id`、`access_key_secret` | `endpoint` 覆盖、`service_level`(默认为 `pro`,也可设为 `basic`),以及下文的流式控制。所选服务等级必须已在阿里云中开通。 | | `bedrock` | `guardrail_id`、`guardrail_version`、`region`、`aws_credentials`(`{kind: static, access_key_id, secret_access_key}`)、`latency_mode`(`{kind: serial}` 或 `{kind: timed, timeout_ms: 100–5000}`) | — | 可选择流式处理模式的类型包括 Azure 文本审核、阿里云内容审核、阿里云 AI 安全护栏和 `custom`。它们支持窗口处理或完整缓冲。语义检查必须比较完整文本,因此始终缓冲完整输出。 | 字段 | 适用范围 | 行为 | | ------------------------ | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `stream_processing_mode` | 可选择流式处理模式的类型 | `window` 以滑动窗口增量释放内容,也是默认值;`buffer_full` 会在释放前保留完整响应。 | | `window_size` | 可选择流式处理模式的类型 | 设置滑动窗口大小。 | | `window_overlap_size` | 可选择流式处理模式的类型 | 设置连续窗口之间的重叠大小。 | | `max_buffer_bytes` | PII、Lakera、Presidio、`semantic`,以及使用 `buffer_full` 模式且可选择流式处理模式的类型 | 为检查而保留的最大响应字节数。默认 `262144`。 | | `on_buffer_exceeded` | 上述缓冲类型 | `fail_closed` 在超过缓冲区限制时拒绝处理,也是默认值;`fail_open` 会释放内容。 | 服务提供方凭证(`api_key`、`access_key_secret`、`aws_credentials.secret_access_key`)和自定义脚本的 `secrets` 值属于敏感信息,请以 `${VAR}` 形式提供。各类型的行为请参见[安全护栏指南](https://docs.apiseven.com/ai-gateway/traffic-controls/guardrails/overview.md)。 以下示例将本地输入检查与远程内容审核组合起来。`block-secrets` 会在上游调用前拒绝匹配的请求文本;`content-moderation` 则在默认的 `both` 钩子上使用 OpenAI Moderation API 检查请求和响应。 resources.yaml ``` _format_version: "1" guardrails: # 仅作用于请求侧的进程内关键词阻断列表。 - name: block-secrets kind: keyword hook_point: input patterns: - kind: literal value: internal-project-codename - kind: regex value: '\bAKIA[0-9A-Z]{16}\b' # 远程内容审核;所列类别达到阈值时阻断。 - name: content-moderation kind: openai_moderation api_key: ${OPENAI_API_KEY} category_thresholds: violence: 0.5 ``` ## 安全护栏绑定[​](#guardrail-attachments "安全护栏绑定的直接链接") 绑定关系将一个安全护栏关联到它要检查的流量。没有任何绑定的安全护栏会正常加载、计入资源总数,但不检查任何流量——网关会为它记录一次包含其名称的警告,`aisix validate` 也会列出它,但退出码仍为 `0`。这是一个合法状态:绑定通过标识引用目标,而该目标可能已从文件中移除。 | 字段 | 类型 | 必填 | 说明 | | -------------- | ------- | -------- | --------------------------------------------------------------------------------------------------- | | `guardrail_id` | string | 是 | 要绑定的安全护栏名称,必须匹配 `guardrails` 中的条目。 | | `scope_type` | string | 是 | `env`、`model`、`mcp_server`、`api_key`、`team`、`passthrough_route` 之一。 | | `scope_id` | string | 条件必填 | 作用目标的标识。`scope_type: env` 时省略,其余作用域必填。 | | `priority` | integer | 是 | 同一请求的多条绑定选中同一个安全护栏时,数值大的优先。 | | `enabled` | boolean | 否 | 默认为 `true`。已禁用的绑定不产生作用范围,但仍算作该安全护栏已被附加,因此不会被报告为「未附加」。 | `scope_id` 使用目标集合自身的标识书写——模型的 `display_name`、MCP 服务器或透传路由的 `name`、调用方 API Key 的 `display_name`——加载器会把它解析成与目标条目相同的派生 ID。`scope_type: team` 在文件中没有对应集合,因此其 `scope_id` 原样保留,与调用方 API Key 声明的 `team_id` 直接比较。 以下局部配置块假定完整资源文件已定义 `gpt-4o`;请合并到完整配置后再校验。 resources.yaml(安全护栏绑定) ``` guardrails: - name: no-secrets kind: keyword patterns: - kind: literal value: supersecret-banned-token guardrail_attachments: # 检查该网关处理的每个请求。 - guardrail_id: no-secrets scope_type: env priority: 100 # ……或只检查发往某个模型的流量。 - guardrail_id: no-secrets scope_type: model scope_id: gpt-4o priority: 100 ``` 上面两条绑定指向同一个安全护栏,因此发往 `gpt-4o` 的请求只会执行它一次:优先级最高的匹配生效,重复项被丢弃。 ## MCP 服务器[​](#mcp-servers "MCP 服务器的直接链接") MCP 服务器条目以 `<name>__<tool>` 的形式向 MCP 客户端公开工具。它可以连接上游 MCP 服务器,也可以根据内联 OpenAPI 文档生成工具。两种情况下,上游凭证均由网关保存;该凭证不会从调用方客户端转发,也不会暴露给调用方。 | 字段 | 类型 | 必填 | 说明 | | ------------------------ | ---------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | 是 | 条目标识,在 `mcp_servers` 中唯一,也是该服务器工具的命名空间前缀。不得包含保留分隔符 `__`。可以使用 `display_name` 作为替代写法,但只能使用其中一种。 | | `type` | enum | 否 | `mcp`(默认)连接真实 MCP 服务器;`openapi` 根据 OpenAPI 文档生成工具,并将调用作为常规 HTTP 请求发送。 | | `url` | string | 是 | 对于 `type: mcp`,这是上游 MCP 端点;对于 `type: openapi`,这是生成工具调用所用的 REST API 基础 URL。 | | `spec` | object | 是\* | 内联 OpenAPI 3.x 文档,`type: openapi` 时必填,`type: mcp` 时忽略。在资源文件中,将文档写成嵌套 YAML 映射。 | | `transport` | enum | 否 | `streamable_http`,这是 `type: mcp` 唯一受支持的传输方式,也是默认值。 | | `protocol_version` | enum | 否 | 上游会话使用的 MCP 协议修订版,仅对 `type: mcp` 有效。除非服务器要求无状态的 `2026-07-28` 修订版,否则不要设置:默认的 `initialize` 握手会自动协商修订版,对保持向后兼容的 `2026-07-28` 服务器同样适用。请为该值加引号,使 YAML 将其解析为字符串。 | | `auth_type` | enum | 否 | 网关向上游认证的方式:`none`(默认)、`bearer`(将 `secret` 作为 `Authorization: Bearer` 发送)、`api_key`(将 `secret` 作为 API Key 请求头发送),或 `oauth2`(客户端凭证授权;Token 会缓存到即将过期前)。 | | `api_key_header` | string | 否 | `type: openapi` 且 `auth_type: api_key` 时使用的请求头。默认 `x-api-key`。真实 MCP 服务器始终使用 `x-api-key` 进行 API Key 身份认证。 | | `forward_client_headers` | 字符串数组 | 否 | 中继给该服务器的入站客户端请求头,取值为精确名称或含一个 `*` 的通配符(例如 `x-trace-*`),匹配不区分大小写。为空(默认值)时不转发任何请求头。`type: mcp` 和 `type: openapi` 均适用,因此以工具形式暴露的 REST API 在每次工具调用时都会收到它们。[凭证槽位](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#headers-that-must-be-named-exactly)以及 `traceparent`/`tracestate` 只有在模式精确点名时才会中继。中继的凭证会占用 `auth_type` 本会填入的槽位,而不是与之并存,其中包括 `api_key_header` 指定的那个请求头——只要它被改成该清单之外的名称,通配符就能匹配到它。`host`、逐跳请求头、`x-aisix-*`、网关会重新序列化的请求体与内容协商请求头、`set-cookie`、`anthropic-version`、`x-stainless-*`,以及 MCP 会话槽位(`mcp-session-id`、`mcp-protocol-version`、`last-event-id`)绝不会被中继。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md)。 | | `secret` | string | 否 | 根据 `auth_type`,表示 Bearer Token、API Key 或 OAuth 客户端 Secret。请以 `${VAR}` 形式提供。 | | `client_id` | string | 否 | OAuth 客户端标识符,与 `auth_type: oauth2` 一起使用。 | | `token_url` | string | 否 | 交换客户端凭证的 OAuth Token 端点,与 `auth_type: oauth2` 一起使用。 | | `scopes` | 字符串数组 | 否 | OAuth 作用域,会以空格连接后写入 Token 请求。 | | `timeout_ms` | integer | 否 | 每个上游操作(建立会话、列出工具、调用工具)的截止时间。最小 `1`,默认 30,000 ms。 | | `enabled` | boolean | 否 | `false` 会从列表和调用中移除该服务器的工具。默认 `true`。 | 通过每个 Key 的 [`api_keys[].mcp_access`](#caller-api-keys) 授予调用方工具访问权限。调用方连接流程请参见 [MCP 网关概览](https://docs.apiseven.com/ai-gateway/mcp-gateway/overview.md)。 以下条目将远程 MCP 服务器公开为 `github` 工具命名空间,并通过环境变量中的 Bearer Token 向上游进行身份认证: resources.yaml ``` _format_version: "1" mcp_servers: - name: github type: mcp url: https://api.example.com/mcp auth_type: bearer secret: ${GITHUB_MCP_TOKEN} ``` ### 基于 OpenAPI 的服务器[​](#openapi-backed-servers "基于 OpenAPI 的服务器的直接链接") 对于 `type: openapi`,受支持的 HTTP 操作会成为 MCP 工具。存在 `operationId` 时,AISIX 使用它作为工具名称;否则根据 HTTP 方法和路径派生名称。资源文件直接在 `spec` 下接受文档,不接受 AISIX Cloud 的写入字段 `spec_content` 或 `spec_url`。 以下示例中,`listItems` 操作成为 `inventory` 命名空间中的 MCP 工具。工具调用会携带插值后的 API Key,通过 `X-Inventory-Key` 发送到已配置的 REST API。 resources.yaml ``` _format_version: "1" mcp_servers: - name: inventory type: openapi url: https://inventory.example.com/api auth_type: api_key api_key_header: X-Inventory-Key secret: ${INVENTORY_API_KEY} spec: openapi: 3.0.0 info: title: Inventory API version: 1.0.0 paths: /items: get: operationId: listItems responses: "200": description: Items returned successfully ``` ## A2A Agent[​](#a2a-agents "A2A Agent的直接链接") A2A Agent 条目注册一个上游 Agent,网关通过 `/a2a/<name>` 向调用方暴露它,并提供已将 URL 重写到网关的 Agent Card。与 MCP 服务器一样,上游凭证会保留在网关中。 | 字段 | 类型 | 必填 | 说明 | | ------------------------ | ---------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | 是 | 条目标识,在 `a2a_agents` 中唯一,也是面向调用方的路径片段。可以使用 `display_name` 作为替代写法,但只能使用其中一种。 | | `url` | string | 是 | 上游 Agent 基础 URL。 | | `protocol_version` | enum | 否 | A2A 传输格式:`"1.0"`(默认)或 `"0.3"`。请为值添加引号,确保 YAML 将其保留为字符串。 | | `auth_type` | enum | 否 | `none`(默认)、`bearer` 或 `api_key`,语义与 MCP 服务器相同。 | | `secret` | string | 否 | 根据 `auth_type` 使用的上游凭证。请以 `${VAR}` 形式提供。 | | `forward_client_headers` | 字符串数组 | 否 | 中继给该 Agent 的入站客户端请求头,取值为精确名称或含一个 `*` 的通配符(例如 `x-trace-*`),匹配不区分大小写。为空(默认值)时不转发任何请求头。它对 `/a2a/<name>/.well-known/agent-card.json` 上的 Agent Card 拉取,以及 `/a2a/<name>` 上的每个 JSON-RPC 方法都生效,因此 `message/send`、`message/stream` 和各类 task 操作都会收到它们。[凭证槽位](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md#headers-that-must-be-named-exactly)以及 `traceparent`/`tracestate` 只有在模式精确点名时才会中继。中继的凭证会占用 `auth_type` 本会填入的槽位——`bearer` 填 `authorization`,`api_key` 填 `x-api-key`——而不是与之并存。`host`、逐跳请求头、`x-aisix-*`、网关会重新序列化的请求体与内容协商请求头、`set-cookie`、`anthropic-version`、`x-stainless-*`,以及 `a2a-version` 绝不会被中继。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md)。 | | `timeout_ms` | integer | 否 | 每个上游操作(包括获取 Agent Card)的截止时间。对流式方法(`message/stream`、`tasks/resubscribe`)而言,它约束的是建立流的过程而非流的时长,因此长任务不会被中断。最小 `1`,默认 30,000 ms。 | | `enabled` | boolean | 否 | `false` 会停止提供该 Agent。默认 `true`。 | 通过每个 Key 的 [`api_keys[].allowed_agents`](#caller-api-keys) 授予调用方访问权限。完整的调用方连接流程请参阅[配置 Agent 网关](https://docs.apiseven.com/ai-gateway/agent-gateway/setup.md)。 以下条目在 `/a2a/invoice-processor` 发布上游 Agent,并从环境变量提供其 Bearer Token: resources.yaml ``` _format_version: "1" a2a_agents: - name: invoice-processor url: https://agents.example.com/a2a auth_type: bearer secret: ${INVOICE_AGENT_TOKEN} ``` ## 透传路由[​](#passthrough-routes "透传路由的直接链接") 透传路由将匹配的 HTTP 流量中继到服务提供方端点,AISIX 不对正文做归一化,但仍然应用调用方身份认证、路由授权、护栏、限流和遥测。正文信封(chat、completions、Responses API 或不透明)会按请求识别,无需任何配置。SSE 响应会增量中继,除非输出安全护栏为执行检查而暂存帧。匹配、认证、凭证与识别模型的说明见[透传路由](https://docs.apiseven.com/ai-gateway/endpoints/provider-passthrough.md);本表覆盖文件形式。 以下局部配置块展示一个透传路由。它假定完整资源文件中已经定义了 `openai-prod`: resources.yaml(透传路由) ``` passthrough_routes: - name: openai-raw path_prefix: /passthrough/openai target_url: https://api.openai.com provider_key: openai-prod ``` | 字段 | 类型 | 必填 | 说明 | | ------------------------ | ---------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | 是 | 条目标识,在 `passthrough_routes` 中唯一。也接受 `display_name` 写法;只能使用其中一种。调用方 Key 通过 `allowed_routes` 授予对该名称的访问。 | | `path_prefix` | string | 条件 | 路由认领的 URL 路径前缀,例如 `/passthrough/openai`。`path_prefix` 和 `hosts` 至少必须设置其一。**不带** `hosts` 的路由不得认领保留的网关命名空间(`/v1`、`/mcp`、`/a2a`、`/admin`、`/livez`、`/readyz`、`/metrics`)——网关自身的端点会遮蔽它;**带** `hosts` 的路由则可以,因为 host 匹配的请求在这些端点之前分发。在 `target_url` 路由上前缀是挂载点,转发前会被剥离;在 `preserve_host` 路由上前缀仅用于筛选该路由认领哪些请求,完整路径原样转发。 | | `hosts` | 字符串数组 | 条件 | 路由认领的入站 `Host` 值,在路径路由之前匹配。条目是精确 host,或带单个前导 `*.` 通配符且保留至少两个字面标签(`*.example.com` 可以,`*.com` 不行)。 | | `target_url` | string | 条件 | 匹配请求中继到的上游基础 URL。`target_url` 和 `preserve_host: true` 必须恰好设置其一。 | | `preserve_host` | boolean | 条件 | 以 `https://<matched host>` 推导目标,替代固定 `target_url`。要求设置 `hosts`。默认 `false`。 | | `auth_mode` | enum | 否 | 网关认证调用方的方式:`gateway_key`(标准 `Authorization` 调用方 Key)、`header_key`(从 `auth_header_name` 读取调用方 Key,不动 `Authorization`),或 `anonymous`(无凭证;路由以 `anonymous_key` 主体运行)。默认 `gateway_key`。 | | `auth_header_name` | string | 条件 | 携带网关 Key 的小写请求头。`header_key` 模式必填,其他 `auth_mode` 下设置会被拒绝。`authorization`、`proxy-authorization`、`cookie`、`set-cookie` 和 `x-api-key` 会被拒绝。除非 `forward_client_headers` 完整写出它的名称,否则会在转发前剥离;通配符触及不到它。 | | `anonymous_key` | string | 条件 | 匿名流量以其身份、限流和归因运行的调用方 Key 显示名称。`anonymous` 模式必填(需同时设置 `source_cidrs`),其他模式下设置会被拒绝。 | | `source_cidrs` | 字符串数组 | 条件 | 客户端 CIDR 白名单。`anonymous` 模式必填;其他模式可选。来源不在列表内时以 `403` 和 `error.code: ip_restricted` 拒绝。 | | `credential_mode` | enum | 否 | 上游凭证处理:`inject`(发送所引用服务提供方密钥的凭证;要求 `provider_key`)或 `forward_client`(经过身份认证模式和固定请求头剥离后,中继调用方的上游凭证;禁止设置 `provider_key`)。采用 `gateway_key` 时,AISIX 会剥离 `authorization` 和 `x-api-key`;上游凭证使用其中任一请求头时,请采用 `header_key` 或 `anonymous`。默认 `inject`。 | | `provider_key` | string | 条件 | 注入到上游的服务提供方密钥显示名称。`inject` 必填,`forward_client` 禁止。 | | `identity_header` | string | 否 | 其值记录为用量事件 `client_identity` 并在转发前剥离的小写请求头,除非 `forward_client_headers` 完整写出它的名称;通配符触及不到它。`authorization`、`proxy-authorization`、`cookie`、`set-cookie` 和 `x-api-key` 会被拒绝。 | | `forward_client_headers` | 字符串数组 | 否 | 即使该路由本会剥离,也仍要中继给上游的入站客户端请求头,取值为精确名称或含一个 `*` 的通配符(例如 `x-trace-*`),匹配不区分大小写。为空(默认值)时不覆盖任何剥离行为。路由默认就会中继调用方的请求头,因此该字段只对它会删除的那些有意义:`credential_mode: inject` 下服务提供方密钥的 `strip_headers`,以及网关用来认证调用方的那个槽位。在 `auth_mode: gateway_key` 下点名 `authorization`,会把调用方自己的凭证放到上游请求上,取代注入的那份,而不是两份并存。凭证槽位以及 `traceparent`/`tracestate` 只有在模式精确点名时才会中继,该路由自己的 `auth_header_name` 和 `identity_header` 同理。路由剥离的其他任何名称,通配符都足以放回去,包括 `strip_headers` 条目——不过该列表四个默认值中有三个属于凭证槽位,仍需单独点名,只有 `set-cookie` 是通配符能放回的默认项。无论模式如何,`host`、`content-length`、逐跳请求头和 `x-aisix-*` 都会被剥离。参见[上游请求头](https://docs.apiseven.com/ai-gateway/models/upstream-request-headers.md)。 | | `timeout_ms` | integer | 否 | 响应头阶段和非流式正文读取的上游超时(毫秒)。健康的 SSE 中继绝不会被该超时切断。省略时使用网关默认值。 | | `enabled` | boolean | 否 | 不删除路由而将其停用;停用的路由停止匹配。默认 `true`。 | ## 缓存策略[​](#cache-policies "缓存策略的直接链接") 缓存策略会缓存其匹配请求中符合条件的非流式 Chat Completions 响应;其它端点族和流式响应不会缓存。代理会为每个请求选择第一个匹配且已启用的策略。Key 匹配和验证请参见[响应缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/caching.md)。 | 字段 | 类型 | 必填 | 说明 | | ------------------ | ------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | 是 | 条目标识,在 `cache_policies` 中唯一,长度 1–120 个字符,并显示在指标标签和缓存响应头中。 | | `enabled` | boolean | 否 | `false` 会暂存策略而不应用。默认 `true`。 | | `backend` | enum | 否 | `memory`(默认)或 `redis`。`redis` 后端需要网关静态 `cache.redis` 配置;缺少时,匹配请求不会缓存。 | | `ttl_seconds` | integer | 否 | 条目生存时间,1–604,800 秒(7 天)。默认 `3600`。 | | `applies_to` | string | 否 | 资格选择器:`all`(默认)、`model:<alias>`(以路由分发前的模型别名为目标的请求),或 `api_key:<id>`(由该资源 ID 的调用方 API Key 认证的请求)。 | | `scope` | enum | 否 | 缓存条目的共享边界,对两个匹配层同时生效:`api_key`(默认——条目仅对写入它的调用方 API Key 可见)或 `env`(环境内所有调用方共享条目)。 | | `purge_generation` | integer | 否 | 失效计数器,默认 `0`。递增它会使该策略在更早取值下存储的所有条目失效——两个匹配层、所有网关实例。 | | `semantic` | object | 否 | 在精确层之上启用向量相似度匹配。见下方子表。 | AISIX Cloud 通过清空操作管理 `purge_generation`。在资源文件中,请让该值单调递增,并在每次更新时保留当前值。降低或省略该值可能会使更早的精确缓存条目重新可用,直至其 TTL 过期。 `semantic` 字段: | 字段 | 类型 | 必填 | 说明 | | ---------------------- | ------- | ---- | ------------------------------------------------------------------------------------------------------------- | | `embedding_model` | string | 是 | 本文件中带 [`embedding` 块](#models)的模型条目的 `display_name`。其 `dimensions` 值固定该策略条目的向量维度。 | | `threshold` | number | 是 | 条目被返回所需的最小余弦相似度,取值 `0`–`1`,越高越严格;低于约 `0.9` 时错误答案风险显著上升。 | | `max_entries` | integer | 否 | `memory` 后端下的条目上限,1–10,000,默认 `1000`,最旧的先被淘汰。共享后端按 TTL 控制规模并忽略此值。 | | `embedding_timeout_ms` | integer | 否 | 向量嵌入调用的单次超时。超时后请求不经缓存直接发往上游。`0` 或缺省表示不设单独超时。 | 只有消息内容全部为文本的请求才参与相似度匹配。在 `backend: redis` 上,语义层需要 Redis 8+(向量检索)、RESP2,以及 `single` 或 `sentinel` 模式。不满足这些要求时,策略只提供精确匹配并记录警告。参见[语义缓存](https://docs.apiseven.com/ai-gateway/traffic-controls/semantic-caching.md)。 `applies_to` 值在请求时匹配,不会在加载时解析。对于 `api_key`,资源加载器不会解析 `display_name`,请使用[派生 ID](#identity-and-derived-ids)。不匹配任何内容的模型别名不会产生缓存。与之不同,`semantic.embedding_model` 引用必须指向同一文件中的向量嵌入模型条目——悬空的名字会在记录警告后禁用语义层,精确缓存继续工作。 注意 无法识别的 `applies_to` 前缀按 `all` 处理。因此,前缀拼写错误会扩大缓存范围,而不是禁用策略。 以下完整示例在内存中缓存 `gpt-4o` 别名的非流式响应,缓存时间为 10 分钟: resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-prod provider: openai api_key: ${OPENAI_API_KEY} models: - display_name: gpt-4o provider: openai model_name: gpt-4o-2024-11-20 provider_key: openai-prod cache_policies: - name: gpt-4o-cache backend: memory ttl_seconds: 600 applies_to: "model:gpt-4o" ``` ## 可观测性导出器[​](#observability-exporters "可观测性导出器的直接链接") 可观测性导出器会把请求遥测发送到外部系统。`kind` 字段选择后端,该类型的字段直接位于条目中。每种类型都是封闭的,因此会拒绝未知字段,包括任何明文凭证字段。 所有类型共享以下字段: | 字段 | 类型 | 必填 | 说明 | | --------- | ------- | ---- | ------------------------------------------------------------------ | | `name` | string | 是 | 条目标识,在 `observability_exporters` 中唯一,长度 1–120 个字符。 | | `kind` | enum | 是 | `otlp_http`、`aliyun_sls`、`datadog` 或 `object_store`。 | | `enabled` | boolean | 否 | 已禁用的导出器保留配置,但不会接收遥测。默认 `true`。 | 所选 `kind` 还会添加该后端的专用字段: | `kind` | 必填字段 | 可选字段 | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `otlp_http` | `endpoint`:包含接收器路径的完整 OTLP/HTTP 链路 URL,例如 `https://api.honeycomb.io/v1/traces`。除回环和测试主机外必须使用 `https://`。 | `headers`(每个导出请求的静态请求头,请把 API Key 放在 `${VAR}` 值中)、`sample_rate`(0.0–1.0;省略时,不会通过采样丢弃任何已发出的请求链路)、`content_mode`、`content_max_bytes`。 | | `aliyun_sls` | `endpoint`(区域 `*.aliyuncs.com` 主机,不带协议)、`project`、`logstore`、`credential_ref` | `content_mode`、`content_max_bytes`。 | | `datadog` | `site`(已知 Datadog 站点,例如 `datadoghq.com` 或 `datadoghq.eu`)、`service`、`credential_ref` | `ddsource`(默认 `aisix-ai-gateway`)、`tags`(渲染为 `ddtags`)、`content_mode`、`content_max_bytes`。 | | `object_store` | `provider`(`s3`、`gcs` 或 `azure_blob`)、`bucket`、`prefix` | `region`(S3 签名作用域)、`endpoint`(MinIO、OSS、R2 的 S3 兼容覆盖;除回环和测试主机外必须使用 `https://`)、`compression`(默认 `gzip`,或 `none`)、`auth_mode`、`credential_ref`。 | 对于 `otlp_http`、`aliyun_sls` 和 `datadog`,`content_mode` 控制导出记录是省略提示词和响应内容(`metadata_only`,默认值),还是包含这些内容(`full`)。在 `full` 模式下,`content_max_bytes` 将每个捕获内容字段限制为 1–1,048,576 字节,默认 131,072。`object_store` 类型不接受这两个字段。 有关投递和内容捕获行为,请参见[可观测性导出器](https://docs.apiseven.com/ai-gateway/observability/exporters.md)。 远程凭证绝不会直接保存在导出器资源中。在下列变量名中,`<REF>` 是把导出器的 `credential_ref` 转成大写,并将非字母数字字符替换为下划线后的结果,例如 `datadog-prod` 会变成 `DATADOG_PROD`。 | 导出器 | 凭证来源 | | ---------- | --------------------------------------------------------------------------------------------------------------------------------------- | | OTLP/HTTP | 将 API Key 放在插值后的 `headers` 值中。 | | 阿里云 SLS | 名为 `<REF>` 的凭证引用会解析 `SLS_CRED_<REF>_AK_ID` 和 `SLS_CRED_<REF>_AK_SECRET`。 | | Datadog | 名为 `<REF>` 的凭证引用会解析 `DD_CRED_<REF>_API_KEY`。 | | 对象存储 | 名为 `<REF>` 的凭证引用会解析适用的 `OBJSTORE_CRED_<REF>_*` 变量。对于 S3 和 GCS,`cloud_identity` 使用主机挂载的身份,不需要凭证引用。 | 以下示例比较三种凭证加载方式:直接在 OTLP 请求头中插值、使用命名的 Datadog 凭证引用,以及为 S3 使用挂载的云身份。YAML 下方的带圈数字说明高亮字段会解析为何值。 resources.yaml ``` _format_version: "1" observability_exporters: - name: honeycomb-prod kind: otlp_http endpoint: https://api.honeycomb.io/v1/traces headers: x-honeycomb-team: ${HONEYCOMB_API_KEY} sample_rate: 0.25 - name: datadog-prod kind: datadog site: datadoghq.com credential_ref: datadog-prod service: ai-gateway tags: ["team:platform", "tier:prod"] - name: s3-events kind: object_store provider: s3 bucket: acme-aisix-events prefix: ai-gateway region: us-east-1 auth_mode: cloud_identity ``` ❶ 标准资源插值会从 `HONEYCOMB_API_KEY` 提供 Honeycomb API Key。 ❷ `datadog-prod` 引用会从 `DD_CRED_DATADOG_PROD_API_KEY` 解析 API Key;该凭证绝不会出现在资源文件中。 ❸ `cloud_identity` 使用主机挂载的云身份,而不是静态 Key。此模式支持 S3 和 GCS 导出器。 ## 限流策略[​](#rate-limit-policies "限流策略的直接链接") 限流策略独立于模型和调用方 API Key 上的内联 `rate_limit` 块,对请求数或 Token 数施加上限。需要匹配多个请求属性或按维度拆分计数器时,请使用条件式;针对一个主体和一个固定窗口时,请使用经典形式。每个条目必须且只能使用一种形式;混用两种形式的字段会导致加载错误。有关配置路径和验证方法,请参见[限流策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md)。 ### 条件式[​](#conditional-form "条件式的直接链接") 新策略请使用条件式。它通过条件树匹配请求,可以按维度拆分计数器,并支持请求、Token 和并发限制。 | 字段 | 类型 | 必填 | 说明 | | ------------ | ------ | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | 是 | 条目标识,在 `rate_limit_policies` 中唯一。计数器以派生 ID 为 Key,因此可以跨重新加载保留。 | | `conditions` | array | 否 | 请求必须满足的条件节点。顶层节点全部生效(AND);空数组或省略表示匹配所有请求。每个节点可以是条件(`dimension`、`operator`、可选 `negate`、`value`),也可以是分组(`logic: and \| or`、可选 `negate`、`children`)。每条策略最多嵌套 3 层并包含 16 个条件。节点字段见下文。 | | `group_by` | array | 否 | 用于拆分桶的维度,可以是 `team`、`member`、`api_key`、`model`、`provider` 的任意子集。每种不同的值组合使用独立计数桶和相同的限制;空数组或省略表示使用一个共享桶。如果匹配的请求缺少其中某个维度,则该策略不适用于该请求。 | | `limits` | object | 是 | 至少包含 `rps`、`rpm`、`rph`、`rpd`、`tpm`、`tpd`、`concurrency` 中的一项,最小值均为 1;其结构和语义与内联 `rate_limit` 块相同。 | | `action` | enum | 否 | 超限行为。目前仅支持 `reject`(返回 HTTP `429`),也是默认值。 | | `schedules` | array | 否 | 周期性暂停窗口,与经典形式相同,见下文。 | `conditions` 节点可以是条件或分组。条件接受以下字段: | 字段 | 类型 | 必填 | 说明 | | ----------- | --------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dimension` | enum | 是 | `team`、`member`、`api_key`、`model`、`model_name` 或 `provider`。对于 `api_key` 和 `model`,值为同一文件中所定义条目的 `display_name`;加载时会解析它,未知名称会导致加载错误。`team`/`member` 值与调用方 API Key 的 `team_id`/`user_id` 原样匹配。`model` 和 `model_name` 匹配分发模型,并且——当请求经由模型组、语义路由器或合议模型路由时——同时匹配调用方所指向的父条目:组名可以选中所有经由该组路由的请求,成员名无论直接调用还是经组调用都会被选中;`negate` 会同时排除两个身份。`provider` 匹配分发模型的服务提供方 ID。 | | `operator` | enum | 是 | `==`、`~=`(不等于)、`in`、`~~`(正则表达式)或 `~*`(不区分大小写的正则表达式),即 [lua-resty-expr](https://github.com/api7/lua-resty-expr) Token。正则表达式运算符仅适用于 `model_name` 和 `provider`;模式最长 256 个字符且必须能够编译。 | | `negate` | boolean | 否 | 对条件取反,即 lua-resty-expr 的 `!` 前缀;`negate` 与 `in` 组合表示“不在其中”。不携带该维度的请求既不匹配原条件,也不匹配其取反。 | | `value` | string 或 array | 是 | 标量运算符使用一个字符串;`in` 使用包含 1–64 个字符串的数组。 | 如需使用嵌套布尔逻辑,请使用分组节点: | 字段 | 类型 | 必填 | 说明 | | ---------- | ------- | ---- | -------------------------------------------------- | | `logic` | enum | 是 | `and` 或 `or`,决定 `children` 的组合方式。 | | `negate` | boolean | 否 | 对分组结果取反(`!AND`/`!OR`)。 | | `children` | array | 是 | 至少包含一个嵌套节点,可以是条件或更深一层的分组。 | ### 经典形式[​](#classic-form "经典形式的直接链接") 针对一个主体的策略仍然完整支持经典形式。 | 字段 | 类型 | 必填 | 说明 | | -------------- | ------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `scope` | enum | 是 | 主体类型:`api_key`、`model`、`team`(整个团队共享一个桶)、`member`,或 `team_member`(团队限制,但每个成员使用独立计数器)。 | | `scope_ref` | string | 是 | 指定主体。对于 `scope: api_key` 或 `scope: model`,填写同一文件中所定义条目的 `display_name`;加载时会解析它,未知名称会导致加载错误。对于 `team`、`member` 和 `team_member`,填写团队或用户 ID,并与调用方 API Key 的 `team_id` 或 `user_id` 原样匹配。 | | `window` | enum | 是 | `second`、`minute`、`hour` 或 `day`。 | | `max_requests` | integer | 否\* | 每个窗口允许的请求数,最小 1。`max_requests` 和 `max_tokens` 至少配置一个。 | | `max_tokens` | integer | 否\* | 每个窗口允许的 Token 数,最小 1。Token 上限在 `minute` 和 `day` 窗口执行;在 `second` 和 `hour` 窗口中,该值可以接受但不会应用。请将 `max_tokens` 与 `minute` 或 `day` 窗口配合使用,参见[管理经典单作用域策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md#manage-classic-single-scope-policies)。 | | `schedules` | array | 否 | 周期性挂钟时间窗口,窗口内暂停执行该策略。窗口结束后会在相同计数器上自动恢复执行。条目字段见下文,也可参阅[按时间表暂停策略](https://docs.apiseven.com/ai-gateway/traffic-controls/rate-limit-policies.md#suspend-a-policy-on-a-schedule)。 | 每个 `schedules` 条目按星期(`days_of_week`)或显式日期(`dates`)选择生效日,两者必须且只能配置一个: | 字段 | 类型 | 必填 | 说明 | | -------------- | ------ | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `timezone` | string | 是 | 用于解释该条目挂钟时间字段的 IANA 时区,例如 `Asia/Shanghai`。 | | `days_of_week` | array | 否\* | 每周重复,可包含 `mon`、`tue`、`wed`、`thu`、`fri`、`sat`、`sun`;与 `dates` 互斥。 | | `dates` | array | 否\* | `timezone` 时区下显式指定的 `YYYY-MM-DD` 日期,用于节假日或其他不规则日期;与 `days_of_week` 互斥。 | | `start_time` | string | 是 | 窗口开始时间,采用 `HH:MM` 挂钟时间,包含该时刻。 | | `end_time` | string | 是 | 窗口结束时间,采用 `HH:MM` 挂钟时间,不包含该时刻;`24:00` 表示当天结束。结束时间早于开始时间表示跨越午夜,窗口归属于其开始日。相同的起止时间会被 AISIX Cloud 拒绝,并且在资源文件中永不匹配。例如 `days_of_week: [fri]` 且时间为 `22:00` 至 `09:00` 时,窗口覆盖星期五 22:00 至星期六 09:00。 | 以下示例以两种形式设置每分钟 300 个请求的限额。条件式策略为 `gpt-4` 模型系列的每个团队创建独立计数器;经典策略为 `gpt-4o` 模型别名创建一个计数器。 resources.yaml ``` _format_version: "1" provider_keys: - display_name: openai-prod provider: openai api_key: ${OPENAI_API_KEY} models: - display_name: gpt-4o provider: openai model_name: gpt-4o-2024-11-20 provider_key: openai-prod rate_limit_policies: # 条件式:gpt-4 系列按团队共享一个 300 RPM 的配额池。 - name: gpt4-family-per-team conditions: - dimension: model_name operator: "~~" value: "^gpt-4" group_by: [team] limits: rpm: 300 # 经典形式(旧版):每条策略对应一个主体。 - name: cap-gpt4o scope: model scope_ref: gpt-4o window: minute max_requests: 300 max_tokens: 100000 ``` --- # 发布说明 本页汇总 AISIX 网关、控制面、控制台和部署包中面向用户的变更,按版本从新到旧排列。 如果一次升级跳过了若干版本,其间每个版本的**升级说明**依然适用。请按从旧到新的顺序阅读——从你当前版本的下一个版本开始,一直读到目标版本。支持的升级路径和升级顺序参见[升级 AISIX](https://docs.apiseven.com/ai-gateway/on-premises/upgrade.md)。 发布产物包括 `docker.io/api7/aisix` 网关镜像、`docker.io/api7/aisix-cp-*` 下的控制面镜像、`aisix-cp` Helm Chart 和离线安装包。 ## 1.2.0[​](#120 "1.2.0的直接链接") **发布日期:** 2026 年 9 月 8 日 本版本明确了最低支持版本,并加强了网关配置兼容性校验:控制面会在保存前拒绝已注册网关无法加载的配置。网关优化了配置变更处理,避免每次 watch 事件都产生与完整配置规模成正比的开销,解决批量修改配置导致请求处理阻塞的问题。此外,运维人员可以按指标选择标签集合;OpenAI 上游返回的原始缓存写入计数也会完整保留在网关响应、用量日志及其导出结果中。 ### 行为变化[​](#行为变化 "行为变化的直接链接") * **Token 用量恰好达到窗口上限时,网关现在会拒绝新请求。** 此前,当已提交的 Token 计数恰好达到上限时,`tpm` 和 `tpd` 仍会额外放行一个请求,只有超过上限后才会拒绝。内存和共享 Redis 两种后端现在使用相同的上限判断规则,切换后端不会改变实际限流行为。此变更适用于所有 Token 窗口,包括由策略派生的窗口和 API Key 级窗口。窗口上限显式配置为 `0` 时,现在会拒绝所有请求,与上限为 `0` 的请求计数窗口(例如 `rpm`)保持一致。请求计数采用预扣方式,此前已能准确执行上限,因此行为不变。 * **控制面现在会拒绝保存已注册网关无法加载的配置。** 控制面会根据目标环境中各已注册网关版本的配置读取规则,校验每份投影文档;只要某个受支持版本无法加载该文档,就返回 `422 DP_INCOMPATIBLE`。此前,写入会成功,响应中仅包含一条 `row_rejected` 告警,此时资源可能已在部分网关上停止生效。`error.message` 会完整说明网关版本、受影响的网关及配置中存在问题的部分;`error.dp_compat` 则以结构化字段提供相同信息。`row_rejected` 告警码已移除。新增的 `below_floor` 告警用于报告低于控制面最低支持版本的网关;控制面不对这些旧版本网关执行兼容性校验。 网关停止上报后,其注册信息仍会保留 5 分钟。因此,集群升级后的一段时间内,拒绝信息仍可能列出集群中已不再运行的旧版本。这是预期的保守校验行为:旧注册信息过期前,控制面仍会将其纳入检查。拒绝信息包含 `last_heartbeat_age_seconds`,可在过期注册信息被清理后重试。 * **数据库记录的上一次控制面版本低于 0.12.0 时,控制面会拒绝启动。** 控制面 API 服务(`cp-api`)会在启动迁移时记录自身版本。如果数据库中记录的版本低于最低支持版本,服务会停止启动,并提示已记录的版本及处理方式。离线安装包的 `run.sh` 也会在启动任何容器前拒绝此类升级。请先升级到受支持的版本,或在完成备份后设置 `AISIX_ALLOW_UNSUPPORTED_UPGRADE=1`。API 服务和安装脚本均支持该环境变量,Helm Chart 中可通过 `api.extraEnvVars` 设置。全新安装不受此限制;上一次使用该数据库的控制面版本尚未引入版本记录机制时,也不受此限制。 * **显式为空的 `ignore_statuses` 列表现在会被保留。** 此前,创建或修改模型时提交的空列表会被接受,但随后会被替换为 `[408, 429]`,并以该默认值存储、返回和投影。这导致后台健康探测仍会忽略 `408` 和 `429`,未按用户配置将其视为失败,且没有提示输入已被覆盖。现在,空列表在存储、`GET` 返回结果和网关配置中均保持为空列表。省略该字段的行为不变,仍使用默认值 `[408, 429]`。本版本之前保存的模型会保留已被替换的默认值,需显式设置为空列表后重新保存。 * **使用非 Anthropic 上游时,系统提示词中的 Anthropic 计费归属行会被移除。** Anthropic 原生客户端会在系统提示词开头添加一行 `x-anthropic-billing-header`;在某些部署中,该行的部分内容会随请求变化,导致其他模型服务提供方收到的提示词前缀每轮都不同,无法命中提示词缓存。对于 `POST /v1/messages` 和 `POST /v1/messages/count_tokens`,如果解析出的目标并非目录中的第一方 `anthropic` 提供方,网关会在构建上游请求前移除该行:对于数组形式的 `system`,移除计费归属块;对于字符串形式的 `system`,移除第一行。提示词其余部分(包括 `cache_control` 标记)逐字节保留,`messages` 不会被修改。判断依据是目录中的厂商 ID:指向区域性或经代理的 Anthropic 端点的第一方凭据会保留该行;OpenAI Chat 桥接、第三方 Anthropic 兼容透传,以及 Bedrock、Vertex、Azure 平台适配均会移除该行。此变更无需调整配置,未发送该行的调用方不受影响。 ### 新功能[​](#新功能 "新功能的直接链接") * **按指标选择标签。** 新增 `observability.metrics.labels` 配置块,用于声明每个指标族的完整标签列表;也可通过环境变量 `AISIX_OBSERVABILITY__METRICS__LABELS` 以 JSON 对象形式配置。未配置的指标族保留原有默认标签,因此升级后无需调整现有指标配置。标签选择在观测值累加前生效,移除 counter 或 histogram 的标签会聚合对应的观测值,不会丢弃观测数据;gauge 会保留用于标识序列的必需标签。未知的指标名称、不支持的标签变量或重复标签会导致启动失败,配置变更需重启后生效。首 Token 时间和请求延迟指标现在支持在原生和桥接请求路径上添加模型服务提供方凭证及调用方归属标签,这些标签默认不启用。 * **控制台的网关安装页面支持选择指标标签。** 运维人员可以添加受支持的标签、移除默认标签或恢复默认配置。Docker、Compose、Helm 和 systemd 安装指令都会通过启动环境变量包含完整的标签配置。这是网关进程级设置,不新增资源字段,也不改变资源投影。 * **完整保留 OpenAI 上游返回的原始缓存写入计数。** `cache_write_tokens` 现在会保留在网关响应的 `usage.prompt_tokens_details.cache_write_tokens` 中,并传递至用量事件、Admin API 的用量日志列表与导出结果,以及控制台的日志详情。此功能覆盖原生 OpenAI 请求、各协议桥接、旧版非流式 Completions 及可识别的透传用量。显式返回的 `0` 与字段缺失保持区分,上游未提供该字段时不会补值。该字段保存原始计数,与 Anthropic 可累加的 `cache_creation_tokens` 分开存储,不改变 Token 总数,也不影响计费。历史用量记录中的该字段不会补填。 ### 改进[​](#改进 "改进的直接链接") * **批量修改配置不再阻塞网关请求处理。** 此前,每次配置写入成功后,网关都会深拷贝完整快照,重新解析所有存储文档并进行规范化序列化,以重新计算两个哈希值,随后递增全局版本号。所有派生缓存均使用该版本号判断是否失效,因此每次写入的处理开销都与完整配置规模成正比。各工作线程收到下一个请求时,还会同步重建完整的护栏索引:为每个启用的挂载创建运行时和 HTTP 客户端,并分别重新加载 CA 存储。如果构建期间快照发生变化,构建会反复重试,且没有重试次数上限。该线程上的 `/livez` 请求也需等待这些操作完成。 派生缓存现在根据其读取