iT邦幫忙

2022 iThome 鐵人賽

DAY 17
0
Modern Web

這些那些你可能不知道我不知道的Web技術細節系列 第 17

你可能不知道cookie是怎麼被製造出來的

  • 分享至 

  • xImage
  •  

前言

你是タコたち嗎?你喜歡吃cookies嗎?那麼你知道cookies是怎麼被製造出來的嗎?

cookie是怎麼被製造出來的

cookies是在瀏覽器儲存的小小資料片段,通常來說當瀏覽器發出request時,有可能同時將cookie發送出去。利用這個特性,可以將通常來說無狀態的HTTP保有記憶,做到登入功能、追蹤行爲等等。

雖然我們可以透過瀏覽器開發工具新增cookie。

但通常這是由Web Server製造,然後透過Response Headers發送給瀏覽器。

Lab

這次同樣使用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>

然後同樣利用FileResponseindex.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

這次得用FileResponseset_cookie方法製造cookies。然後瀏覽 http://localhost:8000/index1.html

消費cookie

就像之前所說,瀏覽器會把cookie跟著request發送出去。這次多添加一個endpoint並不製造任何cookies:

@app.get('/index0.html')
def index0():
    return FileResponse('index.html')

瀏覽 http://localhost:8000/index0.html

有效期限

如果沒有寫上有效期限,就意味者這個cookie是個 即期食品 。當瀏覽器關閉重開後也就過期了。

警告: 然而,很多 Web 浏览器支持会话恢复功能,这个功能可以使浏览器保留所有的 tab 标签,然后在重新打开浏览器的时候将其还原。与此同时,cookie 也会恢复,就跟从来没有关闭浏览器一样。^1

設置 Expires

如果要設定過期時間,可以在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

或者可以設置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

如果同時設定了ExpiresMax-Age。那麼Max-Age有更高的優先圈。

刪除 cookie

Set-Cookie並沒有刪除cookie的操作,不過透過設定有效期限ExpiresMax-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.htmlhttp://localhost:8000/index3-1.html 後,瀏覽器就會分別把2day1day的cookies丟棄。

參考資料

本文同時發表於我的隨筆


上一篇
你可能不知道的Function.prototype.bind()
下一篇
你可能不知道cookie可以寄城市還可以分路段
系列文
這些那些你可能不知道我不知道的Web技術細節33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言