Tìm hiểu Rack Apps và Middleware trong ROR

Tram Ho

Nhiều nhà phát triển web làm việc ở mức độ trừu tượng cao nhất khi chúng tôi lập trình. Và đôi khi thật dễ dàng coi mọi thứ là điều hiển nhiên. Đặc biệt là khi chúng tôi đang sử dụng Rails.

Bạn đã bao giờ tìm hiểu sâu về cách thức hoạt động của chu trình yêu cầu / phản hồi trong Rails chưa? Gần đây tôi nhận ra rằng tôi hầu như không biết gì về cách thức hoạt động của ứng dụng Rack hoặc phần mềm trung gian — vì vậy tôi đã dành một ít thời gian để tìm hiểu. Dưới đây là những phát hiện của tôi.

Rack là gì?

Bạn có biết rằng Rails là một ứng dụng Rack? Sinatra cũng vậy. Rack là gì? Tôi rất vui vì bạn đã hỏi. Rack là một gói Ruby cung cấp giao diện dễ sử dụng giữa máy chủ web và framework web.

Có thể nhanh chóng tạo các ứng dụng web đơn giản chỉ bằng Rack.

Để bắt đầu, bạn cần một đối tượng phản hồi khi có một lời gọi, sử dụng Environment Hash và trả về một mảng có mã HTTP response code, headerresponse body . Khi bạn đã viết mã máy chủ, tất cả những gì bạn phải làm là khởi động nó bằng máy chủ Ruby chẳng hạn như Rack::Handler::WEBrick hoặc đặt nó vào tệp config.ru và chạy nó từ dòng lệnh với rackup config.ru.

Ok, tuyệt. Nhưng Rack thực sự làm gì?

Rack hoạt động như thế nào?

Rack thực sự chỉ là một cách để nhà phát triển tạo ứng dụng máy chủ trong khi tránh mã soạn sẵn để hỗ trợ các máy chủ web Ruby khác nhau. Nếu bạn đã viết một số mã đáp ứng các thông số kỹ thuật của Rack, bạn có thể tải nó lên máy chủ Ruby như WEBrick, Mongrel hoặc Thin — và bạn sẽ sẵn sàng chấp nhận các yêu cầu và phản hồi chúng.

Có một số phương pháp bạn nên biết được cung cấp cho bạn. Bạn có thể gọi chúng trực tiếp từ trong tệp config.ru của mình.

run

Lấy một ứng dụng — đối tượng phản hồi cuộc gọi — làm đối số. Đoạn mã sau đây từ trang web Rack cho thấy cách này:

map

Lấy một chuỗi chỉ định đường dẫn cần xử lý và một khối chứa mã ứng dụng Rack sẽ được chạy khi nhận được yêu cầu với đường dẫn đó.

Đây là một ví dụ:

use

Điều này cho biết Rack sử dụng một số phần mềm trung gian nhất định.

Vì vậy, những gì khác bạn cần biết? Hãy xem xét kỹ hơn hàm băm môi trường và mảng phản hồi.

Environment Hash

Các đối tượng máy chủ Rack nhận trong một môi trường băm. Có gì trong hàm băm đó? Dưới đây là một số phần thú vị hơn:

  • REQUEST_METHOD: Động từ HTTP của yêu cầu. Điều này là bắt buộc.

  • PATH_INFO: Đường dẫn URL yêu cầu, liên quan đến thư mục gốc của ứng dụng.

  • QUERY_STRING: Bất cứ điều gì tiếp theo? trong chuỗi URL yêu cầu.

  • SERVER_NAMESERVER_PORT: Địa chỉ và cổng của máy chủ.

  • rack.version: Phiên bản rack đang được sử dụng.

  • rack.url_scheme: Đó là http hay https?

  • rack.input: Một đối tượng giống IO chứa dữ liệu HTTP POST thô.

  • rack.errors: Một đối tượng phản hồi để đặt, viết và xả.

  • rack.session: Kho giá trị khóa để lưu trữ dữ liệu phiên yêu cầu.

  • rack.logger: Một đối tượng có thể ghi các giao diện. Nó phải triển khai các phương thức thông tin, gỡ lỗi, cảnh báo, lỗi và nghiêm trọng.

Rất nhiều khung công tác được xây dựng trên Rack bọc env hash trong một đối tượng Rack::Request. Đối tượng này cung cấp rất nhiều phương thức tiện lợi. Ví dụ: request_method, query_string, session và logger trả về các giá trị từ các khóa được mô tả ở trên. Nó cũng cho phép bạn kiểm tra những thứ như tham số, lược đồ HTTP hoặc nếu bạn đang sử dụng ssl.

Response

Khi đối tượng máy chủ Rack của bạn trả về một phản hồi, nó phải chứa ba phần:

  • Status
  • Header
  • Body

