谈谈ngx.exit与ngx.eof的区别 exponential和index的区别
yuyutoo 2024-11-10 13:47 5 浏览 0 评论
事由
我们基于Vanilla开发了一个类似于一个网关的流量分发服务,在原来的业务线上对不同的业务使用不同的后端(PHP、Python、Lua...)进行处理,最近在紧锣密鼓的测试(当然这里咱们主要看问题),在扫荡日志的过程中发现有这样的一条[error]
(日志已打码)
没错,就是条: attempt to set ngx.status after sending out response headers while sending to client,大致意思是我在响应头已经发出后又尝试对 ngx.status 进行了修改,可是我肯定不会想那么干的,而且页面请求看着明明是正常的。
本着认真负责的态度,我又对代码逻辑和写法前前后后梳理数次,然事实上并没有发现我试图那么干,至少本意是确定的。面对这个幽灵般的错误,一个程序员的直觉告诉我,肯定是我写了一个bug?或者我的某些逻辑触发了Vanilla的bug?或者触发了OpenResty的bug?越想越激动,我必须把它找出来。
为了避免大家混淆各种Vanilla,这里先附上Vanilla项目地址:
Github:https://github.com/idevz/vanilla
GitOSC:http://git.oschina.net/idevz/vanilla
Debug
逻辑上肉眼没看出什么问题,只能通过debug来解决。到底哪行报出来的错误呢?在公司开发机上添加 --with-debug
参数重新编译了OpenResty,打开debug日志。
一看果然是在响应发出后报的错,但日志没有反应出报错的具体位置。没办法,我只能通过“二分步进法”,打一堆日志来跟进,人肉找出来到底什么地方报的错。
最后跟到这样一处逻辑:
请求正常完成后,response:response()
执行结果确定是true,问题一定出在 ngx.eof()
, 我的本意在于如果在routerShutdown阶段(Vanilla请求处理的第二个阶段)请求完成响应,则后面的几个阶段就不再执行,直接结束当前请求。查阅文档发现 ngx.eof()
只是显式指定了响应流输出结束,后面的代码逻辑会在服务端继续执行。而我期望的当前请求直接终止,不应该使用 ngx.eof()
而是 ngx.exit()
。下面我们细节来认识下这两个API。
ngx.eof() 与 ngx.exit()
虽然在OpenResty ngx-lua
模块文档中这两个API文档位置紧邻,但用法和功能方面却截然不同。
ngx.exit
用法: ngx.exit(status) 执行上下文: rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua* ngx.exit()
的使用相对简单些:
当传入的status >= 200(200即为ngx.HTTP_OK),
ngx.exit()
会中断当前请求,并将传入的状态码(status)返回给nginx。当传入的status == 0(0即为ngx.OK)则
ngx.exit()
会中断当前执行的phrase(ngx-lua模块处理请求的阶段,如content_by_lua*),进而继续执行下面的phrase。对于
ngx.exit()
需要进一步注意的是参数status的使用,status可以传入ngx-lua所定义的所有的HTTP状态码常量(如:ngx.HTTP_OK、ngx.HTTP_GONE、ngx.HTTP_INTERNAL_SERVER_ERROR等)和两个ngx-lua模块内核常量(只支持NGX_OK和NGX_ERROR这两个,如果传入其他的如ngx.AGAIN等则进程hang住)。文档中推荐的
ngx.exit()
最佳实践是同return
语句组合使用,目的在于增强请求被终止的语义(return ngx.exit(...)
)。
ngx.eof
用法: ok, err = ngx.eof() 执行上下文: rewrite_by_lua, access_by_lua, content_by_lua* ngx.eof
除了前面所说的显式指定了响应流输出的结束,后面的逻辑继续在服务端执行外,还需要注意以下几点:
当你禁用了HTTP1.1的keep-alive特性后可以通过调用
ngx.eof()
来使客户端主动断开连接,这个技巧可以用来做一些back-ground jobs 而不需要HTTP客户端等待连接(不过文档推荐的back-ground jobs的处理方式是ngx.timer.at
API,详情请看文档说明)。当你创建子请求来请求在其他
location
配置的上游模块时,你应该配置这些上游模块来忽略客户端连接的中断,如果默认不是忽略的话。例如默认的标准ngx_http_proxy_module
模块会在客户端断开连接后立即同时终止子请求和主请求,所以在模块ngx_http_proxy_module
将proxy_ignore_client_abort
设置为开启(proxy_ignore_client_abort on;
)就十分重要。自
v0.8.3
起,ngx.eof()
执行成功返回1,失败则返回nil
和错误描述信息。
实践发现 ngx.exit()
和 ngx.eof()
本质区别在于ngx.exit()
作用在于中断当前操作,不管是ngx-lua模块请求处理的当前阶段还是整个请求,而 ngx.eof()
只是结束响应流的输出,中断HTTP连接,后面的代码逻辑还会继续在服务端执行,而且 ngx.eof()
支持运行的上下文比 ngx.exit()
少太多, ngx.eof()
有返回值, ngx.exit()
则没有,因为请求已经结束。
在bug和debug中成长
其实这是一个不大不小的bug,说它小,因为后来我在文档中对ngx.status的描述中发现这么一句 Setting ngx.status after the response header is sent out has no effect but leaving an error message in your nginx's error log file
说明,也就是试图在响应头发出后更改ngx.status会在错误日志中记录一条 [error]
但是这个错误对本次请求的响应没有影响;说它大,如果没有仔细查出来这个没有影响,那一切都是未知,很可能给系统埋下一个未知的坑,不知道哪天就会爆出来坑你一下,关键的一点还是对API的理解。OpenResty的文档是我见过开源项目中写的比较好的,虽然是英文。还是值得仔细研习。
相关推荐
- URL URI傻傻分不清楚,dart告诉你该怎么用
-
简介如果我们要访问一个网站,需要知道这个网站的地址,网站的地址一般被称为URL,他的全称是UniformResourceLocator。那么什么是URI呢?...
- 你最深爱的编程语言其实很烂
-
我最近写了几篇比较严肃的博客,是关于一些沮丧的事情,结果我开始有些忧郁。很严重。所以,我想应该说些比较轻松的事情。我要做的就是数落大家最喜欢的编程语言。你会问我为什么,为什么要搞这种恶作剧?亲爱的朋友...
- 路由器交换机基础配置6——命令行显示信息设置
-
一、控制命令行显示信息设备中的部分命令执行后会出现提示、警告、执行结果等显示信息,用户可以控制这些显示信息的显示方式,以方便阅读。1、提示和警告信息提供中、英文两种语言显示。可以通过language-...
- python是一种什么类型的编程语言
-
Python(英国发音:/'paθn/美国发音:/'paθɑn/)是一种广泛使用的解释型、高级编程、通用型编程语言,由吉多·范罗苏姆创造,第一版发布于1991年。可以视之为一种改良(加入一些其他编程...
- 60年了,LISP语言的进化史是否会引发你对AI未来的新思考?
-
图:pixabay作为长期垄断AI领域的高级计算机语言程序,Lisp语言到底经过了怎样的变迁?也许,我们可能已经忘记了一些在今天仍然有用的东西,或者说,至少了解这些历史对一些新的想法产生有所影响。o2...
- Java 和 JavaScript 的关系
-
Java和JavaScript不同之处:●出身不同:Javascript与Java是由不同的公司开发的不同产品。Javascript是Netscape公司的脚本语言,而Java...
- Micro:命令行文本编辑器 (Go)
-
Micro是一款基于终端的文本编辑器,使用Go开发。Micro是个命令行编辑器,主要特性是易用,直观,并且包含所有现代化终端的优点。功能:易用常用快捷键绑定(ctrl-s,ctrl-c,...
- 7 行代码 3 分钟:从零开始实现一门编程语言
-
本文最初发布于MattMight的个人博客。...
- 码上去学海南公司:C语言到底能干什么?我列举了8种经典案例
-
虽然C语言执行速度极快,占用资源极少,但是它使用起来非常麻烦,完全没有Java、Python、Go、JavaScript、C#等方便和灵活,会严重拖慢项目的开发进度,所以,通常只有在“不得不”的情...
- 什么是 JavaScript?
-
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注!作者|慕课网精英讲师然冬...
- 新人如何自学安卓手机软件开发?
-
当我们问一个人,你是做什么的,听到我是做软件开发的,不由自主就会感觉,这个人好厉害。越来越多的人投身于软件开发行业,可能有些人本身不是学这个专业的,出于对这个行业的热爱,自学软件开发。现在这个社会,多...
- Android开发基础入门(一):UI与基础控件
-
Android基础入门前言:...
- 第02章 《小Z安卓程序员之路》Android Studio
-
不积跬步无以至千里,不积小流无以成江海!!每天进步一点点我是杨哲丶,一个梦想把科技和艺术结合在一起的程序猿!!小Z在开始查询的如何使用SVN和如何使用Git版本控制工具的时候,发现网上大部分居然是关于...
- 支付宝团队 | 移动客户端实战教程(iOS和Android)
-
今天给大家推荐一个非常好的PPT,是github在线的,是支付宝团队内部分享技术用的PPT,适合Web端和移动端的同学入门客户端开发,是我见过的最详细的《iOS&Android开发从入门到...
- 只需二步,就可以在win11操作系统上运行Android程序,非常简单
-
你想像过吗,只需几个简单的步骤即可在你的Windows电脑上运行Android应用程序。现在,在Windows11中运行安卓应用程序现在就像在手机上运行应用程序一样简单。微软和亚马逊联手打造了数千款...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)