Explorer le rack

Si vous êtes un programmeur Ruby ayant fait tout type de développement Web, vous avez certainement utilisé Rack, que vous le sachiez ou non, car c'est la base sur laquelle la plupart des frameworks Web Ruby (Rails, Sinatra, etc.) sont construits. sur. Explorons certains des concepts de base de Rack et construisons même une petite application ou deux..


Qu'est-ce que Rack, exactement?

Rack est plusieurs choses, en fait:

  • une interface de serveur web
  • un protocole pour la construction et la composition d'applications Web
  • une collection d'utilitaires middleware

Une interface de serveur Web

L’un des avantages de Rack est qu’il offre aux applications Ruby un moyen normalisé de communiquer avec les serveurs Web, d’en extraire le contenu du serveur (écoute sur un port, acceptation de connexions, analyse de requêtes et de réponses HTTP, etc.) afin que vous puissiez: se concentrer sur ce que fait votre application.


Le protocole

Le protocole Rack est très simple: une application Rack est simplement un objet Ruby avec une appel méthode. Cette méthode doit accepter un hachage d'environnement décrivant la demande entrante et renvoyer un tableau à trois éléments sous la forme: [statut, en-têtes, corps], où:

  • statut est le code de statut HTTP.
  • en-têtes est un hachage d'en-têtes HTTP pour la réponse.
  • corps est le corps réel de la réponse (par exemple, le code HTML que vous voulez utiliser)
    afficher). Le corps doit également répondre à chaque.

Le moyen le plus simple de comprendre le protocole de Rack consiste à examiner un code.

Tout d’abord, récupérez le joyau du rack et configurez un répertoire:

 $ gem installer rack $ mkdir hellorack $ cd hellorack

