Đối với Sự kiện gửi máy chủ (SSE), cấu hình proxy Nginx có phù hợp?


20

Tôi đã đọc một loạt các câu hỏi khác nhau về cấu hình Nginx nào phù hợp với SSE và đưa ra một số kết quả khó hiểu về việc sử dụng cài đặt nào:

Vậy câu trả lời đúng là gì?

Câu trả lời:


44

Kết nối lâu dài

Sự kiện gửi máy chủ (SSE) là một kết nối HTTP chạy dài **, vì vậy, đối với người mới bắt đầu, chúng tôi cần điều này:

proxy_http_version 1.1;
proxy_set_header Connection "";

LƯU Ý: Theo mặc định, các kết nối TCP trong HTTP / 1.1 vẫn tồn tại, do đó, đặt tiêu đề Kết nối thành trống sẽ là điều đúng đắn và là gợi ý Nginx.

Chunked chuyển mã hóa

Bây giờ là một bên; Phản hồi SSE không đặt tiêu đề Độ dài nội dung vì họ không thể biết lượng dữ liệu sẽ được gửi, thay vào đó họ cần sử dụng tiêu đề Mã hóa chuyển [0] [1], cho phép kết nối truyền phát. Cũng lưu ý: nếu bạn không thêm Độ dài nội dung, hầu hết các máy chủ HTTP sẽ đặt Transfer-Encoding: chunked;cho bạn. Kỳ lạ thay, HTTP chunking cảnh báo chống lại và gây nhầm lẫn.

Sự nhầm lẫn bắt nguồn từ một cảnh báo hơi mơ hồ trong phần Ghi chú của mô tả W3 EventSource:

Các tác giả cũng được cảnh báo rằng việc phân chia HTTP có thể có những tác động tiêu cực không mong muốn đối với độ tin cậy của giao thức này. Nếu có thể, chunking nên bị vô hiệu hóa để phục vụ các luồng sự kiện trừ khi tỷ lệ tin nhắn đủ cao để điều này không thành vấn đề.

Điều đó sẽ khiến người ta tin rằng đó Transfer-Encoding: chunked;là một điều tồi tệ đối với SSE. Tuy nhiên: điều này không nhất thiết phải như vậy, nó chỉ là vấn đề khi máy chủ web của bạn đang làm việc với bạn (không biết thông tin về dữ liệu của bạn). Vì vậy, trong khi hầu hết các bài viết sẽ đề xuất thêm chunked_transfer_encoding off;điều này là không cần thiết trong trường hợp điển hình [3].

Bộ đệm (vấn đề thực sự)

Trường hợp hầu hết các vấn đề đến từ việc có bất kỳ loại bộ đệm nào giữa máy chủ ứng dụng và máy khách. Theo mặc định [4], Nginx sử dụng proxy_buffering on(cũng hãy xem uwsgi_bufferingfastcgi_bufferingtùy thuộc vào ứng dụng của bạn) và có thể chọn để đệm các đoạn mà bạn muốn thoát ra cho khách hàng của mình. Đây là một điều xấu vì bản chất thời gian thực của SSE bị phá vỡ.

Tuy nhiên, thay vì bật proxy_buffering offmọi thứ, thực sự tốt nhất (nếu bạn có thể) thêm X-Accel-Buffering: notiêu đề làm phản hồi trong mã máy chủ ứng dụng của mình để chỉ tắt bộ đệm cho phản hồi dựa trên SSE chứ không phải cho tất cả các phản hồi đến từ ứng dụng của bạn người phục vụ. Tiền thưởng: điều này cũng sẽ làm việc cho uwsgifastcgi.

Giải pháp

Và do đó, các cài đặt thực sự quan trọng thực sự là các tiêu đề phản hồi của máy chủ ứng dụng:

Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;

Và có khả năng thực hiện một số cơ chế ping để kết nối không ở trạng thái quá lâu. Điều nguy hiểm của điều này là Nginx sẽ đóng các kết nối nhàn rỗi như được đặt bằng cách sử dụng keepalivecài đặt.


[0] https://tools.ietf.org/html/rfc2616#section-3.6
[1] https://en.wikipedia.org/wiki/Chunked_transfer_encoding
[2] https://www.w3.org/TR / 2009 / WD-eventource-20091029 / # text-event-stream
[3] https://github.com/whatwg/html/issues/515
[4] http://nginx.org/en/docs/http/ ngx_http_proxy_module.html # proxy_buffering
[5] https://tools.ietf.org/html/rfc7230#section-6.3
[6] https://gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88


Bạn có thể giải thích cơ chế ping là gì không? Có phải nó chỉ đơn giản là đẩy một tin nhắn trống đến kênh? Tôi đã thiết lập các tiêu đề cấp nginx và cấp ứng dụng nhưng tôi vẫn nhận được thời gian chờ 504 từ nginx cho bất kỳ điểm cuối nguồn sự kiện nào.
wgwz

một ping sẽ chỉ là một số dữ liệu (không có thật) được gửi tại một khoảng thời gian trên kết nối, trên máy khách bạn có thể xử lý ping này và bỏ qua nó. LƯU Ý: nếu kết nối của bạn hoàn toàn không hoạt động, ping sẽ không giúp ích, điều gì đó khác là sai.
c4urself

2
Tôi đã thêm các tiêu đề phản hồi theo đề xuất và nó hoạt động. Tôi đã không thay đổi cấu hình nginx v1.12 và cho đến nay không có vấn đề gì.
Mikkel

1
Thêm X-Accel-Buffering: notiêu đề là chìa khóa đối với tôi, nhưng quan trọng, tôi phải làm như @ c4urself đã viết: "thêm X-Accel-Buffering: không làm tiêu đề phản hồi trong mã máy chủ ứng dụng của bạn ". Thêm tiêu đề này vào phần vị trí trong cấu hình nginx của tôi không hoạt động - toàn bộ luồng sự kiện đã chờ để được gửi cho đến khi ứng dụng kết thúc / kết thúc.
MDMower

proxy_http_version 1.1; cần thiết không? Tôi đang cố gắng chạy hơn 6 luồng SSE từ trình duyệt và do đó tôi cần HTTP2.
Bilal Fazlani
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.