国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【技術(shù)干貨】聽(tīng)阿里云CDN安防技術(shù)專家金九講tengine+lua開(kāi)發(fā)

Hegel_Gu / 1742人閱讀

摘要:例如設(shè)置響應(yīng)狀態(tài)碼并退出注意,設(shè)置狀態(tài)碼僅在響應(yīng)頭發(fā)送前有效,并且該函數(shù)調(diào)用之后該函數(shù)后面的將被忽略掉,因?yàn)橐呀?jīng)了。

一、介紹
二、安裝
三、運(yùn)行
四、開(kāi)發(fā)

1. 介紹

Tengine:輕量級(jí)、高性能、高并發(fā)、配置化、模塊化、可擴(kuò)展、可移植的Web和反向代理 服務(wù)器,Tengine是nginx超集,但做了很多優(yōu)化,包含了很多比較有用的模塊,比如直接包含了lua、proc等很有用的模塊。

Lua:一個(gè)很輕量級(jí)的 腳本,也號(hào)稱性能最高的 腳本。代碼總共不到600k,32個(gè)C文件,23個(gè)頭文件:

root@j9 ~/lua-5.1.5/src# du -sh ./
572K    ./
root@j9 ~/lua-5.1.5/src# ls *.c | wc -l
32
root@j9 ~/lua-5.1.5/src# ls *.h | wc -l 
23
root@j9 ~/lua-5.1.5/src#

可以非常容易的嵌入C和C++工程中,也比較容易與C和C++互動(dòng),這也是目前Lua主要的用法。
ngx_lua:一個(gè)nginx很重要的第三方模塊,作者:章亦春(agentzh、春哥),結(jié)合了nginx和Lua各自優(yōu)點(diǎn),把Lua嵌入nginx中,使其支持Lua來(lái)快速開(kāi)發(fā)基于nginx下的業(yè)務(wù)邏輯。
https://github.com/openresty/lua-nginx-module

2. 安裝

2.1、LuaJIT

wget -c http://luajit.org/download/LuaJIT-2.0.4.tar.gz
tar xzvf LuaJIT-2.0.4.tar.gz
cd LuaJIT-2.0.4
make install PREFIX=/usr/local/luajit
#注意環(huán)境變量!
export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0

2.2、Tengine

tengine最新代碼中已經(jīng)包含lua模塊了,直接git clone下來(lái)就可以

git clone https://github.com/alibaba/tengine.git
cd tengine
./configure --prefix=/opt/tengine --with-http_lua_module
make
make install

如果是原生nginx的話,得自行下載lua模塊代碼:

wget http://nginx.org/download/nginx-1.7.8.tar.gz
tar xvf nginx-1.7.8.tar.gz
cd nginx-1.7.8
mkdir modules
cd modules
git clone https://github.com/openresty/lua-nginx-module.git
cd ..
./configure --prefix=/opt/nginx --add-module=./modules/lua-nginx-module/
make
make install
3. 運(yùn)行

修改/opt/tengine/conf/nginx.conf:

worker_processes  1;

error_log  logs/error.log;
pid        logs/nginx.pid;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  "$remote_addr - $remote_user [$time_local] "$request" "
                      "$status $body_bytes_sent "$http_referer" "
                      ""$http_user_agent" "$http_x_forwarded_for"";

    access_log  logs/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location /hello_lua {
            content_by_lua "
                ngx.say("Lua: hello world!")
            ";
        }
    }
}

運(yùn)行tengine:

root@j9 ~/tengine# /opt/tengine/sbin/nginx

curl訪問(wèn)一下hello_lua:

root@j9 ~/tengine# curl http://localhost/hello_lua
Lua: hello world!

運(yùn)行ok。

4、開(kāi)發(fā)

語(yǔ)法
入門(mén)
深入

4.1、語(yǔ)法

參考:
Lua簡(jiǎn)明教程
Lua在線lua學(xué)習(xí)教程

4.2、入門(mén)

4.2.1、API

ngx.print
輸出響應(yīng)內(nèi)容體;

例如:ngx.print("a", "b", "c")

ngx.say
跟ngx.print的區(qū)別只是最后會(huì)多輸出一個(gè)換行符;

例如:ngx.say("a", "b", "c")

ngx.status
設(shè)置響應(yīng)HTTP狀態(tài)碼;

注意,設(shè)置狀態(tài)碼僅在響應(yīng)頭發(fā)送前有效。當(dāng)調(diào)用ngx.say或者ngx.print時(shí)自動(dòng)發(fā)送響應(yīng)狀態(tài)碼(默認(rèn)為200);可以通ngx.headers_sent來(lái)判斷是否發(fā)送了響應(yīng)狀態(tài)碼。
例如:ngx.status = 200

