django.utils.http是 Django 開發者不可或缺的非常有用且常用的模塊。

這個模塊彙集了處理 HTTP 協議本身或安全操作 URL 所需的核心工具函數。重點在於構建 URL 和查詢字符串,並在 HTTP 環境中安全地傳遞數據,而不是發送 HTTP 請求(例如:requests庫)。

這篇文章將探討django.utils.http的核心功能。


1. URL 安全的 Base64 編碼: urlsafe_base64_encode / decode



這個模塊展現其光芒的時刻。

一般的 Base64 編碼會包含+/等特殊字符。這些字符在 URL 中有特殊的意義(如空格、路徑分隔等),因此在通過 URL 傳遞值時可能會造成問題。

urlsafe_base64_encode會將這些字符用在 URL 中安全使用的-_替代,以進行編碼。

主要使用情境:

  • 基於電子郵件的註冊認證令牌
  • 密碼重設鏈接的用戶 ID(pk) 編碼

範例: (生成密碼重設鏈接)

from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
from django.contrib.auth.models import User

# 1. 在生成令牌時(編碼)
user = User.objects.get(username='testuser')
# 重要:編碼前必須始終轉換為 bytes。
uid_bytes = force_bytes(user.pk)
uid_token = urlsafe_base64_encode(uid_bytes)

print(f"編碼的令牌: {uid_token}")
# 例如: 'Mg' (假設 user.pk 是 2)
# reset_url = f"/password-reset/{uid_token}/..."


# 2. 當用戶點擊鏈接時(解碼)
try:
    # 將從 URL 接收到的令牌重新解碼為 bytes
    uid_bytes_decoded = urlsafe_base64_decode(uid_token)
    # 轉換回字符串(或整數)
    user_pk = force_str(uid_bytes_decoded)
    user = User.objects.get(pk=user_pk)
    print(f"恢復的 PK: {user.pk}")
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
    user = None

注意: force_bytesforce_strdjango.utils.encoding 模塊中,通常與 urlsafe_base64 函數一起使用。


2. 查詢字符串生成器: urlencode

將 Python 字典(dict) 對象輕鬆轉換為 HTTP GET 請求所用的查詢字符串(例如:?key=value&key2=value2)。

範例:

from django.utils.http import urlencode

params = {
    'page': 3,
    'q': 'django rest framework',
    'region': 'ja'
}

# 將字典的鍵和值進行 URL 編碼以生成查詢字符串。
# 'django rest framework' 的空格將安全地編碼為 '+' 或 '%20'。
query_string = urlencode(params)

print(query_string)
# 輸出: 'page=3&q=django+rest+framework&region=ko'

3. 確認安全重定向: is_safe_url



這是一個安全性至關重要的功能。用於防止“開放重定向”漏洞。

登錄後,通常會將用戶重定向回他們先前所在的頁面,例如?next=/profile/。如果攻擊者將外部 URL(如?next=http://malicious-site.com)插入next值,則在用戶完成登錄後可能會將其轉移到惡意網站。

is_safe_url將檢查給定的 URL 是否屬於當前應用程序的主機(域名)內的“安全” URL,或是否為相對路徑。

範例: (登錄視圖)

from django.utils.http import is_safe_url
from django.shortcuts import redirect, resolve_url

def login_success_redirect(request):
    # 從 GET 參數中獲取 'next' 值。
    next_url = request.GET.get('next')

    # 1. 確保 next 值存在且
    # 2. 必須通過 is_safe_url 檢查才能重定向到該 URL。
    if next_url and is_safe_url(
        url=next_url,
        allowed_hosts={request.get_host()},  # 只允許當前請求的主機
        require_https=request.is_secure()   # 如果當前請求是 HTTPS,則重定向也必須是 HTTPS
    ):
        return redirect(next_url)

    # 如果不安全或不存在 'next' 值,則重定向到默認頁面。
    return redirect(resolve_url('main-dashboard'))

4. 其他有用的函數

  • urlquote(value) / urlunquote(value): urlencode將整個字典變為查詢字符串,而urlquote將字符串一個中的特殊字符(空格、CJK 字符等)編碼為%XX形式(百分比編碼)。這在構建 URL 路徑(path)的某一部分時很有用。
  • parse_http_date(date_str) / http_date(timestamp): 用於解析或生成Last-ModifiedExpires等 HTTP 標頭中使用的標準日期格式(RFC 1123)字符串。

總結

django.utils.http是一個出色的範例,展示了 Django 如何深度處理 HTTP 標準。

特別是,使用urlsafe_base64_encode 進行安全的令牌傳遞以及透過is_safe_url 確保重定向的安全性,這是所有 Django 開發者必須了解的核心功能。有效利用這個模塊可以使 HTTP 數據處理更加安全和穩健。