通过nginx 反向代理 emqx服务后调用REST API部分接口可能遇到的URL编码问题

使用emqx提供的docker镜像进行布署后,通常会考虑通过nginx代理具体的服务。

如:EMQX Dashboard, 容器访问地址为:127.0.0.1:18083

可以在nginx.conf 中增加对EMQX Dashboard的代理,以实现通过自定义端口、域名的访问需求

示例如下:

server {
        listen <target>;
        server_name <domain>

        location / {
            proxy_pass  http://127.0.0.1:18083/;
            proxy_set_header Host $host;
            ...
	}
}

EMQX 提供的服务中包含 REST API,Dashboard中本身也使用了REST API。

如: Dashboard - 问题分析 - 主题监控 - 主题详情 对应的REST API地址为:

http://127.0.0.1:18083/api/v5/mqtt/topic_metrics/{topic}

根据 api-doc 对 GET: /mqtt/topic_metrics/{topic} 接口描述:

Topic string. Notice: Topic string in url path must be encoded

需要对Topic编码,以解决Topic也是使用 “/” 实现多层级对url造成的冲突。

类似需要使用topic做为参数的接口还有如:

- DELETE: /mqtt/topic_metrics/{topic}
- GET: /topics/{topic}

测试中直接调用EMQX提供地址并根据要求对topic进行编码,并不会导致问题,但是如需通过nginx代理,就存在url被nginx自行decode,再传递给容器导致请求错误的可能性。

示例问题如下, 当:

 topic=testtopic/1

编码后对应请求url:

http://192.168.0.9:8080/api/v5/mqtt/topic_metrics/testtopic%2F1

nginx在接收到请求后,会将 testtopic%2F1 进行decode并传递:

http://127.0.0.1:18083/api/v5/mqtt/topic_metrics/testtopic/1

但rest api实际并没有对应 /api/v5/mqtt/topic_metrics/testtopic/1 的资源,导致 响应错误。

这是由于nginx.conf → location → proxy_pass 支持多种匹配配置:

proxy_pass  http://127.0.0.1:18083/;
proxy_pass  http://127.0.0.1:18083;
proxy_pass  http://127.0.0.1:18083$1;

通过测试,当配置为 proxy_pass http://127.0.0.1:18083/ 时,nginx会自动进行UrlDecode,导致上述问题发生。

因此,解决这个问题也比较简单,只需将proxy_pass http://127.0.0.1:18083/ 修改为:proxy_pass http://127.0.0.1:18083; ,nginx重新加载配置,再次请求接口测试,响应恢复正常。

1 个赞

赞!思路清晰!
PS:不止是这一个 API,EMQX 的所有 http rest api 应该都是要对 url 做url decode 的。