nginx自定義模塊編寫-根據post參數路由到不同服務器


nginx可以輕松實現根據不同的url 或者 get參數來轉發到不同的服務器,然而當我們需要根據http包體來進行請求路由時,nginx默認的配置規則就捉襟見肘了,但是沒關系,nginx提供了強大的自定義模塊功能,我們只要進行需要的擴展就行了。

我們來理一下思路,我們的需求是:

nginx根據http包體的參數,來選擇合適的路由

在這之前,我們先來考慮另一個問題:

在nginx默認配置的支持下,能否實現服務器間的跳轉呢?即類似於狀態機,從一個服務器執行OK后,跳轉到另一台服務器,按照規則依次傳遞下去。

答案是可以的,這也是我之前寫bayonet之后,在nginx上特意嘗試的功能。

一個示例的配置如下:

 

 

看明白了吧?我們使用了 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模塊開發指南

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

 

我們注冊了一個回調函數 ngx_http_foo_post_handler,當包體全部接受完成時就會調用。之后我們調用了get_route_id來獲取返回碼,然后通過 ngx_http_finalize_request(r, result); 來告訴nginx處理的結果。

這里有個小插曲,即get_route_id。我們來看一下它定義的原型:

第一個參數是 ngx_log_t *log,是為了方便在報錯的時候打印日志。然而在最開始的時候,get_route_id 的原型是這樣:

結果在 get_route_id 函數內部,調用

的結果總是null,至今也不知道為什么。(知道了是lua頭文件和ngx頭文件順序的問題,把ngx頭文件放到最前面即可)

OK,接下來我們只要在get_route_id中增加邏輯代碼,讀幾行配置,判斷一下就可以了~ 但是,我想要的遠不止如此。

二.lua解析器的加入
老博友應該都看過我之前寫的一篇博客: 代碼即數據,數據即代碼(1)-把難以變更的代碼變成易於變更的數據,而這一次的需求也非常符合使用腳本的原則:

只需要告訴我返回nginx哪個返回碼,具體怎么算出來的,再復雜,再多變,都放到腳本里面去。

所以接下來我又寫了c調用lua的代碼:

 

比較郁悶的是,lua 5.2的很多函數都變了,比如lua_open廢棄,變成luaL_newstate等,不過總體來說還算沒浪費太多時間。

接下來是req_route.lua的內容,我只截取入口函數如下:

 

OK,結合了lua解析器之后,無論多復雜的調整,我們都基本可以做到只修改lua腳本而不需要重新修改、編譯nginx模塊代碼了。

接下來,就該是體驗我們的成果了。
三.nginx配置

 

OK,enjoy it!

最后,放出代碼如下:
https://vimercode.googlecode.com/svn/trunk/nginx_req_route


用perl or lua的版本如下
http://www.php-oa.com/2010/09/25/perl-perl-nginx.html
https://github.com/chaoslawful/lua-nginx-module


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM