Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีที่ Nginx ส่งผ่าน HTTP Headers ไปยังแอป Ruby ของคุณ: คู่มือที่ชัดเจนและมืออาชีพ

ในปัจจุบัน การพัฒนาเว็บเกือบทุกอย่างทำงานกับเฟรมเวิร์ก ไม่ว่าคุณจะใช้ Rails, Sinatra หรือ Lotus คุณไม่จำเป็นต้องคิดมากเกี่ยวกับวิธีที่คุกกี้และเฮดเดอร์อื่นๆ ผ่านจาก Nginx หรือ Apache ไปยังแอปพลิเคชันเซิร์ฟเวอร์และเข้าไปในแอปของคุณ มันจะทำงานได้เอง

เราจะสำรวจการเดินทางนี้ให้ลึกซึ้งขึ้น เนื่องจากเรื่องราวของเฮดเดอร์มีข้อมูลน่าสนใจมากเกี่ยวกับประวัติศาสตร์ของเว็บ

HTTP Headers คืออะไร?

ทุกครั้งที่เว็บเบราว์เซอร์ส่งคำขอ มันจะส่งสิ่งที่เรียกว่า HTTP Headers พร้อมกัน เฮดเดอร์เหล่านี้มีคุกกี้ ข้อมูลเกี่ยวกับ User Agent ข้อมูลแคช และอีกมากมายที่มีประโยชน์มาก

คุณสามารถดูว่ามีเฮดเดอร์อะไรถูกส่งโดยการดูคำขอในเครื่องมือนักพัฒนาของเบราว์เซอร์ นี่คือตัวอย่าง คุณจะเห็นว่าเฮดเดอร์ไม่ได้มีอะไรลึกลับ มันคือแค่ข้อความที่จัดรูปแบบในลักษณะเฉพาะ

วิธีที่ Nginx ส่งผ่าน HTTP Headers ไปยังแอป Ruby ของคุณ: คู่มือที่ชัดเจนและมืออาชีพ

เฮดเดอร์ไม่ได้ถูกส่งไปยังแอปของคุณอย่างไร

ถ้าคุณเคยเขียนแอป Rack คุณอาจเคยเห็นแฮช env ซึ่งมีตัวแปรสภาพแวดล้อมของแอป หากดูภายใน คุณจะเห็นว่านอกจากตัวแปรสภาพแวดล้อมของระบบปกติแล้ว ยังมีเฮดเดอร์คำขอทั้งหมดด้วย

# config.ru
run lambda { |env| [200, {"Content-Type" => "text/plain"}, [env.inspect]] }
# Outputs:
# { "HTTP_HOST"=>"localhost:9000", "HTTP_CONNECTION"=>"keep-alive", "HTTP_PRAGMA"=>"no-cache", "HTTP_CACHE_CONTROL"=>"no-cache", "HTTP_ACCEPT"=>"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "HTTP_UPGRADE_INSECURE_REQUESTS"=>"1", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36", ... }

นี่ไม่ใช่ วิธีที่ Nginx ส่งเฮดเดอร์ไปยังแอปของคุณ :)

แอปพลิเคชันเซิร์ฟเวอร์

ในปัจจุบัน แอปเว็บ Ruby ส่วนใหญ่ทำงานบนแอปพลิเคชันเซิร์ฟเวอร์อย่าง Unicorn เนื่องจากแอปเซิร์ฟเวอร์ไม่ได้ถูกสร้างโดย Nginx ดังนั้น Nginx จึงไม่สามารถตั้งค่าตัวแปรสภาพแวดล้อมของพวกเขาได้

เฮดเดอร์เดินทางจาก Nginx ไปยัง Unicorn อย่างไร? ง่ายมาก เมื่อ Nginx ส่งต่อคำขอไปยังแอปเซิร์ฟเวอร์ มันจะส่งคำขอทั้งหมด — รวมถึงเฮดเดอร์

เพื่อสาธิต这一点 ผมสร้างแอปพลิเคชันเซิร์ฟเวอร์ง่ายๆ ที่ dump ทุกอย่างที่ Nginx ส่งมาไปที่ STDOUT

