Rack :: Deflater和Rack :: URLMap

时间:2015-10-07 23:09:50

标签: ruby rack

我想根据响应正文的大小有条件地启用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对象的情况下确定响应主体的大小?

1 个答案:

答案 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,有时bodyRack::BodyProxy个对象,body.bodyRack::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)
}

远非优雅......