OpenResty 處理一個請求,它的處理流程請參考下圖(從 Request start 開始):
http://wiki.jikexueyuan.com/project/openresty/images/openresty_phases.png" alt="openresty_phases" />
我們在這里做個測試,示例代碼如下:
location /mixed {
set_by_lua_block $a {
ngx.log(ngx.ERR, "set_by_lua*")
}
rewrite_by_lua_block {
ngx.log(ngx.ERR, "rewrite_by_lua*")
}
access_by_lua_block {
ngx.log(ngx.ERR, "access_by_lua*")
}
content_by_lua_block {
ngx.log(ngx.ERR, "content_by_lua*")
}
header_filter_by_lua_block {
ngx.log(ngx.ERR, "header_filter_by_lua*")
}
body_filter_by_lua_block {
ngx.log(ngx.ERR, "body_filter_by_lua*")
}
log_by_lua_block {
ngx.log(ngx.ERR, "log_by_lua*")
}
}
執(zhí)行結(jié)果日志(截取了一下):
set_by_lua*
rewrite_by_lua*
access_by_lua*
content_by_lua*
header_filter_by_lua*
body_filter_by_lua*
log_by_lua*
這幾個階段的存在,應該是 OpenResty 不同于其他多數(shù) Web 平臺編程的最明顯特征了。由于 Nginx 把一個請求分成了很多階段,這樣第三方模塊就可以根據(jù)自己行為,掛載到不同階段進行處理達到目的。OpenResty 也應用了同樣的特性。所不同的是,OpenResty 掛載的是我們編寫的 Lua 代碼。
這樣我們就可以根據(jù)我們的需要,在不同的階段直接完成大部分典型處理了。
set_by_lua*
: 流程分支處理判斷變量初始化rewrite_by_lua*
: 轉(zhuǎn)發(fā)、重定向、緩存等功能(例如特定請求代理到外網(wǎng))access_by_lua*
: IP 準入、接口權(quán)限等情況集中處理(例如配合 iptable 完成簡單防火墻)content_by_lua*
: 內(nèi)容生成header_filter_by_lua*
: 響應頭部過濾處理(例如添加頭部信息)body_filter_by_lua*
: 響應體過濾處理(例如完成應答內(nèi)容統(tǒng)一成大寫)log_by_lua*
: 會話完成后本地異步完成日志記錄(日志可以記錄在本地,還可以同步到其他機器)實際上我們只使用其中一個階段 content_by_lua*
,也可以完成所有的處理。但這樣做,會讓我們的代碼比較臃腫,越到后期越發(fā)難以維護。把我們的邏輯放在不同階段,分工明確,代碼獨立,后期發(fā)力可以有很多有意思的玩法。
舉一個例子,如果在最開始的開發(fā)中,請求體和響應體都是通過 HTTP 明文傳輸,后面需要使用 aes 加密,利用不同的執(zhí)行階段,我們可以非常簡單的實現(xiàn):
# 明文協(xié)議版本
location /mixed {
content_by_lua_file ...; # 請求處理
}
# 加密協(xié)議版本
location /mixed {
access_by_lua_file ...; # 請求加密解碼
content_by_lua_file ...; # 請求處理,不需要關(guān)心通信協(xié)議
body_filter_by_lua_file ...; # 應答加密編碼
}
內(nèi)容處理部分都是在 content_by_lua*
階段完成,第一版本 API 接口開發(fā)都是基于明文。為了傳輸體積、安全等要求,我們設(shè)計了支持壓縮、加密的密文協(xié)議(上下行),痛點就來了,我們要更改所有 API 的入口、出口么?
最后我們是在 access_by_lua*
完成密文協(xié)議解碼,body_filter_by_lua*
完成應答加密編碼。如此一來世界都寧靜了,我們沒有更改已實現(xiàn)功能的一行代碼,只是利用 OpenResty 的階段處理特性,非常優(yōu)雅的解決了這個問題。
不同的階段,有不同的處理行為,這是 OpenResty 的一大特色。學會它,適應它,會給你打開新的一扇門。這些東西不是 OpenResty 自身所創(chuàng),而是 Nginx module 對外開放的處理階段。理解了他,也能更好的理解 Nginx 的設(shè)計思維。