require "socket"
# สร้าง socket และ "บันทึก" ไว้ในระบบไฟล์
server = UNIXServer.new('/tmp/socktest.sock')
# รอการเชื่อมต่อ (โดย Nginx)
socket = server.accept
# อ่านทุกอย่างจาก socket
while line = socket.readline
  puts line.inspect
end
socket.close

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

วิธีที่ Nginx ส่งผ่าน HTTP Headers ไปยังแอป Ruby ของคุณ: คู่มือที่ชัดเจนและมืออาชีพ

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียน upstream app server แบบง่าย ดูโพสต์เกี่ยวกับ Unix sockets ของผม

ทำไมจึงต้องกังวลกับตัวแปรสภาพแวดล้อม?

ในปี 1993 NSCA เผยแพร่สเปกสำหรับสิ่งที่เรียกว่า "Common Gateway Interface" หรือ CGI สำหรับเรียกสั้นๆ

วิธีที่ Nginx ส่งผ่าน HTTP Headers ไปยังแอป Ruby ของคุณ: คู่มือที่ชัดเจนและมืออาชีพ

มันเป็นวิธีสำหรับเซิร์ฟเวอร์อย่าง Apache ให้รันโปรแกรมอะไรก็ตามบนดิสก์เพื่อสร้างเพจเว็บไดนามิก ผู้ใช้ร้องขอหน้าเว็บ และ Apache จะเรียกใช้โปรแกรมจริงๆ เพื่อสร้างผลลัพธ์ เนื่องจาก Apache สร้างแอปโดยตรง มันจึงสามารถตั้งค่าตัวแปรสภาพแวดล้อมของพวกเขาได้

มาตรฐาน CGI ระบุว่า HTTP headers ควรถูกส่งผ่านเป็นตัวแปรสภาพแวดล้อม และเพื่อหลีกเลี่ยงการชนกันของชื่อกับตัวแปรสภาพแวดล้อมที่มีอยู่ มันระบุว่าควรนำ "HTTP_" ไปต่อหน้าชื่อ

ดังนั้นคุณจะได้ชุดตัวแปรสภาพแวดล้อมที่ดูแบบนี้:

HTTP_ACCEPT="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"
HTTP_ACCEPT_ENCODING="gzip, deflate"
HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"
HTTP_CONNECTION="keep-alive"
HTTP_HOST="example.com"
HTTP_USER_AGENT="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0"

ในปัจจุบัน ไม่ค่อยมีใครใช้ CGI สำหรับการพัฒนาใหม่ แต่ยังคงพบได้บ่อยที่ HTTP headers ถูกเก็บเป็นตัวแปรสภาพแวดล้อม — แม้ว่าบางครั้งจะเป็นตัวแปรสภาพแวดล้อม "ปลอม" ก็ตาม

แอปเซิร์ฟเวอร์ปลอมมันอย่างไร

แอปพลิเคชันเซิร์ฟเวอร์แยกวิเคราะห์เฮดเดอร์ออกจาก raw HTTP request ดังนั้นมันจึงไปอยู่ในสภาพแวดล้อมได้อย่างไร? คำตอบคือ แอปเซิร์ฟเวอร์คือตัวที่วางมันไว้ที่นั่น

ผมขุดโค้ด WEBrick เล็กน้อยและพบ "หลักฐานประการ":

self.each{|key, val|
  next if /^content-type$/i =~ key
  next if /^content-length$/i =~ key
  name = "HTTP_" + key
  name.gsub!(/-/o, "_")
  name.upcase!
  meta[name] = val
}

ในที่สุด ตัวแปรสภาพแวดล้อม "ปลอม" เหล่านี้จะถูกรวมกับตัวแปรสภาพแวดล้อมจริงอื่นๆ และส่งต่อไปยังแอป Rack ของคุณ และต่อไปถึง Rails ซึ่งนำมันกลับออกมาจากแฮชสภาพแวดล้อมอีกครั้ง :)