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

วิธีที่ส่วนหัว HTTP ถูกส่งผ่านจาก nginx ไปยังแอป Ruby ของคุณ

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

เราจะตรวจสอบการเดินทางนี้ในเชิงลึกอีกเล็กน้อย เพราะปรากฎว่าเรื่องของ headers มีข้อมูลที่น่าสนใจมากมายเกี่ยวกับประวัติของเว็บ

ส่วนหัว HTTP คืออะไร

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

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

วิธีที่ส่วนหัว HTTP ถูกส่งผ่านจาก nginx ไปยังแอป Ruby ของคุณ

วิธีไม่ส่งส่วนหัวไปยังแอปของคุณ

หากคุณเคยเขียนแอปแร็ค คุณอาจเคยเห็น 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 ไปยังยูนิคอร์นได้อย่างไร? เรียบง่าย. เมื่อ nginx ส่งต่อคำขอไปยังเซิร์ฟเวอร์แอป จะส่งคำขอทั้งหมด — ส่วนหัวและทั้งหมด

เพื่อแสดงสิ่งนี้ ฉันสร้างแอปพลิเคชันเซิร์ฟเวอร์อย่างง่ายที่จะทิ้งทุกอย่างที่ nginx ส่งไปที่ STDOUT

require "socket"

# Create the socket and "save it" to the file system
server = UNIXServer.new('/tmp/socktest.sock')

# Wait until for a connection (by nginx)
socket = server.accept

# Read everything from the socket
while line = socket.readline
  puts line.inspect
end

socket.close

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

วิธีที่ส่วนหัว HTTP ถูกส่งผ่านจาก nginx ไปยังแอป Ruby ของคุณ

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการเขียนเซิร์ฟเวอร์แอปอัปสตรีมอย่างง่าย โปรดดูโพสต์ของฉันบนซ็อกเก็ตยูนิกซ์

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

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

วิธีที่ส่วนหัว HTTP ถูกส่งผ่านจาก nginx ไปยังแอป Ruby ของคุณ

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

มาตรฐาน CGI ระบุว่าส่วนหัว HTTP ถูกส่งผ่านเป็นตัวแปรสภาพแวดล้อม และเพื่อหลีกเลี่ยงความขัดแย้งในการตั้งชื่อกับตัวแปรสภาพแวดล้อมที่มีอยู่ ตัวแปรดังกล่าวจึงระบุว่าควรเติม "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 ที่จัดเก็บเป็นตัวแปรสภาพแวดล้อม แม้ว่าบางครั้งอาจเป็นตัวแปรสภาพแวดล้อมปลอม

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

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

ฉันขุดเว็บริคเล็กน้อยและพบปืนสูบบุหรี่ได้:


      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
      }

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