簡體   English   中英

為什么rails不斷發回Set-Cookie標頭?

[英]Why is rails constantly sending back a Set-Cookie header?

我遇到了彈性負載均衡器和清漆緩存方面的問題,因為cookie和會話在rails和客戶端之間混淆了。 部分問題是,rails幾乎在每個請求上都添加了一個“Set-Cookie”標頭,並且會話ID。 如果客戶端已經發送了session_id,並且它匹配rails將要設置的session_id ..為什么rails會不斷告訴客戶“哦是啊..你的會話ID是......”

簡介:幾乎每個響應都設置了Set-Cookie標頭,因為

  1. 默認會話存儲將嘗試將會話數據寫入已訪問會話的任何請求的加密cookie(要么從中讀取或寫入它),
  2. 即使純文本值沒有,加密值也會改變,
  3. 加密發生在它到達負責檢查cookie值是否已更改以避免冗余Set-Cookie標頭的代碼之前。

純文本cookie

在Rails中, ActionDispatch::Cookies中間件負責根據ActionDispatch::Cookies::CookieJar的內容編寫Set-Cookie響應頭。

正常行為是您所期望的:如果cookie的值沒有從請求的Cookie標頭中更改,並且到期日期沒有更新,那么Rails將不會發送新的Set-Cookie標頭響應。

這由CookieJar#[]=的條件處理, CookieJar#[]=已存儲在cookie jar中的值與正在寫入的新值進行比較。

加密的cookie

為了處理加密的cookie,Rails提供了一個ActionDispatch::Cookies::EncryptedCookieJar類。

EncryptedCookieJar依賴於ActiveSupport::MessageEncryptor來提供加密和解密,每次調用時都使用隨機初始化向量 這意味着即使給出相同的純文本字符串,它幾乎可以保證返回不同的加密字符串。 換句話說,如果我解密我的會話數據,然后重新加密它,我最終會得到一個與我開始的字符串不同的字符串。

EncryptedCookieJar並沒有做太多的事情:它包裝了一個常規的CookieJar ,只是在數據進入時提供加密,並在數據恢復時進行解密。 這意味着CookieJar#[]=方法仍然負責檢查cookie的值是否已經改變,並且它甚至不知道它被賦予的值是加密的。

EncryptedCookieJar這兩個屬性解釋了為什么設置加密cookie而不更改其值將始終產生Set-Cookie標頭。

會話商店

Rails提供不同的會話存儲。 它們中的大多數ActionDispatch::Session::CookieStore話數據存儲在服務器上(例如,在memcached中),但ActionDispatch::Session::CookieStore使用EncryptedCookieJar將所有數據存儲在加密的cookie中。

ActionDispatch::Session::CookieStore繼承了#commit_session? Rack::Session::Abstract::Persisted ,用於確定是否應設置cookie。 如果會話已加載,則答案幾乎總是“是,設置cookie”。

正如我們已經看到的那樣,在會話已加載但未更改的情況下,我們仍然會以不同的加密值結束,因此也就是Set-Cookie標頭。

請參閱@georgebrock的答案,了解為何會發生這種情況。 修補rails很容易將此行為更改為僅在會話更改時設置cookie。 只需將此代碼放在initializers目錄中即可。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM