我遇到了关于Cookie和会话在弹道和客户端之间混淆的弹性负载均衡器和清漆缓存问题。部分问题是,rails正在添加一个" Set-Cookie"几乎每个请求都有一个会话ID。如果客户端已经在发送session_id,并且它匹配rails将要设置的session_id ..为什么rails会不断地告诉客户"哦是啊..你的会话ID是......"
答案 0 :(得分:9)
摘要: Set-Cookie
标题几乎都在每个回复中设置,因为
Set-Cookie
标头的代码之前。在Rails中,ActionDispatch::Cookies
中间件负责根据Set-Cookie
的内容编写ActionDispatch::Cookies::CookieJar
响应标头。
正常行为是您所期望的:如果cookie的值没有从请求的Cookie
标头中更改,并且有效期未更新,则Rails将不会发送响应中新的Set-Cookie
标头。
这由CookieJar#[]=
中的条件处理,它将已存储在cookie jar中的值与正在写入的新值进行比较。
为了处理加密的cookie,Rails提供了ActionDispatch::Cookies::EncryptedCookieJar
类。
EncryptedCookieJar
依赖于ActiveSupport::MessageEncryptor
来提供加密和解密,每次调用时都使用随机initialisation vector。这意味着即使给出相同的纯文本字符串,它几乎可以保证返回不同的加密字符串。换句话说,如果我解密我的会话数据,然后重新加密它,我最终会得到一个与我开始的字符串不同的字符串。
EncryptedCookieJar
并没有做太多的事情:它包装了一个普通的CookieJar
,只是在数据进入时提供加密,并在数据恢复时进行解密。这意味着CookieJar#[]=
方法仍然负责检查cookie的值是否已更改,并且它甚至不知道已经给出的值已加密。
EncryptedCookieJar
的这两个属性解释了为什么设置加密Cookie而不更改其值将始终产生Set-Cookie
标题。
Rails提供不同的会话存储。其中大多数将会话数据存储在服务器上(例如,在memcached中),但默认值为ActionDispatch::Session::CookieStore
- 使用EncryptedCookieJar
将所有数据存储在加密的cookie中。
ActionDispatch::Session::CookieStore
从#commit_session?
继承Rack::Session::Abstract::Persisted
方法,该方法确定是否应设置Cookie。如果会话被加载,那么答案几乎总是“是的,设置cookie”。
正如我们已经看到的那样,在会话已加载但未更改的情况下,我们仍将以不同的加密值结束,因此标题为Set-Cookie
。
答案 1 :(得分:0)
请参阅@georgebrock的答案以了解发生这种情况的原因。修补rails来更改此行为以仅在会话更改时设置cookie相当容易。只需将此代码放在初始化程序目录中即可。
require 'rack/session/abstract/id' # defeat autoloading
module ActionDispatch
class Request
class Session # :nodoc:
def changed?;@changed;end
def load_for_write!
load! unless loaded?
@changed = true
end
end
end
end
module Rack
module Session
module Abstract
class Persisted
private
def commit_session?(req, session, options)
if options[:skip]
false
else
has_session = session.changed? || forced_session_update?(session, options)
has_session && security_matches?(req, options)
end
end
end
end
end
end