千家信息网

Nginx自定义模块中根据post参数路由到不同服务器的示例分析

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇文章给大家分享的是有关Nginx自定义模块中根据post参数路由到不同服务器的示例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
千家信息网最后更新 2026年11月03日Nginx自定义模块中根据post参数路由到不同服务器的示例分析

本篇文章给大家分享的是有关Nginx自定义模块中根据post参数路由到不同服务器的示例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

Nginx可以轻松实现根据不同的url 或者 get参数来转发到不同的服务器,然而当我们需要根据http包体来进行请求路由时,Nginx默认的配置规则就捉襟见肘了,但是没关系,Nginx提供了强大的自定义模块功能,我们只要进行需要的扩展就行了。

我们来理一下思路,我们的需求是:

Nginx根据http包体的参数,来选择合适的路由

在这之前,我们先来考虑另一个问题:

在Nginx默认配置的支持下,能否实现服务器间的跳转呢?即类似于状态机,从一个服务器执行OK后,跳转到另一台服务器,按照规则依次传递下去。

答案是可以的,这也是我之前写bayonet之后,在nginx上特意尝试的功能。

一个示例的配置如下:

server {     listen       8080;     server_name  localhost;     location / {         proxy_pass http://localhost:8888;         error_page 433 = @433;         error_page 434 = @434;     }     location @433 {         proxy_pass http://localhost:6788;     }     location @434 {         proxy_pass http://localhost:6789;     }     error_page   500 502 503 504  /50x.html;     location = /50x.html {         root   html;     } }

看明白了吧?我们使用了 433和434 这两个非标准http协议的返回码,所有请求进入时都默认进入 http://localhost:8888;,然后再根据返回码是 433 还是 434 来选择进入 http://localhost:6788 还是 http://localhost:6789。

OK,也许你已经猜到我将这个例子的用意了,是的,我们只要在我们的自定义模块中,根据http的包体返回不同的返回码,进而 proxy_pass 到不同的后端服务器即可。

好吧,接下来,我们正式进入nginx自定义模块的编写中来。

一. nginx 自定义模块编写 由于这也是我***次写nginx模块,所以也是参考了非常多文档,我一一列在这里,所以详细的入门就不说了,只说比较不太一样的地方。 参考链接:

  1. nginx的helloworld模块的helloworld

  2. nginx 一个例子模块,简单的将http请求的内容返输出

  3. nginx 自定义协议 扩展模块开发

  4. Emiller的Nginx模块开发指南

而我们这个模块一个***的特点就是,需要等包体整个接收完才能进行处理,所以有如下代码:

void ngx_http_foo_post_handler(ngx_http_request_t *r){     // 请求全部读完后从这里入口, 可以产生响应     ngx_http_request_body_t* rrb = r->request_body;       char* body = NULL;     int body_size = 0;       if (rb && rb->buf)     {         body = (char*)rb->buf->pos;         body_size = rb->buf->last - rb->buf->pos;     }       int result = get_route_id(r->connection->log,                                (int)r->method,                               (char*)r->uri.data,                               (char*)r->args.data,                               body,                               body_size                               );     if (result < 0)     {         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "get_route_id fail, result:%d", result);         result = DFT_ROUTE_ID;     }     ngx_http_finalize_request(r, result);   } static ngx_int_t ngx_http_req_route_handler(ngx_http_request_t *r) {     ngx_http_read_client_request_body(r, ngx_http_foo_post_handler);     return NGX_DONE; // 主handler结束 }

我们注册了一个回调函数 ngx_http_foo_post_handler,当包体全部接受完成时就会调用。之后我们调用了get_route_id来获取返回码,然后通过 ngx_http_finalize_request(r, result); 来告诉nginx处理的结果。

这里有个小插曲,即get_route_id。我们来看一下它定义的原型:

extern int get_route_id(ngx_log_t *log, int method, char* uri, char* args, char* body, int body_size)

***个参数是 ngx_log_t *log,是为了方便在报错的时候打印日志。然而在最开始的时候,get_route_id 的原型是这样:

extern int get_route_id(ngx_http_request_t *r, int method, char* uri, char* args, char* body, int body_size);

结果在 get_route_id 函数内部,调用:

r->connection->log

的结果总是null,至今也不知道为什么。

OK,接下来我们只要在get_route_id中增加逻辑代码,读几行配置,判断一下就可以了~ 但是,我想要的远不止如此。

二、lua解析器的加入

老博友应该都看过我之前写的一篇博客: 代码即数据,数据即代码(1)-把难以变更的代码变成易于变更的数据,而这一次的需求也非常符合使用脚本的原则:

只需要告诉我返回nginx哪个返回码,具体怎么算出来的,再复杂,再多变,都放到脚本里面去。

所以接下来我又写了c调用lua的代码:

int get_route_id(ngx_log_t *log, int method, char* uri, char* args, char* body, int body_size) {     const char lua_funcname[] = "get_route_id";     lua_State *L = luaL_newstate();     luaL_openlibs(L);     if (luaL_loadfile(L, LUA_FILENAME) || lua_pcall(L, 0, 0, 0))     {         ngx_log_error(NGX_LOG_ERR, log, 0, "cannot run configuration file: %s", lua_tostring(L, -1));         lua_close(L);         return -1;     }      lua_getglobal(L, lua_funcname); /* function to be called */     lua_pushnumber(L, method);     lua_pushstring(L, uri);     lua_pushstring(L, args);     lua_pushlstring(L, body, body_size);     /* do the call (1 arguments, 1 result) */     if (lua_pcall(L, 4, 1, 0) != 0)     {         ngx_log_error(NGX_LOG_ERR, log, 0, "error running function %s: %s", lua_funcname, lua_tostring(L, -1));         lua_close(L);         return -2;     }     /* retrieve result */     if (!lua_isnumber(L, -1))     {         ngx_log_error(NGX_LOG_ERR, log, 0, "function %s must return a number", lua_funcname);         lua_close(L);         return -3;     }     int result = (int)lua_tonumber(L, -1);       lua_pop(L, 1); /* pop returned value */       lua_close(L);     return result; }

比较郁闷的是,lua 5.2的很多函数都变了,比如lua_open废弃,变成luaL_newstate等,不过总体来说还算没浪费太多时间。

接下来是req_route.lua的内容,我只截取入口函数如下:

function get_route_id(method, uri, args, body)     loc, pf ,appid = get_need_vals(method, uri, args, body)     if loc == nil or pf == nil or appid == nil then         return OUT_CODE     end     --到这里位置,就把所有的数据都拿到了     --print (loc, pf, appid)     -- 找是否在对应的url, loc中     if not is_match_pf_and_loc(pf, loc) then         return OUT_CODE     end     -- 找是否在对应的appid中     if not is_match_appid(appid) then         return OUT_CODE     end     return IN_CODE end

OK,结合了lua解析器之后,无论多复杂的调整,我们都基本可以做到只修改lua脚本而不需要重新修改、编译nginx模块代码了。

接下来,就该是体验我们的成果了。

三、Nginx配置

server {     listen       8080;     server_name  localhost;       location /req_route {         req_route;         error_page 433 = @433;         error_page 434 = @434;     }     location @433 {         proxy_pass http://localhost:6788;     }     location @434 {         proxy_pass http://localhost:6789;     }     error_page   500 502 503 504  /50x.html;     location = /50x.html {         root   html;     } }

OK,enjoy it!

以上就是Nginx自定义模块中根据post参数路由到不同服务器的示例分析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

模块 服务器 服务 代码 不同 参数 接下来 配置 路由 函数 数据 示例 结果 脚本 分析 复杂 例子 入口 内容 功能 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网黑科技 科技互联网政务服务 深圳互联网科技公司 北京互联网科技有限公司 西安互联网科技 深圳齐家互联网科技 致聘互联网科技 大白互联网科技 开启互联网科技时代小说 中盈科技互联网信息有限公司 互联网科技中介 昭通互联网科技选哪家 中国航天科技大学国际工业互联网 晓花互联网科技有限公司网址 朱啸虎曾投资哪些互联网科技企业 南博望互联网科技有限公司 高科技互联网套路 互联网科技融合创新 陕西云淼互联网科技公司 瑞安市蟠桃会互联网科技有限公司 上海挚品互联网科技有限公司 百单网互联网科技有限公司 互联网科技的未来发展 深圳国际航运科技和互联网 成都铂石互联网科技做什么的 恒生互联网科技指数跳水 互联网科技企业商标注意事项 北京互联网科技类企业分布 恒生科技互联网指数十大成分股 互联网 科技节活动 微视频大赛
0