日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Nginx >内容正文

Nginx

nginx 加路由时报错_Nginx自定义模块编写:根据post参数路由到不同服务器

發布時間:2023/12/19 Nginx 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 nginx 加路由时报错_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模塊,所以也是參考了非常多文檔,我一一列在這里,所以詳細的入門就不說了,只說比較不太一樣的地方。 參考鏈接:

而我們這個模塊一個***的特點就是,需要等包體整個接收完才能進行處理,所以有如下代碼:

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?orpf==?nil?orappid==?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!

***,放出代碼如下:

【編輯推薦】

【責任編輯:黃丹 TEL:(010)68476606】

點贊 0

總結

以上是生活随笔為你收集整理的nginx 加路由时报错_Nginx自定义模块编写:根据post参数路由到不同服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。