首先,web應用程序是使用HTTP協議進行數據傳輸,由於HTTP協議是無狀態的,因此一旦提交數據完成後,客戶端和服務器端的鏈接就會被關閉,再次進行數據的交換就得從新創建新的鏈接,那麼,有個問題就是服務器沒法經過鏈接來跟蹤用戶的會話。接下來,對於Session和Cookie這個技術就出來了。html
簡單介紹一下Session和Cookie:python
Session:經過在服務器端記錄用戶信息從而來確認用戶身份,保存在服務器上,每一個用戶會話都有一個對應的sessionweb
Cookie:經過在客戶端記錄信息確認身份,客戶端瀏覽器會把Cookie保存起來,當再次訪問的時候,把該Cookie一同提交給服務器,就能夠進行用戶的辨認了redis
工做時,須要對Tornado的Cookie設置過時時間,而後對於Tornado來講,查看源碼得知對Cookie的處理有4個方法。chrome
下面給出4個方法的源碼:瀏覽器
版本說明: Tornado版本爲4.4.2緩存
a. get_cookie()服務器
def get_cookie(self, name, default=None): """Gets the value of the cookie with the given name, else default.""" if self.request.cookies is not None and name in self.request.cookies: return self.request.cookies[name].value return default
能夠從源碼註釋中容易的明白,其爲獲取cookie的方法,經過給予參數name後拿到cookie的值cookie
b. set_cookie()session
def set_cookie(self, name, value, domain=None, expires=None, path="/", expires_days=None, **kwargs): """Sets the given cookie name/value with the given options. Additional keyword arguments are set on the Cookie.Morsel directly. See http://docs.python.org/library/cookie.html#morsel-objects for available attributes. """ # The cookie library only accepts type str, in both python 2 and 3 name = escape.native_str(name) value = escape.native_str(value) if re.search(r"[\x00-\x20]", name + value): # Don't let us accidentally inject bad stuff raise ValueError("Invalid cookie %r: %r" % (name, value)) if not hasattr(self, "_new_cookie"): self._new_cookie = Cookie.SimpleCookie() if name in self._new_cookie: del self._new_cookie[name] self._new_cookie[name] = value morsel = self._new_cookie[name] if domain: morsel["domain"] = domain if expires_days is not None and not expires: expires = datetime.datetime.utcnow() + datetime.timedelta( days=expires_days) if expires: morsel["expires"] = httputil.format_timestamp(expires) if path: morsel["path"] = path for k, v in kwargs.items(): if k == 'max_age': k = 'max-age' # skip falsy values for httponly and secure flags because # SimpleCookie sets them regardless if k in ['httponly', 'secure'] and not v: continue morsel[k] = v
這個是對Cookie的設置方法,看到expires和expires_days彷佛就是咱們所要用到的過時時間的設置項
c. get_secure_cookie()
def get_secure_cookie(self, name, value=None, max_age_days=31, min_version=None): """Returns the given signed cookie if it validates, or None. The decoded cookie value is returned as a byte string (unlike `get_cookie`). .. versionchanged:: 3.2.1 Added the ``min_version`` argument. Introduced cookie version 2; both versions 1 and 2 are accepted by default. """ self.require_setting("cookie_secret", "secure cookies") if value is None: value = self.get_cookie(name) return decode_signed_value(self.application.settings["cookie_secret"], name, value, max_age_days=max_age_days, min_version=min_version)
這個get_secure_cookie()也是獲取cookie的方法,可是和上面的get_cookie()不一樣在於這個cookie值是一個加密的字符串,經過加密傳輸,可是get_cookie()是明文進行傳輸的,而後還注意到有一個參數 max_age_day=31,這個能夠結合下面set_secure_cookie進行理解
d. set_secure_cookie()
def set_secure_cookie(self, name, value, expires_days=30, version=None, **kwargs): """Signs and timestamps a cookie so it cannot be forged. You must specify the ``cookie_secret`` setting in your Application to use this method. It should be a long, random sequence of bytes to be used as the HMAC secret for the signature. To read a cookie set with this method, use `get_secure_cookie()`. Note that the ``expires_days`` parameter sets the lifetime of the cookie in the browser, but is independent of the ``max_age_days`` parameter to `get_secure_cookie`. Secure cookies may contain arbitrary byte values, not just unicode strings (unlike regular cookies) .. versionchanged:: 3.2.1 Added the ``version`` argument. Introduced cookie version 2 and made it the default. """ self.set_cookie(name, self.create_signed_value(name, value, version=version), expires_days=expires_days, **kwargs)
經過查看該方法,咱們能夠發現,其實該方法就是對第一個set_cookie的進一步封裝,經過註釋能夠知道:要使用這個方法對cookie進行設置,必須在項目的Application中,定義一個「cookie_secret」 --> 這個cookie_secret應該是隨機的,而且長字符串,固然你能夠設置成你本身定義的固定的字符串。而後還有一個參數expires_days特別須要值得注意,這裏若是咱們不進行設置的話,cookie的過時時間將爲30天,固然,這個跟get_secure_cookie中的max_age_day是相互獨立的。
接下來,咱們經過源碼分析後,咱們想對cookie設置過時時間,只須要在set_secure_cookie()函數中,將expires_day進行重寫就能夠了。
這裏須要注意一下幾點,是我在設置過程當中踩過的坑,記錄下來:
1.這個設置過時時間的參數 expires_day,若是想以秒做爲過時單位的話,應該這樣寫:expires_day = time.time() + 對應的秒數
2.若是想設置,關閉瀏覽器就清楚cookie的話,應該這樣設置,將過時時間重寫置空:expires_day = None
3.這個問題,也是我遇到最蛋疼的問題,當時,我設置後,設置關閉瀏覽器清楚cookie一直沒法失效,還一度懷疑是tornado對於chorme瀏覽器的bug,以後發現瞭解決辦法,請看圖:
就是由於chrome這個設置選項,默認是勾選了「關閉瀏覽器後繼續運行後臺應用」,因此我每次關閉瀏覽器打開後cookie永遠不會失效。(Ubuntu系統,不一樣ps去查看系統進程的話根本發現不了沒有關閉chrome的進程)
最後總結一下,Session和Cookie在整個項目中具體的設置和開發方法:
兩種狀態:
1.對於登錄是會話級別的,就是在系統上面一直有操做的,能夠自定義cookie的過時時間
2.對於客戶端來講,選擇關閉瀏覽器就清楚cookie
開發方法:
1.對於登錄是會話級別,當用戶一直有操做的時候,咱們不能讓cookie直接過時,因此咱們在調用set_secure_cookie時,應該設置expires_day=None(關閉瀏覽器直接過時,若是expires_day後面有過時時間的話,會致使用戶在操做途中直接cookie過時而要求從新登錄);
2.而後,咱們如何保持用戶在沒有操做的一段時間後進行過時呢? 這就要看咱們的記錄在服務器端的session了,通常咱們會把服務器端的session存儲在memcache、redis等緩存服務器中,而後設置相應的緩存過時時間,每次當用戶在系統上面有操做,有請求發生的時候,咱們就重寫緩存,重置session的過時時間,當用戶一段時間沒有操做的時候,存儲在緩存中的session就會過時被清除,當用戶再次發送請求後發現沒法找到對應的session,從而讓用戶沒法進行相應的操做客戶端會提示從新登錄。這樣子,就能夠實現當用戶有操做就不過時,沒有操做就在必定的時間斷內過時要求用戶從新登錄了。