知识库首页 模版 customer-portal-route.ts.md

customer portal route.ts

本地来源:模版/模版文档对比说明/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 });
}

认证步骤

  1. 会话获取: 从当前会话获取用户信息
  2. 用户验证: 检查用户是否存在和有效
  3. 错误处理: 认证失败返回 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 });
}

数据库查询

  1. 服务角色客户端: 使用管理员权限查询数据
  2. 客户记录查询: 根据用户ID查找客户记录
  3. 字段选择: 只选择需要的 creem_customer_id 字段
  4. 单记录获取: 使用 .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

响应处理

  1. 状态检查: 验证 API 调用是否成功
  2. 数据解析: 解析返回的 JSON 数据
  3. 响应转发: 将 Creem 的响应转发给客户端

环境变量依赖

process.env.CREEM_API_URL
process.env.CREEM_API_KEY
  • CREEM_API_URL: Creem API 基础URL
  • CREEM_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密钥保护

最佳实践总结

  1. 安全性: 严格的用户认证和权限检查
  2. 错误处理: 完善的错误处理机制
  3. 日志记录: 详细的错误日志
  4. 状态码: 准确的HTTP状态码
  5. 数据最小化: 只查询必要的字段
  6. 异步处理: 使用 async/await 处理异步操作
  7. 环境配置: 正确使用环境变量

使用场景

客户端调用

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调用响应时间
  • 错误发生频率
  • 用户认证失败次数

调试建议

  1. 日志级别: 根据环境调整日志详细程度
  2. API测试: 定期测试 Creem API 连接
  3. 数据检查: 验证客户记录完整性

这个客户门户路由提供了一个安全、可靠的方式让用户访问 Creem 客户门户,通过完善的认证机制和错误处理,确保了用户数据的安全性和系统的稳定性。

本文档为站内渲染。原始文件本地路径:saas/source/templates/模版-模版文档对比说明-08-API路由-customer-portal-route-ts-bb945d.md(仅本地保留,不入库不部署)