- Socket 编程发展
- OpenResty 简介
- Lua 入门
- Nginx
- 子查询
- 不同阶段共享变量
- 防止 SQL 注入
- 如何发起新 HTTP 请求
- 访问有授权验证的 Redis
- select+set_keepalive 组合操作引起的数据读写错误
- redis 接口的二次封装(简化建连、拆连等细节)
- redis 接口的二次封装(发布订阅)
- pipeline 压缩请求数量
- script 压缩复杂请求
- 动态生成的 lua-resty-redis 模块方法
- LuaCjsonLibrary
- json解析的异常捕获
- 稀疏数组
- 空table编码为array还是object
- PostgresNginxModule
- 调用方式简介
- 不支持事务
- 超时
- 健康监测
- SQL注入
- LuaNginxModule
- 执行阶段概念
- 正确的记录日志
- 热装载代码
- 阻塞操作
- 缓存
- sleep
- 定时任务
- 禁止某些终端访问
- 请求返回后继续执行
- 调试
- 请求中断后的处理
- 我的 lua 代码需要调优么
- 变量的共享范围
- 动态限速
- shared.dict 非队列性质
- 正确使用长链接
- 如何引用第三方 resty 库
- 典型应用场景
- 怎样理解 cosocket
- 如何安全启动唯一实例的 timer
- 如何正确的解析域名
- LuaRestyDNSLibrary
- 使用动态 DNS 来完成 HTTP 请求
- LuaRestyLock
- 缓存失效风暴
- HTTPS 时代
- 动态加载证书和 OCSP stapling
- TLS session resumption
- 测试
- Web 服务
- 火焰图
- 如何定位问题
- module 是邪恶的
- FFI
- 什么是 JIT
如何发起新 HTTP 请求
OpenResty 最主要的应用场景之一是 API Server,有别于传统 Nginx 的代理转发应用场景,API Server 中心内部有各种复杂的交易流程和判断逻辑,学会高效的与其他 HTTP Server 调用是必备基础。本文将介绍 OpenResty 中两个最常见 HTTP 接口调用方法。
我们先来模拟一个接口场景,一个公共服务专门用来对外提供加了“盐” md5 计算,业务系统调用这个公共服务完成业务逻辑,用来判断请求本身是否合法。
利用 proxy_pass
参考下面示例,利用 proxy_pass 完成 HTTP 接口访问的成熟配置+调用方法。
http {
upstream md5_server{
server 127.0.0.1:81; # ①
keepalive 20; # ②
}
server {
listen 80;
location /test {
content_by_lua_block {
ngx.req.read_body()
local args, err = ngx.req.get_uri_args()
-- ③
local res = ngx.location.capture('/spe_md5',
{
method = ngx.HTTP_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
}
}
location /spe_md5 {
proxy_pass http://md5_server; -- ④
#For HTTP, the proxy_http_version directive should be set to “1.1” and the “Connection”
#header field should be cleared.(from:http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive)
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
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"))
}
}
}
}
重点说明: ① 上游访问地址清单(可以按需配置不同的权重规则); ② 上游访问长连接,是否开启长连接,对整体性能影响比较大(大家可以实测一下); ③ 接口访问通过 ngx.location.capture
的子查询方式发起; ④ 由于 ngx.location.capture
方式只能是 nginx 自身的子查询,需要借助 proxy_pass 发出 HTTP 连接信号; ⑤ 公共 API 输出服务;
这里大家可以看到,借用 nginx 周边成熟组件力量,为了发起一个 HTTP 请求,我们需要绕好几个弯子,甚至还有可能踩到坑(upstream 中长连接的细节处理),显然没有足够优雅,所以我们继续看下一章节。
利用 cosocket
立马开始我们的新篇章,给大家展示优雅的解决方式。
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。 ② 参考 resty-http
官方 wiki 说明,我们可以知道 request_uri 函数完成了连接池、HTTP 请求等一系列动作。
题外话,为什么这么简单的方法我们还要求助外部开源组件呢?其实我也觉得这个功能太基础了,真的应该集成到 OpenResty 官方包里面,只不过目前官方默认包里还没有。
如果你的内部请求比较少,使用 ngx.location.capture
+proxy_pass
的方式还没什么问题。但如果你的请求数量比较多,或者需要频繁的修改上游地址,那么 resty.http
就更适合你。
另外 ngx.thread.*
与 resty.http
相互结合也是很不错的玩法,推荐大家有时间研究一下。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论