Nginx ลบส่วนหัวความยาวเนื้อหาสำหรับเนื้อหาที่มีการแยก


10

ฉันใช้ nginx 1.2.3 เพื่อ proxy ไปยังสคริปต์:

proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8880;
proxy_buffering off;
proxy_read_timeout 300s;
gzip off;

สคริปต์ส่งทั้งสองTransfer-encoding: chunkedและContent-Length: 251:

HTTP/1.0 307 Temporary Redirect
Content-length: 251
Pragma: no-cache
Location: /...
Cache-control: no-cache
Transfer-encoding: chunked

ฉันต้องการทั้งสองอย่าง แต่ nginx ลบโดยอัตโนมัติContent-Length:

HTTP/1.1 302 Found
Server: nginx/1.2.3
Content-Type: application/json; charset=utf-8
Content-Length: 58
Connection: keep-alive
Location: /...

เป็นผลให้ลูกค้าไม่รอให้ชิ้นที่จะส่ง สิ่งนี้เคยทำงานกับ nginx รุ่นก่อนหน้า


ส่วนหัวมีลักษณะอย่างไรจากพร็อกซี nginx
วิ่งเหยาะ

เวอร์ชันใดที่เคยใช้กับ
cnst

มันเคยทำงานกับ nginx 0.9.8
Julien

คุณกำลังละเมิดโปรโตคอล HTTP มันทำงานได้กับ nginx 0.9.8 เพราะจนถึงเวอร์ชั่น 1.1.4 มันไม่รองรับการเข้ารหัสแบบ chunked เลย
VBart

คำตอบ:


11

น่าเสียดายที่ฉันไม่สามารถแสดงความคิดเห็นในโพสต์ของ cnst ดังนั้นฉันจะตอบที่นี่

nginx_http_proxyโมดูลโดยการเจรจาเริ่มต้นกับต้นน้ำใน HTTP / 1.0 proxy_http_version 1.1นี้สามารถเปลี่ยนแปลงได้ด้วยคำสั่ง

นี่อาจเป็นสาเหตุให้สคริปต์ของคุณส่งคืนคำตอบ HTTP / 1.0 แม้ว่าจะไม่มีการเข้ารหัสและรหัสสถานะ307ในเวอร์ชันนี้

คุณไม่ควรใช้การเข้ารหัสแบบ chunked ด้วยการเปลี่ยนเส้นทางเช่นนี้เพราะมันไม่สมเหตุสมผล

นอกจากนี้ดูเหมือนว่า nginx จะไม่ส่งชิ้นข้อมูลจากอัปสตรีมไปยังไคลเอนต์ทีละรายการ แต่จะบัฟเฟอร์การตอบสนองของอัปสตรีContent-Lengthฟิลด์ส่วนหัวจะถูกละเว้นเพราะมันผิดความหมาย ฉันต้องดูซอร์สโค้ดของโมดูลเพราะทั้งหมดนี้ดูเหมือนว่าจะไม่มีเอกสาร

คุณอาจต้องการลองใช้งานnginx_tcp_proxy_moduleพร็อกซีเนื้อหาที่มีการเชื่อมโยงเป็นข้อมูลดิบ TCP: โมดูลที่ Github


UPDATE (10.04.14) โมดูลมีการสนับสนุนส่วนหัวซึ่งหนึ่ง ( ) ควบคุมว่าการตอบสนองที่ควรจะบัฟเฟอร์หรือไม่
nginx_http_proxyX-Accel-* X-Accel-Buffering: yes|no

การเพิ่มส่วนหัวนี้ ( X-Accel-Buffering: no) ลงในการตอบสนองของแบ็กเอนด์จะทำให้ nginx ส่งชิ้นข้อมูลไปยังลูกค้าโดยตรง

หัวข้อนี้จะช่วยให้การควบคุมบัฟเฟอร์บนพื้นฐานต่อการร้องขอ

โมดูลนี้ยังมีคำสั่งกำหนดค่า proxy_bufferingเพื่อเปิดใช้งานหรือปิดใช้งานการบัฟเฟอร์การตอบสนอง (ไม่บัฟเฟอร์หมายถึงการส่งชิ้นงานจะทำงาน)

บัฟเฟอร์พร็อกซี (ทั้งหัวและสั่ง based) เป็นเอกสารที่นี่


nginx_tcp_proxy_moduleเขาไม่ควรทำอย่างนั้นแม้จะมี ใช้งานได้กับเบราว์เซอร์บางตัวเท่านั้นเพราะทนต่อข้อผิดพลาดได้มาก
VBart

เพราะทั้งหมดนี้ดูเหมือนจะไม่ถูกต้องผิด เป็นเอกสารใน RFC 2616. See 13.5.1
VBart

@VBart แน่ใจว่ามีมาตรฐาน - แต่มีเพียงข้อมูลน้อยมากเกี่ยวกับวิธีการห่างไกลโดยเฉพาะอย่างยิ่งNginxดำเนิน them.The TCP โมดูลพร็อกซี่คือ Hust ได้รับการแนะนำวิธีแก้ปัญหา
Lukas

9

ในฐานะที่เป็น Lukas จะทำให้ HTTP 1.1 ห้ามContent-LengthหากมีTransfer-Encodingชุด

การอ้างอิงhttp://www.ietf.org/rfc/rfc2616.txt :

   3.If a Content-Length header field (section 14.13) is present, its
     decimal value in OCTETs represents both the entity-length and the
     transfer-length. The Content-Length header field MUST NOT be sent
     if these two lengths are different (i.e., if a Transfer-Encoding
     header field is present). If a message is received with both a
     Transfer-Encoding header field and a Content-Length header field,
     the latter MUST be ignored.

