2

我在 Rails 项目中有一个 Sinatra 类。它使用 eventmachine 和 async_sinatra 对外部站点进行异步调用。我想写入一个会话对象(理想情况下,与 Rails 使用的对象相同),但到目前为止我只能:

  • 从 Rails 写入单独的会话对象(默认情况下,Sinatra 将其会话命名为与 Rails 不同的名称)
  • 仅针对同步调用写入同一会话

当我进行异步调用时,用 async_sinatra 代码编写的会话不会被推送到客户端机器。我怀疑正在发生两件事之一:

  • 标头已经发送到客户端,存储会话的局部变量(在 Sinatra 中)将在操作结束时刷新。客户端永远不会看到来自服务器的将这些数据保存到 cookie 的请求。

  • 标头发送到客户端,但 Rails 立即发送另一个,指示客户端将 Rails 存储在其变量中的内容写入 cookie session,覆盖 Sinatra 写入的内容。

无论哪种方式,我都想在 Sinatra 和 Rails 中获得简单的会话功能。解释我做错了什么也很好:)

代码的完整工作副本在 github 上,但我相信问题出在这段代码中:

class ExternalCall < Sinatra::Base
  use ActionDispatch::Session::CookieStore
  register Sinatra::Async  

  get '/sinatra/local' do
    session[:demo] = "sinatra can write to Rails' session"
  end

  aget '/sinatra/goog' do
    session[:async_call]="async sinatra calls cannot write to Rails' session"
    make_async_req :get, "http://www.google.com/" do |http_callback|
      if http_callback
        session[:em_callback] = "this also isn't saving for me" 
      else
        headers 'Status' => '422'
      end
      async_schedule { redirect '/' }

    end
  end


  helpers do
    def make_async_req(method, host, opts={}, &block)
      opts[:head] = { 'Accept' => 'text/html', 'Connection' => 'keep-alive' }
      http = EM::HttpRequest.new(host)
      http = http.send(method, {:head => opts[:head], :body => {}, :query => {}})
      http.callback &block
    end
  end
end

编辑 7/15

更改了 Github 上的代码以包含 Async-Rack。当会话不与 Rails 共享时,Async-sinatra 可以写入会话。比较mastersegmented_sessions分支的行为差异。(或在master分支上,更改use ActionDispatch::Session::CookieStoreenable :sessions

4

1 回答 1

1

这是因为默认async_sinatra使用throw :async,有效地跳过了用于存储内容的会话中间件逻辑。您可以像这样覆盖async_response

helpers do
  def async_response
    [-1, {}, []]
  end
end
于 2011-07-14T21:10:34.133 回答