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