ngx.exit
設(shè)置響應(yīng)HTTP狀態(tài)碼并退出;

注意,設(shè)置狀態(tài)碼僅在響應(yīng)頭發(fā)送前有效,并且該函數(shù)調(diào)用之后該函數(shù)后面的lua將被忽略掉,因?yàn)橐呀?jīng)exit了。
例如:ngx.exit(200)

ngx.header
輸出響應(yīng)頭;

注意,頭部字段中含有橫杠(-)的要轉(zhuǎn)換成下劃線(_),ngx_lua模塊自動(dòng)將_轉(zhuǎn)換成-。
例如:ngx.header["X-Cache"] = "HIT" 或者 ngx.header.X_Cache = "HIT"或者ngx.header.X_Cache = {"AA", "BB"}

ngx.redirect
301或者302重定向

例如:ngx.redirect("http://www.taobao.org", 301)

ngx.log
打印nginx錯(cuò)誤日志,日志級(jí)別有:ngx.STDERR、ngx.EMERG、ngx.ALERT、ngx.CRIT、ngx.ERR、ngx.WARN、ngx.NOTICE、ngx.INFO、ngx.DEBUG

例如:ngx.log(ngx.ERR, "test: ", "ok")

例子:

server {               
        listen       9898;        
        location / {                 
            default_type "text/html";       
            content_by_lua "             
                local headers_sent_1 = ngx.headers_sent
                ngx.header["X-Cache"] = "HIT"     
                ngx.header.Y_Cache = "MISS"      
                ngx.header.Z_Cache = {"AA", "BB"}  
                ngx.status = 602      
                local headers_sent_2 = ngx.headers_sent
                ngx.print("a", "b")  
                local headers_sent_3 = ngx.headers_sent
                ngx.say("c", "d") 
                ngx.say("e", "f")   
                ngx.say("headers_sent_1: ", tostring(headers_sent_1))
                ngx.say("headers_sent_2: ", tostring(headers_sent_2))
                ngx.say("headers_sent_3: ", tostring(headers_sent_3))
                ngx.log(ngx.ERR, "ngx.log test ok")
                ngx.exit(601)        
                ngx.say("g", "h")      
            ";        
        } 

        location ^~ /redirect {                                                    
            content_by_lua "                                                       
                ngx.redirect("http://www.taobao.org", 301)                         
            ";                                                                     
        } 
    }

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9898/" -i
HTTP/1.1 602 
Server: Tengine/2.2.0
Date: Mon, 19 Oct 2015 16:10:42 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Cache: HIT
Y-Cache: MISS
Z-Cache: AA
Z-Cache: BB

abcd
ef
headers_sent_1: false
headers_sent_2: false
headers_sent_3: true
root@j9 ~# curl "http://127.0.0.1:9898/redirect" -i
HTTP/1.1 301 Moved Permanently
Server: Tengine/2.2.0
Date: Mon, 19 Oct 2015 16:18:16 GMT
Content-Type: text/html
Content-Length: 284
Connection: keep-alive
Location: http://www.taobao.org



301 Moved Permanently

301 Moved Permanently

The requested resource has been assigned a new permanent URI.


Powered by Tengine/2.2.0 root@j9 ~#

ngx.var
讀取nginx變量,如nginx變量為$a,則在Lua中通過(guò)ngx.var.a獲取,也可以給nginx變量賦值如ngx.var.a = "aa",前提是該變量在nginx中必須存在,不能在Lua中創(chuàng)建nginx變量。另外,對(duì)于nginx location中使用正則捕獲的捕獲組可以使用ngx.var[捕獲組數(shù)字]獲取。

例子

server {               
        listen       9898;        
        location ~ /var/([^/]*)/([^/]*) {     
            default_type "text/html";   
            set $a "aaa";     
            set $b $host;    
            content_by_lua "        
                ngx.say("$a: ", ngx.var.a)    
                ngx.say("$b: ", ngx.var.b)     
                ngx.say("$host: ", ngx.var.host)   
                ngx.say("$arg_id: ", ngx.var.arg_id)   
                ngx.say("$1: ", ngx.var[1])     
                ngx.say("$2: ", ngx.var[2])    
            ";    
        }  
    }

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9898/var/aaaa/bbbb?id=22" -H "Host: www.taobao.org"
$a: aaa
$b: www.taobao.org
$host: www.taobao.org
$arg_id: 22
$1: aaaa
$2: bbbb
root@j9 ~#

