尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

EMQX 插件 API 网关修复:HTTP 请求头与查询参数透传机制深度解析

EMQX 插件 API 网关修复:HTTP 请求头与查询参数透传机制深度解析 后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载导读本文围绕 EMQX 开源仓库中的一条缺陷修复记录fix-16843.en.md展开插件 API 处理回调on_handle_api_call此前收到的 HTTP 请求头与查询字符串参数为空导致插件无法感知上游请求携带的认证信息、追踪标识与查询条件。文章以该修复为切入点结合emqx_plugins应用源码与测试用例完整讲解 EMQX 插件 API 网关/plugin_api/:plugin/[...]的路由注册、请求信息ReqInfo组装、敏感头脱敏、响应头白名单、超时配置与错误映射等机制帮助读者理解修复原理并掌握插件 API 的调用与调试方法。修复背景插件 API 网关中的“空 headers”问题EMQX 的插件Plugin应用通过emqx_plugins框架与主进程解耦。为了让插件能够暴露自定义 HTTP APIemqx_plugins提供了一条以/plugin_api/:plugin/[...]为前缀的网关路由把请求转发给已激活插件的on_handle_api_call/4回调。修复前的问题正如变更记录所述HTTP 请求头headers和查询字符串参数query string没有被透传给插件 API 处理回调导致插件收到的是空的 headers 和缺失的 query 参数。对于依赖Authorization、X-Request-Id、?limit、?page等信息的插件而言这意味着请求上下文信息在网关层丢失插件既无法做细粒度鉴权也无法实现分页、过滤等常见功能。修复涉及的核心模块为 emqx_plugins_api_endpoint.erl该模块实现了minirest_api行为作为 HTTP 网关把请求转换成插件回调所需的ReqInfo数据结构。网关路由何时注册如何匹配emqx_plugins_api_endpoint的paths/0返回路由列表且路由注册受到功能开关feature gate约束paths() - case emqx_machine_features:is_umbrella_application_enabled(emqx_plugins) of false - []; true - [/plugin_api/:plugin/[...]] end.从源码结构看当EMQX_FEATURES预设中未启用plugins时emqx_plugins应用不会启动网关路由也就不会注册这是保证插件框架作为门控特性gated feature正确工作的关键。模块内的paths_gated_by_feature_test_()测试用例也验证了这一行为启用plugins特性时paths()返回非空列表仅启用dashboard时返回空列表。路由匹配后parse_request_path/1会兼容两种路径形态/api/v5/plugin_api/plugin/path...经 minirest 的 base_path 提供服务即实际对外形态/plugin_api/plugin/path...测试或回退路径中的直连形态。路径剩余部分会逐段做百分号解码uri_string:percent_decode/1保证%2F等转义字符能正确还原为路径片段相关行为由测试t_plugin_api_path_remainder_is_percent_decoded覆盖。修复核心ReqInfo 中 headers 与 query_string 的透传网关入口函数gateway/3是本次修复的核心位置。它从 Cowboy 请求中提取真实数据组装成插件回调可用的请求信息Headers case maps:get(headers, Params, undefined) of undefined - cowboy_req:headers(Request); H - H end, QueryString case maps:get(query_string, Params, undefined) of undefined - maps:from_list(cowboy_req:parse_qs(Request)); Qs - Qs end, ReqInfo #{ method Method, query_string QueryString, headers sanitize_headers(Headers), body maps:get(body, Params, #{}) },修复的关键在于headers 透传当框架未显式提供headers时直接调用cowboy_req:headers/1获取当前 HTTP 请求的全部请求头而不是回退为空 mapquery string 透传通过cowboy_req:parse_qs/1解析查询字符串并转为 key-value map键值均为二进制再放进ReqInfo.query_stringbody 透传ReqInfo.body默认取Params中的body缺省为空 map。同时Context中会携带认证元数据与命名空间Context #{ auth_meta AuthMeta, namespace request_namespace(Params) },request_namespace/1优先取auth_meta.namespace否则回退到全局命名空间?global_ns供插件在多租户/多命名空间场景下识别请求归属。安全边界请求头脱敏与响应头白名单透传不等于全盘转发网关在两个方向上都做了安全约束。请求方向——敏感请求头脱敏。sanitize_headers/1会移除authorization与cookie两个请求头后再传给插件回调避免插件侧误用或泄露网关自身的认证凭据sanitize_headers(Headers) - maps:without([authorization, cookie], Headers).注意 Cowboy 会对请求头名做小写归一化因此脱敏匹配使用小写二进制 key。响应方向——响应头白名单allow-list。插件回调返回的自定义响应头并非全部放行而是经过 emqx_plugins.erl 中filter_plugin_api_headers/1的过滤只有命中?PLUGIN_API_ALLOWED_HEADERS白名单如content-type、etag、cache-control、x-request-id、x-ratelimit-limit等内容元数据、缓存、实体校验、关联 ID、限流相关头部或以x-plugin-为前缀的自定义头部才会被透传回客户端。选用白名单而非黑名单的设计意图在源码注释中写得很明确黑名单永远不完整每出现一个新的浏览器安全机制就要追加一条set-cookie、location、access-control-allow-origin等存在安全风险的响应头一律被拦截。回调调用链与超时配置请求信息组装完成后网关把控制权交给插件框架call_plugin_api(Plugin, Method, PathRemainder, ReqInfo, Context) - Timeout emqx:get_config( [plugins, api_endpoint, timeout], emqx:get_config([plugins, api_gateway, timeout], ?DEFAULT_TIMEOUT) ), Request #{method Method, path PathRemainder, request ReqInfo, context Context}, emqx_plugins:handle_api_call(Plugin, Request, Timeout).完整调用链为HTTP 请求 → emqx_plugins_api_endpoint:gateway/3 组装 ReqInfo/Context → emqx_plugins:handle_api_call/3 解析插件名、执行超时控制 → emqx_plugins_apps:on_handle_api_call/4 定位插件应用模块 → 插件模块:on_handle_api_call(Method, Path, Request, Context)其中emqx_plugins:handle_api_call/3负责两件事插件名解析resolve_active_name_vsn/1先在活跃插件列表中精确匹配再按plugin_name(NameVsn) : Plugin做模糊匹配找不到时返回{error, not_found}并映射为 HTTP 404超时与异常兜底回调通过emqx_utils:nolink_apply/2在受控进程中执行超时默认 5 秒返回 HTTP 503PLUGIN_API_TIMEOUT回调崩溃返回 HTTP 500INTERNAL_ERROR同时记录结构化日志plugin_api_callback_timeout/plugin_api_callback_crash日志中会提示可通过调大plugins.api_endpoint.timeout来延长合法长耗时回调的预算。超时配置定义在 emqx_plugins_schema.erl 的api_endpoint字段下plugins { api_endpoint { timeout 5s } }api_endpoint.timeout类型为timeout_duration_ms默认5s代码中读取时先查新配置键[plugins, api_endpoint, timeout]未设置时回退到旧键[plugins, api_gateway, timeout]最终回退到模块常量?DEFAULT_TIMEOUT5000ms保证升级平滑。测试验证修复如何被锁定emqx_plugins_api_endpoint_SUITE.erl 用 meck 模拟emqx_plugins:handle_api_call/3从真实 HTTP 层面对网关行为做了系统性验证其中与本修复直接相关的用例包括测试用例验证点t_plugin_api_headers_passthrough请求头应来自 Cowboy 请求而非空 mapheader_count 0并断言content-type存在t_plugin_api_sensitive_headers_redactedauthorization、cookie被移除普通自定义头x-test保留t_plugin_api_query_string_passthrough?foobarused_gte1中的参数完整透传且值为二进制字符串t_plugin_api_path_remainder_is_percent_decoded路径段百分号解码user%2Fname→user/namet_plugin_api_forbidden_headers_filtered响应头白名单过滤set-cookie、location、access-control-allow-origin、非x-plugin-前缀的x-custom被剔除x-plugin-custom保留t_plugin_api_ok/not_found/unauthorized/callback_crash200/404/401/500 状态码与响应体映射此外emqx_plugins_tests.erl等测试覆盖了emqx_plugins框架层的回调分发共同保证“修复不再回归”。实际排查插件 API 问题时可参考测试中的请求方式用curl携带自定义头与查询参数直接访问/api/v5/plugin_api/plugin/path观察插件回调收到的ReqInfo是否正确。修复价值与使用建议本次修复补齐了插件 API 网关的请求上下文透传能力使插件可以读取业务自定义请求头如追踪 ID、租户标识参与鉴权与日志关联读取查询参数实现分页、过滤、排序等 RESTful 语义通过Context.auth_meta.namespace感知请求命名空间适配多租户部署。实际开发插件 API 时建议遵循以下约束均可从仓库源码与测试中得到印证不要把网关自身的authorization、cookie请求头当作插件私有输入——它们已被脱敏插件回调如需返回自定义响应头必须使用x-plugin-前缀否则会被响应头白名单拦截长耗时回调应评估plugins.api_endpoint.timeout默认 5s必要时显式调大避免被当作超时返回 503回调返回值遵循{ok, Status, Headers, Body}/{error, Status, Headers, Body}/{error, Code, Msg}/{error, not_found}等约定形态非法返回值统一映射为 500INTERNAL_ERROR。至此从一条缺陷修复记录出发EMQX 插件 API 网关的请求透传、安全边界、超时控制与错误映射机制已完整呈现读者既可以在 emqx_plugins_api_endpoint.erl 中对照实现也可以借助 emqx_plugins_api_endpoint_SUITE.erl 中的用例复现验证。赞分享后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载相关推荐EMQX 插件自定义 HTTP API深入解析 /api/v5/plugin_api/{plugin}/... 网关机制EMQX 插件自定义 HTTP API深入解析 /api/v5/plugin_api/{plugin}/... 网关机制 本文基于仓库变更记录 changes后端物联网消息队列通信HTTP Prompt请求组合技巧多参数传递与复杂查询构建HTTP Prompt请求组合技巧多参数传递与复杂查询构建 在API测试过程中我们经常需要构建包含多个参数的复杂HTTP请求。传统命令行工具需要记忆繁琐的语开发工具接口测试如何永久保存你的数字记忆微信聊天记录本地化终极指南如何永久保存你的数字记忆微信聊天记录本地化终极指南 你是否曾因手机丢失而懊悔那些无法找回的珍贵对话是否担心重要的商务沟通记录会随时间消失在数字时代微信聊创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表