OpenResty简介及学习笔记
OpenResty簡介及學習筆記
- 摘要
- 簡介
- 一、OpenResty綜述
- 二、指令說明:
- *_by_lua
- *_by_lua_block {lua_script}
- *_by_lua_file
- 三、登陸驗證
- IP防火墻
- 操作頭信息檢測
- 登陸緩存
- 過濾參數
- 四、輸出過濾
- header_filter_by_lua*
- body_filter_by_lua*
- 五、Redis
摘要
OpenResty系列文章之一。
前些日子做的一些研究,期間收獲了一些對web后臺應用的理解,nginx運行機理的部分理解。
本篇包括簡介、部分模塊的介紹。
簡介
OpenResty?(也稱為?ngx_openresty)是一個全功能的 Web 應用服務器。它打包了標準的?Nginx 核心,很多的常用的第三方模塊,以及它們的大多數依賴項。
通過眾多進行良好設計的 Nginx 模塊,OpenResty 有效地把 Nginx 服務器轉變為一個強大的 Web 應用服務器,基于它開發人員可以使用Lua 編程語言對 Nginx 核心以及現有的各種Nginx C 模塊進行腳本編程,構建出可以處理一萬以上并發請求的極端高性能的 Web 應用。
OpenResty 致力于將你的服務器端應用完全運行于 Nginx 服務器中,充分利用 Nginx 的事件模型來進行非阻塞 I/O 通信。不僅僅是和 HTTP 客戶端間的網絡通信是非阻塞的,與MySQL、PostgreSQL、Memcached、以及 Redis 等眾多遠方后端之間的網絡通信也是非阻塞的。
因為 OpenResty 軟件包的維護者也是其中打包的許多 Nginx 模塊的作者,所以 OpenResty 可以確保所包含的所有組件可以可靠地協同工作。
作者簡介:
agentzh,本名章亦春,現任 CloudFare 系統工程師,主要是 Nginx 和 OpenResty 開發,是一名快樂的程序員,現定居美國舊金山。曾經在北京的時候供職于 Yahoo!中國以及淘寶(阿里巴巴)。
教程:agentzh 的 Nginx 教程
其他內容可以參看:?OpenResty簡介,OpenResty 作者章亦春訪談實錄
一、OpenResty綜述
?
?
?
?
OpenResty?通過 Lua 擴展 NGINX 實現的可伸縮的 Web 平臺
先扔三個網站:
?
首先,OpenResty官網!
還有Github:OpenResty
為數不多的書籍:OpenResty最佳實踐(Lua語言入門也可以全靠它)
下圖給出的是Lua Nginx Module中各指令的執行順序
- set_by_lua: 流程分支處理判斷變量初始化
- rewrite_by_lua: 轉發、重定向、緩存等功能(例如特定請求代理到外網)
- access_by_lua: IP 準入、接口權限等情況集中處理(例如配合 iptable 完成簡單防火墻)
- content_by_lua: 內容生成
- header_filter_by_lua: 應答 HTTP 過濾處理(例如添加頭部信息)
- body_filter_by_lua: 應答 BODY 過濾處理(例如完成應答內容統一成大寫)
- log_by_lua: 會話完成后本地異步完成日志記錄(日志可以記錄在本地,還可以同步到其他機器)
實際上我們只使用其中一個階段 content_by_lua,也可以完成所有的處理。但這樣做,會讓我們的代碼比較臃腫,越到后期越發難以維護。把我們的邏輯放在不同階段,分工明確,代碼獨立,后期發力可以有很多有意思的玩法。
二、指令說明:
*_by_lua < lua-script-str >
無后綴的指令,后加字符串型的lua程序。
如:
- location / {
- default_type text/html;
- content_by_lua '
- ngx.say("<p>hello, world</p>")
- ';
- }
nginx
*_by_lua_block {lua_script}
有block后綴,可以直接跟lua程序段。
如:
- location / {
- content_by_lua_block{
- local test = 'Hello,world'
- ngx.say(test)
- }
- }
*_by_lua_file < path-to-lua-script-file >
file后綴跟lua文件路徑
如:
- location ~ ^/api/([-_a-zA-Z0-9/]+) {
- # 準入階段完成參數驗證
- access_by_lua_file lua/access_check.lua;
- ?
- #內容生成階段
- content_by_lua_file lua/$1.lua;
- ?
- }
nginx
三、登陸驗證
在access_by_lua*中集中進行一些權限認證,防止惡意ip、非法行為進入到服務器中。
- location / {
- access_by_lua_block{
- ngx.exit(ngx.HTTP_FORBIDDEN)
- }
- content_by_lua_block{
- --內容生產階段
- }
- }
IP防火墻
OpenResty最佳實踐提到:禁止某些終端訪問
上面文檔下方推薦第三方包:Github,Lua-resty-iputils
操作頭信息檢測
通過access_by_lua*可以對請求進行過濾,比如可以在這里檢查有沒有帶authorization頭部信息,若沒有帶可以用ngx.exit()直接退出。
登陸緩存
Github:?lua-resty-jwt模塊進行jwt校驗
結合lua-resty-jwt和lua-resty-redis甚至可以將服務器登陸緩存移植到nginx上。
過濾參數
還未嘗試。
防止 SQL 注入
四、輸出過濾
通常是header_filter_by_lua*與body_filter_by_lua*配合實現。
【文檔來源官方】:
注意下列API函數現在還不能在set_by_lua*、header_filter_by_lua*、body_filter_by_lua*、log_by_lua*四個環境中使用:
- 輸出API 函數 (e.g., ngx.say and ngx.send_headers)
- 控制API 函數 (e.g., ngx.redirect and ngx.exec)
- 子請求API 函數 (e.g., ngx.location.capture and ngx.location.capture_multi)
- Cosocket API 函數 (e.g., ngx.socket.tcp and ngx.req.socket).
header_filter_by_lua*
使用Lua代碼在lua塊中定義輸出頭信息。
example1:
- location / {
- proxy_pass http://mybackend;
- header_filter_by_lua 'ngx.header.Foo = "blah"';
- }
nginx
example2:
- header_filter_by_lua_block {
- ngx.header["content-length"] = nil
- }
body_filter_by_lua*
參考:
談談 OpenResty 中的 body_filter_by_lua*
輸入數據塊chunks要經過ngx.arg1?(Lua 字符串)的過濾,"eof"標志指示響應體數據流的末端通過ngx.arg2?(Lua bollean值)顯示。
這個情景下,"eof"標志就是主請求的last_buf或子請求的?last_in_chain。"eof" == "true" 表示此次nginx請求的響應結束了。
由于響應體可能會分多塊發送,body_filter_by_lua*可能會被多次調用。詳細機理參考上面文獻有提到。
- location /t {
- echo hello world;
- echo hiya globe;
- ?
- body_filter_by_lua '
- ......
- ';
- }
nginx
比如上面,body_filter_by_lua*首次調用時ngx.arg1?的值只是hello world,不包括下面的hiya globe。
我驗證了一下:
- location = /test_bf {
- echo hello world;
- echo this;
- echo is;
- echo world;
- header_filter_by_lua_block {
- ngx.header.content_length = nil
- }
- body_filter_by_lua_block {
- if string.match(ngx.arg[1], "this") then
- ngx.arg[2] = true
- ngx.arg[1] = "end"
- return
- end
- }
- }
上述location發送四塊數據,匹配到this便設置"eof"不再發送下去了。
- $ curl
結果:
- $ hello world
- $ end
要點:
①?ngx.arg[2] = true設置新的"eof"標志使截斷響應,設置"eof"依舊是有效的響應。
②?ngx.arg[1] = "end"修改ngx.arg[1]?的值,即為修改輸出響應。而當需要替換一些信息,僅需一行代碼即可實現。
- ngx.arg[1] = ngx.re.gsub(ngx.arg[1], "o", "*")
上文也提到。上述即為將所有 ' o ' 字符替換為 ' * ' 字符
若該location作為其他location的子請求,而作為子請求不想被過濾數據。需要通過ngx.is_subrequest判斷。
- body_filter_by_lua_block {
- if ngx.arg[1] and not ngx.is_subrequest then
- ......
- end
- }
nginx
還有一點,如果在body_filter_by_lua*中的Lua代碼會修改響應體的長度,這就需要去把Content-Length的響應頭去除掉。我之前測試與前端聯調時,就是發現body過濾必須要字符數相同才會顯示,很頭疼不知道什么原因。其實只要去掉這個頭就行了。
- location = / {
- proxy_pass ......
- header_filter_by_lua_block {
- ngx.header.content_length = nil
- }
- body_filter_by_lua_block {
- ngx.arg[1] = ngx.re.gsub(ngx.arg[1], "o", "**")
- }
- }
五、Redis
官方github:lua-resty-redis
OpenResty最佳實踐:訪問有授權驗證的 Redis
官方包封裝了一些Redis的方法,使用起來還是挺舒適的。
本文鏈接:https://blog.maozhiting.com/post/openresty_notes.html
--?EOF?--
作者?毛毛?發表于?2017-11-05 15:11:55?,并被添加「?OpenResty?」標簽 ,最后修改于?2017-11-05 15:47:30
總結
以上是生活随笔為你收集整理的OpenResty简介及学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lua-resty-iputils, 在
- 下一篇: resty资源推荐