ngx.req.raw_header

未解析的請(qǐng)求頭字符串;
例如:ngx.req.raw_header()

ngx.req.get_headers

獲取請(qǐng)求頭,默認(rèn)只獲取前100個(gè)頭部,如果想要獲取所有頭部可以調(diào)用ngx.req.get_headers(0);獲取帶中劃線的請(qǐng)求頭時(shí)要把中劃線轉(zhuǎn)換成下劃線使用如headers.user_agent這種方式;如果一個(gè)請(qǐng)求頭有多個(gè)值,則返回的是table;
例如:ngx.req.get_headers()

ngx.req.get_uri_args

獲取url請(qǐng)求參數(shù),其用法與ngx.req.get_headers類似;

ngx.req.get_post_args

獲取post請(qǐng)求body參數(shù),其用法與ngx.req.get_uri_args類似,但必須提前調(diào)用ngx.req.read_body();

ngx.req.read_body

如果要獲取請(qǐng)求的body,則需要調(diào)用ngx.req.read_body(),否則獲取不到body數(shù)據(jù),(ps:也可以在nginx配置文件中加入指令lua_need_request_body on;來(lái)開(kāi)啟讀取body,但官方不推薦)

ngx.req.discard_body

忽略請(qǐng)求的body
注意,如果處理一個(gè)包含body的請(qǐng)求且需要ngx.exit時(shí),需要調(diào)用此函數(shù)來(lái)忽略body,否則nginx可能將body當(dāng)成header來(lái)解析,從而導(dǎo)致400錯(cuò)誤;

ngx.req.get_body_data

獲取請(qǐng)求body數(shù)據(jù)

例子

location ^~ /req {
    content_by_lua "
        ngx.say("===========ngx.req.raw_header=")
        ngx.say(ngx.req.raw_header())
        local headers = ngx.req.get_headers()
        ngx.say("===========headers============")
        ngx.say("Host: ", headers["Host"])
        ngx.say("user-agent: ", headers.user_agent)
        ngx.say("===========all headers========")
        for k,v in pairs(headers) do
          if type(v) == "table" then
            ngx.say(k, ": ", table.concat(v, ","))
          else
            ngx.say(k, ": ", v)
          end
        end

        ngx.say("===========args===============")
        local args = ngx.req.get_uri_args()
        for k,v in pairs(args) do
          ngx.say(k, ": ", v)
        end                                                         
        ngx.say("===========body===============")
        ngx.say("body data: ", ngx.req.get_body_data())
        ngx.req.read_body()
        local post_args = ngx.req.get_post_args()
        for k,v in pairs(post_args) do
          ngx.say(k, ": ", v)
        end
        ngx.say("body data: ", ngx.req.get_body_data())
    ";
}

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9898/req?a=11&b=22&c=33" --data "d=11&e=22&f=33"
===========ngx.req.raw_header=
POST /req?a=11&b=22&c=33 HTTP/1.1
User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
Host: 127.0.0.1:9898
Accept: */*
Content-Length: 14
Content-Type: application/x-www-form-urlencoded

===========headers============
Host: 127.0.0.1:9898
user-agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
===========all headers========
host: 127.0.0.1:9898
content-type: application/x-www-form-urlencoded
accept: */*
content-length: 14
user-agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
===========args===============
b: 22
a: 11
c: 33
===========body===============
body data: nil
d: 11
f: 33
e: 22
body data: d=11&e=22&f=33
root@j9 ~#

ngx.escape_uri/ngx.unescape_uri

uri編碼解碼

ngx.encode_args/ngx.decode_args

參數(shù)編碼解碼

ngx.encode_base64/ngx.decode_base64

BASE64編碼解碼

ngx.md5

md5加密

例子

location ^~ /code {
    content_by_lua "
        local request_uri = ngx.var.request_uri
        local args = {a=11, b=22}
        ngx.say("request uri: ", request_uri)
        ngx.say("unescape request uri: ", ngx.unescape_uri(request_uri))
        ngx.say("encode args: ", ngx.encode_args(args))
        ngx.say("encode base64 request uri: ", ngx.encode_base64(request_uri))
        ngx.say("md5(123456): ", ngx.md5("123456"))
    ";
}

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9898/code?name=%E9%87%91%E4%B9%9D"    
 request uri: /code?name=%E9%87%91%E4%B9%9D    
unescape request uri: /code?name=金九    
encode args: a=11&b=22    
encode base64 request uri: L2NvZGU/bmFtZT0lRTklODclOTElRTQlQjklOUQ=    
md5(123456): e10adc3949ba59abbe56e057f20f883e    
 root@j9 ~#

