Ruby'de Rack ara katmanı nedir? "Ara katman" ile ne anlama geldiklerine dair iyi bir açıklama bulamadım.
Ruby'de Rack ara katmanı nedir? "Ara katman" ile ne anlama geldiklerine dair iyi bir açıklama bulamadım.
Yanıtlar:
Raf ara katman yazılımı "bir isteği ve yanıtı filtrelemenin bir yolu" dan fazlasıdır - Rack kullanan web sunucuları için boru hattı tasarım modelinin bir uygulamasıdır .
Bir talebi işlemenin farklı aşamalarını çok temiz bir şekilde ayırır - endişelerin ayrılması, iyi tasarlanmış tüm yazılım ürünlerinin temel amacıdır.
Örneğin Rack I ile boru hattının ayrı aşamaları olabilir:
Kimlik doğrulama : istek geldiğinde, kullanıcılar oturum açma ayrıntıları doğru mu? Bu OAuth, HTTP Temel Kimlik Doğrulaması, adı / şifresini nasıl doğrularım?
Yetkilendirme : "kullanıcı bu görevi yerine getirme yetkisine sahip mi?", Yani rol tabanlı güvenlik.
Önbellekleme : Bu isteği zaten işledim mi, önbelleğe alınmış bir sonuç döndürebilir miyim?
Dekorasyon : sonraki işlemleri daha iyi hale getirme talebini nasıl artırabilirim?
Performans ve Kullanım İzleme : istek ve yanıttan hangi istatistikleri alabilirim?
Yürütme : aslında isteği işleme ve bir yanıt verme.
Farklı aşamaları ayırabilmek (ve isteğe bağlı olarak bunları dahil edebilmek) iyi yapılandırılmış uygulamalar geliştirmede çok yardımcı olur.
Rack Middleware etrafında gelişen harika bir eko-sistem de var - yukarıdaki tüm adımları ve daha fazlasını yapmak için önceden oluşturulmuş raf bileşenlerini bulabilmeniz gerekir. Ara katman yazılımı listesi için Rack GitHub wiki dosyasına bakın .
Ara katman yazılımı, bir görevin yürütülmesine yardımcı olan ancak doğrudan ilgili olmayan herhangi bir yazılım bileşenini / kitaplığını ifade eden korkunç bir terimdir. Çok yaygın örnekler günlüğe kaydetme, kimlik doğrulama ve diğer yaygın yatay işleme bileşenleridir . Bunlar, herkesin birden fazla uygulamada ihtiyaç duyduğu şeyler olma eğilimindedir, ancak çok fazla insan kendilerini inşa etmekle ilgilenmez (veya ilgilenmemelidir).
İstekleri filtrelemenin bir yolu olması hakkındaki yorum muhtemelen RailsCast bölüm 151: Rack Middleware ekranından geliyor .
Katman Rack dışında gelişti ve büyük bir intro var Rack ortakatmanını Raf Introduction to .
Wikipedia'da ara katman yazılımına bir giriş var .
Her şeyden önce, Rack tam olarak iki şeydir:
Raf - Web Sunucusu Arayüzü
Rafın temelleri basit bir kongre. Her raf uyumlu web sunucusu, ona verdiğiniz bir nesne üzerinde her zaman bir çağrı yöntemini çağırır ve bu yöntemin sonucunu sunar. Kabin, bu çağrı yönteminin nasıl görünmesi gerektiğini ve ne döndürmesi gerektiğini tam olarak belirtir. Bu raf.
Basit bir deneyelim. WEBrick'i raf uyumlu web sunucusu olarak kullanacağım, ancak herhangi biri yapacak. Bir JSON dizesi döndüren basit bir web uygulaması oluşturalım. Bunun için config.ru adlı bir dosya oluşturacağız. Config.ru, rafın uyumlu bir web sunucusunda config.ru içeriğini çalıştıracak olan raf taşının komut rafı tarafından otomatik olarak çağrılır. Öyleyse config.ru dosyasına aşağıdakileri ekleyelim:
class JSONServer
def call(env)
[200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
end
end
map '/hello.json' do
run JSONServer.new
end
Kuralda belirtildiği gibi, sunucumuzun bir ortam karmasını kabul eden ve web sunucusunun sunması için [durum, başlıklar, gövde] biçiminde bir dizi döndüren çağrı adı verilen bir yöntemi vardır. Sadece rackup'ı arayarak deneyelim. Varsayılan raf uyumlu bir sunucu, belki WEBrick veya Mongrel başlayacak ve hemen isteklerin sunulmasını bekleyecektir.
$ rackup
[2012-02-19 22:39:26] INFO WEBrick 1.3.1
[2012-02-19 22:39:26] INFO ruby 1.9.3 (2012-01-17) [x86_64-darwin11.2.0]
[2012-02-19 22:39:26] INFO WEBrick::HTTPServer#start: pid=16121 port=9292
URL http://localhost:9292/hello.json
ve voila'yı kıvırıp ziyaret ederek yeni JSON sunucumuzu test edelim :
$ curl http://localhost:9292/hello.json
{ message: "Hello!" }
İşe yarıyor. Harika! Rails veya Sinatra gibi her web çerçevesinin temeli budur. Bir noktada bir çağrı yöntemi uygularlar, tüm çerçeve kodlarını kullanırlar ve son olarak tipik [durum, başlıklar, gövde] biçiminde bir yanıt döndürürler.
Örneğin Ruby on Rails'te raf istekleri ActionDispatch::Routing.Mapper
şuna benzer sınıfa vurur :
module ActionDispatch
module Routing
class Mapper
...
def initialize(app, constraints, request)
@app, @constraints, @request = app, constraints, request
end
def matches?(env)
req = @request.new(env)
...
return true
end
def call(env)
matches?(env) ? @app.call(env) : [ 404, {'X-Cascade' => 'pass'}, [] ]
end
...
end
end
Temel olarak Rails kontrolleri, eğer herhangi bir rota eşleşirse env hash değerine bağlı olarak. Eğer öyleyse env karma değerini yanıtı hesaplamak için uygulamaya geçirir, aksi takdirde hemen bir 404 ile yanıt verir.
Ara Katman
Raf aynı zamanda ara katman katmanlarının oluşturulmasını da destekler. Temelde bir isteği keser, onunla bir şeyler yaparlar ve iletirler. Bu çok yönlü görevler için çok kullanışlıdır.
Diyelim ki JSON sunucumuza bir isteğin ne kadar sürdüğünü de ölçen günlük kaydı eklemek istiyoruz. Tam olarak bunu yapan bir ara katman kayıt cihazı oluşturabiliriz:
class RackLogger
def initialize(app)
@app = app
end
def call(env)
@start = Time.now
@status, @headers, @body = @app.call(env)
@duration = ((Time.now - @start).to_f * 1000).round(2)
puts "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} - Took: #{@duration} ms"
[@status, @headers, @body]
end
end
Oluşturulduğunda, kendisini gerçek raf uygulamasının bir kopyasını kaydeder. Bizim durumumuzda bu JSONServer'ımızın bir örneğidir. Rack, ara katman yazılımındaki çağrı yöntemini otomatik olarak çağırır ve [status, headers, body]
tıpkı JSONServer'ımızın döndürdüğü gibi bir dizi bekler .
Bu ara yazılımda, başlangıç noktası alınır, daha sonra JSONServer'a gerçek çağrı yapılır @app.call(env)
, daha sonra logger günlük girişini çıkarır ve son olarak yanıtı olarak döndürür [@status, @headers, @body]
.
Bizim küçük rackup.ru bu katman kullanmak için, bunun gibi bir kullanım RackLogger ekleyin:
class JSONServer
def call(env)
[200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
end
end
class RackLogger
def initialize(app)
@app = app
end
def call(env)
@start = Time.now
@status, @headers, @body = @app.call(env)
@duration = ((Time.now - @start).to_f * 1000).round(2)
puts "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} - Took: #{@duration} ms"
[@status, @headers, @body]
end
end
use RackLogger
map '/hello.json' do
run JSONServer.new
end
Sunucuyu ve voila'yı yeniden başlatın, her istek üzerine bir günlük çıkarır. Raf, eklendikleri sırayla çağrılan birden çok orta yol eklemenizi sağlar. Raf uygulamasının çekirdeğini değiştirmeden işlevsellik eklemenin harika bir yoludur.
Raf - Mücevher
Raf - her şeyden önce - bir kongre olmasına rağmen, aynı zamanda mükemmel işlevsellik sağlayan bir mücevher. Bunlardan biri zaten JSON sunucumuz için, rackup komutu için kullandık. Ama dahası var! Raf taşı, statik dosyaları veya hatta tüm dizinleri sunmak gibi birçok kullanım durumu için küçük uygulamalar sağlar. Basit bir dosyaya nasıl hizmet ettiğimizi görelim, örneğin htmls / index.html adresinde bulunan çok temel bir HTML dosyası:
<!DOCTYPE HTML>
<html>
<head>
<title>The Index</title>
</head>
<body>
<p>Index Page</p>
</body>
</html>
Bu dosyayı web sitesi kökünden sunmak istiyoruz, bu yüzden aşağıdaki ayarları config.ru adresimize ekleyelim:
map '/' do
run Rack::File.new "htmls/index.html"
end
Ziyaret http://localhost:9292
edersek, html dosyamızın mükemmel bir şekilde oluşturulduğunu görürüz. Kolaydı, değil mi?
/ Javascriptts altında bazı javascript dosyaları oluşturarak ve config.ru dosyasına aşağıdakileri ekleyerek javascript dosyalarının tam bir dizinini ekleyelim:
map '/javascripts' do
run Rack::Directory.new "javascripts"
end
Sunucuyu yeniden başlatın ve adresini ziyaret edin http://localhost:9292/javascript
. Artık doğrudan istediğiniz yerden ekleyebileceğiniz tüm javascript dosyalarının bir listesini göreceksiniz.
Rafı iyi bir süre anlamaya çalışırken sorun yaşadım. Sadece bu minyatür Ruby web sunucusunu kendim yapmaya çalıştıktan sonra tamamen anladım . Rack hakkında öğrendiklerimi (bir hikaye şeklinde) blogumda paylaştım: http://gauravchande.com/what-is-rack-in-ruby-rails
Geribildirim hoş geldiniz daha.
config.ru
minimal çalıştırılabilir örnek
app = Proc.new do |env|
[
200,
{
'Content-Type' => 'text/plain'
},
["main\n"]
]
end
class Middleware
def initialize(app)
@app = app
end
def call(env)
@status, @headers, @body = @app.call(env)
[@status, @headers, @body << "Middleware\n"]
end
end
use(Middleware)
run(app)
Kaç rackup
ve ziyaret et localhost:9292
. Çıktı:
main
Middleware
Bu yüzden Middleware
ana uygulamayı sarar ve çağırır. Bu nedenle, isteği önceden işleyebilir ve yanıtı herhangi bir şekilde sonradan işleyebilir.
Açıklandığı gibi: http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack , Rails birçok işlevselliği için Rack middlewares kullanır ve siz de config.middleware.use
aile yöntemleriyle kendiniz ekleyebilirsiniz .
Bir ara katman yazılımında işlevsellik uygulamanın avantajı, onu sadece Rails değil, tüm büyük Ruby olanlar için herhangi bir Rack çerçevede yeniden kullanabilmenizdir.
Raf ara katman yazılımı, uygulamanıza gelen bir istek ve yanıtı filtrelemenin bir yoludur. Bir ara katman bileşeni, gelen istekleri ve giden yanıtları işleyerek istemci ve sunucu arasında oturur, ancak web sunucusuyla konuşmak için kullanılabilecek arabirimden daha fazlasıdır. Genellikle Ruby sınıfları olan modülleri gruplamak ve sıralamak ve aralarındaki bağımlılığı belirtmek için kullanılır. Raf ara katman yazılımı modülü yalnızca şunları yapmalıdır: - yığındaki sonraki uygulamayı parametre olarak alan yapıcıya sahip olmalıdır - ortam karmasını parametre olarak alan “call” yöntemine yanıt verir. Bu çağrıdan değer döndürmek bir dizi dizisidir: durum kodu, ortam karması ve yanıt gövdesi.
Rack problemlerini birkaç problemi çözmek için kullandım:
Her iki durumda da oldukça zarif düzeltmeler sağladı.
Rack, Ruby ve Ruby çerçevelerini destekleyen web sunucuları arasında minimum bir arayüz sağlar.
Rack kullanarak bir Rack Uygulaması yazabilirsiniz.
Rack, bir istemciden, CGI benzeri başlıklardan oluşan bir HTTP isteğinin içinde yer alan bir Hash) Rack Uygulamanıza bu karma işleminde bulunan şeyleri istediği gibi kullanabilen Aktarma uygulamanıza geçirir.
Rack'i kullanmak için bir 'uygulama' sağlamalısınız - bu #call
yöntem Ortam Karma ile parametreye parametre olarak yanıt veren bir nesne (genellikle olarak tanımlanır env
). #call
tam olarak üç değerden oluşan bir Dizi döndürmelidir:
each
).Böyle bir dizi döndüren bir Rack Uygulaması yazabilirsiniz - bu, bir Yanıt içinde Rack tarafından istemcinize geri gönderilir (bu aslında bir Sınıf örneğidirRack::Response
[belgelere gitmek için tıklayın]).
gem install rack
config.ru
dosya oluşturun - Rack bunu aramayı bilir.Rack::Response
Yanıt Gövdesi String içeren bir dizi olan bir Yanıt (örneği ) döndüren küçük bir Rack Uygulaması oluşturacağız "Hello, World!"
.
Komutu kullanarak yerel bir sunucuyu tetikleyeceğiz rackup
.
Tarayıcımızdaki ilgili bağlantı noktasını ziyaret ettiğinizde "Merhaba, Dünya!" görünümünde render.
#./message_app.rb
class MessageApp
def call(env)
[200, {}, ['Hello, World!']]
end
end
#./config.ru
require_relative './message_app'
run MessageApp.new
Yerel bir sunucuyu başlatın ve localhost'urackup
ziyaret edin : 9292 ve 'Merhaba, Dünya!' render.
Bu kapsamlı bir açıklama değildir, ancak esasen burada olan şey, İstemcinin (tarayıcı) yerel sunucunuz aracılığıyla Rack'e bir HTTP İsteği göndermesidir ve Rack , Ortam Karma'yı yöntem olarak bir parametre olarak geçirerek başlatır MessageApp
ve çalışır call
( env
argüman).
Rack, dönüş değerini (dizi) alır ve bunu bir örneği oluşturmak için kullanır ve bunu Rack::Response
İstemciye geri gönderir. Tarayıcı kullanan sihirli yazdırmak için 'Merhaba, Dünya!' ekrana getirin.
Bu arada, ortamın nasıl göründüğünü görmek istiyorsanız, puts env
altına koyun def call(env)
.
En az olduğu gibi, burada yazdıklarınız bir Rack uygulamasıdır!
Küçük Rack uygulamamızda, env
karma ile etkileşime girebiliriz ( Çevre karma hakkında daha fazla bilgi için buraya bakın ).
Kullanıcının URL'ye kendi sorgu dizesini girme yeteneğini uygulayacağız; bu nedenle, bu dizgi, Ortam karmasının anahtar / değer çiftlerinden birinde bir değer olarak kapsüllenen HTTP isteğinde bulunacaktır.
Rack uygulamamız bu sorgu dizesine Ortam karmasından erişir ve bunu Yanıttaki Gövde aracılığıyla istemciye (bu durumda tarayıcımız) gönderir.
Ortam Karması'ndaki Raf belgelerinden: "QUERY_STRING: İstek URL'sinin? Varsa onu takip eden bölümü. Boş olabilir, ancak her zaman gereklidir!"
#./message_app.rb
class MessageApp
def call(env)
message = env['QUERY_STRING']
[200, {}, [message]]
end
end
Şimdi, rackup
adresini ziyaret edin localhost:9292?hello
( ?hello
sorgu dizesi olmak üzere) ve görünüm penceresinde 'merhaba' ifadesini görmelisiniz.
Yapacağız:
MessageSetter
,env
,MessageSetter
Bir ekleyecektir 'MESSAGE'
env karma içine anahtar, kendi değerini 'Hello, World!'
ise env['QUERY_STRING']
boş; env['QUERY_STRING']
değilse,@app.call(env)
- @app
: 'Yığın' sonraki uygulama olma MessageApp
.İlk olarak, 'uzun el' versiyonu:
#./middleware/message_setter.rb
class MessageSetter
def initialize(app)
@app = app
end
def call(env)
if env['QUERY_STRING'].empty?
env['MESSAGE'] = 'Hello, World!'
else
env['MESSAGE'] = env['QUERY_STRING']
end
@app.call(env)
end
end
#./message_app.rb (same as before)
class MessageApp
def call(env)
message = env['QUERY_STRING']
[200, {}, [message]]
end
end
#config.ru
require_relative './message_app'
require_relative './middleware/message_setter'
app = Rack::Builder.new do
use MessageSetter
run MessageApp.new
end
run app
Gönderen Rack :: Oluşturucu docs biz görüyoruz Rack::Builder
uygular iteratif yapı Raf uygulamalara küçük DSL. Bu temel olarak, bir veya daha fazla Middlewares ve gönderilecek bir 'alt seviye' uygulamasından oluşan bir 'Stack' oluşturabileceğiniz anlamına gelir. Alt düzey uygulamanıza gönderilen tüm istekler ilk önce Ara Yazılım (lar) nız tarafından işlenir.
#use
bir yığın içinde kullanılacak ara katman yazılımını belirtir. Ara katmanı argüman olarak alır.
Rack Middleware şunları yapmalıdır:
call
Ortam karmasını parametre olarak alan yönteme yanıt verir .Bizim durumumuzda, 'Middleware', MessageSetter
'yapıcı' MessageSetter'ın initialize
yöntemidir, yığındaki 'sonraki uygulama' dır MessageApp
.
Ne çünkü Yani burada, Rack::Builder
kaputun altında yapar app
argümanı MessageSetter
bireyin initialize
yönteme olduğunu MessageApp
.
(devam etmeden önce başınızı yukarı çevirin)
Bu nedenle, her bir Middleware parçası temel olarak mevcut Ortam karmasını zincirdeki bir sonraki uygulamaya 'aktarır' - böylece, ortamdaki karma değerini yığında bir sonraki uygulamaya geçirmeden önce değiştirme olanağına sahipsiniz.
#run
#call
bir Rack Response (yanıt Rack::Response
) yanıtı (ve örneği ) döndüren bir nesne olan bir argüman alır .
Kullanarak Rack::Builder
Middlewares zincirleri oluşturabilirsiniz ve uygulamanıza herhangi bir talep, her bir Middleware tarafından nihayetinde yığındaki son parça tarafından işlenmeden önce (bizim durumumuzda MessageApp
) işlenecektir . Bu son derece kullanışlıdır, çünkü işleme isteklerinin farklı aşamalarını ayırır. 'Endişelerin ayrılması' açısından, daha temiz olamazdı!
Aşağıdakiler gibi şeylerle ilgilenen birkaç Middlewares'den oluşan bir 'istek boru hattı' oluşturabilirsiniz:
(bu konudaki başka bir cevaptan madde işaretleri yukarıda)
Bunu profesyonel Sinatra uygulamalarında sık sık göreceksiniz. Sinatra Rack kullanıyor! Sinatra IS'nin tanımı için buraya bakın !
Son bir not olarak, config.ru
tam olarak aynı işlevselliği üreten kısa el tarzında yazılabilir (ve genellikle göreceğiniz şey budur):
require_relative './message_app'
require_relative './middleware/message_setter'
use MessageSetter
run MessageApp.new
Ve ne MessageApp
yaptığını daha açık bir şekilde göstermek için #call
, Rack::Response
gerekli üç argümanla yeni bir örnek oluşturduğunu açıkça gösteren 'uzun el' versiyonu .
class MessageApp
def call(env)
Rack::Response.new([env['MESSAGE']], 200, {})
end
end
Raf - Web ve Uygulama Sunucusundaki Arayüz
Rack, bir web sunucusunun uygulama ile iletişim kurması için bir arabirim sağlayan bir Ruby paketidir. İsteğinizin / yanıtınızın davranış biçimini değiştirmek için web sunucusu ile uygulama arasına ara katman bileşenleri eklemek kolaydır. Orta katman bileşeni, gelen istekleri ve giden yanıtları işleyerek istemci ve sunucu arasında oturur.
Layman kelimelerle, temelde bir sunucu ve bir Rails uygulamasının (veya herhangi bir Ruby web uygulamasının) birbirleriyle nasıl konuşması gerektiğine dair bir dizi kılavuzdur .
Rack'i kullanmak için bir "uygulama" sağlayın: çağrı yöntemine yanıt veren, ortam karmasını parametre olarak alan ve üç öğeli bir Dizi döndüren bir nesne:
Daha fazla açıklama için aşağıdaki bağlantıları takip edebilirsiniz.
1. https://rack.github.io/
2. https://redpanthers.co/rack-middleware/
3. https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware
4. https://guides.rubyonrails.org/rails_on_rack.html#resources
Raylarda, bir raf dosyası olarak config.ru var, herhangi bir raf dosyasını rackup
komutla çalıştırabilirsiniz . Ve bunun için varsayılan bağlantı noktası 9292
. Bunu test etmek rackup
için, raylar dizininizde çalışabilir ve sonucu görebilirsiniz. Ayrıca üzerinde çalıştırmak istediğiniz bağlantı noktasını da atayabilirsiniz. Herhangi bir bağlantı noktasında rack dosyasını çalıştırma komutu
rackup -p PORT_NUMBER
Rack, soyut HTTP isteğine / yanıtına basit bir arayüz sağlayan bir mücevherdir. Raf, adaptör olarak web çerçeveleri (Raylar, Sinatra vb.) Ve web sunucuları (tek boynuzlu at, puma) arasında oturur. Yukarıdaki görüntüden bu, tek boynuzlu at sunucusunu raylar hakkında bilmekten tamamen bağımsız tutar ve raylar tek boynuzlu at hakkında bilmez. Bu gevşek bağlantıya , endişelerin ayrılmasına iyi bir örnektir .
Görüntü rafa bu raylar konferans konuşma dan Üstü https://youtu.be/3PnUV9QzB0g daha derin bir anlayış için izlemenizi öneririz.