2015-10-07 30 views
2

我想基於響應主體的大小有條件地允許Rack::Deflater,就像這樣:機架:: Deflater和機架:: URLMap

use Rack::Deflater, :if => lambda { |*, body| body.map(&:bytesize).reduce(0, :+) > 512 } 

如果我裏面插入我的機架應用之一Rack::Deflater中間件,這個lambda工作正常; body是一串字符串。但是,如果我在Rack::URLMapconfig.ru)之前插入Rack::Deflater中間件,則不會;因爲body現在是一個Rack::BodyProxy對象。

我查看了Rack::BodyProxy的定義,看起來有點不透明。沒有一個明確的方法來解決這個對象的實際身體; body.body返回nil。在這種情況下,最簡單/最好的方式決定響應體的大小,而不是將Rack::Deflater中間件向下移動到每個Rack應用程序中?

tl; dr:如何確定給定Rack::BodyProxy對象的響應主體的大小?

回答

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 
} 

UPDATE: 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) 
} 

遠離優雅...