ngx.shared.DICT

共享內(nèi)存接口,其中DICT為共享內(nèi)存zone名稱,在nginx.conf中通過(guò)指令lua_shared_dict配置,而且lua_shared_dict指令配置的共享內(nèi)存大小最小值為8k。

例子

lua_shared_dict cc_shared_data 16k;

    server {
        listen       9999;
        default_type "text/html";
        location ^~ /shared_data {
            content_by_lua "
                local shared_data = ngx.shared.cc_shared_data
                local i = shared_data:get("i")
                if not i then
                  shared_data:set("i", 1)
                end
                i = shared_data:incr("i", 1)
                ngx.say("i: ", i)
            ";
        }
    }

測(cè)試結(jié)果

root@j9 ~# curl "http://127.0.0.1:9999/shared_data"
i: 2
root@j9 ~# curl "http://127.0.0.1:9999/shared_data"
i: 3
root@j9 ~#

ngx.shared.DICT詳細(xì)說(shuō)明:http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT

4.2.2、指令

指令 階段 范圍 說(shuō)明
init_by_lua/init_by_lua_file loading-config http nginx master進(jìn)程加載配置時(shí)執(zhí)行;通常用于初始化全局配置/預(yù)加載Lua模塊
init_worker_by_lua/init_worker_by_lua_file starting-worker http 每個(gè)nginx worker進(jìn)程啟動(dòng)時(shí)調(diào)用的計(jì)時(shí)器,如果master進(jìn)程不允許則只會(huì)在init_by_lua之后調(diào)用;通常用于定時(shí)拉取配置/數(shù)據(jù),或者后端服務(wù)的健康檢查
set_by_lua/set_by_lua_file rewrite server,server if,location,location if 設(shè)置nginx變量,可以實(shí)現(xiàn)復(fù)雜的賦值邏輯;此處是阻塞的,Lua代碼要做到非常快
rewrite_by_lua/rewrite_by_lua_file rewrite tail http,server,location,location if rewrite 階段處理,可以實(shí)現(xiàn)復(fù)雜的轉(zhuǎn)發(fā)/重定向邏輯
access_by_lua/access_by_lua_file access tail http,server,location,location if 請(qǐng)求訪問(wèn)階段處理,用于訪問(wèn)控制
content_by_lua/content_by_lua_file content location,location if 內(nèi)容處理器,接收請(qǐng)求處理并輸出響應(yīng)
header_filter_by_lua/header_filter_by_lua_file output-header-filter http,server,location,location if 設(shè)置header和cookie
body_filter_by_lua/body_filter_by_lua_file output-body-filter http,server,location,location if 對(duì)響應(yīng)數(shù)據(jù)進(jìn)行過(guò)濾,比如截?cái)唷⑻鎿Q
log_by_lua/log_by_lua_file log http,server,location,location if log 階段處理,比如記錄訪問(wèn)量/統(tǒng)計(jì)平均響應(yīng)時(shí)間

更詳細(xì)的解釋請(qǐng)參考官網(wǎng):http://wiki.nginx.org/HttpLua...

init_by_lua

每次nginx重新加載配置時(shí)執(zhí)行,可以用它來(lái)完成一些耗時(shí)模塊的加載,或者初始化一些全局配置;

例子:

init_by_lua "
        cjson = require("cjson")
        ngx.log(ngx.ERR, "init_by_lua ok")
    ";

    server {
        listen       9292;
        default_type "text/html";
        location / {
            content_by_lua "
                local arg_json = cjson.decode(ngx.var.arg_json)
                ngx.say("aa: ", arg_json.aa)
            ";
        }
    }

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9292/?json={"aa":111,"bbb":222}"
aa: 111
root@j9 ~#

init_worker_by_lua

每個(gè)worker啟動(dòng)之后初始化時(shí)執(zhí)行,通常用于每個(gè)worker都要做的工作,比如啟動(dòng)定時(shí)任務(wù)

例子:

worker_processes  2;  
http {
    #這里省略了其他配置
    init_worker_by_lua "
        ngx.log(ngx.ERR, "test init_worker_by_lua")
        -- TODO: 啟動(dòng)定時(shí)任務(wù)
    ";  
}

grep一下error.log,會(huì)發(fā)現(xiàn)兩條包含"test init_worker_by_lua"關(guān)鍵字的log,說(shuō)明每個(gè)worker都會(huì)執(zhí)行這個(gè)Lua代碼。

set_by_lua

語(yǔ)法:set_by_lua resluascriptstr

