สำหรับเหตุการณ์ที่เซิร์ฟเวอร์ส่ง (SSE) การกำหนดค่าพร็อกซี Nginx มีความเหมาะสมอย่างไร


20

ฉันได้อ่านคำถามมากมายเกี่ยวกับการกำหนดค่า Nginx ที่เหมาะสมสำหรับ SSE และเกิดผลลัพธ์ที่สับสนเกี่ยวกับการตั้งค่าที่จะใช้:

ดังนั้นคำตอบที่ถูกต้องคืออะไร?

คำตอบ:


45

การเชื่อมต่อที่ยาวนาน

เหตุการณ์ที่เซิร์ฟเวอร์ส่ง (SSE) เป็นการเชื่อมต่อ HTTP ที่ใช้งานมานาน ** ดังนั้นสำหรับผู้เริ่มต้นเราต้องการสิ่งนี้:

proxy_http_version 1.1;
proxy_set_header Connection "";

หมายเหตุ: การเชื่อมต่อ TCP ใน HTTP / 1.1 จะคงอยู่ตามค่าเริ่มต้นดังนั้นการตั้งค่าส่วนหัวการเชื่อมต่อให้ว่างเปล่าทำสิ่งที่ถูกต้องและเป็นคำแนะนำของ Nginx

การถ่ายโอนการเข้ารหัส Chunked

ตอนนี้กัน; การตอบสนองของ SSE ไม่ได้ตั้งค่าส่วนหัวความยาวเนื้อหาเพราะพวกเขาไม่สามารถรู้ได้ว่าจะส่งข้อมูลจำนวนเท่าใด แต่จะต้องใช้ส่วนหัวการเข้ารหัสการโอนย้าย [0] [1] สิ่งที่ช่วยให้สามารถเชื่อมต่อสตรีมได้ หมายเหตุ: หากคุณไม่เพิ่มเซิร์ฟเวอร์ HTTP ที่มีความยาวเนื้อหาส่วนใหญ่จะตั้งค่าTransfer-Encoding: chunked;ให้คุณ HTTP chunking เตือนและทำให้เกิดความสับสน

ความสับสนเกิดจากคำเตือนที่ค่อนข้างคลุมเครือในส่วน Notes ของคำอธิบาย W3 EventSource:

ผู้เขียนยังได้รับการเตือนว่า HTTP chunking อาจมีผลกระทบเชิงลบที่ไม่คาดคิดต่อความน่าเชื่อถือของโปรโตคอลนี้ หากเป็นไปได้ควรปิดการใช้งาน chunking เพื่อให้บริการสตรีมเหตุการณ์เว้นแต่ว่าอัตราการส่งข้อความจะสูงพอสำหรับเรื่องนี้

ซึ่งจะนำไปสู่การเชื่อว่าTransfer-Encoding: chunked;เป็นสิ่งที่ไม่ดีสำหรับ SSE อย่างไรก็ตาม: นี่ไม่จำเป็นต้องเป็นกรณีนี้เป็นเพียงปัญหาเมื่อเว็บเซิร์ฟเวอร์ของคุณกำลังทำการส่งข้อมูลให้คุณ (ไม่ทราบข้อมูลเกี่ยวกับข้อมูลของคุณ) ดังนั้นในขณะที่โพสต์ส่วนใหญ่จะแนะนำให้เพิ่มchunked_transfer_encoding off;สิ่งนี้ไม่จำเป็นในกรณีทั่วไป [3]

บัฟเฟอร์ (ปัญหาจริง)

จุดที่ปัญหาส่วนใหญ่เกิดจากการบัฟเฟอร์ระหว่างแอพเซิร์ฟเวอร์กับไคลเอนต์ ตามค่าเริ่มต้น [4] Nginx ใช้ proxy_buffering on(ดูที่uwsgi_bufferingและfastcgi_bufferingขึ้นอยู่กับแอปพลิเคชันของคุณด้วย) และอาจเลือกที่จะบัฟเฟอร์ชิ้นที่คุณต้องการออกไปยังไคลเอนต์ของคุณ สิ่งนี้เป็นสิ่งที่ไม่ดีเนื่องจากลักษณะการแบ่งเวลาตามจริงของ SSE

อย่างไรก็ตามแทนที่จะเปลี่ยนproxy_buffering offทุกอย่างจะดีที่สุด (ถ้าคุณสามารถทำได้) เพื่อเพิ่มX-Accel-Buffering: noส่วนหัวการตอบกลับในรหัสเซิร์ฟเวอร์แอปพลิเคชันของคุณเพื่อปิดการบัฟเฟอร์เฉพาะสำหรับการตอบสนองแบบ SSE ไม่ใช่สำหรับการตอบกลับทั้งหมดที่มาจากแอปของคุณ เซิร์ฟเวอร์ โบนัส: นี้จะทำงานสำหรับและuwsgifastcgi

วิธีการแก้

ดังนั้นการตั้งค่าที่สำคัญจริงๆคือส่วนหัวการตอบกลับของแอปเซิร์ฟเวอร์:

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

และอาจเป็นการใช้กลไกการ ping บางอย่างเพื่อให้การเชื่อมต่อไม่ได้ใช้งานนานเกินไป อันตรายของสิ่งนี้คือ Nginx จะปิดการเชื่อมต่อที่ไม่ได้ใช้งานตามที่กำหนดไว้โดยใช้การkeepaliveตั้งค่า


[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-eventsource-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


คุณอธิบายรายละเอียดเกี่ยวกับกลไกการ ping ได้อย่างไร มันเป็นเพียงการผลักดันข้อความว่างเปล่าไปยังช่อง? ฉันได้ตั้งค่าส่วนหัวระดับ nginx และแอป แต่ฉันยังคงได้รับการหมดเวลา 504 จาก nginx สำหรับจุดสิ้นสุดแหล่งที่มาของเหตุการณ์
wgwz

ping จะเป็นข้อมูล (ปลอม) ที่ส่งมาในช่วงเวลาหนึ่งผ่านการเชื่อมต่อบนไคลเอนต์คุณสามารถจัดการ ping นี้และละเว้นมันได้ หมายเหตุ: หากการเชื่อมต่อของคุณใช้งานไม่ได้การส่ง Ping จะไม่ช่วยอะไรผิดปกติ
c4urself

2
ฉันเพิ่มส่วนหัวการตอบสนองตามที่แนะนำและใช้งานได้ ฉันไม่ทำการเปลี่ยนแปลงการกำหนดค่า nginx v1.12 และยังไม่มีปัญหา
Mikkel

1
การเพิ่มX-Accel-Buffering: noส่วนหัวเป็นกุญแจสำคัญสำหรับฉัน แต่ที่สำคัญฉันต้องทำตามที่ @ c4urself เขียนว่า: "เพิ่ม X-Accel-Buffering: ไม่เป็นส่วนหัวการตอบสนองในรหัสเซิร์ฟเวอร์แอปพลิเคชันของคุณ " การเพิ่มส่วนหัวนี้ไปยังส่วนสถานที่ตั้งในการตั้งค่า nginx ของฉันไม่ทำงาน - สตรีมเหตุการณ์ทั้งหมดรอที่จะส่งจนกระทั่งหลังจากแอปพลิเคชันเสร็จสิ้น / สิ้นสุดลง
MDMower

คือproxy_http_version 1.1; จำเป็น? ฉันพยายามเรียกใช้สตรีม SSE มากกว่า 6 รายการจากเบราว์เซอร์และด้วยเหตุนี้ฉันจึงต้องการ HTTP2
Bilal Fazlani
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.