นอกจากนี้พฤติกรรมที่ถูกต้องของ Nginx ที่สอดคล้องกับ HTTP 1.1 จะช่วยป้องกันการโจมตีการลักลอบขนย้าย HTTP
AMN

3

คุณยังไม่ได้ระบุรายละเอียดโดยเฉพาะว่าทำไมสคริปต์ของคุณต้องมีการเข้ารหัสแบบเรียงลำดับตั้งแต่แรกโดยเฉพาะอย่างยิ่งเมื่อมีการตอบกลับการเปลี่ยนเส้นทาง

ฉันเห็นปัญหามากมายที่นี่

  • Transfer-Encoding: chunkedเป็นHTTP/1.1คุณสมบัติ (และสคริปต์ของคุณดูเหมือนจะตอบกลับด้วยHTTP/1.0ส่วนหัว)

  • ไม่มี307ในHTTP/1.0

  • วัตถุประสงค์ทั้งหมดของการchunkedที่คุณไม่ทราบว่าสิ่งที่คุณContent-Lengthจะได้รับchunkedจะถูกนำมาใช้แทนการให้ความยาวภายในContent-Lengthซึ่งแทนที่จะให้ความยาวภายในร่างกายของการตอบสนองที่ผสมกับเนื้อหาจริง; มันจะไม่มีจุดหมายสำหรับสคริปต์ที่จะสร้างทั้งสองส่วนหัวล่วงหน้า

ฉันไม่คุ้นเคยเป็นการส่วนตัวchunkedแต่เป็นข้อมูลพื้นฐานที่http://en.wikipedia.org/wiki/Chunked_transfer_encodingและhttp://tools.ietf.org/html/rfc2616#section-3.6.1 , ฉันเดาว่าการจัดการการเข้ารหัสทั้งหมดของสคริปต์ของคุณอาจผิดทั้งหมด

หากสิ่งที่กล่าวมาข้างต้นยังไม่ครอบคลุมและในความเป็นจริงทั้งหมดมันก็ไม่ชัดเจนว่าทำไมการตอบกลับด้วย307หรือ302รหัสสถานะ HTTP ควรมีการเข้ารหัส "แปลก" เมื่อเร็ว ๆ นี้มีการอภิปรายที่คล้ายกันในรายการส่งเมล nginx เกี่ยวกับ410 Goneและหน้าข้อผิดพลาดอื่น ๆ จะถูกแยกออกจากการgzipบีบอัดเสมอและฉันคิดว่าความเชื่อมั่นจะมีผลเท่ากัน ( http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html )


ฉันใช้เพื่อให้ผู้ใช้รอ: ฉันส่งชิ้นทุกวินาทีเพื่อให้ผู้ใช้จะรอการเปลี่ยนเส้นทางสำหรับ X วินาทีโดยไม่ได้รับการหมดเวลา
Julien

ผมขอแนะนำให้คุณแก้ไข HTTP แรก / 1.0 HTTP / 1.1 (สิ่งเหล่านี้ทำสร้างความแตกต่าง) และให้แน่ใจว่าการเข้ารหัส chunked ของคุณไม่ได้ที่ไม่เหมาะสม เวอร์ชันใหม่กว่าของ nginx อาจทิ้งส่วนหัวบางส่วนที่คุณพึ่งพาเนื่องจากมันผิด
cnst

1

ฉันมีปัญหาเดียวกันกับการสตรีมไฟล์ mp4 ผ่านแท็กวิดีโอ html5

Safari และ Firefox ทำงานได้ตามปกติขณะที่ Chrome เรียกใช้ ERR_CONTENT_LENGTH_MISMATCH ในบางจุด (แต่มันทำให้ฉันสามารถเล่นวิดีโอได้หลายนาทีก่อนที่จะล้มเหลว)

ปัญหาไม่ได้ทำซ้ำหลังจากฉันปิดการควบคุมแคชสำหรับไฟล์ mp4


0

แบ่งปันคำตอบนี้ฉันโพสต์ไปยัง SO ในกรณีที่เป็นประโยชน์: /programming/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

ฉันมีปัญหาที่คล้ายกันกับการเล่น mp4 เนื่องจากไม่ได้รับชิ้นส่วนและยืนยันปัญหาตามคู่มือของ Apple ตามรายการด้านล่าง ฉันตรวจสอบว่าฉันกำลังดาวน์โหลดไฟล์ทั้งหมดและหลังจากการแก้ไขด้านล่างเฉพาะอันแรกเท่านั้น

curl --range 0-99 http://example.com/test.mov -o /dev/null

ฉันแก้ไขการเล่น Safari .mp4 ของฉันโดยเปลี่ยนการตั้งค่าการบีบอัด gzip ใน nginx.conf ของฉันเพื่อลบการบีบอัด gzip ของไฟล์. mp4

นี่คือบล็อกใน nginx สำหรับการอ้างอิง (หมายเหตุ: ขึ้นอยู่กับการกำหนดค่าแอพของคุณคุณอาจต้องเปลี่ยนบรรทัดตำแหน่งเป็นlocation ~ \.mp4$ {

location ~ ^/(assets|system|videos)/  {
   expires max;
   add_header Cache-Control public;
   add_header ETag "";
   gzip on;
   gzip_http_version 1.1;
   gzip_vary on;
   gzip_comp_level 6;
   gzip_proxied any;

   # Reference configuration
   #gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript video/mp4 application/mp4 image/jpeg image/png image/svg+xml application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;

   # Kelton trying to fix cloudflare by removing the mp4 settings
   gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript image/jpeg image/png image/svg+xml application/application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;
}

เชื่อมโยงไปยังเอกสารอ้างอิงของ Apple: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/Perocation

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.