前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于OpenResty里的ngx.on_abort

关于OpenResty里的ngx.on_abort

作者头像
LA0WAN9
发布2021-12-14 09:01:18
6840
发布2021-12-14 09:01:18
举报
文章被收录于专栏:火丁笔记

关于 OpenResty 里的 ngx.on_abort,官方文档里是这样说明的:

Registers a user Lua function as the callback which gets called automatically when the client closes the (downstream) connection prematurely.

也就是说:当客户端提前关闭连接的时候,在 ngx.on_abort 里注册的函数会被触发,下面做个实验看看,把如下代码加入 nginx.conf,并 reload 进程使其生效:

代码语言:javascript
复制
lua_check_client_abort on;

location /test_http {
    content_by_lua_block {
        ngx.on_abort(function(a)
            ngx.log(ngx.ERR, "abort")
        end)

        ngx.sleep(100)
    }
}

开启两个命令行窗口:一个 tail -f error.log,另一个 curl http://127.0.0.1/test_http。因为我在代码里设置了 sleep,所以 curl 无疑会卡住,通过执行 Ctrl+c 强行终止,以此构造出一个客户端提前关闭连接的场景,此时我们在 tail 窗口就能看到输出了 log,由此可知当客户端提前关闭连接的时候,在 http 的情况下, ngx.on_abort 里注册的函数会被触发。

不过如果你仔细查看和 ngx.on_abort 相关的 lua_check_client_abort 的文档,会发现:

According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via ngx.req.socket, then ngx_lua will neither stop all the running “light threads” nor call the user callback (if ngx.on_abort has been called). Instead, the reading operation on ngx.req.socket will just return the error message “client aborted” as the second return value (the first return value is surely nil).

也就是说,当客户端提前关闭连接的时候,如果 ngx.req.socket 中的数据没有被读取,那么 ngx.on_abort 里注册的函数不会被触发。实际上指的就是非 http 情况,也就是自己处理 socket 的情况,比如 websocket:

代码语言:javascript
复制
lua_check_client_abort on;

location /test_websocket {
    content_by_lua_block {
        ngx.on_abort(function()
            ngx.log(ngx.ERR, "abort")
        end)

        local server = require "resty.websocket.server"
        local wb = server:new()

        while true do
            local data, typ, err = wb:recv_frame()

            if wb.fatal then
                ngx.log(ngx.ERR, err)
                return ngx.exit(444)
            end
        end
    }
}

然后通过一个网页来调用如上的 websocket 服务:

代码语言:javascript
复制
<script>
var ws = new WebSocket('ws://127.0.0.1/websocket');
ws.send("test");
</script>

与之前不同的是,因为我们要执行网页中的 javascript 代码,所以必须通过浏览器来执行 test_websocket 请求,而不是 curl,当请求发出后,会连接 websocket 发送一个字符串,直接关闭浏览器,以此构造出一个客户端提前关闭连接的场景,需要说明的是这里不用 sleep,因为已经连上 websocket 了,此时我们在 tail 窗口就能看到输出了 log,但是却不是 ngx.on_abort 的 log,而是 wb.fatal 的 log:

failed to receive the first 2 bytes: client aborted

由此可知当客户端提前关闭连接的时候,在 websocket 的情况下, ngx.on_abort 里注册的函数不会被触发。

结论:通过 ngx.on_abort 检测客户端是否提前断开连接的方法,仅仅对 http 场景有效,对其它需要要手动处理 socket 数据的场景(比如 websocket)无效,对于此类场景,可以读取 socket 数据,通过报错信息来判断客户端是否提前关闭了连接,需要留意的是文档描述是错误信息等于「client aborted」表示客户端提前关闭了连接,但是 lua-resty-websocket 把这个报错信息重新加工了一下,所以不能按等于判断,必须按包含判断,可见通过判断错误信息等于什么来判断错误类型的方式有点不靠谱,其实在 websocket 场景,如果要求不是特别严格的话,那么只要 fatal 为真就可以认为客户端已经断开了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档