fastapi: 第二十九章:访问redis

一,安装用到的第三方库

$ pip install redis

说明:

redis库和aioredis库两者有什么区别?

这是一个非常经典的“历史遗留”问题。其实在今天,它们已经没有区别了,因为它们已经合并成了同一个库。

简单来说:aioredis 已经被合并到了官方的 redis 库中。

二,代码:

连接

# app/core/redislink.py
import asyncio
from contextlib import asynccontextmanager
from typing import AsyncGenerator
from fastapi import FastAPI, Depends, HTTPException
import redis.asyncio as aioredis

# 定义一个全局的 Redis 连接池变量
redis_pool: aioredis.ConnectionPool | None = None

# 1. 使用 Lifespan 管理管理 Redis 连接池的生命周期
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    global redis_pool
    print("正在连接 Redis...")
    # 初始化异步连接池
    redis_pool = aioredis.ConnectionPool(
        host="localhost",
        port=6379,
        db=0,
        decode_responses=True  # 自动将字节解码为字符串
    )
    yield
    # 应用关闭时,优雅地关闭连接池
    print("正在关闭 Redis 连接...")
    await redis_pool.disconnect()

# 2. 创建一个 Dependency(依赖项),用于在接口中获取 Redis 客户端
async def get_redis() -> AsyncGenerator[aioredis.Redis, None]:
    if redis_pool is None:
        raise RuntimeError("Redis 连接池未初始化")
    # 从连接池中获取一个连接
    async with aioredis.Redis(connection_pool=redis_pool) as client:
        yield client

main

# 创建FastAPI应用,并传入 lifespan
app = FastAPI(lifespan=lifespan,title="我的API项目")

调用:

# --- 3. 编写 API 接口 ---
from fastapi import HTTPException, APIRouter, Depends
import redis.asyncio as aioredis
from app.core.redislink import get_redis

router = APIRouter(prefix="/toke", tags=["token管理"])

@router.get("/set/{key}")
async def set_value(key: str, value: str, r: aioredis.Redis = Depends(get_redis)):
    """设置键值对,并设置 60 秒过期时间"""
    await r.set(key, value, ex=60)
    return {"status": "success", "message": f"键 '{key}' 已保存,60秒后过期"}

@router.get("/get/{key}")
async def get_value(key: str, r: aioredis.Redis = Depends(get_redis)):
    """获取键值对"""
    value = await r.get(key)
    if value is None:
        raise HTTPException(status_code=404, detail="未找到该键或已过期")
    return {"key": key, "value": value}

@router.get("/delete/{key}")
async def delete_value(key: str, r: aioredis.Redis = Depends(get_redis)):
    """删除键值对"""
    result = await r.delete(key)
    if result == 0:
        raise HTTPException(status_code=404, detail="键不存在,无法删除")
    return {"status": "success", "message": f"键 '{key}' 已删除"}

相关的说明:

💡 为什么用 lifespan

旧版本的 FastAPI 使用 @app.on_event("startup"),但这已被官方废弃。现在的 lifespan 机制可以将启动和关闭逻辑写在同一个函数里(通过 yield 分割),更加直观且安全。

💡 为什么要用 ConnectionPool(连接池)?

频繁地创建和销毁 Redis 连接非常消耗性能。通过连接池,多个请求可以复用已有的连接。

💡 decode_responses=True 的作用

如果不加这个参数,Redis 返回的数据默认是 Python 的 bytes 类型(例如 b"value")。加上后,连接器会自动帮你转换成 str(例如 "value"),省去了手动 .decode('utf-8') 的麻烦。

三,测试效果 :

image

image

 

posted @ 2026-06-12 10:53  刘宏缔的架构森林  阅读(19)  评论(0)    收藏  举报