Computer >> Máy Tính >  >> Lập trình >> Ruby

Cách truyền tiêu đề HTTP từ nginx sang ứng dụng Ruby của bạn

Ngày nay hầu như tất cả việc phát triển web đều được thực hiện với các khuôn khổ. Cho dù bạn sử dụng rails, Sinatra hay Lotus, bạn không thực sự phải nghĩ về cách cookie và các tiêu đề khác truyền từ nginx hoặc apache, đến máy chủ ứng dụng và vào ứng dụng của bạn. Họ chỉ làm.

Chúng ta sẽ xem xét hành trình này sâu hơn một chút. Bởi vì nó chỉ ra rằng câu chuyện về tiêu đề chứa rất nhiều thông tin thú vị về lịch sử của web.

Tiêu đề HTTP là gì?

Bất cứ khi nào trình duyệt web tạo một văn bản yêu cầu, nó sẽ gửi những thứ này được gọi là tiêu đề HTTP. Chúng chứa cookie, thông tin về tác nhân người dùng, thông tin bộ nhớ đệm - rất nhiều thứ thực sự hữu ích.

Bạn có thể xem những tiêu đề nào đang được gửi bằng cách xem một yêu cầu trong các công cụ phát triển của trình duyệt của bạn. Đây là một ví dụ. Như bạn có thể thấy, các tiêu đề không phải là bất cứ điều gì kỳ diệu. Chúng chỉ là văn bản được định dạng theo một cách nhất định.

Cách truyền tiêu đề HTTP từ nginx sang ứng dụng Ruby của bạn

Cách tiêu đề không được chuyển đến ứng dụng của bạn

Nếu bạn đã từng viết một ứng dụng rack, chắc hẳn bạn đã thấy env hàm băm, chứa các biến môi trường của ứng dụng. Nếu bạn nhìn vào bên trong nó, bạn sẽ thấy rằng ngoài các biến môi trường hệ thống thông thường, nó cũng chứa tất cả các tiêu đề yêu cầu.

# 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", ... }

Đây không cách nginx chuyển tiêu đề đến ứng dụng của bạn. :)

Máy chủ ứng dụng

Ngày nay, hầu hết các ứng dụng web Ruby đều chạy trong các máy chủ ứng dụng như Unicorn. Vì các máy chủ ứng dụng không được tạo ra bởi nginx, nên nginx không thể đặt các biến môi trường của chúng.

Sau đó, làm thế nào để các tiêu đề di chuyển từ nginx sang unicorn? Giản dị. Khi nginx chuyển tiếp yêu cầu đến máy chủ ứng dụng, nó sẽ gửi toàn bộ yêu cầu - tiêu đề và tất cả.

Để chứng minh điều này, tôi đã xây dựng một máy chủ ứng dụng đơn giản để kết xuất mọi thứ mà nginx gửi đến 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

Nếu bạn định cấu hình nginx để kết nối với máy chủ này thay vì Unicorn, bạn sẽ thấy chính xác thông tin nào đang được gửi đến máy chủ ứng dụng:chỉ là một yêu cầu HTTP bình thường. Tiêu đề và tất cả.

Cách truyền tiêu đề HTTP từ nginx sang ứng dụng Ruby của bạn

Để biết thêm thông tin về cách viết một máy chủ ứng dụng ngược dòng đơn giản, hãy xem bài đăng của tôi trên ổ cắm unix.

Tại sao lại quan tâm đến các biến môi trường?

Năm 1993, NSCA đã công bố một thông số kỹ thuật cho một thứ gọi là "Giao diện cổng chung" hay viết tắt là CGI.

Cách truyền tiêu đề HTTP từ nginx sang ứng dụng Ruby của bạn

Đó là một cách để các máy chủ như Apache chạy các chương trình tùy ý trên đĩa để tạo các trang web động. Một người dùng sẽ yêu cầu một trang và Apache thực sự sẽ tách ra và chạy một chương trình để tạo ra kết quả. Vì Apache tạo ra các ứng dụng trực tiếp nên nó có thể đặt các biến môi trường của chúng.

Tiêu chuẩn CGI chỉ định rằng tiêu đề HTTP được chuyển vào dưới dạng các biến môi trường. Và để tránh mọi va chạm đặt tên với các biến môi trường hiện có, nó chỉ định rằng "HTTP_" nên được thêm vào trước tên.

Vì vậy, bạn kết thúc với một loạt các biến môi trường giống như sau:

 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"

Ngày nay hầu như không ai sử dụng CGI để phát triển mới, nhưng vẫn rất phổ biến khi thấy các tiêu đề HTTP được lưu trữ dưới dạng các biến môi trường - mặc dù đôi khi chúng là các biến môi trường giả mạo.

Cách máy chủ ứng dụng giả mạo nó

Máy chủ ứng dụng phân tích cú pháp các tiêu đề ra khỏi yêu cầu HTTP thô. Vậy làm thế nào để chúng có được trong môi trường? Chà, máy chủ ứng dụng đặt chúng ở đó.

Tôi tìm hiểu một chút trong webrick và có thể tìm thấy khẩu súng hút thuốc:


      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
      }

Cuối cùng, các biến môi trường "giả" này được hợp nhất với các biến môi trường thực khác và được chuyển vào ứng dụng rack của bạn và chuyển đến Rails, đưa chúng trở lại hàm băm môi trường. :)