Middleware ของ Rack ใน Ruby คืออะไร? ฉันไม่สามารถหาคำอธิบายที่ดีสำหรับสิ่งที่พวกเขาหมายถึงโดย "มิดเดิลแวร์"
Middleware ของ Rack ใน Ruby คืออะไร? ฉันไม่สามารถหาคำอธิบายที่ดีสำหรับสิ่งที่พวกเขาหมายถึงโดย "มิดเดิลแวร์"
คำตอบ:
Rack middleware เป็นมากกว่า "วิธีกรองคำขอและการตอบกลับ" - เป็นการใช้รูปแบบการออกแบบไปป์ไลน์สำหรับเว็บเซิร์ฟเวอร์ที่ใช้Rackแร็ค
มันแยกขั้นตอนการประมวลผลคำขอออกจากกันอย่างหมดจดโดยแยกข้อกังวลออกเป็นเป้าหมายหลักของผลิตภัณฑ์ซอฟต์แวร์ที่ออกแบบมาอย่างดี
ตัวอย่างเช่นด้วย Rack ฉันสามารถแยกขั้นตอนการทำงานของไปป์ไลน์ได้:
การรับรองความถูกต้อง : เมื่อคำขอมาถึงรายละเอียดการเข้าสู่ระบบของผู้ใช้ถูกต้องหรือไม่ ฉันจะตรวจสอบ OAuth นี้การตรวจสอบสิทธิ์พื้นฐาน HTTP ชื่อ / รหัสผ่านได้อย่างไร
การอนุญาต : "เป็นผู้ใช้ที่ได้รับอนุญาตให้ทำงานนี้หรือไม่" เช่นความปลอดภัยตามบทบาท
การแคช : ฉันได้ดำเนินการตามคำขอนี้ไปแล้วฉันจะคืนผลลัพธ์ที่แคชได้หรือไม่?
การตกแต่ง : ฉันจะปรับปรุงการร้องขอเพื่อให้การประมวลผลดาวน์สตรีมดีขึ้นได้อย่างไร
การตรวจสอบประสิทธิภาพและการใช้งาน : ฉันจะได้รับสถิติอะไรจากคำขอและการตอบกลับ
การดำเนินการ : จัดการคำขอจริงและให้การตอบสนอง
ความสามารถในการแยกขั้นตอนที่แตกต่างกัน (และรวมไว้ด้วยตนเอง) เป็นความช่วยเหลือที่ดีในการพัฒนาแอปพลิเคชันที่มีโครงสร้าง
นอกจากนี้ยังมีระบบนิเวศที่ยอดเยี่ยมในการพัฒนา Rack Middleware - คุณควรจะสามารถหาส่วนประกอบของแร็คที่สร้างไว้ล่วงหน้าเพื่อทำตามขั้นตอนทั้งหมดข้างต้นและอื่น ๆ ดูแร็ค GitHub วิกิพีเดียสำหรับรายชื่อของตัวกลาง
Middleware เป็นคำที่น่ากลัวซึ่งหมายถึงส่วนประกอบซอฟต์แวร์ / ไลบรารีที่ช่วยเหลือด้วย แต่ไม่เกี่ยวข้องโดยตรงในการทำงานบางอย่าง ตัวอย่างที่พบบ่อยมากมีการเข้าสู่ระบบการตรวจสอบและอื่น ๆทั่วไปส่วนประกอบการประมวลผลในแนวนอน สิ่งเหล่านี้มีแนวโน้มที่จะเป็นสิ่งที่ทุกคนต้องการในแอพพลิเคชั่นที่หลากหลาย แต่มีคนจำนวนไม่มากที่สนใจ (หรือควร) ในการสร้างตัวเอง
ความคิดเห็นเกี่ยวกับมันเป็นวิธีการกรองคำขออาจมาจากตอนที่ RailsCast ตอนที่ 151:หน้าจอRack Middleware
Rack ตัวกลางวิวัฒนาการมาจากตู้แร็คและมีความเป็นบทนำที่ดีในเบื้องต้นเกี่ยวกับ Rack มิดเดิลแวร์
ประการแรก Rack เป็นสองสิ่ง:
ชั้นวาง - ส่วนต่อประสานเว็บเซิร์ฟเวอร์
พื้นฐานมากของแร็คคือการประชุมที่เรียบง่าย เว็บเซิร์ฟเวอร์ที่สอดคล้องกับชั้นวางทุกคนจะเรียกวิธีการโทรบนวัตถุที่คุณให้เขาและแสดงผลลัพธ์ของวิธีการนั้นเสมอ ชั้นวางระบุวิธีการเรียกวิธีการนี้ให้มีลักษณะและสิ่งที่จะต้องกลับ นั่นคือชั้นวาง
ลองทำดูง่ายๆ ฉันจะใช้ WEBrick เป็นเว็บเซิร์ฟเวอร์ที่สอดคล้องกับชั้นวาง แต่อย่างใดอย่างหนึ่งจะทำ มาสร้างเว็บแอปพลิเคชั่นง่ายๆที่ส่งคืนสตริง JSON สำหรับสิ่งนี้เราจะสร้างไฟล์ชื่อ config.ru config.ru จะถูกเรียกโดยอัตโนมัติโดยคำสั่ง rackup ของ rackup ซึ่งจะเรียกใช้เนื้อหาของ config.ru ในเว็บเซิร์ฟเวอร์ที่สอดคล้องกับชั้นวาง ดังนั้นให้เพิ่มสิ่งต่อไปนี้ในไฟล์ config.ru:
class JSONServer
def call(env)
[200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
end
end
map '/hello.json' do
run JSONServer.new
end
เนื่องจากการประชุมระบุเซิร์ฟเวอร์ของเรามีวิธีที่เรียกว่าการเรียกที่ยอมรับการแฮ็สภาพแวดล้อมและส่งกลับอาร์เรย์ที่มีรูปแบบ [สถานะส่วนหัวร่างกาย] สำหรับเว็บเซิร์ฟเวอร์ที่จะให้บริการ ลองทำโดยการเรียกแร็ค เซิร์ฟเวอร์ที่รองรับแร็คเริ่มต้นบางที WEBrick หรือ Mongrel จะเริ่มต้นและรอคำขอที่จะให้บริการทันที
$ 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
ลองทดสอบเซิร์ฟเวอร์ JSON ใหม่ของเราโดยการดัดผมหรือไปที่ url http://localhost:9292/hello.json
และ voila:
$ curl http://localhost:9292/hello.json
{ message: "Hello!" }
มันได้ผล. ที่ดี! นั่นเป็นพื้นฐานสำหรับทุก ๆ เว็บเฟรมเวิร์กไม่ว่าจะเป็น Rails หรือ Sinatra เมื่อถึงจุดหนึ่งพวกเขาใช้วิธีการโทรทำงานผ่านรหัสกรอบทั้งหมดและในที่สุดก็กลับมาตอบสนองในรูปแบบ [สถานะส่วนหัวร่างกาย]
ใน Ruby on Rails ตัวอย่างเช่น rack ร้องขอจำนวนActionDispatch::Routing.Mapper
คลาสที่มีลักษณะดังนี้:
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
ดังนั้นโดยทั่วไปการตรวจสอบ Rails ขึ้นอยู่กับการแฮช env หากเส้นทางใดตรงกัน ถ้ามันผ่านการแฮ็ค env ไปยังแอปพลิเคชันเพื่อคำนวณการตอบสนองมิฉะนั้นจะตอบกลับด้วย 404 ทันทีดังนั้นเว็บเซิร์ฟเวอร์ใด ๆ ที่เข้ากันได้กับการประชุมส่วนต่อประสานชั้นวางสามารถให้บริการแอปพลิเคชั่น
มิดเดิ้ล
ชั้นวางยังรองรับการสร้างเลเยอร์มิดเดิลแวร์ พวกเขาโดยทั่วไปจะดักคำขอทำอะไรกับมันและส่งต่อ สิ่งนี้มีประโยชน์มากสำหรับงานอเนกประสงค์
สมมติว่าเราต้องการเพิ่มการบันทึกไปยังเซิร์ฟเวอร์ JSON ของเราที่วัดระยะเวลาที่คำขอใช้ เราสามารถสร้างตัวบันทึกมิดเดิลแวร์ที่ทำสิ่งนี้:
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
เมื่อสร้างขึ้นมันจะบันทึกสำเนาของแอ็พพลิเคชันแร็คจริง ในกรณีของเรานั่นเป็นตัวอย่างของ JSONServer ของเรา Rack จะเรียกวิธีการโทรบนมิดเดิลแวร์โดยอัตโนมัติและคาดว่าจะกลับมา[status, headers, body]
อาเรย์เช่นเดียวกับที่ JSONServer ของเราส่งคืน
ดังนั้นในมิดเดิลแวร์นี้จุดเริ่มต้นจะถูกนำมาใช้จากนั้นจะทำการโทรไปยัง JSONServer จริง@app.call(env)
จากนั้นตัวบันทึกจะแสดงรายการบันทึกและส่งกลับการตอบสนองในที่สุด[@status, @headers, @body]
ที่สุด
ในการทำให้ rackup.ru ของเราใช้มิดเดิลแวร์นี้ให้เพิ่มการใช้ RackLogger ให้เป็นดังนี้:
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
รีสตาร์ทเซิร์ฟเวอร์และ voila มันส่งผลให้เข้าสู่ระบบทุกคำขอ ชั้นวางช่วยให้คุณเพิ่มมิดเดิ้ลแวร์หลายตัวที่ถูกเรียกตามลำดับที่เพิ่มเข้ามา มันเป็นวิธีที่ยอดเยี่ยมในการเพิ่มฟังก์ชันการทำงานโดยไม่ต้องเปลี่ยนแกนหลักของแอปพลิเคชันชั้นวาง
ชั้นวาง - อัญมณี
แม้ว่าชั้นวาง - ก่อนอื่น - เป็นแบบแผน แต่ก็เป็นอัญมณีที่ให้การทำงานที่ยอดเยี่ยม หนึ่งในนั้นเราใช้สำหรับเซิร์ฟเวอร์ JSON ของเราคือคำสั่ง rackup แต่มีอีกมากมาย! rack gem ให้แอปพลิเคชั่นเล็ก ๆ น้อย ๆ สำหรับกรณีการใช้งานจำนวนมากเช่นการให้บริการไฟล์แบบคงที่หรือแม้แต่ไดเรกทอรีทั้งหมด เรามาดูกันว่าเราให้บริการไฟล์ง่าย ๆ อย่างไรเช่นไฟล์ HTML พื้นฐานที่อยู่ใน htmls / index.html:
<!DOCTYPE HTML>
<html>
<head>
<title>The Index</title>
</head>
<body>
<p>Index Page</p>
</body>
</html>
เราอาจต้องการแสดงไฟล์นี้จากรูทเว็บไซต์ดังนั้นให้เพิ่มสิ่งต่อไปนี้ใน config.ru ของเรา:
map '/' do
run Rack::File.new "htmls/index.html"
end
หากเราเข้าชมhttp://localhost:9292
เราจะเห็นไฟล์ html ของเราแสดงผลอย่างสมบูรณ์ นั่นเป็นเรื่องง่ายใช่มั้ย
มาเพิ่มไดเรกทอรีทั้งหมดของไฟล์จาวาสคริปต์โดยสร้างไฟล์จาวาสคริปต์ใน / javascripts และเพิ่มสิ่งต่อไปนี้ใน config.ru:
map '/javascripts' do
run Rack::Directory.new "javascripts"
end
รีสตาร์ทเซิร์ฟเวอร์แล้วไปที่http://localhost:9292/javascript
และคุณจะเห็นรายการไฟล์จาวาสคริปต์ทั้งหมดที่คุณสามารถรวมได้ทันทีจากที่ใดก็ได้
ฉันมีปัญหาในการทำความเข้าใจแร็คตัวเองในเวลาที่เหมาะสม ฉันเข้าใจอย่างถ่องแท้แล้วหลังจากที่ทำเว็บเซิร์ฟเวอร์ Ruby ขนาดเล็กนี้ขึ้นมา ฉันได้แบ่งปันการเรียนรู้ของฉันเกี่ยวกับ Rack (ในรูปแบบของเรื่องราว) ที่นี่ในบล็อกของฉัน: http://gauravchande.com/what-is-rack-in-ruby-rails
ข้อเสนอแนะเป็นมากกว่าการต้อนรับ
config.ru
ตัวอย่าง runnable น้อยที่สุด
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)
เรียกใช้และการเยี่ยมชมrackup
localhost:9292
ผลลัพธ์คือ:
main
Middleware
ดังนั้นจึงเป็นที่ชัดเจนว่าMiddleware
wraps และเรียกแอปหลัก ดังนั้นจึงสามารถดำเนินการตามคำขอล่วงหน้าได้และดำเนินการตอบกลับด้วยวิธีใดก็ได้
ตามที่อธิบายไว้ที่: http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack , Rails ใช้ Middlewares ของ Rack สำหรับฟังก์ชั่นมากมายและคุณสามารถเพิ่มคุณเองด้วยconfig.middleware.use
วิธีการแบบครอบครัว
ข้อได้เปรียบของการใช้งานฟังก์ชั่นในมิดเดิลแวร์คือคุณสามารถนำมันกลับมาใช้ใหม่บนเฟรมเวิร์กแร็คใด ๆ ก็ได้ดังนั้นรูบีหลักที่สำคัญทั้งหมดไม่ใช่แค่ Rails
Rack middleware เป็นวิธีการกรองคำขอและการตอบสนองที่เข้ามาในแอปพลิเคชันของคุณ คอมโพเนนต์มิดเดิลแวร์อยู่ระหว่างไคลเอนต์และเซิร์ฟเวอร์ประมวลผลคำขอขาเข้าและตอบกลับขาออก แต่เป็นมากกว่าส่วนติดต่อที่สามารถใช้เพื่อพูดคุยกับเว็บเซิร์ฟเวอร์ มันถูกใช้ในการจัดกลุ่มและโมดูลการสั่งซื้อซึ่งมักจะเป็นคลาสทับทิมและระบุการพึ่งพาระหว่างพวกเขา โมดูลมิดเดิลแวร์ของชั้นวางเท่านั้น: - มีตัวสร้างที่ใช้แอปพลิเคชันถัดไปในสแต็กเป็นพารามิเตอร์ - ตอบสนองต่อวิธีการ "เรียก" ที่ใช้แฮสภาพแวดล้อมเป็นพารามิเตอร์ ค่าที่ส่งคืนจากการโทรนี้คืออาร์เรย์ของ: รหัสสถานะแฮชของสภาพแวดล้อมและเนื้อหาการตอบกลับ
ฉันใช้ Middleware ของ Rack เพื่อแก้ปัญหาสองข้อ:
มันจ่ายการแก้ไขที่หรูหราสวยในทั้งสองกรณี
Rack จัดเตรียมอินเตอร์เฟสที่น้อยที่สุดระหว่างเว็บเซิร์ฟเวอร์ที่สนับสนุนเฟรมเวิร์ก Ruby และ Ruby
การใช้ชั้นวางคุณสามารถเขียนแอปพลิเคชันชั้นวางได้
ชั้นวางจะผ่านการแฮชของสภาพแวดล้อม (แฮชที่อยู่ภายในคำขอ HTTP จากไคลเอนต์ซึ่งประกอบด้วยหัวคล้าย CGI) ไปยังแอปพลิเคชันชั้นวางของคุณซึ่งสามารถใช้สิ่งต่าง ๆ ที่อยู่ในแฮชนี้เพื่อทำสิ่งที่มันต้องการ
ในการใช้ Rack คุณต้องระบุ 'แอพ' - วัตถุที่ตอบสนองต่อ#call
วิธีการที่มีแฮชของสภาพแวดล้อมเป็นพารามิเตอร์ (โดยทั่วไปจะกำหนดเป็นenv
) #call
ต้องส่งคืน Array ที่มีสามค่าอย่างแน่นอน:
each
)คุณสามารถเขียนแอปพลิเคชันชั้นวางที่ส่งกลับอาร์เรย์ดังกล่าว - ซึ่งจะถูกส่งกลับไปยังไคลเอนต์ของคุณโดยชั้นวางในการตอบกลับ (ซึ่งจริงๆแล้วจะเป็นตัวอย่างของ Class Rack::Response
[คลิกเพื่อไปที่เอกสาร])
gem install rack
config.ru
ไฟล์ - Rack รู้ที่จะมองหาสิ่งนี้เราจะสร้างแอปพลิเคชัน Rack ขนาดเล็กที่ส่งกลับการตอบสนอง (ตัวอย่างของRack::Response
) Who's Response Body เป็นอาร์เรย์ที่มีสตริง:"Hello, World!"
ที่ตอบสนองของร่างกายคืออาร์เรย์ที่มีสตริง:
เราจะเปิดไฟเซิร์ฟเวอร์ภายในโดยใช้คำสั่ง rackup
เราจะยิงขึ้นเซิร์ฟเวอร์ท้องถิ่นโดยใช้คำสั่ง
เมื่อไปที่พอร์ตที่เกี่ยวข้องในเบราว์เซอร์ของเราเราจะเห็น "สวัสดีโลก!" เรนเดอร์ในวิวพอร์ต
#./message_app.rb
class MessageApp
def call(env)
[200, {}, ['Hello, World!']]
end
end
#./config.ru
require_relative './message_app'
run MessageApp.new
เปิดไฟเซิร์ฟเวอร์ภายในด้วยrackup
และเยี่ยมชมlocalhost: 9292และคุณควรเห็น 'Hello, World!' การแสดงผล
นี่ไม่ใช่คำอธิบายที่ครอบคลุม แต่ที่สำคัญสิ่งที่เกิดขึ้นที่นี่คือไคลเอนต์ (เบราว์เซอร์) ส่งคำร้องขอ HTTP ไปยัง Rack ผ่านเซิร์ฟเวอร์ภายในเครื่องของคุณและ Rack MessageApp
จะเริ่มต้นและเรียกใช้call
โดยส่งผ่าน Hash ของสภาพแวดล้อมเป็นพารามิเตอร์env
อาร์กิวเมนต์)
Rack ใช้ค่าส่งคืน (อาร์เรย์) และใช้เพื่อสร้างอินสแตนซ์Rack::Response
และส่งกลับไปยังไคลเอนต์ เบราว์เซอร์ใช้เวทย์มนตร์ในการพิมพ์ 'Hello, World!' ไปที่หน้าจอ
หากคุณต้องการดูว่าแฮชของสภาพแวดล้อมเป็นอย่างไรให้วางไว้puts env
ข้างใต้def call(env)
ที่อยู่ภายใต้
น้อยที่สุดเท่าที่มันเป็นสิ่งที่คุณเขียนที่นี่เป็นโปรแกรมชั้น!
ในแอพชั้นวางเล็ก ๆ ของเราเราสามารถโต้ตอบกับenv
แฮช (ดูที่นี่สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแฮชของสภาพแวดล้อม)
เราจะใช้ความสามารถสำหรับผู้ใช้ในการป้อนสตริงการสืบค้นของตัวเองลงใน URL ดังนั้นสตริงนั้นจะถูกนำเสนอในคำขอ HTTP ซึ่งห่อหุ้มเป็นค่าในหนึ่งในคู่ของคีย์ / ค่าของแฮชของสภาพแวดล้อม
แอพชั้นวางของเราจะเข้าถึงสตริงข้อความค้นหานั้นจากแฮชของสภาพแวดล้อมและส่งกลับไปยังไคลเอนต์ (เบราว์เซอร์ของเราในกรณีนี้) ผ่านทางเนื้อความในการตอบกลับ
จาก Rack docs บน Environment Hash: "QUERY_STRING: ส่วนของ URL คำขอที่ตามหลัง? ถ้ามีอาจว่างเปล่า แต่จำเป็นเสมอ!"
#./message_app.rb
class MessageApp
def call(env)
message = env['QUERY_STRING']
[200, {}, [message]]
end
end
ตอนนี้rackup
และไปที่localhost:9292?hello
( ?hello
เป็นสตริงข้อความค้นหา) และคุณควรเห็น 'hello' แสดงผลในวิวพอร์ต
เราจะ:
MessageSetter
,env
,MessageSetter
จะแทรก'MESSAGE'
คีย์ลงในแฮช env ค่าของมันคือ'Hello, World!'
ถ้าenv['QUERY_STRING']
ว่างเปล่า;env['QUERY_STRING']
ถ้าไม่,@app.call(env)
- @app
เป็นแอปต่อไปใน MessageApp
'กอง':ครั้งแรกรุ่น 'มือยาว':
#./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
จากเอกสารRack :: Builderเราเห็นว่าRack::Builder
ใช้ DSL ขนาดเล็กไปจนถึงการสร้างแอปพลิเคชัน Rack ซ้ำ ๆ โดยทั่วไปหมายความว่าคุณสามารถสร้าง 'สแต็ค' ซึ่งประกอบด้วยมิดเดิ้ลแวร์หนึ่งรายการขึ้นไปและแอปพลิเคชัน 'ระดับล่าง' เพื่อส่งไปยัง คำขอทั้งหมดที่ดำเนินการผ่านแอปพลิเคชันระดับล่างของคุณจะได้รับการดำเนินการครั้งแรกโดย Middleware ของคุณ
#use
ระบุมิดเดิลแวร์ที่จะใช้ในสแต็ก มันใช้มิดเดิลแวร์เป็นอาร์กิวเมนต์
Middleware ของ Rack ต้อง:
call
วิธีการที่ใช้การแฮชของสภาพแวดล้อมเป็นพารามิเตอร์ในกรณีของเรา 'Middleware' คือMessageSetter
'constructor' เป็นinitialize
เมธอดMessageSetter 'แอปพลิเคชันถัดไป' ในสแต็กคือMessageApp
'ในกองเป็น
ดังนั้นที่นี่เพราะสิ่งที่Rack::Builder
ไม่ภายใต้ประทุนที่app
ข้อโต้แย้งของMessageSetter
's วิธีคือinitialize
MessageApp
(เอาหัวของคุณไปรอบ ๆ ด้านบนก่อนที่จะไปต่อ)
ดังนั้นมิดเดิ้ลของแต่ละชิ้นส่วนใหญ่จะ 'ส่งผ่าน' แฮชของสภาพแวดล้อมที่มีอยู่ไปยังแอปพลิเคชันถัดไปในโซ่ดังนั้นคุณจึงมีโอกาสที่จะกลายพันธุ์ของแฮชของสภาพแวดล้อมนั้นในมิดเดิลแวร์ก่อนส่งต่อไปยัง
#run
รับอาร์กิวเมนต์ที่เป็นวัตถุที่ตอบสนอง#call
และส่งกลับ Rack Response (อินสแตนซ์ของRack::Response
)
การใช้Rack::Builder
คุณสามารถสร้างเครือข่ายของ Middlewares และคำขอใด ๆ ไปยังแอปพลิเคชันของคุณจะถูกประมวลผลโดย Middleware แต่ละรายการก่อนที่จะถูกประมวลผลโดยชิ้นสุดท้ายในสแต็ก (ในกรณีของเราMessageApp
) สิ่งนี้มีประโยชน์มากเพราะแยกขั้นตอนการประมวลผลคำขอที่แตกต่างออกไป ในแง่ของ 'การแยกความกังวล' มันไม่ค่อยสะอาดเท่าไหร่นัก!
คุณสามารถสร้าง 'ไปป์ไลน์ที่ร้องขอ' ซึ่งประกอบด้วยมิดเดิ้ลแวร์จำนวนมากที่จัดการกับสิ่งต่าง ๆ เช่น:
(เหนือสัญลักษณ์แสดงหัวข้อย่อยจากคำตอบอื่นในหัวข้อนี้)
คุณมักจะเห็นสิ่งนี้ในแอปพลิเคชัน Sinatra แบบมืออาชีพ ซินาตร้าใช้ Rack! ดูที่นี่สำหรับความหมายของสิ่งที่ซินาตร้าIS !
ในฐานะที่เป็นโน้ตสุดท้ายเราconfig.ru
สามารถเขียนในรูปแบบของมือสั้นสร้างฟังก์ชั่นที่เหมือนกัน (และนี่คือสิ่งที่คุณมักจะเห็น):
require_relative './message_app'
require_relative './middleware/message_setter'
use MessageSetter
run MessageApp.new
และเพื่อแสดงให้ชัดเจนยิ่งขึ้นว่าMessageApp
กำลังทำอะไรอยู่นี่คือรุ่น 'มือยาว' ที่แสดงให้เห็นอย่างชัดเจนว่า#call
กำลังสร้างอินสแตนซ์ใหม่Rack::Response
ด้วยอาร์กิวเมนต์สามตัวที่จำเป็น
class MessageApp
def call(env)
Rack::Response.new([env['MESSAGE']], 200, {})
end
end
ชั้นวาง - อินเทอร์เฟซ b / w เว็บและเซิร์ฟเวอร์แอป
Rack เป็นแพ็กเกจ Ruby ซึ่งมีอินเตอร์เฟสสำหรับเว็บเซิร์ฟเวอร์เพื่อสื่อสารกับแอปพลิเคชัน มันง่ายในการเพิ่มส่วนประกอบมิดเดิลแวร์ระหว่างเว็บเซิร์ฟเวอร์และแอพเพื่อปรับเปลี่ยนวิธีการทำงานของคำขอ / การตอบสนองของคุณ คอมโพเนนต์มิดเดิลแวร์อยู่ระหว่างไคลเอ็นต์และเซิร์ฟเวอร์ประมวลผลคำร้องขอขาเข้าและตอบกลับขาออก
ในคำพูดของคนธรรมดามันเป็นเพียงชุดของแนวทางสำหรับวิธีเซิร์ฟเวอร์และแอพพลิเค Rails (หรือเว็บแอปทับทิมอื่น ๆ ) ควรพูดคุยกับแต่ละอื่น ๆ
ในการใช้ Rack ให้ระบุ "แอป": วัตถุที่ตอบสนองต่อวิธีการโทรรับแฮชของสภาพแวดล้อมเป็นพารามิเตอร์และส่งกลับ Array ด้วยองค์ประกอบสามประการ:
สำหรับคำอธิบายเพิ่มเติมคุณสามารถไปที่ลิงค์ด้านล่าง
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
ในรางเรามี config.ru เป็นไฟล์ชั้นวางคุณสามารถเรียกใช้ไฟล์ชั้นวางใด ๆ ด้วยrackup
คำสั่ง 9292
และพอร์ตเริ่มต้นสำหรับเรื่องนี้คือ เพื่อทดสอบสิ่งนี้คุณสามารถเรียกใช้rackup
ในไดเรกทอรีรถไฟของคุณและดูผลลัพธ์ นอกจากนี้คุณยังสามารถกำหนดพอร์ตที่คุณต้องการเรียกใช้ คำสั่งเรียกใช้ไฟล์ rack บนพอร์ตเฉพาะใด ๆ คือ
rackup -p PORT_NUMBER
Rack เป็นอัญมณีที่มีอินเตอร์เฟสที่ง่ายต่อการร้องขอ / ตอบกลับ HTTP แบบนามธรรม แร็คตั้งอยู่ระหว่างเฟรมเวิร์กเว็บ (Rails, Sinatra ฯลฯ ) และเว็บเซิร์ฟเวอร์ (ยูนิคอร์น, puma) เป็นอะแดปเตอร์ จากภาพด้านบนสิ่งนี้ทำให้เซิร์ฟเวอร์ยูนิคอร์นเป็นอิสระอย่างสมบูรณ์จากการรู้เกี่ยวกับรางและรางไม่ทราบเกี่ยวกับยูนิคอร์น นี่คือตัวอย่างที่ดีของการมีเพศสัมพันธ์หลวม , แยกของความกังวล
ภาพด้านบนมาจากการพูดคุยการประชุมทางรถไฟบนชั้นวาง https://youtu.be/3PnUV9QzB0gฉันขอแนะนำให้ดูเพื่อความเข้าใจที่ลึกซึ้งยิ่งขึ้น