arg1 $arg2...; 在Lua代碼中可以實(shí)現(xiàn)所有復(fù)雜的邏輯,但是要執(zhí)行速度很快,不要阻塞;
需要注意的是,這個(gè)指令需要加入模塊ngx_devel_kit,否則不支持這個(gè)指令。

這個(gè)指令的Lua代碼中不支持以下API:
1、輸出(ngx.say、ngx.send_headers……)
2、控制(ngx.exit……)
3、子請(qǐng)求(ngx.location.capture、ngx.location.capture_multi……)
4、cosocket(ngx.socket.tcp、ngx.req.socket……)
5、ngx.sleep

例子:

server {
    listen       9393;
    default_type "text/html";
    location /add {
        set $diff "";
        set $double_c "";

        set_by_lua $sum "
            local a = ngx.var.arg_a
            local b = ngx.var.arg_b
            ngx.var.diff = a - b
            ngx.var.double_c = 2 * tonumber(ngx.arg[1])
            return a + b;
        " $arg_c;
        return 200 "a + b = $sum, a - b = $diff, 2 * c = $double_c";
    }
}

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9393/add?a=11&b=22&c=88"
a + b = 33, a - b = -11, 2 * c = 176
root@j9 ~#

rewrite_by_lua

執(zhí)行內(nèi)部URL重寫(xiě)或者外部重定向(301或者302),典型的如偽靜態(tài)化的URL重寫(xiě)。其默認(rèn)執(zhí)行在rewrite處理階段的最后。

需要注意的是:
1、在長(zhǎng)連接中如果調(diào)用了ngx.exit(200)一個(gè)請(qǐng)求,則需要調(diào)用ngx.req.discard_body(),否則nginx可能會(huì)把當(dāng)前請(qǐng)求的body當(dāng)成header解析,從而導(dǎo)致400錯(cuò)誤返回碼并且長(zhǎng)連接被關(guān)閉。
2、如果該階段調(diào)用了ngx.exit(ngx.OK),content_by_lua階段仍然能得到執(zhí)行。

例子:

server {
    listen       9494;
    default_type "text/html";
    location /rewrite_by_lua {
        set $a 11;
        rewrite_by_lua "
            ngx.var.a = "aa"
            if ngx.var.arg_exit == "ok" then
              ngx.exit(ngx.OK)
            else
              ngx.exit(200)
            end
        ";
        content_by_lua "
            ngx.say("a: ", ngx.var.a)
        ";
    }
}

測(cè)試結(jié)果

root@j9 ~# curl "http://127.0.0.1:9494/rewrite_by_lua?exit=ok"
a: aa

root@j9 ~# curl "http://127.0.0.1:9494/rewrite_by_lua?exit=200"

root@j9 ~# 

access_by_lua

用于訪問(wèn)控制,比如IP黑白名單限制、鑒權(quán)。

例子:

server {
    listen 9595;
    default_type "text/html";
    location / {
        access_by_lua "
            local auth = ngx.var.arg_auth;
            local key = "alicdnj9";
            if ngx.md5(key) ~= auth then
                return ngx.exit(403)
            end
        ";
        content_by_lua "
            ngx.say("access ok")
        ";
    }
}

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9595/?auth=xx"             


403 Forbidden

403 Forbidden

You don"t have permission to access the URL on this server. Sorry for the inconvenience.
Please report this message and include the following information to us.
Thank you very much!

URL: http://127.0.0.1:9595/?auth=xx
Server: j9
Date: 2015/10/27 16:47:20

Powered by Tengine/2.2.0 root@j9 ~# echo -n alicdnj9 | md5sum 50652c84270d22210593318f5d3016a1 - root@j9 ~# curl "http://127.0.0.1:9595/?auth=50652c84270d22210593318f5d3016a1" access ok root@j9 ~#

注意,如果在access_by_lua中調(diào)用ngx.exit(ngx.OK),content階段仍然能得到執(zhí)行。

content_by_lua

content階段,注意在同一個(gè)Location中不要和其他content階段指令一起使用,比如proxy_pass。
例子:略

header_filter_by_lua和body_filter_by_lua

分別為header_filter階段和body_filter階段,其中body_filter可能會(huì)被執(zhí)行多次。

不支持以下API:

輸出 (ngx.say、ngx.send_headers)

控制 (ngx.exit、ngx.exec)

子請(qǐng)求 (ngx.location.capture、ngx.location.capture_multi)

Cosocket (ngx.socket.tcp、ngx.req.socket).

比如對(duì)后端chunked長(zhǎng)度做限制:

