Was ist Rack-Middleware in Ruby? Ich konnte keine gute Erklärung dafür finden, was sie unter "Middleware" verstehen.
ruby-on-rails
ruby
http
web-applications
rack
chrisgoyal
quelle
quelle
Antworten:
Rack als Design
Rack-Middleware ist mehr als "eine Möglichkeit, eine Anfrage und Antwort zu filtern" - es ist eine Implementierung des Pipeline-Entwurfsmusters für Webserver, die Rack verwenden .
Die verschiedenen Phasen der Bearbeitung einer Anfrage werden sehr sauber voneinander getrennt. Die Trennung von Bedenken ist ein zentrales Ziel aller gut gestalteten Softwareprodukte.
Zum Beispiel kann ich mit Rack separate Phasen der Pipeline ausführen:
Authentifizierung : Sind die Anmeldedaten des Benutzers korrekt, wenn die Anforderung eingeht? Wie überprüfe ich diese OAuth, HTTP Basic Authentication, Name / Passwort?
Autorisierung : " Ist der Benutzer berechtigt, diese bestimmte Aufgabe auszuführen?", Dh rollenbasierte Sicherheit.
Caching : Habe ich diese Anfrage bereits bearbeitet? Kann ich ein zwischengespeichertes Ergebnis zurückgeben?
Dekoration : Wie kann ich die Anfrage verbessern, um die Weiterverarbeitung zu verbessern?
Leistungs- und Nutzungsüberwachung : Welche Statistiken kann ich aus der Anfrage und Antwort erhalten?
Ausführung : Behandeln Sie die Anforderung tatsächlich und geben Sie eine Antwort.
Die Möglichkeit, die verschiedenen Phasen zu trennen (und optional einzuschließen), ist eine große Hilfe bei der Entwicklung gut strukturierter Anwendungen.
Gemeinschaft
Es gibt auch ein großartiges Ökosystem, das sich um Rack Middleware entwickelt - Sie sollten in der Lage sein, vorgefertigte Rack-Komponenten zu finden, um alle oben genannten Schritte und mehr auszuführen. Eine Liste der Middleware finden Sie im Rack GitHub-Wiki .
Was ist Middleware?
Middleware ist ein schrecklicher Begriff, der sich auf jede Softwarekomponente / Bibliothek bezieht, die bei der Ausführung einer Aufgabe hilft, aber nicht direkt daran beteiligt ist. Sehr häufige Beispiele sind Protokollierung, Authentifizierung und die anderen gängigen horizontalen Verarbeitungskomponenten . Dies sind in der Regel die Dinge, die jeder für mehrere Anwendungen benötigt, aber nicht zu viele Menschen sind daran interessiert (oder sollten es sein), sich selbst aufzubauen.
Mehr Informationen
Der Kommentar, dass dies eine Möglichkeit zum Filtern von Anfragen ist, stammt wahrscheinlich aus der RailsCast-Episode 151: Rack Middleware- Bildschirmbesetzung.
Die Rack-Middleware wurde aus dem Rack heraus entwickelt und es gibt ein großartiges Intro unter Einführung in die Rack-Middleware .
Es gibt ein Intro auf Wikipedia über Middleware hier .
quelle
Zunächst einmal ist Rack genau zwei Dinge:
Rack - Die Webserver-Schnittstelle
Die Grundlagen des Racks sind eine einfache Konvention. Jeder Rack-kompatible Webserver ruft immer eine Aufrufmethode für ein Objekt auf, das Sie ihm geben, und liefert das Ergebnis dieser Methode. Rack gibt genau an, wie diese Aufrufmethode aussehen und wie sie zurückgegeben werden muss. Das ist Rack.
Probieren wir es einfach aus. Ich werde WEBrick als Rack-kompatiblen Webserver verwenden, aber jeder von ihnen wird es tun. Erstellen wir eine einfache Webanwendung, die eine JSON-Zeichenfolge zurückgibt. Dazu erstellen wir eine Datei namens config.ru. Die config.ru wird automatisch vom Befehlackup des Rack-Gem aufgerufen, der einfach den Inhalt der config.ru auf einem Rack-kompatiblen Webserver ausführt. Fügen wir der Datei config.ru also Folgendes hinzu:
Wie in der Konvention angegeben, verfügt unser Server über eine Methode namens call, die einen Umgebungs-Hash akzeptiert und ein Array mit der Form [Status, Header, Body] zurückgibt, die der Webserver bedienen soll. Probieren wir es einfach aus, indem wir Rackup anrufen. Ein Standard-Rack-kompatibler Server, möglicherweise WEBrick oder Mongrel, wird gestartet und wartet sofort auf Anfragen.
Testen wir unseren neuen JSON-Server, indem wir entweder die URL
http://localhost:9292/hello.json
und voila locken oder besuchen :Es klappt. Toll! Das ist die Basis für jedes Webframework, sei es Rails oder Sinatra. Irgendwann implementieren sie eine Aufrufmethode, arbeiten den gesamten Framework-Code durch und geben schließlich eine Antwort in der typischen Form [Status, Header, Body] zurück.
In Ruby on Rails zum Beispiel treffen die Rack-Anforderungen die
ActionDispatch::Routing.Mapper
Klasse, die so aussieht:Grundsätzlich prüft Rails, abhängig vom Env-Hash, ob eine Route übereinstimmt. In diesem Fall wird der env-Hash an die Anwendung weitergeleitet, um die Antwort zu berechnen. Andernfalls antwortet er sofort mit einem 404. Jeder Webserver, der der Rack-Schnittstellenkonvention entspricht, kann eine vollständig ausgefüllte Rails-Anwendung bereitstellen.
Middleware
Rack unterstützt auch die Erstellung von Middleware-Schichten. Sie fangen im Grunde eine Anfrage ab, machen etwas damit und geben sie weiter. Dies ist sehr nützlich für vielseitige Aufgaben.
Angenommen, wir möchten unserem JSON-Server eine Protokollierung hinzufügen, die auch misst, wie lange eine Anforderung dauert. Wir können einfach einen Middleware-Logger erstellen, der genau dies tut:
Wenn es erstellt wird, speichert es sich selbst eine Kopie der eigentlichen Rack-Anwendung. In unserem Fall ist dies eine Instanz unseres JSONServers. Rack ruft automatisch die
[status, headers, body]
Aufrufmethode für die Middleware auf und erwartet ein Array zurück, genau wie unser JSONServer zurückgibt.In dieser Middleware wird also der Startpunkt festgelegt, der eigentliche Aufruf des JSONServers erfolgt mit
@app.call(env)
, der Logger gibt den Protokollierungseintrag aus und gibt schließlich die Antwort als zurück[@status, @headers, @body]
.Um unser kleines Rackup.ru dazu zu bringen, diese Middleware zu verwenden, fügen Sie einen RackLogger wie folgt hinzu:
Starten Sie den Server neu und voila, es gibt ein Protokoll bei jeder Anfrage. Mit Rack können Sie mehrere Middlewares hinzufügen, die in der Reihenfolge aufgerufen werden, in der sie hinzugefügt wurden. Es ist einfach eine großartige Möglichkeit, Funktionen hinzuzufügen, ohne den Kern der Rack-Anwendung zu ändern.
Rack - Der Edelstein
Obwohl Rack - vor allem - eine Konvention ist, ist es auch ein Juwel, das großartige Funktionalität bietet. Eine davon haben wir bereits für unseren JSON-Server verwendet, den Befehl rampup. Aber es gibt noch mehr! Das Rack-Juwel bietet kleine Anwendungen für viele Anwendungsfälle, z. B. das Bereitstellen statischer Dateien oder sogar ganzer Verzeichnisse. Mal sehen, wie wir eine einfache Datei bereitstellen, zum Beispiel eine sehr einfache HTML-Datei unter htmls / index.html:
Wir möchten diese Datei möglicherweise über das Website-Stammverzeichnis bereitstellen. Fügen Sie daher Folgendes zu unserer config.ru hinzu:
Wenn wir besuchen
http://localhost:9292
, sehen wir unsere HTML-Datei perfekt gerendert. Das war einfach, oder?Fügen wir ein ganzes Verzeichnis von Javascript-Dateien hinzu, indem wir einige Javascript-Dateien unter / javascripts erstellen und der config.ru Folgendes hinzufügen:
Starten Sie den Server neu und besuchen
http://localhost:9292/javascript
Sie und Sie sehen eine Liste aller Javascript-Dateien, die Sie jetzt direkt von überall einschließen können.quelle
Ich hatte ein Problem damit, Rack selbst für eine gute Zeit zu verstehen. Ich habe es erst vollständig verstanden, nachdem ich daran gearbeitet habe, diesen Miniatur-Ruby-Webserver selbst herzustellen. Ich habe meine Erkenntnisse über Rack (in Form einer Geschichte) hier in meinem Blog geteilt: http://gauravchande.com/what-is-rack-in-ruby-rails
Feedback ist mehr als willkommen.
quelle
config.ru
minimales lauffähiges BeispielLaufen
rackup
und besuchenlocalhost:9292
. Die Ausgabe ist:Es ist also klar, dass
Middleware
die Haupt-App umbrochen und aufgerufen wird. Daher kann es die Anforderung vorverarbeiten und die Antwort auf irgendeine Weise nachbearbeiten.Wie unter http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack erläutert , verwendet Rails Rack-Middleware für einen Großteil seiner Funktionalität, und Sie können auch eigene mit
config.middleware.use
Familienmethoden hinzufügen .Der Vorteil der Implementierung von Funktionen in einer Middleware besteht darin, dass Sie sie in jedem Rack-Framework wiederverwenden können, also in allen wichtigen Ruby-Frameworks und nicht nur in Rails.
quelle
Mit der Rack-Middleware können Sie eine Anfrage und Antwort filtern, die in Ihre Anwendung eingehen. Eine Middleware-Komponente befindet sich zwischen dem Client und dem Server und verarbeitet eingehende Anforderungen und ausgehende Antworten. Sie ist jedoch mehr als nur eine Schnittstelle, über die mit dem Webserver kommuniziert werden kann. Es wird verwendet, um Module, die normalerweise Ruby-Klassen sind, zu gruppieren und zu ordnen und die Abhängigkeit zwischen ihnen anzugeben. Das Rack-Middleware-Modul darf nur: - über einen Konstruktor verfügen, der die nächste Anwendung im Stapel als Parameter verwendet - auf die Aufrufmethode reagieren, die den Umgebungs-Hash als Parameter verwendet. Der von diesem Aufruf zurückgegebene Wert besteht aus folgenden Elementen: Statuscode, Umgebungs-Hash und Antworttext.
quelle
Ich habe Rack-Middleware verwendet, um einige Probleme zu lösen:
In beiden Fällen wurden ziemlich elegante Korrekturen vorgenommen.
quelle
Was ist Rack?
Rack bietet eine minimale Schnittstelle zwischen Webservern, die Ruby- und Ruby-Frameworks unterstützen.
Mit Rack können Sie eine Rack-Anwendung schreiben.
Rack übergibt den Umgebungs-Hash (einen Hash, der in einer HTTP-Anforderung eines Clients enthalten ist und aus CGI-ähnlichen Headern besteht) an Ihre Rack-Anwendung, die die in diesem Hash enthaltenen Elemente verwenden kann, um zu tun, was sie wollen.
Was ist eine Rack-Anwendung?
Um Rack verwenden zu können, müssen Sie eine 'App' bereitstellen - ein Objekt, das auf die
#call
Methode mit dem Umgebungs-Hash als Parameter reagiert (normalerweise definiert alsenv
).#call
muss ein Array mit genau drei Werten zurückgeben:each
).Sie können eine Rack-Anwendung schreiben, die ein solches Array zurückgibt. Diese wird von Rack innerhalb einer Antwort an Ihren Client zurückgesendet (dies ist tatsächlich eine Instanz der Klasse
Rack::Response
[Klicken, um zu den Dokumenten zu gelangen]).Eine sehr einfache Rack-Anwendung:
gem install rack
config.ru
Datei - Rack muss danach suchen.Wir werden eine winzige Rack-Anwendung erstellen, die eine Antwort (eine Instanz von
Rack::Response
) zurückgibt , deren Antworttext ein Array ist, das eine Zeichenfolge enthält :"Hello, World!"
.Wir werden einen lokalen Server mit dem Befehl starten
rackup
.Wenn Sie den entsprechenden Port in unserem Browser besuchen, sehen Sie "Hallo Welt!" im Ansichtsfenster gerendert.
Starten Sie einen lokalen Server mit
rackup
und besuchen Sie localhost: 9292, und Sie sollten "Hallo Welt!" gerendert.Dies ist keine umfassende Erklärung, aber im Wesentlichen geschieht hier, dass der Client (der Browser) über Ihren lokalen Server eine HTTP-Anforderung an Rack sendet und Rack instanziiert
MessageApp
und ausgeführt wirdcall
, wobei der Umgebungs-Hash als Parameter an die Methode übergeben wird ( dasenv
Argument).Rack verwendet den Rückgabewert (das Array) und erstellt daraus eine Instanz von
Rack::Response
und sendet diese an den Client zurück. Der Browser verwendet Magie , um "Hallo Welt!" Zu drucken. auf den Bildschirm.Übrigens, wenn Sie sehen möchten, wie der Umgebungs-Hash aussieht, legen Sie ihn einfach
puts env
darunterdef call(env)
.Minimal wie es ist, was Sie hier geschrieben haben, ist eine Rack-Anwendung!
Eine Rack-Anwendung mit dem Hash der eingehenden Umgebung interagieren lassen
In unserer kleinen Rack - App können wir mit dem interagieren
env
Hash (siehe hier für mehr über das Umwelt - Hash).Wir werden die Möglichkeit für den Benutzer implementieren, eine eigene Abfragezeichenfolge in die URL einzugeben. Daher ist diese Zeichenfolge in der HTTP-Anforderung vorhanden, die als Wert in einem der Schlüssel / Wert-Paare des Umgebungs-Hashs gekapselt ist.
Unsere Rack-App greift über den Umgebungs-Hash auf diese Abfragezeichenfolge zu und sendet sie über den Text in der Antwort an den Client (in diesem Fall unseren Browser) zurück.
Aus den Rack-Dokumenten zum Umgebungs-Hash: "QUERY_STRING: Der Teil der Anforderungs-URL, der auf das? Gefolgt wird, falls vorhanden. Kann leer sein, ist aber immer erforderlich!"
Wenn Sie jetzt
rackup
besuchenlocalhost:9292?hello
(?hello
als Abfragezeichenfolge), sollte im Ansichtsfenster "Hallo" angezeigt werden.Rack-Middleware
Wir werden:
MessageSetter
,env
,MessageSetter
fügt einen'MESSAGE'
Schlüssel in den env-Hash ein, dessen Wert'Hello, World!'
ifenv['QUERY_STRING']
ist , wenn er leer ist;env['QUERY_STRING']
wenn nicht,@app.call(env)
-@app
als nächste App im 'Stack' :MessageApp
.Erstens die "Langhand" -Version:
Aus den Rack :: Builder-Dokumenten geht hervor , dass
Rack::Builder
ein kleines DSL implementiert wird , um Rack-Anwendungen iterativ zu erstellen. Dies bedeutet im Grunde, dass Sie einen "Stapel" erstellen können, der aus einem oder mehreren Middlewares und einer "untersten" Anwendung besteht, an die gesendet werden soll. Alle Anfragen, die an Ihre unterste Anwendung weitergeleitet werden, werden zuerst von Ihren Middleware (s) verarbeitet.#use
Gibt die Middleware an, die in einem Stapel verwendet werden soll. Es nimmt die Middleware als Argument.Rack Middleware muss:
call
Methode, die den Umgebungs-Hash als Parameter verwendet.In unserem Fall ist die 'Middleware'
MessageSetter
, der 'Konstruktor' die MessageSetter-initialize
Methode, die 'nächste Anwendung' im StapelMessageApp
.Also hier, wegen dem , was
Rack::Builder
tut unter der Haube, dasapp
Argument vonMessageSetter
‚s -initialize
Methode istMessageApp
.(Machen Sie sich mit dem Kopf vertraut, bevor Sie fortfahren)
Daher gibt jede Middleware den vorhandenen Umgebungs-Hash im Wesentlichen an die nächste Anwendung in der Kette weiter. Sie haben also die Möglichkeit, diesen Umgebungs-Hash in der Middleware zu mutieren, bevor Sie ihn an die nächste Anwendung im Stapel weitergeben.
#run
Nimmt ein Argument, das ein Objekt ist, das auf#call
eine Rack-Antwort (eine Instanz vonRack::Response
) reagiert und diese zurückgibt .Schlussfolgerungen
Mit können
Rack::Builder
Sie Ketten von Middlewares erstellen, und jede Anforderung an Ihre Anwendung wird von jeder Middleware nacheinander verarbeitet, bevor sie schließlich vom letzten Teil des Stapels (in unserem FallMessageApp
) verarbeitet wird. Dies ist äußerst nützlich, da verschiedene Phasen der Verarbeitung von Anforderungen getrennt werden. In Bezug auf die Trennung von Bedenken könnte es nicht viel sauberer sein!Sie können eine 'Anforderungspipeline' erstellen, die aus mehreren Middlewares besteht, die sich mit folgenden Dingen befassen:
(über den Aufzählungspunkten einer anderen Antwort in diesem Thread)
Sie werden dies häufig in professionellen Sinatra-Anwendungen sehen. Sinatra benutzt Rack! Sehen Sie hier für die Definition dessen , was Sinatra IST !
Als letzte Anmerkung
config.ru
können wir in einem Kurzschriftstil geschrieben werden, der genau die gleiche Funktionalität erzeugt (und dies ist, was Sie normalerweise sehen werden):Um genauer zu zeigen, was
MessageApp
gerade getan wird, finden Sie hier die 'Langhand'-Version, die explizit zeigt,#call
dass eine neue Instanz vonRack::Response
mit den erforderlichen drei Argumenten erstellt wird.Nützliche Links
quelle
Rack - Die Schnittstelle zwischen Web- und App-Server
Rack ist ein Ruby-Paket, das eine Schnittstelle für die Kommunikation eines Webservers mit der Anwendung bietet. Es ist einfach, Middleware-Komponenten zwischen dem Webserver und der App hinzuzufügen, um das Verhalten Ihrer Anfrage / Antwort zu ändern. Die Middleware-Komponente befindet sich zwischen dem Client und dem Server und verarbeitet eingehende Anforderungen und ausgehende Antworten.
In Laienwörtern handelt es sich im Grunde genommen nur um eine Reihe von Richtlinien, wie ein Server und eine Rails-App (oder eine andere Ruby-Web-App) miteinander kommunizieren sollen .
Um Rack zu verwenden, geben Sie eine "App" an: ein Objekt, das auf die Aufrufmethode reagiert, den Umgebungs-Hash als Parameter verwendet und ein Array mit drei Elementen zurückgibt:
Weitere Erklärungen finden Sie unter den folgenden Links.
In Rails haben wir config.ru als Rack-Datei. Sie können jede Rack-Datei mit dem
rackup
Befehl ausführen . Und der Standardport dafür ist9292
. Um dies zu testen, können Sie einfachrackup
in Ihrem Rails-Verzeichnis laufen und das Ergebnis sehen. Sie können auch einen Port zuweisen, auf dem Sie ihn ausführen möchten. Der Befehl zum Ausführen der Rack-Datei an einem bestimmten Port lautetquelle
Rack ist ein Juwel, das eine einfache Schnittstelle zur abstrakten HTTP-Anforderung / Antwort bietet. Das Rack befindet sich zwischen Web-Frameworks (Rails, Sinatra usw.) und Webservern (Unicorn, Puma) als Adapter. Auf dem obigen Bild bleibt der Einhornserver völlig unabhängig von der Kenntnis von Schienen, und die Schienen wissen nichts über Einhorn. Dies ist ein gutes Beispiel für lose Kopplung und Trennung von Bedenken .
Das obige Bild stammt von diesem Rails-Konferenzgespräch im Rack https://youtu.be/3PnUV9QzB0g. Ich empfehle, es für ein tieferes Verständnis anzusehen.
quelle