ทุกวันนี้การพัฒนาเว็บเกือบทั้งหมดทำด้วยเฟรมเวิร์ก ไม่ว่าคุณจะใช้ Rails, Sinatra หรือ Lotus คุณไม่จำเป็นต้องคิดว่าคุกกี้และส่วนหัวอื่นๆ ส่งผ่านจาก nginx หรือ apache ไปยังแอปพลิเคชันเซิร์ฟเวอร์และในแอปของคุณอย่างไร ก็แค่นั้นแหละ
เราจะตรวจสอบการเดินทางนี้ในเชิงลึกอีกเล็กน้อย เพราะปรากฎว่าเรื่องของ headers มีข้อมูลที่น่าสนใจมากมายเกี่ยวกับประวัติของเว็บ
ส่วนหัว HTTP คืออะไร
เมื่อใดก็ตามที่เว็บเบราว์เซอร์สร้างคำขอ มันจะส่งสิ่งเหล่านี้ที่เรียกว่าส่วนหัว HTTP ซึ่งประกอบด้วยคุกกี้ ข้อมูลเกี่ยวกับตัวแทนผู้ใช้ ข้อมูลแคช — ข้อมูลที่เป็นประโยชน์มากมาย
คุณสามารถดูส่วนหัวที่ถูกส่งโดยดูที่คำขอในเครื่องมือพัฒนาของเบราว์เซอร์ของคุณ นี่คือตัวอย่าง อย่างที่คุณเห็น ส่วนหัวไม่ได้วิเศษอะไร เป็นเพียงรูปแบบข้อความในลักษณะบางอย่าง
วิธีไม่ส่งส่วนหัวไปยังแอปของคุณ
หากคุณเคยเขียนแอปแร็ค คุณอาจเคยเห็น 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 ปกติ ส่วนหัวและทั้งหมด
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการเขียนเซิร์ฟเวอร์แอปอัปสตรีมอย่างง่าย โปรดดูโพสต์ของฉันบนซ็อกเก็ตยูนิกซ์
ทำไมต้องกังวลกับตัวแปรสภาพแวดล้อมด้วย
ในปี 1993 NSCA ได้เผยแพร่ข้อมูลจำเพาะสำหรับสิ่งที่เรียกว่า "Common Gateway Interface" หรือเรียกสั้นๆ ว่า CGI
เป็นวิธีที่เซิร์ฟเวอร์เช่น 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 ซึ่งจะนำพวกมันกลับออกจากแฮชของสภาพแวดล้อม :)