OpenResty 中的流式 HTTP 响应输出
在这个视频中,我将演示如何在 OpenResty 中进行流式 HTTP 响应体输出。
cd ~/
mkdir stream-resp/
cd stream-resp/
我们一如既往地创建子目录结构。
mkdir logs conf html
我们快速写出模板配置。
vim conf/nginx.conf
并在此文件中进行以下编辑。
- 我们创建一个 HTTP 服务器,监听 8080 端口。
- 增加一个
/test
位置。 - 指定这个
application/octet-stream
MIME 类型是很重要的,这样才能让 Chrome 网络浏览器满意。 - 通过 content_by_lua_block 指令添加一些 Lua 代码。
- 我们每隔一秒输出一行输出。
- 我们需要显式调用 ngx.flush 方法来刷新 Nginx 的写缓冲区。这是一个 100% 非阻塞的调用。
- 而我们使用
ngx.sleep
在每次循环迭代中睡一秒钟。这也是非阻塞的。 - 然后我们为
html
目录创建一个根位置。
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080 reuseport;
location = /test {
default_type application/octet-stream;
content_by_lua_block {
for i = 1, 4 do
ngx.say("hello ", i)
ngx.flush(true)
ngx.sleep(1) -- sec
end
}
}
location / {
default_type text/html;
root html;
}
}
}
我们现在就来检查一下整个目录树。
tree .
看起来不错。
现在启动这个 OpenResty 应用程序。
openresty -p $PWD/
是时候用 curl
来查询我们的 HTTP 位置了。
curl 'http://127.0.0.1:8080/test'
酷,确实是每秒生成一行字!
为了验证一切是否真的是非阻塞的,我们可以用 weighttp
工具加载这个 HTTP API。请注意,这将需要一段时间,因为我们在这里故意放慢响应速度。
weighttp -c 500 -k -n 500 127.0.0.1:8080/test
因此,在 500 个并发请求的情况下,我们仍然可以实现每秒 120 个以上的请求!需要注意的是,每个请求需要 4 秒才能完成。而这里我们只使用了一个工作进程和一个操作系统线程。
我们仍然可以将并发量提高很多,但是我们需要对 Nginx 配置进行相应的调整。
vim conf/nginx.conf
比如把 worker_connections
调到一个较大的数值。
通过启用访问日志缓冲也可以获得更好的性能。我们还可以减少请求内存池的大小。
现在让我们创建一个 HTML 页面,在 Web 浏览器中进行测试。
vim html/a.html
我们在这个文件中进行以下编辑。
- 增加一个
DIV
标签,以保持输出。 - 添加一些 JavaScript 来发送 AJAX 请求到我们之前的 HTTP 位置。
- 我们取出
DIV
元素。 - 让我们添加一个 JavaScript 函数来进行流式响应接收。
- 确保有新的数据。
- 将我们的新数据追加到
DIV
元素中。在这里,我们是懒惰的。我们不需要对特殊的 HTML 字符进行转义。 - 而且我们每秒都会检查新的传入响应数据。
- 火狐支持更巧妙的方式,但我们也要支持 Chrome。
- 最后,我们处理响应体流的结束。
- 最后一次检查响应数据。
- 删除我们的定期计时器。
- 并将最终的输出结果追加到网页上。
- 为了简洁起见,我们在此省略错误处理。
<!doctype html>
<html>
<body>
<div style="margin: 2em;" id="out"></div>
<script>
(function () {
let xhttp = new XMLHttpRequest();
xhttp.open("GET", "/test", true);
xhttp.send();
let div = document.getElementById("out")
let total_len = 0
let check_resp = function () {
let resp = xhttp.responseText
let len = resp.length
if (len > total_len) {
let new_data = resp.substring(total_len, len)
total_len = len;
div.innerHTML += new_data + "<br/>"
}
};
let timer = setInterval(check_resp, 1000);
check_resp();
xhttp.onreadystatechange = function () {
if (this.readyState == 4) {
check_resp();
clearInterval(timer);
div.innerHTML += "done<br/>";
}
};
})();
</script>
</body>
</html>
我们再来检查一下整个目录树。
tree .
我们不需要重新加载或重新启动 OpenResty 服务器,因为它只是一个静态的 HTML 页面。
ps aux|grep nginx|grep -v /tmp/
是时候用 Chrome 打开这个 HTML 页面了。
生效了!这就是我今天要讲的全部内容。 如果你喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道 或 B 站频道。谢谢!
关于本文和关联视频
本文和相关联的视频都是完全由我们的 OpenResty Showman 产品从一个简单的剧本文件自动生成的。
关于作者
章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。
章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJIT、GDB、SystemTap、LLVM、Perl 等,并编写过 60 多个开源软件库。
关注我们
如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:
翻译
我们提供了英文版原文和中译版(本文) 。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!