nginx可以定义日志精选的几个变量
字段 | 作用 |
---|---|
$remote_addr与$http_x_forwarded_for | 记录客户端IP地址 |
$remote_user | 记录客户端用户名称 |
$request | 记录请求的URI和HTTP协议 |
$status | 记录请求状态 |
$body_bytes_sent | 发送给客户端的字节数,不包括响应头的大小 |
$bytes_sent | 发送给客户端的总字节数 |
$connection | 连接的序列号 |
$connection_requests | 当前通过一个连接获得的请求数量 |
$http_referer | 记录从哪个页面链接访问过来的 |
$http_user_agent | 记录客户端浏览器相关信息 |
$request_length | 请求的长度(包括请求行,请求头和请求正文) |
$request_time | 请求处理时间,单位为秒,精度毫秒 |
/usr/server/openresty/bin/openresty -s reload
location /test { default_type text/html; echo "uri:$document_uri;args:$args;param.age=$arg_age;"; echo "client ip:$remote_addr"; echo "status:$status;user:$remote_user;$connection_requests";}复制代码
output
uri:/test/a;args:a=1&age=1;param.age=1; client ip:172.17.0.1 status:200;user:;12复制代码
上面是一个很乱的输出,简单说下请求参数, $args是请求的参数,$arg_age是后面具体的某个参数值
一些建议
有时候需要判断文件是否存在
server { root /var/www/example.com; location / { if (!-f $request_filename) { break; } }}复制代码
更好的写法
server { root /var/www/example.com; location / { try_files $uri $uri/ /index.html; }}复制代码
请求 $request_filename:/data/www/xxx/pay/test/ $uri: /test/ try_files优先尝试是否存在$uri,如果不存在尝试$uri/ 否则转向index.html
下面正式进入主题
hello openrestry
location /test { default_type text/html; content_by_lua ' ngx.say("Hello Openrestry") ngx.say(ngx.localtime() ) ';}复制代码
打印字符串 返回当前时间
简单的内部调用
location = /getname { #此处表示属于内部调用,外部无法直接访问 internal; default_type text/html; content_by_lua ' local params = ngx.req.get_uri_args(); ngx.print(params.name); ';}复制代码
location = /test { default_type text/html; content_by_lua ' local res = ngx.location.capture( "/getname", {args={name=ngx.var["arg_name"],age=18}} ) ngx.say(ngx.var["arg_name"]); ngx.say("status:", res.status, " response:", res.body) ';}复制代码
请求url: http://www.xxx.com/test?name=bbb output : bbb status:200 response:bbb复制代码
关键词: ngx.location.capture 发起请求, ngx.var["arg_name"]访问uri参数变量, ngx.say和ngx.print都属于输出数据,但ngx.say会自动在后面加\n
ngx.location.capture 是非阻塞的,ngx.location.capture也可以用来完成http请求,但是它只能请求到相对于当前nginx服务器的路径,不能使用之前的绝对路径进行访问
方法1
location = /getname { internal; default_type text/html; content_by_lua ' local params = ngx.req.get_uri_args(); ngx.print(params.name); ';}复制代码
方法2
location = /getage { internal; default_type text/html; content_by_lua ' local params = ngx.req.get_uri_args(); ngx.print(params.age); ';}复制代码
并行调用并输出返回值
location = /test { default_type text/html; content_by_lua ' local res1,res2 = ngx.location.capture_multi{ {"/getage",{args="age=16&sex=1"}}, {"/getname",{args={name=ngx.var["arg_name"]}}} } ngx.say("status:", res1.status, " response:", res1.body) ngx.say("status:", res2.status, " response:", res2.body) '; }复制代码
可使用ngx.sleep(0.1) 延迟测试,ngx.now()获取毫秒级时间戳,ngx.time()返回秒级别
location = /getname { default_type text/html; content_by_lua ' ngx.say(123) ';}复制代码
http重定向302跳转
location = /test { default_type text/html; rewrite_by_lua ' return ngx.redirect("/getname") '; }复制代码
内部执行
location = /test { default_type text/html; rewrite_by_lua ' return ngx.exec("/getname") '; }复制代码
ngx.exec 方法与 ngx.redirect 是完全不同的,前者是个纯粹的内部跳转并且 没有引入任何额外 HTTP 信号
获取请求参数
获取一个 uri 有两个方法: ngx.req.get_uri_args 、ngx.req.get_post_args
关于指令的优先级问题
location = /test { default_type text/html; content_by_lua ' ngx.say("hello") '; rewrite_by_lua ' ngx.say("rewirite") '; access_by_lua ' ngx.say("access") '; }复制代码
会执行rewrite_by_lua,因为它的优先级比 其他要高
指定lua文件运行
location = /test { default_type text/html; content_by_lua_file /usr/server/openresty/nginx/conf/vhost/content.lua; }复制代码
content.lua
ngx.say("hello world")复制代码
其他access_by_lua_file、access_by_lua_file用法类似
init_by_lua init_by_lua_file
main.conf
init_by_lua ' cjson = require "cjson"';server { ....}复制代码
contnet.lua
ngx.say(cjson.encode({dog=5,cat=6}))--output { "dog":5,"cat":6}复制代码
中断执行
ngx.exit(ngx.HTTP_OK)ngx.exit(404)value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)value = ngx.HTTP_OK (200)value = ngx.HTTP_CREATED (201)value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)value = ngx.HTTP_SPECIAL_RESPONSE (300)value = ngx.HTTP_MOVED_PERMANENTLY (301)value = ngx.HTTP_MOVED_TEMPORARILY (302)value = ngx.HTTP_SEE_OTHER (303)value = ngx.HTTP_NOT_MODIFIED (304)value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)value = ngx.HTTP_BAD_REQUEST (400)value = ngx.HTTP_UNAUTHORIZED (401)value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)value = ngx.HTTP_FORBIDDEN (403)value = ngx.HTTP_NOT_FOUND (404)value = ngx.HTTP_NOT_ALLOWED (405)value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)value = ngx.HTTP_GONE (410)value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)value = ngx.HTTP_SERVICE_UNAVAILABLE (503)value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)复制代码
记录日志 ngx.log
ngx.log(ngx.ERR,"error!error!error!")ngx.STDERRngx.EMERGngx.ALERTngx.CRITngx.ERRngx.WARNngx.NOTICEngx.INFOngx.DEBUG复制代码
查看错误日志 : 2018/07/02 13:52:23 [error] 141#0: *19 [lua] content.lua:2: error!error!error! 在 Nginx 内核中硬编码限制了单条错误信息最长为 2048 字节。这个长度包含了最后的换行符和开始的时间戳。如果信息长度超过这个限制,Nginx 将把信息文本截断
ngx.ctx
这个 Lua 表可以用来存储基于请求的 Lua 环境数据,其生存周期与当前请求相同 (类似 Nginx 变量)。
location /test { rewrite_by_lua_block { ngx.ctx.foo = 76 } access_by_lua_block { ngx.ctx.foo = ngx.ctx.foo + 3 } content_by_lua_block { ngx.say(ngx.ctx.foo) --output : 79 } }复制代码
一个简单的post内部调用
ocation = /getname { default_type text/html; content_by_lua ' ngx.req.read_body() ret = ngx.req.get_body_data() --获取body体,包含post数据 ret = cjson.decode(ret) ngx.say(ret.a,ret.b) ';}复制代码
主程(post请求)
res = ngx.location.capture( '/getname', { method = ngx.HTTP_POST, body = '{"a":123,"b":345}' } )ngx.say("status:", res.status, " response:", res.body) --输出复制代码
output : status:200 response:123345
cjson包 cjson.encode 将table转成json, cjson.decode 将json转成table
重温 : 调用
redis = {ip='127.0.0.1'}function redis:new() ngx.say(self.ip)endredis:new()复制代码
: 调用会将自己传递赋给self
redis使用实例
local credis = require('resty.redis')local redis = credis:new()redis:set_timeout(1000) -- 1 seclocal ok,err = redis:connect('*****',11368)if not ok then ngx.say(err) ngx.eof()endlocal res, err = redis:auth('123456');if not res then ngx.say("failed to authenticate: ", err) returnend--redis:setex('name',60,'test'); local res, err = redis:get("name") if not res then ngx.say("failed to get dog: ", err) return end ngx.say(res)- -把它放入大小为100的连接池中-- 10秒最大空闲时间local ok, err = red:set_keepalive(10000, 100)if not ok then ngx.say("failed to set keepalive: ", err) returnend -- redis:close()复制代码
setex(key,expire_time,value)
mysql操作
local mysql = require "resty.mysql"local db,err = mysql:new()if not db then ngx.say('init failed mysql',err)enddb:set_timeout(1000)local ok,err,errcode,sqlstate = db:connect({ host = "******", port = 3306, database = "edu_large_data", user = "**", password = "****", charset = "utf8", max_packet_size = 1024 * 1024,}) if not ok then ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate) eturn endres, err, errcode, sqlstate = db:query("select * from flow_user_stat order by id desc limit 2")if not res then ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".") returnenddb:set_keepalive(0, 100)ngx.say(cjson.encode(res))复制代码
[{"uv":1000,"id":4,"one_uv":80,"platform":2,"ip":700,"module":2,"pv":"1500","wait_time":"55555","ymd":20180703},{"uv":800,"id":3,"one_uv":150,"platform":1,"ip":500,"module":2,"pv":"900","wait_time":"66666","ymd":20180703}]
模拟发起远程post请求
发起请求
local res = ngx.location.capture('/getuser',{ method = ngx.HTTP_POST, body = '{1,2,3}'})ngx.say(res.status,res.body)复制代码
因为ngx.location.capture只能访问本地,本地转发远程地址
location = /getuser { proxy_http_version 1.1; proxy_set_header Connection ""; proxy_pass http://www.xxx.com/getpostuser;}复制代码
模拟远程地址,只把传来值传回去
location = /getpostuser { content_by_lua ' ngx.req.read_body() ngx.say(ngx.req.get_body_data() ) ';}复制代码
发起请求方输出 ngx.say(res.status,res.body) : 200 {1,2,3}
安装第三方拓展包
- 进入到 /usr/server/openresty/lualib/resty目录,
- wget
- wget
- local http = require "resty.http"
痛苦使用resty.http发送请求
上面已经安装了resty.http包,下面直接请求远程的接口(实际还是本机)
local http = require "resty.http" local httpc = http.new() local res, err = httpc:request_uri("http://XXXX/getpostuser", { method = "POST", body = "a=1&b=2", headers = { ["Content-Type"] = "application/x-www-form-urlencoded", } }) if not res then ngx.say("failed to request: ", err) return end ngx.say(res.body)复制代码
但是一直是失败的,需要配置 resolver,查看本机DNS
cat /etc/resolv.conf
resolver 192.168.65.1;init_by_lua ' cjson = require "cjson"';server { ...}复制代码
再去远程请求本机访问就可以了