我在 Rails 项目中有一个 Sinatra 类。它使用 eventmachine 和 async_sinatra 对外部站点进行异步调用。我想写入一个会话对象(理想情况下,与 Rails 使用的同一个),但到目前为止我只能:
- 写入 Rails 中的一个单独的会话对象(默认情况下,Sinatra 将其会话命名为与 Rails 不同的名称) )
- 写入同一会话仅同步调用
当我进行异步调用时,以 async_sinatra 代码编写的会话不会被推送到客户端计算机。我怀疑发生了以下两件事之一:
不管怎样,我只想在 Sinatra 和 Rails 中获得简单的会话功能。对我做错了什么的解释也很好:)
代码的完整工作副本是 ,但我相信问题具体出在这段代码中:
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
)
I have a Sinatra class in a Rails project. It uses eventmachine and async_sinatra to make asynchronous calls to external sites. I'd like to write to a session object (ideally, the same one that Rails is using), but so far I can only:
- write to a separate session object from Rails' (by default, Sinatra names its session something different from Rails)
- write to the same session for synchronous calls only
When I make asynchronous calls, sessions written in the async_sinatra code don't get pushed out to the client machine. I suspect one of two things is happening:
-
The header has already been sent to the client and the local variable storing the session (in Sinatra) will be flushed out at the end of the action. The client would never see a request from the server to save this data to a cookie.
-
The header is being sent to the client, but Rails immediate sends another, instructing the client to write to the cookie what Rails has stored in its session
variable, overwriting what Sinatra wrote.
Either way, I'd like to just get simple session functionality in both Sinatra and Rails. An explanation of what I'm doing wrong would also be nice :)
A full working copy of the code is on github, but I believe the problem is specifically in this code:
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
EDIT 7/15:
Changed code on Github to include Async-Rack. Async-sinatra can write to sessions when they are not shared with Rails. Compare the master
and segmented_sessions
branches for behavior difference. (Or on the master
branch, change use ActionDispatch::Session::CookieStore
to enable :sessions
)
发布评论
评论(1)
这是因为
async_sinatra
默认情况下使用throw :async
,有效地跳过了用于存储内容的会话中间件逻辑。您可以像这样覆盖 async_response那:This is because
async_sinatra
usesthrow :async
by default, effectively skipping the session middleware logic for storing stuff. You could override async_response like that: