我在 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 可以写入会话。比较master
和segmented_sessions
分支的行为差异。(或在master
分支上,更改use ActionDispatch::Session::CookieStore
为enable :sessions
)