Ruby中的机架中间件是什么?对于他们所说的“中间件”,我找不到任何好的解释。
当前回答
我使用Rack中间件解决了几个问题:
使用自定义机架中间件捕获JSON解析错误,并在客户端提交错误JSON时返回格式化良好的错误消息 内容压缩通过机架::Deflater
在这两种情况下,它都提供了相当优雅的修复。
其他回答
机架- Web和应用服务器的接口
Rack是一个Ruby包,它为web服务器提供了与应用程序通信的接口。在web服务器和应用程序之间添加中间件组件来修改请求/响应的行为方式是很容易的。中间件位于客户机和服务器之间,处理入站请求和出站响应。
通俗地说,它基本上只是一组指导方针,说明服务器和Rails应用程序(或任何其他Ruby web应用程序)应该如何相互通信。
要使用Rack,提供一个“app”:一个响应调用方法的对象,将环境哈希作为参数,并返回一个包含三个元素的数组:
HTTP响应代码 标头哈希 响应体,必须响应每个请求。
欲了解更多解释,请点击以下链接。
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
在rails中,我们将config.ru作为一个机架文件,您可以使用rackup命令运行任何机架文件。默认端口是9292。要测试这一点,只需在rails目录中运行rackup并查看结果。您还可以指定要在哪个端口上运行它。在任何特定端口上运行机架文件的命令为
rackup -p PORT_NUMBER
在很长一段时间里,我自己都无法理解Rack。我是在自己制作了这个小型Ruby web服务器之后才完全理解它的。我在我的博客http://blog.gauravchande.com/what-is-rack-in-ruby-rails上分享了我对Rack的了解(以故事的形式)
非常欢迎反馈。
Rack middleware is a way to filter a request and response coming into your application. A middleware component sits between the client and the server, processing inbound requests and outbound responses, but it's more than interface that can be used to talk to web server. It’s used to group and order modules, which are usually Ruby classes, and specify dependency between them. Rack middleware module must only: – have constructor that takes next application in stack as parameter – respond to “call” method, that takes environment hash as a parameter. Returning value from this call is an array of: status code, environment hash and response body.
首先,Rack就是两件事:
web服务器接口约定 一颗宝石
机架- web服务器接口
机架的基本原理是一个简单的约定。每一个机架兼容的web服务器将总是调用一个调用方法在你给他的对象上,并提供该方法的结果。Rack精确地指定了这个调用方法必须是什么样子,以及它必须返回什么。这是架。
让我们简单地试一试。我将使用WEBrick作为机架兼容的web服务器,但它们中的任何一个都可以。让我们创建一个返回JSON字符串的简单web应用程序。为此,我们将创建一个名为config.ru的文件。config.ru将自动被机架gem的命令rackup调用,该命令将简单地在机架兼容的web服务器中运行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
按照约定,我们的服务器有一个叫做call的方法,它接受一个环境散列,并返回一个格式为[status, headers, body]的数组供web服务器服务。让我们通过简单地调用rackup来尝试一下。一个默认的机架兼容服务器,可能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
让我们通过卷曲或访问url http://localhost:9292/hello.json来测试我们的新JSON服务器,瞧:
$ curl http://localhost:9292/hello.json
{ message: "Hello!" }
它的工作原理。太棒了!这是每个web框架的基础,无论是Rails还是Sinatra。在某种程度上,它们实现了一个调用方法,遍历所有框架代码,最后以典型的[状态,标题,正文]形式返回响应。
例如,在Ruby on Rails中,机架请求命中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。因此,任何符合机架接口约定的web服务器都能够为一个完全成熟的Rails应用程序提供服务。
中间件
Rack还支持中间件层的创建。他们基本上拦截一个请求,处理它,然后传递出去。这对于多功能任务非常有用。
假设我们想要向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返回的那样。
因此,在这个中间件中,取起始点,然后使用@app.call(env)对JSONServer进行实际调用,然后记录器输出日志记录条目,最后以[@status, @headers, @body]的形式返回响应。
为了让我们的小rackup.ru使用这个中间件,添加一个use 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
重新启动服务器,瞧,它对每个请求都输出一条日志。Rack允许您添加多个按照添加顺序调用的中间件。这是一种在不改变机架应用程序核心的情况下添加功能的好方法。
机架-宝石
虽然机架-首先-是一个惯例,它也是一个宝石,提供了伟大的功能。其中一个我们已经在JSON服务器上使用过,即rackup命令。但还有更多!rack gem为很多用例提供了小的应用程序,比如服务静态文件甚至整个目录。让我们看看我们是如何提供一个简单的文件的,例如一个非常基本的HTML文件,位于htmlls /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下创建一些javascript文件来添加一个完整的javascript文件目录,并将以下内容添加到config.ru:
map '/javascripts' do
run Rack::Directory.new "javascripts"
end
重新启动服务器并访问http://localhost:9292/javascript,你会看到一个列表,上面列出了你可以直接从任何地方包含的所有javascript文件。
Rack提供了一个简单的接口来抽象HTTP请求/响应。Rack位于web框架(Rails, Sinatra等)和web服务器(unicorn, puma)之间,作为适配器。从上图来看,这使得unicorn服务器完全独立于了解rails的服务器,而rails不知道unicorn的服务器。这是一个松耦合、关注点分离的好例子。
上图来自机架https://youtu.be/3PnUV9QzB0g上的rails会议演讲,我建议观看它以获得更深入的理解。
推荐文章
- VS2013外部构建错误"error MSB4019: The imported project <path> was not found"
- Rails:如何在Rails 4中引用CSS中的图像
- 为什么说“HTTP是无状态协议”?
- 我需要HTTP GET请求的内容类型报头吗?
- 如何使用RSpec的should_raise与任何类型的异常?
- 如何创建退出消息
- 忽略GEM,因为没有构建它的扩展
- Rails -嵌套包括活动记录?
- 在Gem::Specification.reset期间未解决的规格:
- Delete_all vs destroy_all
- 双引号vs单引号
- 用any可以吗?'来检查数组是否为空?
- Rails获取“each”循环的索引
- 如何让Chrome允许混合内容?
- Ruby类实例变量与类变量