server {
    listen 9696;
    default_type "text/html";
    set $content_len 0;
    location / {
        header_filter_by_lua "
            -- 先去掉Content-Length頭部,轉(zhuǎn)成Chunked傳輸
            ngx.header.content_length = nil
        ";                                                                     
        body_filter_by_lua "
            local content_length = #ngx.arg[1]
            content_length = ngx.var.content_len + content_length
            ngx.var.content_len = content_length
            -- 最多只能傳輸10字節(jié)的body,否則直接關(guān)掉連接
            if content_length > 10 then
                return ngx.ERROR
            end
        ";                                                                     
        content_by_lua "
            for i=1, ngx.var.arg_len do
                ngx.print("a")
            end
        ";
    }  
}

測(cè)試結(jié)果

root@j9 ~# curl "http://127.0.0.1:9696/?len=10" -i
HTTP/1.1 200 OK
Server: Tengine/2.2.0
Date: Mon, 26 Oct 2015 01:48:23 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive

aaaaaaaaaa
root@j9 ~# curl "http://127.0.0.1:9696/?len=11" -i 
curl: (52) Empty reply from server
root@j9 ~#

可以看出當(dāng)參數(shù)len為11時(shí),服務(wù)器就直接不返回?cái)?shù)據(jù)了。

4.3、深入

1、content_by_lua中的代碼一定要注意單引號(hào)或者雙引號(hào),一般用法是外單內(nèi)雙,或者外雙內(nèi)單。

2、在nginx_lua中值為nil的變量不能與字符串或者數(shù)字相加,否則nginx會(huì)報(bào)500錯(cuò)誤。

3、lua調(diào)試: ngx.log(ngx.ERR,xx)。(tail -f logs/error.log)

4、*_by_lua_file指令指定的文件支持絕對(duì)路徑和相對(duì)路徑,其中相對(duì)路徑是相對(duì)nginx工作目錄。

5、lua文件的require函數(shù)指定的lua模塊路徑查找順序,可以從出錯(cuò)信息中看出來(lái):

no file "/opt/libs/lua/a.lua"
no file "./a.lua"
no file "/usr/local/luajit/share/luajit-2.0.4/a.lua"
no file "/usr/local/share/lua/5.1/a.lua"
no file "/usr/local/share/lua/5.1/a/init.lua"
no file "/usr/local/luajit/share/lua/5.1/a.lua"
no file "/usr/local/luajit/share/lua/5.1/a/init.lua"
no file "./a.so"
no file "/usr/local/lib/lua/5.1/a.so"
no file "/usr/local/luajit/lib/lua/5.1/a.so"
no file "/usr/local/lib/lua/5.1/loadall.so"

其中,第一個(gè)/opt/libs/lua/a.lua為lua_package_path指定的路徑:lua_package_path "/opt/libs/lua/?.lua;;";
第二個(gè)./a.lua為相對(duì)路徑,相對(duì)于nginx.conf配置文件,而非包含它的lua文件。
so模塊查找順序類似,但是先查找.lua再查找.so,查找.so時(shí)先在lua_package_cpah指定的路徑查找:lua_package_cpath "/opt/libs/lua_shared/?.so;;";
可以從出錯(cuò)信息中看出來(lái):

no field package.preload["a"]
no file "/opt/libs/lua/a.lua"
no file "./a.lua"
no file "/usr/local/luajit/share/luajit-2.0.4/a.lua"
no file "/usr/local/share/lua/5.1/a.lua"
no file "/usr/local/share/lua/5.1/a/init.lua"
no file "/usr/local/luajit/share/lua/5.1/a.lua"
no file "/usr/local/luajit/share/lua/5.1/a/init.lua"
no file "/opt/libs/lua_shared/a.so"
no file "./a.so"
no file "/usr/local/lib/lua/5.1/a.so"
no file "/usr/local/luajit/lib/lua/5.1/a.so"
no file "/usr/local/lib/lua/5.1/loadall.so"

6、lua代碼一定要健壯,否則不管lua產(chǎn)生什么錯(cuò),nginx都會(huì)返回500錯(cuò)誤,這時(shí)可以從error.log中查看錯(cuò)誤信息來(lái)定位。

7、編寫(xiě)lua代碼時(shí)最好用local局部變量,不要用全局變量。

8、實(shí)現(xiàn)worker級(jí)別的全局變量:

server {
    listen 9797;
    default_type "text/html";
    location / {
        content_by_lua "
            local a = 1
            local b = {b = 1}
            local status = require("status")
            ngx.say("a: ", a, ", b: ", b.b, " counter: ", status.counter)
            a = a + 1
            b.b = b.b + 1
            status.counter = (status.counter or 0) + 1
        ";
    }
}

