如何从 Rails 内部访问 Rack 环境?
-
21-08-2019 - |
题
我有一个 Rack 应用程序,如下所示:
class Foo
def initialize(app)
@app = app
end
def call(env)
env["hello"] = "world"
@app.call(env)
end
end
将我的 Rack 应用程序挂接到 Rails 后,如何访问 env["hello"]
从 Rails 内部?
更新:感谢盖乌斯的回答。Rack 和 Rails 允许您在请求期间或会话期间存储内容:
# in middleware
def call(env)
Rack::Request.new(env)["foo"] = "bar" # sticks around for one request
env["rack.session"] ||= {}
env["rack.session"]["hello"] = "world" # sticks around for duration of session
end
# in Rails
def index
if params["foo"] == "bar"
...
end
if session["hello"] == "world"
...
end
end
解决方案
我很确定你可以使用 Rack::Request
用于传递请求范围变量的对象:
# middleware:
def call(env)
request = Rack::Request.new(env) # no matter how many times you do 'new' you always get the same object
request[:foo] = 'bar'
@app.call(env)
end
# Controller:
def index
if params[:foo] == 'bar'
...
end
end
或者,你可以得到“env
" 直接对象:
# middleware:
def call(env)
env['foo'] = 'bar'
@app.call(env)
end
# controller:
def index
if request.env['foo'] == 'bar'
...
end
end
其他提示
简短回答: 使用 request.env
或者 env
在控制器内。
长答案:
根据 Rails 控制器上的 Rails 指南, ,ActionController提供了一个 request
您可以使用该方法来访问有关控制器正在响应的当前 HTTP 请求的信息。
进一步检查文档后 ActionController::Base#request
, ,我们看到它“返回一个代表当前请求的 ActionDispatch::Request 实例”。
如果我们查看文档 ActionDispatch::Request
, ,我们看到它继承自 Rack::Request
. 。啊哈!开始了。
现在,如果您不熟悉以下文档 Rack::Request
, ,它基本上是 Rack 环境的包装器。因此,在大多数情况下,您应该能够按原样使用它。如果你确实想要原始环境哈希,你可以使用 Rack::Request#env
. 。所以在 Rails 控制器中,那就是 request.env
.
深层发掘:
进一步检查实例方法后 ActionController::Base
, ,我注意到那里没有太多可看的东西。我特别注意到 params
和 session
变量似乎缺失。所以,我提升了一级 ActionController::Metal
, , 哪个 ActionController::Base
继承自.
在 ActionController::Metal
,我发现了一个方法 env
没有关于它做了什么的文档 - 但我可以猜到。事实证明我是对的。该变量是 被分配给 request.env
.
ActionController::Metal
还包含了 params
方法,其中,根据 来源, ,被设置为 request.parameters
默认情况下。事实证明, request.parameters
不是来自 Rack::Request
, , 但 ActionDispatch::Http::参数, ,它包含在 ActionDispatch::Request
. 。这个方法非常类似于 Rack::Request#params
方法,除了改变它会修改 Rails 特定的 Rack 环境变量(因此更改将在 ActionDispatch::Request
).
然而我似乎还是没能找到 session
方法。事实证明,它根本不在文档中。搜索源码后 ActionController::Metal
, ,我终于找到了 这条线. 。没错,这只是一个捷径 请求会话.
总结一下:
在控制器中...
- 使用
request.env
或者env
获取原始环境对象 - 使用
params
读取机架查询字符串并从机架输入流发布数据。(例如。Rack::Request#params
) - 使用
session
来访问的值rack.session
在机架环境中
在中间件...
- 通过环境哈希以通常的方式访问环境的属性
- 通过以下方式访问 Rails 会话
rack.session
环境哈希上的属性 - 读取参数通过
Rack::Request#params
- 通过更新参数
Rack::Request#update_param
和Rack::Request#delete_param
(如文档中所述Rack::Request#params
) - 使用 Rails 特定方式更新参数
ActionDispatch::Http::Parameters#params
通过ActionDispatch::Request