ในปัจจุบัน การพัฒนาเว็บเกือบทุกอย่างทำงานกับเฟรมเวิร์ก ไม่ว่าคุณจะใช้ Rails, Sinatra หรือ Lotus คุณไม่จำเป็นต้องคิดมากเกี่ยวกับวิธีที่คุกกี้และเฮดเดอร์อื่นๆ ผ่านจาก Nginx หรือ Apache ไปยังแอปพลิเคชันเซิร์ฟเวอร์และเข้าไปในแอปของคุณ มันจะทำงานได้เอง
เราจะสำรวจการเดินทางนี้ให้ลึกซึ้งขึ้น เนื่องจากเรื่องราวของเฮดเดอร์มีข้อมูลน่าสนใจมากเกี่ยวกับประวัติศาสตร์ของเว็บ
HTTP Headers คืออะไร?
ทุกครั้งที่เว็บเบราว์เซอร์ส่งคำขอ มันจะส่งสิ่งที่เรียกว่า HTTP Headers พร้อมกัน เฮดเดอร์เหล่านี้มีคุกกี้ ข้อมูลเกี่ยวกับ User Agent ข้อมูลแคช และอีกมากมายที่มีประโยชน์มาก
คุณสามารถดูว่ามีเฮดเดอร์อะไรถูกส่งโดยการดูคำขอในเครื่องมือนักพัฒนาของเบราว์เซอร์ นี่คือตัวอย่าง คุณจะเห็นว่าเฮดเดอร์ไม่ได้มีอะไรลึกลับ มันคือแค่ข้อความที่จัดรูปแบบในลักษณะเฉพาะ

เฮดเดอร์ไม่ได้ถูกส่งไปยังแอปของคุณอย่างไร
ถ้าคุณเคยเขียนแอป 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 ธรรมดา พร้อมเฮดเดอร์และทั้งหมด

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียน upstream app server แบบง่าย ดูโพสต์เกี่ยวกับ Unix sockets ของผม
ทำไมจึงต้องกังวลกับตัวแปรสภาพแวดล้อม?
ในปี 1993 NSCA เผยแพร่สเปกสำหรับสิ่งที่เรียกว่า "Common Gateway Interface" หรือ CGI สำหรับเรียกสั้นๆ

มันเป็นวิธีสำหรับเซิร์ฟเวอร์อย่าง 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 ซึ่งนำมันกลับออกมาจากแฮชสภาพแวดล้อมอีกครั้ง :)