Giống như request, có một đối tượng Rack :: Response cung cấp cho bạn các phương thức tiện lợi như write, set_cookie và finish. Ngoài ra, bạn có thể trả về một mảng chứa ba thành phần.

Status

HTTP Status giống như 200 hay 400

Header

Một cái gì đó đáp ứng với mỗi và tạo ra các cặp khóa-giá trị. Các khóa phải là chuỗi và tuân theo đặc điểm kỹ thuật mã thông báo RFC7230. Đây là nơi bạn có thể đặt Content-TypeContent-Length nếu phù hợp với câu trả lời của bạn.

Body

Phần thân là dữ liệu mà máy chủ gửi lại cho người yêu cầu. Nó phải đáp ứng với từng và giá trị chuỗi mang lại.

Middleware là gì?

Một trong những điều khiến Rack trở nên tuyệt vời là cách dễ dàng thêm các thành phần phần mềm trung gian chuỗi giữa máy chủ web và ứng dụng để tùy chỉnh cách yêu cầu / phản hồi của bạn hoạt động.

Nhưng thành phần phần mềm trung gian là gì?

Một thành phần phần mềm trung gian nằm giữa máy khách và máy chủ, xử lý cả phản hồi gửi đến và gửi đi. Tại sao bạn muốn làm điều đó? Có rất nhiều thành phần phần mềm trung gian có sẵn cho Rack để loại bỏ phỏng đoán khỏi các vấn đề như kích hoạt bộ nhớ đệm, xác thực và bẫy spam.

Sử dụng Middleware trong ứng dụng Rack

Để thêm phần mềm trung gian vào ứng dụng Rack, tất cả những gì bạn phải làm là yêu cầu Rack sử dụng nó. Bạn có thể sử dụng nhiều thành phần phần mềm trung gian và chúng sẽ thay đổi yêu cầu hoặc phản hồi trước khi chuyển nó cho thành phần tiếp theo. Chuỗi thành phần này được gọi là middleware stack.

Warden

Chúng ta sẽ xem xét cách bạn thêm Warden vào một dự án. Warden phải đến sau một số loại phần mềm trung gian phiên trong ngăn xếp, vì vậy chúng tôi cũng sẽ sử dụng Rack::Session::Cookie.

Đầu tiên, thêm nó vào dự án Gemfile của bạn với gem “warden” và cài đặt nó với cài đặt gói.

Bây giờ hãy thêm nó vào tệp config.ru của bạn:

Cuối cùng, run app với rackup. Nó sẽ tìm config.ru và khởi động trên cổng 9292.

Lưu ý rằng có nhiều thiết lập liên quan đến việc để Warden thực sự thực hiện xác thực với ứng dụng của bạn. Đây chỉ là một ví dụ về cách tải nó vào middleware stack. Để xem một ví dụ mạnh mẽ hơn về việc tích hợp Warden, hãy xem ý chính này.

Có một cách khác để xác định middleware stack. Thay vì gọi sử dụng trực tiếp trong config.ru, bạn có thể sử dụng Rack::Builder để bọc một số middleware và (các) ứng dụng trong một ứng dụng lớn.

Ví dụ:

Rack Basic Auth

Một phần mềm trung gian hữu ích là Rack::Auth::Basic, có thể được sử dụng để bảo vệ bất kỳ ứng dụng Rack nào với xác thực cơ bản HTTP. Nó thực sự nhẹ và hữu ích để bảo vệ các bit nhỏ của ứng dụng. Ví dụ: Ryan Bates sử dụng nó để bảo vệ máy chủ Resque trong ứng dụng Rails trong bài viết Railscasts này.

Dưới đây là cách cài đặt:

Sử dụng Middleware trong Rails

Vậy thì sao? Rack là khá tuyệt. Và chúng tôi biết rằng Rails được xây dựng dựa trên nó. Nhưng chỉ vì chúng tôi hiểu nó là gì, nên nó không thực sự hữu ích khi làm việc với một ứng dụng sản xuất.

Cách Rails sử dụng Rack

Bạn đã bao giờ nhận thấy rằng có một tệp config.ru trong thư mục gốc của mọi dự án Rails được tạo chưa? Bạn đã bao giờ nhìn vào bên trong chưa? Đây là những gì nó chứa:

Điều này khá đơn giản. Nó tìm tệp config/environment, sau đó khởi động Rails.application.

Chờ đã, đó là gì? Xem xét config/environment, chúng ta có thể thấy rằng nó được định nghĩa trong config/application.rb. config/environment chỉ là gọi khởi tạo! trên đó.

Vậy có gì trong config / application.rb? Nếu chúng ta để ý, chúng ta sẽ thấy rằng nó tải trong các gem đi kèm từ config/boot.rb, yêu cầu rails/all, tải lên môi trường (development, test, production, v.v.) và xác định phiên bản namespace của ứng dụng của chúng ta .

