diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c12675f..d161749 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,6 +9,8 @@ on: - 'README.md' - 'CHANGELOG.md' - 'zensical.toml' + - 'zensical.zh-TW.toml' + - 'i18n/**' - 'pyproject.toml' - 'uv.lock' - '.github/workflows/docs.yml' @@ -20,6 +22,8 @@ on: - 'README.md' - 'CHANGELOG.md' - 'zensical.toml' + - 'zensical.zh-TW.toml' + - 'i18n/**' - 'pyproject.toml' - 'uv.lock' - '.github/workflows/docs.yml' @@ -46,3 +50,6 @@ jobs: - name: Build (strict) run: uv run --no-sync zensical build --strict + + - name: Build Traditional Chinese translation (strict) + run: uv run --no-sync zensical build --strict -f zensical.zh-TW.toml diff --git a/.gitignore b/.gitignore index 24fec37..0c53729 100644 --- a/.gitignore +++ b/.gitignore @@ -307,6 +307,7 @@ venv.bak/ # mkdocs documentation /site +/site-zh-TW # mypy .mypy_cache/ diff --git a/README.md b/README.md index ba8429d..451b68c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![PyPI version](https://img.shields.io/pypi/v/fastapi-cachex.svg?logo=pypi&logoColor=gold&label=PyPI)](https://pypi.org/project/fastapi-cachex) [![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-cachex.svg?logo=python&label=Python&logoColor=gold)](https://pypi.org/project/fastapi-cachex/) -[English](https://github.com/allen0099/FastAPI-CacheX/blob/master/README.md) | [繁體中文](https://github.com/allen0099/FastAPI-CacheX/blob/master/docs/README.zh-TW.md) +[English](https://github.com/allen0099/FastAPI-CacheX/blob/master/README.md) | [繁體中文](https://github.com/allen0099/FastAPI-CacheX/blob/master/i18n/zh-TW/docs/index.md) A high-performance caching extension for FastAPI: a server-side response cache with `Cache-Control` and `ETag` support, application-level caching, and optional session management. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 30947e5..1e7da2d 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -29,7 +29,9 @@ Please refer to our [Development Guide](DEVELOPMENT.md) for detailed instruction ## Pull Request Process -1. Update the matching guide under `docs/` (and the README if the change belongs on the front page) when you change the interface +1. Update the matching guide under `docs/` (and the README if the change belongs on the front page) when you change the interface. Only the English + pages need updating: the [Traditional Chinese translation](DEVELOPMENT.md#traditional-chinese-translation) + is allowed to lag behind them 2. Add an entry to the `## [Unreleased]` section of [CHANGELOG.md](https://github.com/allen0099/FastAPI-CacheX/blob/master/CHANGELOG.md) if your change alters behaviour, adds public API, or fixes something a user could have hit. That section is what the diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 8af5e4b..f3c45df 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -204,6 +204,25 @@ The **Docs** workflow (`.github/workflows/docs.yml`) and Read the Docs (`.readthedocs.yaml`) both run `zensical build --strict`, so a broken link, snippet path or docstring reference fails the PR. +### Traditional Chinese translation + +A Traditional Chinese (`zh-TW`) translation is published at +. It is a separate Read the +Docs translation project built from `zensical.zh-TW.toml` (build settings in +`i18n/zh-TW/.readthedocs.yaml`), and its pages live in `i18n/zh-TW/docs/` — not +under `docs/`, which would pull them into the English site. + +```bash +uv run zensical serve -f zensical.zh-TW.toml +uv run zensical build --strict -f zensical.zh-TW.toml # also run by the Docs workflow +``` + +The English pages are the source of truth. The translation may lag behind +them, and every translated page carries a banner saying so, with a link to the +English original. Pages that are not translated yet are linked from the +translation's navigation to the English site. When translating, follow the +terms in [`i18n/zh-TW/GLOSSARY.md`](https://github.com/allen0099/FastAPI-CacheX/blob/master/i18n/zh-TW/GLOSSARY.md). + ### Adding API reference pages API pages live under `docs/api/` and are generated from docstrings (Google diff --git a/docs/README.zh-TW.md b/docs/README.zh-TW.md deleted file mode 100644 index fbb9674..0000000 --- a/docs/README.zh-TW.md +++ /dev/null @@ -1,279 +0,0 @@ -# FastAPI-Cache X - -[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv) -[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) -[![Tests](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/test.yml/badge.svg)](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/test.yml) -[![Coverage Status](https://raw.githubusercontent.com/allen0099/FastAPI-CacheX/coverage-badge/coverage.svg)](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/coverage.yml) - -[![Downloads](https://static.pepy.tech/badge/fastapi-cachex)](https://pepy.tech/project/fastapi-cachex) -[![Weekly downloads](https://static.pepy.tech/badge/fastapi-cachex/week)](https://pepy.tech/project/fastapi-cachex) -[![Monthly downloads](https://static.pepy.tech/badge/fastapi-cachex/month)](https://pepy.tech/project/fastapi-cachex) - -[![PyPI version](https://img.shields.io/pypi/v/fastapi-cachex.svg?logo=pypi&logoColor=gold&label=PyPI)](https://pypi.org/project/fastapi-cachex) -[![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-cachex.svg?logo=python&label=Python&logoColor=gold)](https://pypi.org/project/fastapi-cachex/) - -[English](https://github.com/allen0099/FastAPI-CacheX/blob/master/README.md) | [繁體中文](README.zh-TW.md) - -FastAPI-CacheX 是一個為 FastAPI 框架設計的高效能快取擴充套件,提供伺服器端回應快取(支援 `Cache-Control` 與 `ETag`)、應用層快取和可選的 Session 管理。 - -## 功能特點 - -### HTTP 快取 -- 支援多種 HTTP 快取標頭 - - `Cache-Control` - - `ETag` - - `If-None-Match` -- 支援多種後端快取系統 - - Redis - - Memcached - - 記憶體內快取 -- 可在回應中設定常用的 Cache-Control 指令(詳見下表) -- 簡單易用的 `@cache` 裝飾器 - -### Session 管理(可選擴充套件) -- 使用 HMAC-SHA256 權杖簽名的安全 Session 管理 -- IP 地址和 User-Agent 綁定(可選安全功能) -- Header、Bearer 權杖與 Cookie 傳輸(Cookie 需使用 `FastAPICacheXSessionMiddleware`; - 舊的 `SessionMiddleware` 已 deprecated,將於 0.4.0 移除,詳見 - [Session 管理指南](SESSION.md)) -- 自動 Session 更新(滑動過期) -- 跨請求通訊的 Flash Messages -- 支援多種後端(Redis、Memcached、記憶體內) -- 完整的 Session 生命週期管理(建立、驗證、更新、失效) - -### Cache-Control 指令 - -`@cache` 有兩個角色:替瀏覽器與中間層(CDN、反向代理)寫出 `Cache-Control` 標頭,以及在後端維護自己的伺服器端快取。大部分指令只影響前者:它們會寫進標頭,但伺服器端快取的行為不會因此改變。 - -| 指令 | 設定方式 | 寫入標頭 | 對伺服器端快取的影響 | -|--------------------------|-------------------------------------|--------------------|-------------------------------------------------------------| -| `max-age` | `ttl=N` | :white_check_mark: | `N` 秒內直接回傳已儲存的回應,不執行 handler(`ttl=0` 或未設定:不直接回傳)。 | -| `no-cache` | `no_cache=True` | :white_check_mark: | 每次都執行 handler;回應仍會儲存,`If-None-Match` 相符時回 304。 | -| `no-store` | `no_store=True` | :white_check_mark: | 不讀取也不儲存,也不設定 ETag。 | -| `private` | `private=True` | :white_check_mark: | 完全不經過後端;每次都執行 handler,ETag 重新驗證仍有效。 | -| `public` | `public=True` | :white_check_mark: | 無(僅寫入標頭)。 | -| `immutable` | `immutable=True` | :white_check_mark: | 無(僅寫入標頭)。 | -| `must-revalidate` | `must_revalidate=True` | :white_check_mark: | 無(僅寫入標頭)。 | -| `stale-while-revalidate` | `stale="revalidate", stale_ttl=N` | :white_check_mark: | 無(僅寫入標頭):伺服器端快取不會回傳過期內容。 | -| `stale-if-error` | `stale="error", stale_ttl=N` | :white_check_mark: | 無(僅寫入標頭):handler 失敗時不會改用快取回應。 | -| `s-maxage` | — | :x: | — | -| `proxy-revalidate` | — | :x: | — | -| `no-transform` | — | :x: | — | -| `must-understand` | — | :x: | — | - -請求端的 `Cache-Control`(例如瀏覽器強制重新整理時送出的 `no-cache`、`max-age=0`)不會改變 `@cache` 的行為。這是刻意的設計:若請求標頭能繞過快取,任何用戶端都能讓每個請求直接打到 handler。條件式請求仍會處理:`If-None-Match` 相符時回 304。 - -## 安裝指南 - -```bash -uv add fastapi-cachex -``` - -核心套件搭配記憶體後端即可運作;其餘後端與 Session 的選用傳輸方式以 extra 形式提供: - -| Extra | 安裝 | 帶入套件 | 用途 | -|-------|------|---------|------| -| `redis` | `uv add "fastapi-cachex[redis]"` | `redis[hiredis]`、`orjson` | `AsyncRedisCacheBackend` | -| `memcache` | `uv add "fastapi-cachex[memcache]"` | `pymemcache` | `MemcachedBackend`(注意是 `memcache` 不是 `memcached`) | -| `jwt` | `uv add "fastapi-cachex[jwt]"` | `PyJWT` | `SessionConfig(token_format="jwt")` | - -`starlette` extra 已移除:`itsdangerous` 改為基本依賴,`FastAPICacheXSessionMiddleware` -在一般安裝下即可使用。 - -可以合併安裝:`uv add "fastapi-cachex[redis,jwt]"`。 - -### 開發版本安裝 - -```bash -uv add git+https://github.com/allen0099/FastAPI-CacheX.git -``` - -## 快速開始 - -```python -from fastapi import FastAPI -from fastapi_cachex import cache -from fastapi_cachex import CacheBackend - -app = FastAPI() - - -@app.get("/") -@cache(ttl=60) # 快取 60 秒 -async def read_root(): - return {"Hello": "World"} - - -@app.get("/no-cache") -@cache(no_cache=True) # 標記此端點為不可快取 -async def non_cache_endpoint(): - return {"Hello": "World"} - - -@app.get("/no-store") -@cache(no_store=True) # 標記此端點為不可儲存 -async def non_store_endpoint(): - return {"Hello": "World"} - - -@app.get("/clear_cache") -async def remove_cache(cache: CacheBackend): - await cache.clear_path("/path/to/clear") # 清除特定路徑的快取 - # 模式比對的對象是完整金鑰,不是只有路徑 - await cache.clear_pattern("GET|||*|||/path/to/clear/*") -``` - -`clear_pattern` 以 glob 比對**完整邏輯金鑰**。HTTP 快取金鑰的形狀是 -`method|||host|||path|||query`,所以只寫路徑的模式一個都比不到——要按路徑清除請用 -`clear_path(path, include_params=True)`,`clear_pattern` 留給你自己組出來的金鑰。 - -## 後端設定 - -FastAPI-CacheX 支援多種快取後端。你可以使用 `BackendProxy` 輕鬆切換不同的後端。 - -### 快取金鑰格式 - -快取金鑰遵循以下格式以避免衝突: - -``` -{method}|||{host}|||{path}|||{query_params} -``` - -這確保: -- 不同的 HTTP 方法 (GET、POST 等) 不會共享快取 -- 不同的主機不會共享快取(適合多租戶情境) -- 不同的查詢參數將獲得各自獨立的快取項目 -- 同一端點配合不同參數可以獨立快取 - -查詢參數依照客戶端送出的順序取用,不會排序,因此 `?a=1&b=2` 與 `?b=2&a=1` -對同一個邏輯請求會是兩筆不同的快取項目。 - -所有後端會自動為金鑰加上前綴(例如 `fastapi_cachex:`)以避免與其他應用程式衝突。 - -### 快取命中行為 - -當快取項目有效(在 TTL 內)時: -- **預設行為**:直接返回快取內容,連同處理器當初產生的狀態碼與標頭,無需重新執行端點處理器 -- **帶有 `If-None-Match` 標頭**:如果 ETag 匹配則返回 HTTP 304 Not Modified -- **帶有 `no-cache` 指令**:強制重新驗證以確定是否需要返回 304 - -- **使用 `private=True`**:不讀也不寫共享後端,處理器每次都執行,只保留 `If-None-Match` 重新驗證 - -這意味著**快取命中非常快速** - 端點處理器函式永遠不會被執行。 - -只有成功的回應會被儲存。處理器**回傳**的非 2xx 回應(例如 `Response(..., status_code=404)`) -會原樣送出且不寫入快取,因此暫時性錯誤不會覆蓋上一份好的條目;`206 Partial Content` 同樣不快取。 -`Set-Cookie` 永遠不會被存下或重播。 - -### 快取監控端點 - -`add_routes(app)` 會掛上兩個唯讀端點:`{prefix}/cached-hits`(各路由命中次數)與 -`{prefix}/cached-records`(目前所有快取條目,含內容預覽)。 - -> [!WARNING] -> **這兩個端點本身沒有任何認證。** `include_in_schema=False` 只是讓它們不出現在 OpenAPI 文件, -> 猜到路徑的人照樣讀得到,而 `/cached-records` 會外洩快取內容預覽與整個路由結構。 -> 生產環境務必傳入 `dependencies=[Depends(你的認證)]`,或只掛在對內的應用上。 - -> [!NOTE] -> Redis 後端的 `ttl_remaining` 不可用:`get_cache_data()` 不會逐一查詢每個金鑰的 TTL, -> 因此監控畫面會把 Redis 條目一律顯示為永不過期(實際過期仍由 Redis 執行)。 - -### 記憶體快取 (預設後端) - -若未指定後端,FastAPI-CacheX 預設使用記憶體快取。 -適合開發和測試。後端會自動執行清理任務,每 60 秒移除過期項目。 - -```python -from fastapi_cachex.backends import MemoryBackend -from fastapi_cachex import BackendProxy - -backend = MemoryBackend() -BackendProxy.set(backend) -``` - -**注意**:記憶體快取不適合多處理程式的生產環境。 -每個處理程式維護其自己獨立的快取。 - -### Memcached - -```python -from fastapi_cachex.backends import MemcachedBackend -from fastapi_cachex import BackendProxy - -backend = MemcachedBackend(servers=["localhost:11211"]) -BackendProxy.set(backend) -``` - -**限制**: -- Memcached 協議沒有金鑰列舉能力,`clear_pattern()` 與 `get_all_keys()` 都是 no-op - (回傳 `0`/`[]` 並發出 `RuntimeWarning`);建立在其上的 `CacheManager.clear()` - 與 `clear_prefix()` 因此同樣無效 -- 金鑰使用 `fastapi_cachex:` 前綴以避免衝突;超過 Memcached 250 bytes 上限的金鑰 - 會自動改用 SHA-256 摘要 -- 如果需要基於模式的快取清除,請考慮使用 Redis 後端 - -### Redis - -```python -from fastapi_cachex.backends import AsyncRedisCacheBackend -from fastapi_cachex import BackendProxy - -backend = AsyncRedisCacheBackend(host="127.0.0.1", port=6379, db=0) -BackendProxy.set(backend) -``` - -**功能**: -- 完全非同步實現 -- 支援基於模式的金鑰清除 -- 使用 SCAN 而非 KEYS 以保證生產環境安全(非阻塞) -- 預設使用 `fastapi_cachex:` 前綴 -- 支援自訂金鑰前綴用於多租戶情境 - -**自訂前綴範例**: - -```python -backend = AsyncRedisCacheBackend( - host="127.0.0.1", - port=6379, - key_prefix="myapp:cache:", -) -BackendProxy.set(backend) -``` - -## 效能考量 - -### 快取命中效能 - -當快取命中(在 TTL 內)時,回應會直接返回而無需執行端點處理器。這非常快速: - -```python -@app.get("/expensive") -@cache(ttl=3600) # 快取 1 小時 -async def expensive_operation(): - # 只在快取未命中時執行 - # 快取命中時,此函式不會被呼叫 - result = perform_expensive_calculation() - return result -``` - -### 後端選擇 - -- **MemoryBackend**:單處理程式開發時最快;不適合生產環境 -- **Memcached**:適合分散式系統;模式清除有限制 -- **Redis**:最適合生產環境;完全非同步、支援所有功能、非阻塞操作 - -## 文件 - -- [快取流程說明](CACHE_FLOW.md) -- [開發指南](DEVELOPMENT.md) -- [已知限制與待辦](https://github.com/allen0099/FastAPI-CacheX/issues) -- [變更紀錄](https://github.com/allen0099/FastAPI-CacheX/blob/master/CHANGELOG.md) -- [貢獻指南](CONTRIBUTING.md) -- [Session 管理指南](SESSION.md) - 完整的 Session 功能使用指南 -- [State 管理指南](STATE.md) - OAuth/CSRF 一次性 state token -- [JWT Claims 說明](JWT_CLAIMS.md) - JWT session token 的 claim 設計與擴展方式 - -## 授權條款 - -本專案採用 Apache License 2.0 授權條款 - 查看 [LICENSE](https://github.com/allen0099/FastAPI-CacheX/blob/master/LICENSE) 檔案了解更多細節。 diff --git a/i18n/zh-TW/.readthedocs.yaml b/i18n/zh-TW/.readthedocs.yaml new file mode 100644 index 0000000..6ea6c2c --- /dev/null +++ b/i18n/zh-TW/.readthedocs.yaml @@ -0,0 +1,20 @@ +# Read the Docs build of the Traditional Chinese translation: +# https://fastapi-cachex.readthedocs.io/zh-tw/latest/ +# Same as the root .readthedocs.yaml, but built from zensical.zh-TW.toml. The +# translation project points its "Build configuration file" setting here. +version: 2 + +build: + os: ubuntu-24.04 + tools: + python: "3.14" + jobs: + install: + - pip install uv + - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --frozen --only-group docs --no-install-project + build: + html: + - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv run --no-sync zensical build --strict -f zensical.zh-TW.toml + post_build: + - mkdir -p $READTHEDOCS_OUTPUT/html/ + - cp -r site-zh-TW/* $READTHEDOCS_OUTPUT/html/ diff --git a/i18n/zh-TW/GLOSSARY.md b/i18n/zh-TW/GLOSSARY.md new file mode 100644 index 0000000..d51e2ce --- /dev/null +++ b/i18n/zh-TW/GLOSSARY.md @@ -0,0 +1,49 @@ +# 繁體中文翻譯詞彙表 + +翻譯 `i18n/zh-TW/docs/` 時使用的統一譯名,採台灣慣用語。英文文件是唯一的 +正本,譯文可以落後,但不應與英文內容矛盾。 + +## 原則 + +- 程式碼、識別字、參數名稱、HTTP 標頭與指令保持原文,並以 inline code 標示: + `@cache`、`ttl`、`Cache-Control`、`no-store`、`If-None-Match`。 +- 程式碼區塊內的程式碼不翻譯,只翻譯註解。 +- 中文與英文、數字、inline code 之間加一個半形空格;中文句子使用全形標點。 +- 下表標示「保留」的詞在中文句子中直接使用英文。 +- 章節錨點(`#authenticated-endpoints` 等)由英文標題產生;連到英文文件時沿用英文錨點。 + +## 詞彙 + +| 英文 | 譯名 | 備註 | +|------|------|------| +| cache(名詞) | 快取 | | +| cache(動詞) | 快取、存入快取 | | +| cache hit / miss | 快取命中/未命中 | | +| cache key | 快取鍵 | | +| backend | 後端 | | +| header | 標頭 | | +| request / response | 請求/回應 | | +| handler | 保留 | 指路由處理函式 | +| route / endpoint | 路由/端點 | | +| decorator | 裝飾器 | | +| dependency | 依賴項 | FastAPI 的 dependency injection:依賴注入 | +| middleware | 中介軟體 | | +| directive | 指令 | `Cache-Control` 指令 | +| revalidation | 重新驗證 | | +| invalidate / invalidation | 使……失效/快取失效 | | +| expire / expiration | 過期 | | +| sliding expiration | 滑動過期 | | +| TTL | 保留 | | +| prefix / namespace | 前綴/命名空間 | | +| atomic | 原子性、原子操作 | | +| counter | 計數器 | | +| lock | 鎖 | | +| token | 權杖 | | +| signature / sign | 簽章/簽署 | | +| session | 保留(Session) | | +| claim | 保留 | JWT claim | +| state(OAuth) | 保留 | | +| serialize / deserialize | 序列化/反序列化 | | +| extra | 保留 | 套件的選用依賴,例:`redis` extra | +| deprecated | 已棄用 | | +| breaking change | 破壞性變更 | | diff --git a/i18n/zh-TW/docs/index.md b/i18n/zh-TW/docs/index.md new file mode 100644 index 0000000..c08da61 --- /dev/null +++ b/i18n/zh-TW/docs/index.md @@ -0,0 +1,97 @@ +# FastAPI-Cache X + +[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv) +[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) +[![Tests](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/test.yml/badge.svg)](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/test.yml) +[![Coverage Status](https://raw.githubusercontent.com/allen0099/FastAPI-CacheX/coverage-badge/coverage.svg)](https://github.com/allen0099/FastAPI-CacheX/actions/workflows/coverage.yml) + +[![Downloads](https://static.pepy.tech/badge/fastapi-cachex)](https://pepy.tech/project/fastapi-cachex) +[![Weekly downloads](https://static.pepy.tech/badge/fastapi-cachex/week)](https://pepy.tech/project/fastapi-cachex) +[![Monthly downloads](https://static.pepy.tech/badge/fastapi-cachex/month)](https://pepy.tech/project/fastapi-cachex) + +[![PyPI version](https://img.shields.io/pypi/v/fastapi-cachex.svg?logo=pypi&logoColor=gold&label=PyPI)](https://pypi.org/project/fastapi-cachex) +[![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-cachex.svg?logo=python&label=Python&logoColor=gold)](https://pypi.org/project/fastapi-cachex/) + +[English](https://github.com/allen0099/FastAPI-CacheX/blob/master/README.md) | [繁體中文](https://github.com/allen0099/FastAPI-CacheX/blob/master/i18n/zh-TW/docs/index.md) + +FastAPI-CacheX 是 FastAPI 的高效能快取擴充套件:提供支援 `Cache-Control` 與 `ETag` 的伺服器端回應快取、應用層快取,以及可選的 Session 管理。 + +**文件:** (尚未翻譯的指南與完整 API 參考請見[英文文件](https://fastapi-cachex.readthedocs.io/en/latest/)) + +## 功能特點 + +- **HTTP 快取**:GET 路由專用的 `@cache` 裝飾器,支援 `Cache-Control`、 + `ETag` / `If-None-Match`(304)與單一路由的快取失效。 +- **應用層快取**:`CacheManager` 可在自己的程式碼中快取任意 JSON 值,提供 + 未命中時才計算的 `get_or_set()` 與原子性的「不存在才寫入」`add()`。 +- **後端**:記憶體、Redis 與 Memcached,支援原子操作的計數器、一次性取值與鎖。 +- **Session(可選)**:以 HMAC 簽章或 JWT 發行的 Session 權杖,可經由標頭、 + Bearer 權杖或 Cookie 傳遞,支援滑動過期與 IP / User-Agent 綁定。 +- **OAuth state**:OAuth / OIDC 流程中用於防範 CSRF 的一次性 state 權杖。 + +## 安裝 + +```bash +uv add fastapi-cachex +``` + +核心套件搭配記憶體後端即可使用;其他後端與 Session 的選用傳輸方式以 extra 提供: + +| Extra | 安裝 | 帶入套件 | 用途 | +|-------|------|---------|------| +| `redis` | `uv add "fastapi-cachex[redis]"` | `redis[hiredis]`、`orjson` | `AsyncRedisCacheBackend` | +| `memcache` | `uv add "fastapi-cachex[memcache]"` | `pymemcache` | `MemcachedBackend`(注意是 `memcache`,不是 `memcached`) | +| `jwt` | `uv add "fastapi-cachex[jwt]"` | `PyJWT` | `SessionConfig(token_format="jwt")` | + +Extra 可以組合:`uv add "fastapi-cachex[redis,jwt]"`。 + +## 快速開始 + +```python +from fastapi import FastAPI + +from fastapi_cachex import AppCache, BackendProxy, cache +from fastapi_cachex.backends import MemoryBackend + +app = FastAPI() +BackendProxy.set(MemoryBackend()) # 或 AsyncRedisCacheBackend / MemcachedBackend + + +@app.get("/items/{item_id}") +@cache(ttl=60) # 60 秒內直接由快取回應,並支援 ETag 重新驗證 +async def read_item(item_id: int): + return {"item_id": item_id} + + +def build_report() -> dict: + return {"total": 42} # 代表某個耗時的計算 + + +@app.get("/report") +async def report(cache: AppCache): + # 在自己的程式碼中快取任意 JSON 值。 + return await cache.get_or_set("report", build_report, ttl=300) +``` + +> [!WARNING] +> 預設的快取鍵不包含使用者身分。需要驗證身分的端點請使用 `private=True` +> 或依使用者區分的 key builder,詳見 +> [需驗證身分的端點](https://fastapi-cachex.readthedocs.io/en/latest/HTTP_CACHING/#authenticated-endpoints)(英文)。 + +## 文件 + +以下指南尚未翻譯,連結指向英文文件: + +- [HTTP 快取](https://fastapi-cachex.readthedocs.io/en/latest/HTTP_CACHING/):`@cache` 裝飾器、Cache-Control 指令、快取鍵、快取失效與監控路由 +- [快取流程](https://fastapi-cachex.readthedocs.io/en/latest/CACHE_FLOW/):快取請求內部的處理流程 +- [應用層快取](https://fastapi-cachex.readthedocs.io/en/latest/APP_CACHE/):`CacheManager` +- [後端](https://fastapi-cachex.readthedocs.io/en/latest/BACKENDS/):選擇與設定後端、原子操作的基本功能 +- [Session 管理](https://fastapi-cachex.readthedocs.io/en/latest/SESSION/)與 [JWT claims](https://fastapi-cachex.readthedocs.io/en/latest/JWT_CLAIMS/) +- [OAuth state](https://fastapi-cachex.readthedocs.io/en/latest/STATE/):一次性的 OAuth / CSRF state 權杖 +- [API 參考](https://fastapi-cachex.readthedocs.io/en/latest/api/http-caching/) +- [開發指南](https://fastapi-cachex.readthedocs.io/en/latest/DEVELOPMENT/)與[貢獻指南](https://fastapi-cachex.readthedocs.io/en/latest/CONTRIBUTING/) +- [變更紀錄](https://github.com/allen0099/FastAPI-CacheX/blob/master/CHANGELOG.md) · [已知限制與規劃中的工作](https://github.com/allen0099/FastAPI-CacheX/issues) + +## 授權 + +本專案採用 Apache License 2.0 授權,詳見 [LICENSE](https://github.com/allen0099/FastAPI-CacheX/blob/master/LICENSE)。 diff --git a/i18n/zh-TW/overrides/main.html b/i18n/zh-TW/overrides/main.html new file mode 100644 index 0000000..1302c22 --- /dev/null +++ b/i18n/zh-TW/overrides/main.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{#- English is the source of truth and the translation may lag behind it + (see issue #89), so every page says so and links to its original. -#} +{% block announce %} + 本頁譯自英文文件,內容可能未反映最新版本。以 + 英文原文 + 為準。 +{% endblock %} diff --git a/zensical.toml b/zensical.toml index 62397b2..0295cf4 100644 --- a/zensical.toml +++ b/zensical.toml @@ -42,6 +42,18 @@ nav = [ { "Changelog" = "changelog.md" }, ] +# Language switcher. The Traditional Chinese site is a Read the Docs +# translation project built from zensical.zh-TW.toml. +[[project.extra.alternate]] +name = "English" +link = "https://fastapi-cachex.readthedocs.io/en/latest/" +lang = "en" + +[[project.extra.alternate]] +name = "繁體中文" +link = "https://fastapi-cachex.readthedocs.io/zh-tw/latest/" +lang = "zh-Hant" + [project.theme] language = "en" features = [ diff --git a/zensical.zh-TW.toml b/zensical.zh-TW.toml new file mode 100644 index 0000000..c230a0c --- /dev/null +++ b/zensical.zh-TW.toml @@ -0,0 +1,114 @@ +# Traditional Chinese documentation site, a Read the Docs translation of the +# English site (zensical.toml). See "Traditional Chinese translation" in +# docs/DEVELOPMENT.md. +# +# uv run zensical serve -f zensical.zh-TW.toml +# uv run zensical build --strict -f zensical.zh-TW.toml +# +# The pages live outside docs/ because Zensical has no exclude_docs: anything +# under docs/ would also be built into the English site. + +[project] +site_name = "FastAPI-CacheX" +site_description = "FastAPI 的 HTTP 快取、應用層快取與 Session 管理。" +site_url = "https://fastapi-cachex.readthedocs.io/zh-tw/latest/" +repo_url = "https://github.com/allen0099/FastAPI-CacheX" +repo_name = "allen0099/FastAPI-CacheX" +edit_uri = "edit/master/i18n/zh-TW/docs/" +docs_dir = "i18n/zh-TW/docs" +site_dir = "site-zh-TW" + +# Pages that are not translated (yet) point at the English site. Swap an entry +# to the local file once its translation lands. +nav = [ + { "首頁" = "index.md" }, + { "指南" = [ + { "HTTP 快取(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/HTTP_CACHING/" }, + { "快取流程(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/CACHE_FLOW/" }, + { "應用層快取(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/APP_CACHE/" }, + { "後端(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/BACKENDS/" }, + { "Session 管理(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/SESSION/" }, + { "JWT claims(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/JWT_CLAIMS/" }, + { "OAuth state(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/STATE/" }, + ] }, + { "API 參考(英文)" = "https://fastapi-cachex.readthedocs.io/en/latest/api/http-caching/" }, + { "開發(英文)" = [ + { "開發指南" = "https://fastapi-cachex.readthedocs.io/en/latest/DEVELOPMENT/" }, + { "貢獻指南" = "https://fastapi-cachex.readthedocs.io/en/latest/CONTRIBUTING/" }, + ] }, + { "變更紀錄(英文)" = "https://github.com/allen0099/FastAPI-CacheX/blob/master/CHANGELOG.md" }, +] + +[project.extra] +# Base of the English original; the "may be outdated" banner links each page +# to its counterpart there. +english_site = "https://fastapi-cachex.readthedocs.io/en/latest/" + +[[project.extra.alternate]] +name = "English" +link = "https://fastapi-cachex.readthedocs.io/en/latest/" +lang = "en" + +[[project.extra.alternate]] +name = "繁體中文" +link = "https://fastapi-cachex.readthedocs.io/zh-tw/latest/" +lang = "zh-Hant" + +[project.theme] +language = "zh-Hant" +custom_dir = "i18n/zh-TW/overrides" +features = [ + "content.action.edit", + "content.code.annotate", + "content.code.copy", + "content.tabs.link", + "navigation.footer", + "navigation.indexes", + "navigation.instant", + "navigation.path", + "navigation.sections", + "navigation.top", + "navigation.tracking", + "search.highlight", +] + +[[project.theme.palette]] +media = "(prefers-color-scheme)" +toggle.icon = "lucide/sun-moon" +toggle.name = "切換為淺色模式" + +[[project.theme.palette]] +media = "(prefers-color-scheme: light)" +scheme = "default" +toggle.icon = "lucide/sun" +toggle.name = "切換為深色模式" + +[[project.theme.palette]] +media = "(prefers-color-scheme: dark)" +scheme = "slate" +toggle.icon = "lucide/moon" +toggle.name = "切換為跟隨系統" + +# Same extensions as the English site, so a translated page renders like its +# original. +[project.markdown_extensions] +admonition = {} +github-callouts = {} +attr_list = {} +def_list = {} +footnotes = {} +md_in_html = {} +tables = {} +toc.permalink = true +pymdownx.details = {} +pymdownx.emoji.emoji_index = "zensical.extensions.emoji.twemoji" +pymdownx.emoji.emoji_generator = "pymdownx.emoji.to_alt" +pymdownx.highlight.anchor_linenums = true +pymdownx.highlight.line_spans = "__span" +pymdownx.highlight.pygments_lang_class = true +pymdownx.inlinehilite = {} +pymdownx.superfences = {} +pymdownx.tabbed.alternate_style = true +pymdownx.tasklist.custom_checkbox = true +pymdownx.snippets.base_path = ["."] +pymdownx.snippets.check_paths = true