1. 程式人生 > >Cookie的優先順序,你可能誤解的

Cookie的優先順序,你可能誤解的

關鍵字:Cookie,優先順序(Precedence, Priority)

問題

Server端分別在不同的域(domain)或者不同的路徑(Path)添加了名字相同的Cookie,比如:

Cookie名 域名 Path
tokenId mydomain.com / root domain token
tokenId sub1.mydomain.com / sub1 domain token
tokenId sub2.mydomain.com / sub2 domain token
tokenId sub1.mydomain.com /us/index.action sub1 domain /us/index.do token
現在向sub1.mydomain.com/us/index.action傳送請求,request傳送到伺服器的cookie裡tokenId會是什麼呢?

答案

多個值一起帶去,tokenId=root domain token;tokenId=sub1.mydomain.com;tokenId=sub2 domain token;tokenId=sub1 domain /us/index.do token;

吃驚吧!我本以為同名Cookie會根據domain和path有優先順序的。做了個相同domain不同path下同名Cookie的實驗,發現在Header裡面同名Cookie的兩個值都帶去了,也有人做root域和sub域的實驗,也是這種情況(

詳述)。我沒有查到RFC或者其它官方文件裡給出的詳述,但有資料說所有值都會帶去,並且順序是不固定的

標準答案

4.2.2

   In particular,if the Cookie header contains two cookies with the same name (e.g.,
   that were set with different Path or Domain attributes), servers
   SHOULD NOT rely upon the order in which these cookies appear in the
   header.
5.3.  Storage Model

  2.  The user agent SHOULD sort the cookie-list in the following
       order:

       *  Cookies with longer paths are listed before cookies with
          shorter paths.

       *  Among cookies that have equal-length path fields, cookies with
          earlier creation-times are listed before cookies with later
          creation-times.

       NOTE: Not all user agents sort the cookie-list in this order, but
       this order reflects common practice when this document was
       written, and, historically, there have been servers that
       (erroneously) depended on this order.
大概就是:RFC推薦在request header中瀏覽器能夠按path的長短排序,越長說明匹配的越精確,順序越靠前。同時也說明並不是所有的瀏覽器都遵守這個,並且伺服器也不應該依賴於cookie出現的順序。

源自於對一個解決方案的思考

我對Cookie的興趣來自sessionid cookie,因為它用來維持request和伺服器端session的匹配。有一個場景,如下圖所示:


Web應用由Apache後面的兩個子應用支撐。瀏覽器傳送請求給Apache後:

  • Apache會根據URL反向代理(reverse proxy)到Server1或者Server2;
  • Server 1和Server 2都會為請求建立session,就產生名為sessionid的session cookie;
  • Server 2也可能作為伺服器端代理,需要能夠從request中該瀏覽器對server 1的session id,從而代替使用者從server 1獲取一些資訊。

我原本的思路是:

將Server 1的sessionid cookie的path設定成根路徑(/);將server 2的sessionid cookie的path設定成相對具體的路徑,比如/server2/。假設同名cookie有優先順序,那麼路徑具體的cookie的值就會優先帶回,那麼我就可以同時保持對Server 1和Server 2兩個子應用的session了。在Server 2的session沒建立時,我也可以在Server 2通過request header拿到Server 1的session。

不隨我願啊!

看來現在可行的方式只有:

Server 1的子應用是成熟的產品,不能修改,只能把Server 2做成sessionless的了,以Server 1的sessionid做主鍵,在Server 2把使用者資訊儲存到記憶體資料庫中,以此來維護上下文資訊。

一個擔心:

如果Server 2子應用的開發者一不小心建立了session呢,這時候它產生的sessionid cookie可能干擾Server 1對session id和session的對映啊!!並且恰恰兩個server都是在一個domain下。有什麼方法可以強迫Server 2永遠無法建立session呢?思考中,請大俠教我。。。

解決方案:

多謝Apache Tomcat。我們的應用部署在Apache Tomcat中,Tomcat 5.5之後的版本可以修改預設的sessionid cookie的key值,方式很簡單,在bin/catalina.bat中新增如下引數:

JAVA_OPTS="$JAVA_OPTS 
             -Dorg.apache.catalina.SESSION_COOKIE_NAME=MYJSESSIONID 
             -Dorg.apache.catalina.SESSION_PARAMETER_NAME=myjsessionid"

把兩個session id的key值修改下,就不會相互干擾了!