Maintenant, créez un fichier nommé config.ru et remplissez-le avec le texte suivant:

 class Hello Hello def self.call (env) [200, # 200 indique le succès "Content-Type" => "text / plain", # le hachage des en-têtes ["Hello from Rack!"] # nous enveloppons le corps dans un tableau pour qu'il réponde à «chacun»] end end # Dire à Rack quoi exécuter notre application

Enregistrez le fichier, ouvrez votre terminal et lancez le rackup commander:

 $ rackup [2012-12-21 17:48:38] INFO WEBrick 1.3.1 [2012-12-21 17:48:38] INFO ruby ​​1.9.2 (2011-07-09) [x86_64-darwin11.0.1] [2012-12-21 17:48:38] INFO WEBrick :: HTTPServer # start: pid = 1597 port = 9292

Les dernières lignes de sortie, dans le code ci-dessus, vous indiquent que Rack exécute votre application sur le port 9292 à l'aide du serveur Web WEBrick intégré. Pointez votre navigateur sur http: // localhost: 9292 pour voir un message de bienvenue de Rack.

Tuez l'application (ctrl-c) et parlons de ce qui se passe ici.

Lorsque vous exécutez le rackup commande, Rack cherche un rackup fichier de configuration (conventionnellement nommé config.ru, mais vous pouvez le nommer comme vous voulez). Il démarre ensuite un serveur Web (WEBrick par défaut) et exécute votre application..

Ce protocole est la base sur laquelle sont construits des frameworks populaires tels que Rails et Sinatra. Ce qu'ils font, c'est une fonctionnalité de couche comme le rendu des modèles, la répartition des itinéraires, la gestion des connexions à la base de données, la négociation de contenu, etc. au-dessus de cette abstraction fondamentale.

Comment c'est ce qui nous amène au concept de middleware.


Middleware

Le middleware vous permet de composer des applications Rack ensemble.

Un middleware (oui, au singulier et au pluriel) est simplement une application Rack qui est initialisée avec une autre application Rack. Vous pouvez définir différents middleware pour effectuer différents travaux, puis les empiler pour réaliser des tâches utiles..

Par exemple, si vous avez une application Rails qui traîne (vous le faites probablement, si vous êtes un développeur Ruby), vous pouvez CD dans l'application et exécutez la commande rake middleware pour voir quel middleware Rails utilise:

 $ cd le middleware $ rake my-rails-app utilise ActionDispatch :: utilisation statique Rack :: lock use # use Rack :: Runtime utilise Rack :: MethodOverride utilise ActionDispatch :: RequestId utilise Rails :: Rack :: Logger utilise ActionDispatch :: ShowExceptions utilise ActionDispatch :: DebugExceptions utilise ActionDispatch :: RemoteIp utilise ActionDispatch :: Reloader utilise ActionDispatch :: Callbacks utilise ActiveRecord :: ConnectionAdapters :: ConnectionManagement utilise ActiveRecord :: QueryCache utilise ActionDispatch :: Cookies utilise ActionDispatch :: Session :: CookieStore utilise ActionDispatch :: Flash utilise ActionDispatch :: ParamsParser utilise ActionDispatch :: Head utilise Rack :: ConditionalGet utilise Rack :: ETag use ActionDispatch :: BestStandardsSupport exécuter MyRailsApp :: Application.routes

Chaque demande qui arrive dans cette application commence en haut de cette pile, bouillonne, frappe le routeur en bas, qui est envoyé à un contrôleur générant une sorte de réponse (généralement du HTML), qui rebondit ensuite. dans la pile avant d'être renvoyé au navigateur.


Un exemple de middleware

Rien ne permet de comprendre un nouveau concept comme le codage. Construisons donc un middleware très simple qui convertit simplement le corps de la réponse en majuscule. Ouvrez notre config.ru fichier d'avant et ajoutez ce qui suit:

 class ToUpper # Notre classe sera initialisée avec une autre application Rack def initialize (app) @app = app end def call (env) # Appelez tout d'abord '@app' status, headers, body = @ app.call (env) # Iterate à travers le corps, en augmentant chaque morceau upcased_body = body.map | chunk | chunk.upcase # Transférer notre nouveau corps dans [status, en-têtes, upcased_body] end end # Ceci est la même application que celle d’avant, juste sans tous les commentaires de la classe. Hello def self.call (env) [200, "Content -Type "=>" text / plain ", [" Hello from Rack! "]] End end utilise ToUpper # Tell Rack pour utiliser notre middleware nouvellement créé, Hello.

Exécuter le rackup Commande à nouveau et visite http: // localhost: 9292 pour voir notre nouveau middleware en action.

Ce que Rack a fait ici a été de construire une application Rack qui était la composition du ToUpper et Bonjour applications. Interne à Rack, il y a un Constructeur classe qui a effectivement construit une nouvelle application en faisant l'équivalent de:

 app = ToUpper.new (Hello) lance l'application

S'il y avait plus de middleware présent (comme dans la pile Rails), il les imbriquerait complètement:

 utiliser Middleware1 utiliser Middleware2 utiliser Middleware3 exécuter MyApp # => Se résume à Middleware1.new (Middleware2.new (Middleware3.new (MyApp)))

Classes de demande et de réponse

Lorsque vous commencez à écrire des applications et des middlewares Rack, manipulez le [statut, en-têtes, corps] le tableau devient vite fastidieux.

Rack fournit quelques cours pratiques, Rack :: Demande et Rack :: Réponse, rendre la vie un peu plus facile.

Rack :: Demande enveloppe un env hash et vous fournit des méthodes pratiques pour extraire les informations dont vous pourriez avoir besoin:

 def call (env) req = Rack :: Request.new (env) req.request_method # => GET, POST, PUT, etc. req.get? # est-ce une requestion GET req.path_info # le chemin de cette requête est entré sur req.session # accès à l'objet de session, si vous utilisez le # Rack :: Session middleware req.params # un hachage de paramètres GET et POST fusionnés, utile pour # extraire des valeurs d'une chaîne de requête #… et bien d'autres encore

Rack :: Réponse est complémentaire à Rack :: Demande, et vous donne un moyen plus pratique de construire une réponse. Par exemple, notre Bonjour L'application peut être réécrite comme suit:

 class Bonjour Hello de self.call (env) res = Rack :: Response.new # Ceci définira automatiquement l'en-tête Content-Length pour vous. res.write "Hello from Rack!" # renvoie le tableau standard [status, en-têtes, corps] res.finish # Vous pouvez obtenir / définir les en-têtes avec la syntaxe entre crochets: # res ["Content-Type"] = "text / plain" # Vous pouvez définir et supprimer les cookies # res.set_cookie ("user_id", 1) # res.delete_cookie ("user_id") end end

Conclusion

Dans cet article, nous avons abordé les concepts de base de Rack, qui devraient vous permettre de mieux comprendre ce qui se cache sous les nombreux cadres populaires et de vous aider à vous mouiller les pieds si vous êtes intéressé. en développant directement avec Rack.

Code est un excellent professeur, donc si Rack vous intéresse, je vous recommande vivement de regarder sa source. Il contient de nombreux utilitaires et intergiciels très utiles (et bien d’autres chez rack-contrib) que vous pouvez utiliser et apprendre de.