如何在Next.js+Supabase中记录API调用并存储到数据库?
在Supabase + Next.js中实现API调用记录功能
需求说明
需要将所有API调用按如下格式存储到Supabase数据库:
// api_path, called_at, called_by "https://www.test.com/api/create_user",server.now(),"1" "https://www.test.com/api/create_user",server.now(),"1" "https://www.test.com/api/delete_user",server.now(),"1" "https://www.test.com/api/analyze_user",server.now(),"1"
其中called_at为记录添加时的服务器时间,called_by为调用用户ID,比如示例中用户ID为1的用户多次调用不同API。
实现方案
1. 创建Supabase日志表
先在Supabase后台创建用于存储API调用记录的数据表,命名为api_call_logs:
CREATE TABLE api_call_logs ( id SERIAL PRIMARY KEY, api_path TEXT NOT NULL, called_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), called_by TEXT NOT NULL );
这里将called_at的默认值设为NOW(),插入数据时无需手动传值,数据库会自动填充服务器当前时间。
2. 封装通用日志记录函数
在Next.js项目中创建工具函数utils/logApiCall.js,统一处理日志写入逻辑:
import { createClient } from '@supabase/supabase-js'; const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY ); export async function logApiCall(apiPath, userId) { try { await supabase .from('api_call_logs') .insert({ api_path: apiPath, called_by: userId }); } catch (err) { console.error('API日志写入失败:', err); } }
注意使用服务角色密钥(SUPABASE_SERVICE_ROLE_KEY)绕过Row Level Security(RLS)限制,确保日志能正常写入。
3. 在API路由中添加日志记录
在每个需要监控的API路由文件中,引入并调用日志函数。比如pages/api/create_user.js:
import { logApiCall } from '../../utils/logApiCall'; export default async function handler(req, res) { // 根据你的认证方式获取用户ID,示例从已认证的请求对象中获取 const userId = req.user?.id; const apiPath = `${req.headers.origin}${req.url}`; // 异步记录日志,不阻塞业务逻辑 logApiCall(apiPath, userId); // 处理你的核心业务逻辑 // ... res.status(200).json({ success: true }); }
4. 用中间件统一拦截(可选)
如果不想逐个修改API路由,可以用Next.js中间件自动拦截所有API请求并记录日志,创建pages/_middleware.js:
import { NextResponse } from 'next/server'; import { logApiCall } from '../utils/logApiCall'; export async function middleware(req) { // 仅拦截/api开头的请求 if (req.nextUrl.pathname.startsWith('/api/')) { // 根据你的认证方案获取用户ID,示例从Cookie中读取 const userId = req.cookies.get('user_id')?.value || 'anonymous'; const apiPath = `${req.nextUrl.origin}${req.nextUrl.pathname}`; // 异步执行日志记录,避免阻塞请求 logApiCall(apiPath, userId).catch(err => console.error(err)); } return NextResponse.next(); }
注意事项
- 服务角色密钥仅能在服务器端使用,绝对不能暴露在客户端代码中。
- 若存在未认证用户调用API的场景,可将
called_by字段设为可选,或用anonymous作为默认值。 - 日志记录逻辑建议异步执行,避免因数据库写入延迟影响API响应速度。
内容的提问来源于stack exchange,提问作者mmvergara
相关产品推荐
相关产品推荐

