customer portal route.ts
本地来源:模版/template/模版文档对比说明/08-API路由/customer-portal-route.ts.md
Creem客户门户路由 (app/api/creem/customer-portal/route.ts) 逐行分析
文件概述
这是处理客户门户访问的 API 路由。它为已登录的用户提供访问 Creem 客户门户的链接,用户可以在门户中管理自己的订阅、查看账单历史和更新付款信息。
导入语句分析
import { createServiceRoleClient } from "@/utils/supabase/service-role";
import { createClient } from "@/utils/supabase/server";
createServiceRoleClient: 创建具有管理员权限的 Supabase 客户端createClient: 创建服务器端 Supabase 客户端
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
NextResponse: Next.js 的响应对象cookies: Next.js cookies 处理函数(虽然导入但未使用)
主要处理函数分析
export async function GET(request: Request) {
try {
// 用户认证和数据获取逻辑
} catch (error) {
console.error("Error getting customer portal link:", error);
return new NextResponse("Internal Server Error", { status: 500 });
}
}
- 导出 GET 方法处理函数
- 使用 try-catch 进行错误处理
用户认证分析
// Get the user from the session
const supabase = await createClient();
const {
data: { user },
error: userError,
} = await supabase.auth.getUser();
if (userError || !user) {
return new NextResponse("Unauthorized", { status: 401 });
}
认证步骤
- 会话获取: 从当前会话获取用户信息
- 用户验证: 检查用户是否存在和有效
- 错误处理: 认证失败返回 401 未授权
安全性考虑
- 使用服务器端客户端确保安全
- 严格的用户存在性检查
- 明确的错误状态码
客户信息获取分析
// Use service role client for database operations
const serviceClient = createServiceRoleClient();
// Get the customer record for this user
const { data: customer, error: customerError } = await serviceClient
.from("customers")
.select("creem_customer_id")
.eq("user_id", user.id)
.single();
if (customerError || !customer) {
return new NextResponse("No subscription found", { status: 404 });
}
数据库查询
- 服务角色客户端: 使用管理员权限查询数据
- 客户记录查询: 根据用户ID查找客户记录
- 字段选择: 只选择需要的
creem_customer_id字段 - 单记录获取: 使用
.single()确保只返回一条记录
错误处理
- 检查数据库查询错误
- 验证客户记录是否存在
- 返回 404 状态码表示未找到订阅
Creem API调用分析
// Call Creem API to get the customer portal link
const response = await fetch(
`${process.env.CREEM_API_URL}/customers/billing`,
{
method: "POST",
headers: {
"x-api-key": process.env.CREEM_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
customer_id: customer.creem_customer_id,
}),
}
);
if (!response.ok) {
throw new Error("Failed to get customer portal link");
}
const data = await response.json();
return NextResponse.json(data);
API调用配置
- 端点:
/customers/billing获取客户门户链接 - 方法: POST 请求
- 认证: 使用 API Key 认证
- 内容类型: JSON 格式
请求参数
{
customer_id: customer.creem_customer_id,
}
- 传递从数据库获取的 Creem 客户ID
响应处理
- 状态检查: 验证 API 调用是否成功
- 数据解析: 解析返回的 JSON 数据
- 响应转发: 将 Creem 的响应转发给客户端
环境变量依赖
process.env.CREEM_API_URL
process.env.CREEM_API_KEY
CREEM_API_URL: Creem API 基础URLCREEM_API_KEY: Creem API 认证密钥
数据流程分析
1. 用户请求 → 认证检查
2. 认证成功 → 查询客户记录
3. 客户存在 → 调用 Creem API
4. API 成功 → 返回门户链接
5. 任何步骤失败 → 返回错误响应
错误处理策略
认证错误
if (userError || !user) {
return new NextResponse("Unauthorized", { status: 401 });
}
- 用户未登录或会话无效
- 返回 401 未授权状态
数据库错误
if (customerError || !customer) {
return new NextResponse("No subscription found", { status: 404 });
}
- 客户记录不存在
- 返回 404 未找到状态
API调用错误
if (!response.ok) {
throw new Error("Failed to get customer portal link");
}
- Creem API 调用失败
- 抛出异常触发全局错误处理
全局错误处理
} catch (error) {
console.error("Error getting customer portal link:", error);
return new NextResponse("Internal Server Error", { status: 500 });
}
- 记录错误日志
- 返回 500 内部服务器错误
设计模式分析
防御性编程
- 多层错误检查
- 详细的错误日志
- 明确的错误状态码
职责分离
- 认证逻辑分离
- 数据访问分离
- 外部API调用分离
安全性设计
- 用户认证验证
- 数据访问权限控制
- API密钥保护
最佳实践总结
- 安全性: 严格的用户认证和权限检查
- 错误处理: 完善的错误处理机制
- 日志记录: 详细的错误日志
- 状态码: 准确的HTTP状态码
- 数据最小化: 只查询必要的字段
- 异步处理: 使用 async/await 处理异步操作
- 环境配置: 正确使用环境变量
使用场景
客户端调用
const response = await fetch('/api/creem/customer-portal', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
const data = await response.json();
// 重定向到客户门户
window.location.href = data.url;
} else {
// 处理错误
console.error('Failed to get portal link');
}
预期响应
// 成功响应
{
"url": "https://billing.creem.com/portal/...",
"expires_at": "2024-01-01T00:00:00Z"
}
// 错误响应
{
"error": "Unauthorized",
"status": 401
}
部署和监控考虑
环境配置检查
- 验证 Creem API 配置
- 检查数据库连接
- 确认环境变量设置
监控指标
- 门户链接生成成功率
- API调用响应时间
- 错误发生频率
- 用户认证失败次数
调试建议
- 日志级别: 根据环境调整日志详细程度
- API测试: 定期测试 Creem API 连接
- 数据检查: 验证客户记录完整性
这个客户门户路由提供了一个安全、可靠的方式让用户访问 Creem 客户门户,通过完善的认证机制和错误处理,确保了用户数据的安全性和系统的稳定性。
本文档为站内渲染。原始文件本地路径:saas/source/templates/模版-template-模版文档对比说明-08-API路由-customer-portal-route-ts-7aa412.md(仅本地保留,不入库不部署)