其中status.lua為:

local m = {}

m.counter = 1

return m

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:9797/"
a: 1, b: 1 counter: 1
root@j9 ~# curl "http://127.0.0.1:9797/"
a: 1, b: 1 counter: 2
root@j9 ~# curl "http://127.0.0.1:9797/"
a: 1, b: 1 counter: 3
root@j9 ~#

可以看出status.counter的值一直是累加的,這是因?yàn)閞equire一個(gè)模塊只load第一次,后續(xù)require該模塊都會(huì)先看全局表中是否已經(jīng)load過(guò),load過(guò)則就不需要再load了,所以status.counter累加其實(shí)是累加m.counter。

9、定時(shí)任務(wù)

API: ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)
例子:

local delay = 5
local handler
handler = function (premature)
    -- do some routine job in Lua just like a cron job
    if premature then
        return
    end
    local ok, err = ngx.timer.at(delay, handler)
    if not ok then
        ngx.log(ngx.ERR, "failed to create the timer: ", err)
        return
    end
end

local ok, err = ngx.timer.at(delay, handler)
if not ok then
    ngx.log(ngx.ERR, "failed to create the timer: ", err)
    return
end

注意:在timer處理函數(shù)的上下文中不能調(diào)用ngx.var.、ngx.req.、子請(qǐng)求API、輸出API,因?yàn)檫@些API只能在請(qǐng)求上下文中生效。

10、子請(qǐng)求

API:res = ngx.location.capture(uri, options?)

上下文:rewrite_by_lua, access_by_lua, content_by_lua*

例子:
正向代理,當(dāng)源站返回301或者302時(shí)代理客戶端跳轉(zhuǎn)

server {
    listen 8181;                                                            
    default_type "text/html";
    location /test {
        content_by_lua "
            local res = ngx.location.capture("/get" .. ngx.var.request_uri, { method = ngx.HTTP_HEAD })
            if res.status == 200 then
                ngx.exec("/get" .. ngx.var.request_uri)
            elseif res.status == 301 or res.status == 302 then
                location = res.header["Location"]
                local m, err = ngx.re.match(location, "http://([^/]+)(/.*)")
                if not m then
                    ngx.exit(500)
                end
                host = m[1]
                uri = m[2]
                ngx.exec("/redirect/" .. host .. "/" .. ngx.var.request_uri)
            else
                ngx.exit(res.status)
            end
        ";
    }

    location ~ /redirect/([^/]*)/([^/]*) {
        proxy_pass http://$1/$2?$args;
    }

    location /get {
        if ($arg_tag = "1") {
            return 302 "http://127.0.0.1:8282/$request_uri";
        }

        return 200 "ok";
    }
}

server {
    listen 8282;
    default_type "text/html";
    location / {
        return 200 "redirect ok, args: $args";
    }
}

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:8181/test?tag=0" -i
HTTP/1.1 200 OK
Server: Tengine/2.2.0
Date: Mon, 26 Oct 2015 15:17:10 GMT
Content-Type: text/html
Content-Length: 2
Connection: keep-alive

ok
root@j9 ~# curl "http://127.0.0.1:8181/test?tag=1" -i 
HTTP/1.1 200 OK
Server: Tengine/2.2.0
Date: Mon, 26 Oct 2015 15:17:14 GMT
Content-Type: text/html
Content-Length: 19
Connection: keep-alive

redirect ok, args: tag=1
root@j9 ~#

可見(jiàn),當(dāng)傳tag為1時(shí),返回的值就是想要的值,不需要再302重定向了。

注意,子請(qǐng)求只能請(qǐng)求本server的非@location。
另外一個(gè)需要注意的是,發(fā)起子請(qǐng)求之前修改的變量在子請(qǐng)求的location中是獲取不到的,這是因?yàn)樽兞康纳舷挛氖窃谡?qǐng)求結(jié)構(gòu)體r中,而子請(qǐng)求是掛在主請(qǐng)求下面,是兩個(gè)不同的請(qǐng)求。
實(shí)驗(yàn):

server {
    listen 8383;

    default_type "text/html";
    set $cc "cc";
    location /test {
        content_by_lua "
            ngx.var.cc = "11"
            local res = ngx.location.capture("/get" .. ngx.var.request_uri) 
            if res.status == 200 then
                ngx.say(res.body)
                ngx.say("test cc: ", ngx.var.cc)
            else
                ngx.exit(res.status)
            end
        ";
    }

    location /get {
        content_by_lua "
            ngx.say("get cc: ", ngx.var.cc)
            ngx.var.cc = "22"
        ";
    }
}