Nó trông giống như sau:

Điều này có nghĩa là Rails::Application là một ứng dụng Rack. Chắc chắn, nếu chúng ta kiểm tra mã nguồn, nó sẽ phản hồi một lời gọi

Nhưng nó đang sử dụng middleware nào? Nếu quan sát kỹ, chúng tôi thấy nó đang tự động tải rails/application/default_middleware_stack — và kiểm tra, có vẻ như nó đã được định nghĩa trong ActionDispatch.

ActionDispatch đến từ đâu? ActionPack.

Action Dispatch

ActionPack là khuôn khổ của Rails để xử lý các yêu cầu và phản hồi trên web. ActionPack là nơi có khá nhiều tính năng tốt mà bạn tìm thấy trong Rails, chẳng hạn như định tuyến, các bộ điều khiển trừu tượng mà bạn thừa hưởng từ đó và kết xuất chế độ xem.

Phần có liên quan nhất của ActionPack cho cuộc thảo luận của chúng ta ở đây là Action Dispatch. Nó cung cấp một số thành phần phần mềm trung gian xử lý ssl, cookie, gỡ lỗi, tệp tĩnh và nhiều hơn nữa.

Nếu bạn xem xét từng thành phần của phần mềm trung gian ActionDispatch, bạn sẽ nhận thấy tất cả chúng đều tuân theo đặc điểm kỹ thuật của Rack: Tất cả chúng đều phản hồi cuộc gọi, sử dụng ứng dụng và trả về trạng thái, tiêu đề và nội dung. Nhiều người trong số họ cũng sử dụng các đối tượng Rack :: Request và Rack :: Response.

Đọc qua mã trong các thành phần này đã giúp bạn khám phá ra nhiều điều bí ẩn về những gì đang diễn ra đằng sau hậu trường khi đưa ra yêu cầu đối với ứng dụng Rails. Khi tôi nhận ra rằng đó chỉ là một loạt các đối tượng Ruby tuân theo đặc tả Rack — chuyển yêu cầu và phản hồi cho nhau — điều đó đã làm cho toàn bộ phần này của Rails bớt bí ẩn hơn rất nhiều.

Bây giờ chúng ta đã hiểu một chút về những gì đang diễn ra, hãy cùng xem cách thực sự đưa một số phần mềm trung gian tùy chỉnh vào ứng dụng Rails.

Tự thêm Middleware

Hãy tưởng tượng bạn đang lưu trữ một ứng dụng trên Engine Yard. Bạn có một API Rails đang chạy trên một máy chủ và một ứng dụng JavaScript phía máy khách đang chạy trên một máy chủ khác. API có url là https://api.example.com và ứng dụng phía máy khách có tại https://app.example.com.

Bạn sẽ nhanh chóng gặp phải một vấn đề: Bạn không thể truy cập tài nguyên tại api.example.com từ ứng dụng JavaScript của mình do chính sách nguồn gốc giống nhau. Như bạn có thể biết, giải pháp cho vấn đề này là cho phép chia sẻ tài nguyên nguồn gốc chéo (CORS). Có nhiều cách để kích hoạt CORS trên máy chủ của bạn — nhưng một trong những cách dễ nhất là sử dụng gem phần mềm trung gian Rack :: Cors.

Bắt đầu bằng cách yêu cầu nó trong Gemfile:

Cũng như nhiều thứ khác, Rails cung cấp một cách rất dễ dàng để tải phần mềm trung gian. Mặc dù chắc chắn chúng ta có thể thêm nó vào khối Rack :: Builder trong config.ru — như chúng ta đã làm ở trên — quy ước của Rails là đặt nó trong config / application.rb, sử dụng cú pháp sau:

Lưu ý rằng chúng tôi đang sử dụng insert_before ở đây để đảm bảo rằng Rack :: Cors đến trước phần còn lại của phần mềm trung gian được ActionPack đưa vào ngăn xếp (và bất kỳ phần mềm trung gian nào khác mà bạn có thể đang sử dụng).

Nếu bạn khởi động lại máy chủ, bạn nên bắt đầu! Ứng dụng phía máy khách của bạn có thể truy cập api.example.com mà không gặp phải lỗi JavaScript chính sách nguồn gốc.

Kết luận

Trong bài đăng này, chúng ta sẽ xem xét sâu về cách hoạt động của Rack và vòng lặp request/response cho một số framework web Ruby, bao gồm cả Ruby on Rails.

Tôi hy vọng rằng việc hiểu kỹ hơn quá trình một yêu cầu truy cập vào máy chủ của bạn và ứng dụng của bạn gửi lại phản hồi sẽ giúp mọi thứ trở nên rõ ràng. Và khi gặp vấn đề gì đó magic, chúng ta có thể dễ dàng phán đoán ra thông qua cách hoạt động của Rack.

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo