iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0

前言

今天我們會介紹 CORS 是什麼,以及如何處理相關設定。

什麼是 CORS

CORS 是跨域資源共用的簡稱,他是用來限制我們的資源(API)只能被哪些網頁使用。瀏覽器會協助我們去限制這件事情,舉例來說當我今天訪問 https://web.example.com 時這個前端程式使用 Ajax 想要請求 https://api.example.com 那因為這兩個域名是不同的,在預設情況下瀏覽器會限制前端網頁訪問 API。

會做這些限制的原因是為了避免使用者在不知情的情況下訪問了非預期的資源,假設今天是沒有 CORS 限制的情況下就有可能發生你訪問了某個網頁,而這個網頁發起了 Ajax 請求做了奇怪的事情(例如竊取資料等等),但如果有這個限制的話網頁就會將沒有允許被跨站存取的資源訪問。

所以我們需要做的事情就是在 API 這邊設定我們允許哪些跨域的請求(會透過 HTTP Header 告訴瀏覽器)這樣我們的前端程式就能正常訪問我們的 API 了。

P.S. 我這邊只做了簡單且粗淺的說明,如果想要更深入的探索的話可以參考一些資料

設定 CORS

首先我們先來安裝一下 django-cors-headers 這個套件,他可以協助我們快速的設定好跟 CORS 相關的設定

poetry add django-cors-headers

接著我們打開 server/settings.py 這個檔案

# ...... 以上省略 ......

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "rest_framework_simplejwt",
    "drf_spectacular",
    "django_filters",
    "django_extensions",
+   "corsheaders",
    "server.app.common",
    "server.app.todo",
]

# ...... 以下省略 ......

我們將剛剛裝好的套件加入 APP 列表中

接著我們繼續編輯 server/settings.py 檔案

# ...... 以上省略 .....

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
+   "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

# ...... 以下省略 ......

這邊我們將 CorsMiddleware 加入 middleware 列表中,這邊要注意一下 CorsMiddleware 需要盡可能地放在列表前面,最少最少也要放在 CommonMiddleware 這種有可能產生回應的 middleware 前面。

P.S. 這邊補充說明一下什麼是 middleware,middleware 是一個可以重複的被每個請求或回應利用的部分,當 client 端發起請求時會依照這個列表中設定的 middleware 依序呼叫,再進到 view 中,回傳時也是會依照列表「反向」的順序依需呼叫。所以我們可以將每個 view 都需要處理的邏輯就可以放在 middleware 當中,例如 Django 在 middleware 處理跟安全性相關的檢查。

接著我們繼續編輯 server/settings.py 這個檔案(將下方內容貼在檔案最下面)

CORS_ALLOWED_ORIGINS = [
    "https://example.com",
    "https://sub.example.com",
    "http://localhost:8080",
    "http://127.0.0.1:9000",
]

這邊是設定說我們允許哪些網站跨域請求我們,那這邊我們允許了這四個網站。

這個套件除了支援像這樣列表外,還支援使用 regex 設定,或者允許任何網站這幾種設定方法,但允許全部就等於不限制,所以這邊我不太推薦不推薦使用,除非你很清楚你在做什麼。

測試

現在讓我們測試一下我們的設定是否生效,讓我們啟動 server(記得啟動虛擬環境)

python manage.py runserver_plus

接著我們訪問 https://www.test-cors.org 這個小工具,並在畫面中 Remote URL 的欄位中輸入 http://127.0.0.1:8000 這個網址,接著按下 Send Request,這樣就開始測試我們 CORS 有無設定成功了。

這時候應該會看到下方回應出現了關鍵字 Fired XHR event: error 代表我們目前設定是失敗了,原因是因為我們在允許跨域的列表中沒有設定 https://www.test-cors.org 這個網站,所以讓我們打開 server/settings.py 檔案

CORS_ALLOWED_ORIGINS = [
    "https://example.com",
    "https://sub.example.com",
    "http://localhost:8080",
    "http://127.0.0.1:9000",
+   "https://www.test-cors.org",
]

這時候我們再次回到測試網站按下 Send Request,應該會發現剛剛的 Fired XHR event: error 關鍵字不見了,而且再下方一點有出現 XHR status: 404 關鍵字,代表他順利請求到 http://127.0.0.1:8000 這個網址了,同時也代表我們的設定是成功的了。

接著大家只要根據需要將前端的網址或是允許存取的網址放在列表中即可。

結語

今天我們學習了 CORS 並設定好相關的設定了,這樣前端程式就能順利的請求我們的網站了。

結束前別忘了檢查一下今天的程式碼有沒有問題,並排版好喔。

ruff check --fix .
black .
pyright .

今天的內容就到這邊了,讓我們期待明天的內容吧。

P.S. 今天的檔案更新可以參考我的 Git Commit 大家可以搭配服用


上一篇
Day28 - 依據使用者顯示不同的資料
下一篇
Day30 - 總結與回顧
系列文
Django REST 大冒險:探索精彩紛呈的 API 開發世界30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言