使用异步Sinatra流式传输多个正文

3

我希望从JavaScript发起一个长轮询请求,这很好,我期望我的Ruby程序将多个主体部分流式传输到JavaScript。为什么以下(伪)代码不起作用?

require 'rubygems'
require 'sinatra/async'
require 'eventmachine'
require 'thin'
require 'json'

    class Test < Sinatra:Base
      register Sinatra::Async

      aget '/process' do
        for c in 1..10
          body {
            { :data => [ "this is part #{c}" ] }.to_json
          end
        end
      end

      run!
    end

也许我误解了长轮询和异步的作用,但我的期望是能够向客户端发送多个响应体?我需要使用EventMachine或其他什么东西吗?
谢谢。

我现在也在处理这个问题。据我所知,body会关闭请求写入流并发送它。如果你连续两次调用body 'asdf',你只会在页面上看到'asdf'。我发现有一个线索建议使用write或response.write代替。这似乎更好,因为我可以看到浏览器中仍然保持着我的连接。但问题又来了,连续两个write调用的行为不符合预期。 - Eric Hu
赏金信息:我将奖励给能够做到以下两点之一的人:A)解释为什么这种方法不可行(例如由于某些HTTP规范,我怀疑)。B)提供代码以写入正文并在浏览器中显示,然后在2秒钟后写入正文并更新在浏览器中显示。请提供参考或工作代码,除非您希望有人修改您的答案并获得赏金奖励 :) - Eric Hu
抱歉回复晚了,但我重新开始处理这项工作(1.5年后)。因此,这里的用例是例如,如果您通过网页触发FTP操作。在该网页中,我希望实时检索上传的字节。有很多使用netftp的示例,显示输出到命令行。但我认为您的代码展示了如何通过网页完成此操作。我还想通过Ramaze而不是Sinatra来完成这个操作。 - gurpal2000
2个回答

6
require 'rubygems'
require 'sinatra/async'
require 'thin'
require 'json'

class Test < Sinatra::Base
  register Sinatra::Async

  class JSONStream
    include EventMachine::Deferrable

    def stream(object)
      @block.call object.to_json + "\n"
    end

    def each(&block)
      @block = block
    end
  end

  aget '/process' do
    puts 'ok'
    out = JSONStream.new
    body out
    EM.next_tick do
      c = 0
      timer = EM.add_periodic_timer(0.3) do
        c += 1
        out.stream :data => ["this is part #{c}"]
        if c == 100
          timer.cancel
          out.succeed
        end
      end
    end
  end

  run!
end

另请参阅:http://confreaks.net/videos/564-scotlandruby2011-real-time-rack

这里有关于实时Rack的视频。

我还在听演讲的过程中,但这段代码可以用于流式传输。非常感谢您的快速回复(以及进行此次演讲,直到现在我才意识到这是您)。 (StackOverflow要求我等待6个小时才能授予悬赏) - Eric Hu
顺便说一句,我想帮忙撰写一些文档,让其他人不必花费太多时间来弄清这个过程。我相信在此过程中我也会学到一些有用的信息。您对放置HTTP流文档的位置或要添加到哪些项目上有任何建议吗? - Eric Hu
1
我不知道。它并没有得到 Rack 的官方支持,所以好的选择可能是 async_sinatra、我的 async-rack 项目(更像是一个 hack)、thin,或者,嗯,不知道……为 Rack 的异步扩展制定一些规范也很好,这样可以方便其他服务器实现它。 - Konstantin Haase
此外,这种方法是可行的。实际上,它应该能够产生相当不错的性能,并且能够同时处理多个请求。 - Konstantin Haase
你有没有读过关于Rails 3.1中的HTTP流的相关内容?我正在尝试弄清楚是否可以使用新功能来异步地流式传输和推送页面组件。我的印象是,异步地推送页面组件只能将数据追加到页面底部,需要一些客户端JavaScript来将其移动到其他位置。 - Eric Hu
是的,没错。要在Rails 3.1中使用Thin/EventMachine进行流式传输,您可以使用类似于这样的东西 - Konstantin Haase

1

在下面的示例中,似乎需要一个EventMachine事件来触发发送多个主体。还可以参见此前的答案

require 'sinatra/async'

 class AsyncTest < Sinatra::Base
   register Sinatra::Async

   aget '/' do
     body "hello async"
   end

   aget '/delay/:n' do |n|
     EM.add_timer(n.to_i) { body { "delayed for #{n} seconds" } }
   end

 end

1
抱歉,但是这个怎么发送多个主体?它只是发送一个延迟的异步响应? - gurpal2000
据我所知,这会发送一个被延迟n秒的主体。也许有些混淆,因为gurpal想要发送多个请求体,或以流式方式发送一个请求体,使其在有新数据时进行更新。 - Eric Hu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接