【问题标题】:Can't disable buffering on a cgi using nginx, fastcgi and bash无法使用 nginx、fastcgi 和 bash 在 cgi 上禁用缓冲
【发布时间】:2021-02-22 20:11:41
【问题描述】:

我想制作一个启动程序并在网络浏览器中实时显示输出的 CGI。这里的实时是指程序一旦产生一行输出,它就应该显示在浏览器页面上。

我选择用 bash 编写来包装程序执行,以便处理请求参数。

webbrowser -> nginx+fastcgi -> bash -> program

我有一个测试程序,每半秒输出一行,10 次。

我想我可以在响应头中声明一个纯文本上下文类型,然后执行程序。

不幸的是,输出只在执行结束时才出现在浏览器中。我在 Firefox 和 curl 中测试过。

我已经测试了许多选项以及它们的任意组合来解决这个问题:

  • 在 nginx 中使用 fastcgi_buffering off 指令禁用缓冲
  • 添加X-Accel-Buffering标头
  • 使用stdbuf -oL program
  • 使用 xml http 请求 (XHR) + 服务器端事件 (SSE) 而不是纯文本。

没有任何作用。

我猜是 nginx 和 bash 之间的缓冲问题,但我找不到禁用它的方法。

我可以尝试什么?

【问题讨论】:

  • 我不确定它是否有帮助,最近我回答了一个与此相关的问题,nginx 输出是通过 XHR 接收的。检查this的答案,也许它有帮助?

标签: bash nginx fastcgi server-sent-events buffering


【解决方案1】:

我发现无法解决链中的缓冲问题。我尝试了 perl 而不是 bash,但没有成功。

所以我选择填充缓冲区:在受控程序的每一行输出之后,我回显了一堆'\0'。由于网页浏览器无法将这些内容作为纯文本处理,所以我使用服务器发送事件的方式。

#!/bin/sh

printf "HTTP/1.0 200 OK\r\n"
printf "Content-type: text/event-stream\r\n"
printf "Cache-Control: no-cache\r\n"
printf "X-Accel-Buffering: no\r\n"
printf "\r\n"

flush() {
    padding=4100
    dd if=/dev/zero bs=$padding count=1 2>/dev/null
}

subprogram | while read l;
do
    printf "data: ${l}\n\n"
    flush
done

包装页是这样的:

<html>
<head>
   <meta charset="UTF-8">
   <title>Server-sent events demo</title>
</head>
<body>
  <pre></pre>
<script>
var evtSource = new EventSource('/sse.sh?subprogram');
var pre = document.querySelector('pre');
evtSource.onmessage = function(e) {
  pre.textContent += e.data + '\n';
}
</script>
</body>
</html>

在这种情况下,网络浏览器会负责删除多余的“\0”。

缺点是cgi输出远大于程序输出。

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 2011-08-23
    • 2013-01-17
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-30
    • 1970-01-01
    相关资源
    最近更新 更多