Upstash 封装与实践
Upstash 由于其 Serverless 和基于 HTTP 的特性,非常适合集成在 Next.js 的服务端架构(RSC、Middleware、Route Handlers)中。通过合理的封装,可以实现高效的限流、缓存管理和向量检索。
1. 架构流向:Client -> Service -> Integration
由于 Redis 通常涉及敏感操作和 Token 安全,封装建议主要集中在服务端层面:
- Client 层:初始化 Redis 和 Ratelimit 单例。
- Service 层:封装具体的业务逻辑(如:增加点击量、缓存用户信息)。
- 集成层:在渲染组件或中间件中调用。
2. 第 0 步:初始化客户端 (TS 版)
确保环境变量 UPSTASH_REDIS_REST_URL 和 UPSTASH_REDIS_REST_TOKEN 已配置。
// lib/upstash.ts
import { Redis } from "@upstash/redis";
import { Ratelimit } from "@upstash/ratelimit";
// 1. Redis 实例
export const redis = Redis.fromEnv();
// 2. 限流器实例 (基于 Redis)
export const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(10, "10 s"), // 自定义规则
analytics: true,
});
3. 第一步:封装常通业务方法 (Service)
// services/redisService.ts
import { redis, ratelimit } from "../lib/upstash";
/**
* 访问统计:增加计数并返回
*/
export const incrementCount = async (key: string) => {
return await redis.incr(key);
};
/**
* 缓存数据封装
*/
export const cacheData = {
set: async <T>(key: string, value: T, ex = 3600) => {
return await redis.set(key, JSON.stringify(value), { ex });
},
get: async <T>(key: string): Promise<T | null> => {
const data = await redis.get(key);
if (!data) return null;
return typeof data === "string" ? JSON.parse(data) : data;
},
};
/**
* 通用限流校验
*/
export const checkRateLimit = async (identifier: string) => {
const result = await ratelimit.limit(identifier);
return result; // 返回 { success, limit, remaining, reset }
};
4. 第二步:在 Next.js 中的深度应用
方案 A:在 Middleware 中做全局限流
这是保护应用免受恶意请求和爬虫攻击的最佳位置。
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { checkRateLimit } from "./services/redisService";
export async function middleware(request: NextRequest) {
const ip = request.ip ?? "127.0.0.1";
const { success, limit, remaining } = await checkRateLimit(`mw_${ip}`);
if (!success) {
return new NextResponse("请求过于频繁", {
status: 429,
headers: { "X-RateLimit-Limit": limit.toString() },
});
}
return NextResponse.next();
}