你是タコたち嗎?你喜歡吃cookies嗎?那麼你知道cookies是怎麼被製造出來的嗎?
cookies是在瀏覽器儲存的小小資料片段,通常來說當瀏覽器發出request時,有可能同時將cookie發送出去。利用這個特性,可以將通常來說無狀態的HTTP保有記憶,做到登入功能、追蹤行爲等等。
雖然我們可以透過瀏覽器開發工具新增cookie。
但通常這是由Web Server製造,然後透過Response Headers發送給瀏覽器。
這次同樣使用FastAPI建立Web Server提供服務。首先先安裝一下相關套件:
pip install fastapi uvicorn
然後建立index.html
檔案,利用JavaScript將cookie顯式在畫面上:
<!-- index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>takodachi cookies</title>
</head>
<body>
<img alt="" src="https://i.ytimg.com/vi/me4Es5Yqhxk/maxresdefault.jpg"/>
<textarea cols="30" id="display_cookie" name="" rows="10"></textarea>
<script type="text/javascript">
window.addEventListener('load', () => {
console.log(document.cookie);
let textarea = document.querySelector('#display_cookie');
textarea.value = document.cookie;
});
</script>
</body>
</html>
然後同樣利用FileResponse
將index.html
提供給瀏覽器。建立app.py
檔案並輸入以下內容
# app.py
from fastapi import FastAPI
from fastapi.responses import FileResponse, Response
app = FastAPI()
@app.get('/index.html')
def index():
headers = {
'Set-Cookie': 'name=takodachi;',
}
return FileResponse('index.html', headers=headers)
不同的是:需要添加一個自定義的Header,格式爲:Set-Cookie: <key>=<value>
,比如:Set-Cookie: hello=world
。不過<key>
和<value>
還是有一些限制在,有一些字符是具有特殊意義,所以有可能將<value>
使用百分號編碼方式處理。
啓動服務器
uvicorn app:app
然後瀏覽 http://localhost:8000/index.html
你可能不會立馬在畫面上看到結果。可以重新整理畫面看看。
才一個cookie根本不夠,我需要更多、更多、我要更多的cookies。
如果需要多個cookies,那就需要建立多個Set-Cookie
的Headers。上面的寫法就無法滿足要求,需要調整一下寫法。
@app.get('/index1.html')
def index1():
response = FileResponse('index.html')
response.set_cookie('name', 'takodachi')
response.set_cookie('like', 'cookie')
return response
這次得用FileResponse
的set_cookie
方法製造cookies。然後瀏覽 http://localhost:8000/index1.html
就像之前所說,瀏覽器會把cookie跟著request發送出去。這次多添加一個endpoint並不製造任何cookies:
@app.get('/index0.html')
def index0():
return FileResponse('index.html')
瀏覽 http://localhost:8000/index0.html
如果沒有寫上有效期限,就意味者這個cookie是個 即期食品 。當瀏覽器關閉重開後也就過期了。
警告: 然而,很多 Web 浏览器支持会话恢复功能,这个功能可以使浏览器保留所有的 tab 标签,然后在重新打开浏览器的时候将其还原。与此同时,cookie 也会恢复,就跟从来没有关闭浏览器一样。^1
如果要設定過期時間,可以在Response Header多添加Expires
的資訊,通常有效期限的格式是GMT(%a, %d %b %Y %H:%M:%S GMT
)。那麼整個會變成Set-Cookie: <key>=<value>;expires=<有效期限>
,比如:2day=xyz; expires=Tue, 27 Sep 2022 11:17:23 GMT;
。
在FastAPI裡,可以設定過期的秒數,框架會轉換爲GMT格式。
@app.get('/index2.html')
def index2():
response = FileResponse('index.html')
expires = 172800 # 2 day * 24 hour * 60 min * 60 sec
response.set_cookie('2day', 'xyz', expires=expires)
return response
或者可以設置Max-Age
指定幾妙後過期。那麼整個會變成Set-Cookie: <key>=<value>;Max-Age=<有效秒數>
,比如:1day=xyz; Max-Age=86400;
。
@app.get('/index3.html')
def index3():
response = FileResponse('index.html')
max_age = 86400 # 1 day * 24 hour * 60 min * 60 sec
response.set_cookie('1day', 'xyz', max_age=max_age)
return response
如果同時設定了
Expires
和Max-Age
。那麼Max-Age
有更高的優先圈。
Set-Cookie
並沒有刪除cookie的操作,不過透過設定有效期限Expires
或Max-Age
,就可以讓瀏覽器看到:「喔~這過期不能吃了」,然後把它丟掉。
所以可以透過Expires
設定一個過去時間。比如1970年的1月1日。
@app.get('/index2-1.html')
def index2_1():
response = FileResponse('index.html')
response.set_cookie('2day', 'xyz', expires='Thu, 01 Jan 1970 00:00:00 GMT')
return response
這裏我是故意寫成字串的。
但依照FastAPI框架行爲,你可以直接設置爲負數的整數值,便會是過期的時間。
或是將Max-Age
設定爲0
或-1
。
@app.get('/index3-1.html')
def index3_1():
response = FileResponse('index.html')
max_age = -1 # 1 day * 24 hour * 60 min * 60 sec
response.set_cookie('1day', 'xyz', max_age=max_age)
return response
這麼一來,在瀏覽 http://localhost:8000/index2-1.html 和 http://localhost:8000/index3-1.html 後,瀏覽器就會分別把2day
和1day
的cookies丟棄。
本文同時發表於我的隨筆