如果仅使用 nginx 静态服务器完成,服务器发送事件(SSE)将无法工作

问题描述 投票:0回答:1

我一整天都在尝试仅使用 nginx(没有 proxy_pass)使 SSE 工作,后来为了尝试而使用 proxy_pass,但是当使用 JavaScript 的 EventSource 连接到端点时,它在收到第一个事件,然后再次重新连接。这违背了 SSE 的初衷,因为它感觉更像是民意调查。我的目标是当我们将新的 nginx 静态服务器部署到生产环境时,让 SSE 重新连接,以便我可以发送带有当前提交哈希的事件消息(在 docker 构建或 docker 运行期间添加到 nginx 配置中),这里的代码几乎是工作,正如你将看到的,我通过 proxy_pass 尝试了两种方法,如果没有它,两个端点都会遇到相同的“错误”:

# load_module /usr/lib/nginx/modules/ngx_http_headers_more_filter_module.so;
# user       www www;  ## Default: nobody
worker_processes  1;
# error_log  logs/error.log;
# pid        logs/nginx.pid;
# worker_rlimit_nofile 8192;

events {
    worker_connections 1024;
}

http {
    # send_timeout 1800;
    # keepalive_timeout 10m;
    # client_max_body_size 128M;
    # proxy_max_temp_file_size 0;
    # proxy_buffering off;
    # server_names_hash_bucket_size 256;

    server {
        listen 8080;
        server_name localhost;
        # index index.html;
        # root /usr/share/nginx/html;

        location = /sse {
            proxy_set_header Host $host;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_pass http://proxy;
            proxy_buffering off;
            proxy_request_buffering off;
            proxy_cache off;

            # proxy_connect_timeout 159s;
            # proxy_send_timeout   600;
            # proxy_read_timeout   600;
            # proxy_buffer_size    64k;
            # proxy_buffers     16 32k;
            # proxy_busy_buffers_size 64k;
            # proxy_temp_file_write_size 64k;
            fastcgi_keep_conn on;

            # add_header Connection "keep-alive";
            # add_header X-Accel-Buffering "no";
            # chunked_transfer_encoding on;
            # more_clear_headers "Content-Length";
            # default_type text/event-stream;
        }
    }

    server {
        listen 8081;
        server_name localhost;

        location = /sse {
            # add_header Connection "keep-alive";
            # expires off;
            # default_type text/event-stream;
            default_type "";
            add_header Content-Type "text/event-stream; charset=utf-8";
            add_header Cache-Control "no-store";
            add_header Access-Control-Allow-Origin "*";
            chunked_transfer_encoding off;
            push_stream_eventsource_support on;
            
            add_header X-Accel-Buffering "no";
            # chunked_transfer_encoding off;
            # keepalive_timeout 100s;
            return 200 "event: ping\ndata: {\"time\": \"foo\"}\n\n";
        }
    }

    upstream proxy {
        server 127.0.0.1:8081;
    }
}
 document.addEventListener('DOMContentLoaded', () => {
  const source = new EventSource('http://localhost:8080/sse');

  source.addEventListener(
    'open',
    function (e) {
      console.log('Connection was opened.', e.readyState);
    },
    false
  );

  source.addEventListener(
    'error',
    function (e) {
      console.log(e.readyState, e);
      if (e.readyState == EventSource.CLOSED) {
        // Connection was closed.
      }
    },
    false
  );

  source.addEventListener('ping', function (event) {
    console.log('ping', event);
  });
});

我看到的是“连接已打开”。随后成功发送“ping”消息,3 秒后同样如此。连接正在从 nginx 端“关闭”。我已经在一个小型的express.js 服务器上尝试过同样的操作,但这并没有发生,它会按预期工作。发生什么事了?

javascript nginx server-sent-events
1个回答
0
投票

Nginx 将在 3 秒后关闭连接,同时未从客户端接收任何数据。这是因为 SSE 连接预计是单向的。它的服务器向客户端发送数据。

要修复,您需要每隔几秒创建一条从客户端到服务器的心跳消息。这将使连接保持活动状态并防止 Nginx 关闭它。

const source = new EventSource('http://example:8080/sse');

source.addEventListener(
  'open',
  function (event) {
    console.log('Connection was opened.', event.readyState);

    //  This is heartbeat message every 3 sec.
    setInterval(() => {
      source.send('ping');
    }, 3000);
  },
  false
);

© www.soinside.com 2019 - 2024. All rights reserved.