6.OpenResty系列之深入理解(二)
1. 日志输出
vim /usr/local/openresty/nginx/conf/nginx.conf
默认配置如下
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
http {
#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;
我们访问error.log,内容如下:
access.log,内容如下
# $remote_addr - 表示客户端发起请求的IP地址
# $remote_user - 表示发起请求的经过身份验证的用户的用户名(如果有)
# $time_local - 表示请求发起的本地时间
# $request - 表示客户端发起的HTTP请求,包括方法、URL和HTTP版本
# $status - 表示服务器返回的请求的HTTP状态码
# $body_bytes_sent - 表示服务器在响应体中发送的字节数
# $http_referer - 表示HTTP Referer头,指示引导客户端访问当前页面的页面的URL
# $http_user_agent - 表示客户端的Web浏览器或其他HTTP客户端的用户代理字符串
# $http_x_forwarded_for - 表示X-Forwarded-For头,通常用于跟踪客户端通过代理或负载均衡器连接到Web服务器时的原始IP地址
127.0.0.1 - - [07/Jan/2024:06:13:31 +0800] "GET login.cgi HTTP/1.1" 400 163 "-" "-"
如果你的日志需要归集,并且对时效性要求比较高那么用 lua-resty-logger-socket
lua-resty-logger-socket的目标是替代 Nginx 标准的 ngx_http_log_module 以非阻塞 IO 方式推送 access log 到远程服务器上。对远程服务器的要求是支持 syslog-ng 的日志服务
2. 子查询
Nginx 子请求是一种非常强有力的方式,它可以发起非阻塞的内部请求访问目标 location
需要注意的是,子请求只是模拟 HTTP 接口的形式, 没有 额外的 HTTP/TCP 流量,也 没有 IPC (进程间通信) 调用。所有工作在内部高效地在 C 语言级别完成
子请求与 HTTP 301/302 重定向指令 (通过 ngx.redirect) 完全不同,也与内部重定向 ((通过 ngx.exec) 完全不同
在发起子请求前,用户程序应总是读取完整的 HTTP 请求体 (通过调用 ngx.req.read_body 或设置 lua_need_request_body 指令为 on).
该 API 方法(ngx.location.capture_multi 也一样)总是缓冲整个请求体到内存中。因此,当需要处理一个大的子请求响应,用户程序应使用 cosockets 进行流式处理
下面是一个简单例子:
res = ngx.location.capture(uri)
- 返回一个包含四个元素的 Lua 表 (res.status, res.header, res.body, 和 res.truncated)。
- res.status (状态) 保存子请求的响应状态码。
- res.header (头) 用一个标准 Lua 表储子请求响应的所有头信息。如果是“多值”响应头,这些值将使用 Lua (数组) 表顺序存储。例如,如果子请求响应头包含下面的行,则 res.header[“Set-Cookie”] 将存储 Lua 表 {“a=3”, “foo=bar”, “baz=blah”}。
Set-Cookie: a=3
Set-Cookie: foo=bar
Set-Cookie: baz=blah
- res.body (体) 保存子请求的响应体数据,它可能被截断。用户需要检测 res.truncated (截断) 布尔值标记来判断 res.body 是否包含截断的数据。这种数据截断的原因只可能是因为子请求发生了不可恢复的错误,例如远端在发送响应体时过早中断了连接,或子请求在接收远端响应体时超时
3. 不同阶段共享变量
在 OpenResty 的体系中,可以通过共享内存的方式完成不同工作进程的数据共享,可以通过 Lua 模块方式完成单个进程内不同请求的数据共享
如何完成单个请求内不同阶段的数据共享呢?ngx.ctx 表就是为了解决这类问题而设计的
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)
}
}
首先 ngx.ctx 是一个表,所以我们可以对他添加、修改。它用来存储基于请求的 Lua 环境数据,其生存周期与当前请求相同 (类似 Nginx 变量)。它有一个最重要的特性:单个请求内的 rewrite (重写),access (访问),和 content (内容) 等各处理阶段是保持一致的
额外注意,每个请求,包括子请求,都有一份自己的 ngx.ctx 表
location /sub {
content_by_lua_block {
ngx.say("sub pre: ", ngx.ctx.blah)
ngx.ctx.blah = 32
ngx.say("sub post: ", ngx.ctx.blah)
}
}
location /main {
content_by_lua_block {
ngx.ctx.blah = 73
ngx.say("main pre: ", ngx.ctx.blah)
local res = ngx.location.capture("/sub")
ngx.print(res.body)
ngx.say("main post: ", ngx.ctx.blah)
}
}
访问 GET /main 输出
main pre: 73
sub pre: nil
sub post: 32
main post: 73
4. 防止SQL注入
对于 MySQL ,可以调用 ndk.set_var.set_quote_sql_str ,进行一次过滤即可,如果恰巧你使用的是 PostgreSQL ,调用 ndk.set_var.set_quote_pgsql_str 过滤输入变量
-- for MySQL
local req_id = [[1'; drop table cats;--]]
res, err, errno, sqlstate =
db:query(string.format([[select * from cats where id = %s]],
ndk.set_var.set_quote_sql_str(req_id)))
if not res then
ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".")
return
end
5. 发起新HTTP请求
http {
server {
listen 80;
location /test {
content_by_lua_block {
ngx.req.read_body()
local args, err = ngx.req.get_uri_args()
local http = require "resty.http" -- ①
local httpc = http.new()
local res, err = httpc:request_uri( -- ②
"http://127.0.0.1:81/spe_md5",
{
method = "POST",
body = args.data,
}
)
if 200 ~= res.status then
ngx.exit(res.status)
end
if args.key == res.body then
ngx.say("valid request")
else
ngx.say("invalid request")
end
}
}
}
server {
listen 81;
location /spe_md5 {
content_by_lua_block {
ngx.req.read_body()
local data = ngx.req.get_body_data()
ngx.print(ngx.md5(data .. "*&^%$#$^&kjtrKUYG"))
}
}
}
}
重点解释:
① 引用 resty.http 库资源,它来自 github https://github.com/pintsized/lua-resty-http, 下载tar.gz解压lua文件至openresty/lualib/resty/usr/local/openresty/lualib/resty
② 参考 resty-http 官方 wiki 说明,我们可以知道 request_uri 函数完成了连接池、HTTP 请求等一系列动作
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!