【问题标题】:Can I have Sinatra / Rack not read the entire request body into memory?我可以让 Sinatra / Rack 不将整个请求正文读入内存吗?
【发布时间】:2010-06-12 05:08:20
【问题描述】:

假设我有一条 Sinatra 路线 ala:

put '/data' do
  request.body.read
  # ...
end

似乎整个 request.body 都被读入了内存。有没有办法在身体进入系统时将其消耗掉,而不是事先将其全部缓冲在 Rack/Sinatra 中?

我知道我可以这样做以部分读取身体,但整个身体似乎仍然事先被读入内存。

put '/data' do
  while request.body.read(1024) != nil 
    # ...
  end
  # ...
end

【问题讨论】:

    标签: sinatra httprequest rack


    【解决方案1】:

    如果不修补 Sinatra 和/或 Rack,您通常无法避免这种情况。当request.POSTcalled by Sinatra 时由Rack::Request 完成创建params

    但你可以在 Sinatra 前面放置一个中间件来移除主体:

    require 'sinatra'
    require 'stringio'
    
    use Rack::Config do |env|
      if env['PATH_INFO'] == '/data' and env['REQUEST_METHOD'] == 'PUT'
        env['rack.input'], env['data.input'] = StringIO.new, env['rack.input']
      end
    end
    
    put '/data' do
      while request.env['data.input'].body.read(1024) != nil 
        # ...
      end
      # ...
    end
    

    【讨论】:

    • Konstantin - 感谢您的详细回复...您的一些问题需要一两次编辑,我会接受您的回答。 1.(编辑)在你的代码片段中,你能把StrinIO.new改成StringIO.new吗? 2、如果你用Rack来移除body,Rack不会还是将整个body从网络中读取到内存中吗?如果是这种情况,也许对您的答案进行小修改以反映它? 3. 我以前没见过像env['rack.input'], env['data.input'] = StrinIO.new, env['rack.input'] 这样的Ruby。您能否在评论中解释此代码片段在做什么?再次感谢!
    • a,b = 1,2 将 1 分配给 a 并将 2 分配给 b,因此 env['rack.input'], env['data.input'] = StringIO.new, env['rack.input']env['rack.input'] 设置为空的 StringIO 并将其旧值(可能是临时文件句柄)放入 env['data.input']以便您以后参考。
    • BaroqueBobca 是对的。如果您想交换两个变量的值,这种模式尤其常见。假设您有ab,并且想要同时设置a = bb = a。为了不丢失a 的旧值,您必须创建一个临时变量,例如old = a; a = b; b = c。 Ruby 支持另一种语法(Python 也是如此,afaik):a, b = b, a,它避免了临时变量,因为它首先完全评估右手 (b, a),然后进行赋值。
    猜你喜欢
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    相关资源
    最近更新 更多