我想根据响应正文的大小有条件地启用Rack::Deflater
,如下所示:
use Rack::Deflater, :if => lambda { |*, body| body.map(&:bytesize).reduce(0, :+) > 512 }
如果我在我的一个Rack应用程序中插入Rack::Deflater
中间件,这个lambda工作正常; body
是一个字符串数组。但是,如果我在Rack::Deflater
之前插入Rack::URLMap
中间件(在config.ru
中),则不会;因为body
现在是Rack::BodyProxy
对象。
我查看了Rack::BodyProxy
定义,看起来有点不透明。没有一种明确的方法可以从这个对象中解析实际的身体; body.body
返回nil
。在这种情况下,最简单/最好的方法是什么决定响应体大小,而不是将Rack::Deflater
中间件移动到我的每个Rack应用程序中?
tl; dr :如何在给定Rack::BodyProxy
对象的情况下确定响应主体的大小?
答案 0 :(得分:1)
看起来Rack::BodyProxy
确实提供#each
方法作为问题rack/rack#434的解决方法。此方法返回私有@body
ivar元素的枚举器。在调用链中添加.each
可以解决Rack::BodyProxy
个对象的这个问题,对于更普通的基于数组的实体来说,这是一个无操作的问题,所以现在这让我得到了我需要的地方。但是,我仍然想了解为什么我会得到这些对象,以及是否有更好的方法来处理它们。
以下是修改后的工作解决方案:
use Rack::Deflater, :if => lambda { |*, body|
body.each.map(&:bytesize).reduce(0, :+) > 512
}
更新:Hrrm,有时body
是Rack::BodyProxy
个对象,body.body
是Rack::Response
个对象。这有点失控......!这是我现在使用的解决方案:
use Rack::Deflater, :if => lambda { |*, body|
body.map(&:bytesize).reduce(0, :+) > 512 \
if body.respond_to?(:map) \
or body.respond_to?(:each) and (body = body.each).respond_to?(:map)
}
远非优雅......