結(jié)果:

root@j9 ~# curl "http://127.0.0.1:8383/test"
get cc: cc

test cc: 11

root@j9 ~#

11、location @xx

server {
    listen 8484;
    default_type "text/html";
    set $cc "2";
    location / {
        content_by_lua "
            ngx.var.cc = "5";
            if ngx.var.arg_location == "at" then
                ngx.exec("@cc")
            else
                ngx.exec("/cc")
            end
        ";
    }

    location @cc {
        return 200 "this is @cc location, cc: $cc";
    }                                                                          
    location /cc {
        return 200 "this is /cc location, cc: $cc";
    }
}

測(cè)試結(jié)果:

root@j9 ~# curl "http://127.0.0.1:8484/?location=at"
this is @cc location, cc: 5
root@j9 ~# curl "http://127.0.0.1:8484/"            
this is /cc location, cc: 2
root@j9 ~#

在ngx.exec跳轉(zhuǎn)之前已經(jīng)把變量cc的值改成5了,但可以看出這兩種跳轉(zhuǎn)方式變量cc的值不一樣,這是因?yàn)閚gx.exec跳轉(zhuǎn)到@cc這個(gè)location時(shí),從location rewrite階段開(kāi)始執(zhí)行,而跳轉(zhuǎn)到/cc這個(gè)location時(shí)是從server rewrite階段開(kāi)始執(zhí)行,而set指令是在server塊,就是在這個(gè)階段得到執(zhí)行的,所以$cc又被賦值成2了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/10964.html

相關(guān)文章

  • 技術(shù)干貨聽(tīng)阿里CDN安防技術(shù)專家九講tengine+lua開(kāi)發(fā)

    摘要:例如設(shè)置響應(yīng)狀態(tài)碼并退出注意,設(shè)置狀態(tài)碼僅在響應(yīng)頭發(fā)送前有效,并且該函數(shù)調(diào)用之后該函數(shù)后面的將被忽略掉,因?yàn)橐呀?jīng)了。 一、介紹 二、安裝 三、運(yùn)行 四、開(kāi)發(fā) 1. 介紹 Tengine:輕量級(jí)、高性能、高并發(fā)、配置化、模塊化、可擴(kuò)展、可移植的Web和反向代理 服務(wù)器,Tengine是nginx超集,但做了很多優(yōu)化,包含了很多比較有用的模塊,比如直接包含了lua、proc等很...

    番茄西紅柿 評(píng)論0 收藏0
  • 【大量干貨】史上最完整的Tengine HTTPS原理解析、實(shí)踐與調(diào)試

    摘要:內(nèi)容主要有四個(gè)方面趨勢(shì)基礎(chǔ)實(shí)踐調(diào)試。一趨勢(shì)這一章節(jié)主要介紹近幾年和未來(lái)的趨勢(shì),包括兩大瀏覽器和對(duì)的態(tài)度,以及淘寶天貓和阿里云的實(shí)踐情況。完整性是指為了避免網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)被非法篡改,使用算法來(lái)保證消息的完整性。 摘要: 本文邀請(qǐng)阿里云CDN HTTPS技術(shù)專家金九,分享Tengine的一些HTTPS實(shí)踐經(jīng)驗(yàn)。內(nèi)容主要有四個(gè)方面:HTTPS趨勢(shì)、HTTPS基礎(chǔ)、HTTPS實(shí)踐、HTTPS...

    snowell 評(píng)論0 收藏0
  • 深度解析Tengine的調(diào)試與資源監(jiān)控方法論

    摘要:是由淘寶網(wǎng)發(fā)起的服務(wù)器項(xiàng)目。回源監(jiān)控是內(nèi)容分發(fā)網(wǎng)絡(luò)的簡(jiǎn)稱,其分發(fā)的內(nèi)容來(lái)自用戶源站,負(fù)責(zé)回源的模塊是最重要組成部分之一,使跨越單機(jī)的限制,完成網(wǎng)絡(luò)數(shù)據(jù)的接收處理和轉(zhuǎn)發(fā)。這部分主要介紹的一些調(diào)試技巧和回源資源監(jiān)控的內(nèi)容,以及相應(yīng)的實(shí)例分享。 摘要: Tengine是由淘寶網(wǎng)發(fā)起的Web服務(wù)器項(xiàng)目。它在Nginx的基礎(chǔ)上,針對(duì)大訪問(wèn)量網(wǎng)站的需求,提供更強(qiáng)大的流量負(fù)載均衡能力、全站HTTPS...

    everfight 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<