无法使用Nginx,fastcgi和bash在CGI上禁用缓冲

问题描述

我想制作一个CGI,它可以启动程序并在Web浏览器中实时显示输出。实时是指程序生成的输出行应立即显示在浏览器页面上。

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

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

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

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

不幸的是,输出仅在执行结束时一次全部显示在浏览器中。我在Firefox和curl中对其进行了测试。

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

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

什么都没有。

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

我可以尝试什么?

解决方法

我找不到解决链中缓冲问题的方法。我没有运气就尝试了perl而不是bash。

因此,我选择填充缓冲区:在受控程序的每一行输出之后,我都会回显一堆'\ 0'。由于无法通过Web浏览器将该内容处理为纯文本,因此我使用服务器发送事件的方法。

#!/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>

在这种情况下,Web浏览器会删除多余的'\ 0'。

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...