Files
medical-mall/doc_mall/FRONTEND_BACKEND_DEBUGGING.md
2026-01-21 12:12:22 +08:00

19 KiB

🔧 前端与后端联调指南

📋 目录

  1. 联调环境配置
  2. 本地开发环境搭建
  3. 前端连接后端
  4. 调试工具和方法
  5. 常见联调场景
  6. 问题排查

一、联调环境配置

1.1 环境类型

开发环境 (Development)

  • Supabase 本地实例: Docker Compose 运行在 192.168.0.150:8080
  • Supabase 云服务: 使用开发项目
  • 前端: uni-app-x 开发模式

生产环境 (Production)

  • Supabase 云服务: 生产项目
  • 前端: 编译后的应用

1.2 配置文件位置

前端配置

文件: ak/config.uts

// 开发环境 - 本地 Supabase
export const SUPA_URL: string = 'http://192.168.0.150:8080'
export const SUPA_KEY: string = 'your-anon-key'

// 生产环境 - Supabase 云服务
export const SUPA_URL: string = 'https://ak3.oulog.com'
export const SUPA_KEY: string = 'your-anon-key'

// WebSocket 实时连接
export const WS_URL: string = 'wss://ak3.oulog.com/realtime/v1/websocket'

后端配置 (Docker)

文件: doc_chat/supa.env

# Supabase 本地配置
POSTGRES_HOST=db
POSTGRES_DB=postgres
POSTGRES_PORT=5432
POSTGRES_PASSWORD=your-password

# API 配置
KONG_HTTP_PORT=8000
KONG_HTTPS_PORT=8443

# Auth 配置
API_EXTERNAL_URL=http://localhost:8000
SITE_URL=http://localhost:3000

二、本地开发环境搭建

2.1 Supabase 本地实例启动

方式一: Docker Compose (推荐)

# 1. 进入 Supabase 目录
cd doc_chat

# 2. 启动 Supabase 服务
docker-compose -f supa-docker-compose.yml up -d

# 3. 检查服务状态
docker-compose -f supa-docker-compose.yml ps

# 4. 查看日志
docker-compose -f supa-docker-compose.yml logs -f

服务端口:

  • API: http://localhost:8000http://192.168.0.150:8080
  • PostgreSQL: localhost:5432
  • Dashboard: http://localhost:3000

方式二: Supabase CLI

# 1. 安装 Supabase CLI
npm install -g supabase

# 2. 初始化项目
supabase init

# 3. 启动本地实例
supabase start

# 4. 查看服务信息
supabase status

2.2 数据库初始化

# 1. 执行商城数据库脚本
psql -h localhost -U postgres -d postgres -f doc_mall/database/complete_mall_database.sql

# 或使用 Supabase Dashboard SQL Editor
# 1. 打开 http://localhost:3000
# 2. 进入 SQL Editor
# 3. 复制粘贴 complete_mall_database.sql 内容
# 4. 执行脚本

# 2. 插入模拟数据 (可选)
psql -h localhost -U postgres -d postgres -f doc_mall/database/mock_data_insert.sql

# 3. 验证数据库
psql -h localhost -U postgres -d postgres -f doc_mall/database/validation_test.sql

2.3 前端开发环境

# 1. 安装依赖 (如果使用 npm)
npm install

# 2. 启动 uni-app-x 开发服务器
# 在 HBuilderX 中:
# - 运行 -> 运行到浏览器/手机模拟器
# - 或使用命令行工具

# 3. 配置开发环境
# 修改 ak/config.uts 中的 SUPA_URL 和 SUPA_KEY

三、前端连接后端

3.1 Supabase 客户端初始化

全局单例模式

文件: components/supadb/aksupainstance.uts

import AkSupa from './aksupa.uts'
import { SUPA_URL, SUPA_KEY } from '@/ak/config.uts'

// 创建全局 Supabase 客户端实例
const supa = new AkSupa(SUPA_URL, SUPA_KEY)

// 自动登录 (开发环境)
const supaReady: Promise<boolean> = (async () => {
    try {
        await supa.signIn('test@example.com', 'password')
        return true
    } catch (err) {
        console.error('Supabase auto sign-in failed', err)
        return false
    }
})()

export { supaReady }
export default supa

在页面中使用

// pages/mall/consumer/index.uvue
<script setup lang="uts">
import supa from '@/components/supadb/aksupainstance.uts'
import { ProductType } from '@/types/mall-types.uts'

const products = ref<Array<ProductType>>([])

onMounted(async () => {
    // 等待 Supabase 客户端就绪
    await supaReady
    
    // 查询商品列表
    const res = await supa.select('ml_products', {
        status: 1  // 只查询已上架商品
    }, {
        limit: 20,
        order: 'created_at.desc'
    })
    
    if (res.success && res.data) {
        products.value = res.data as Array<ProductType>
    }
})
</script>

3.2 API 调用方式

3.2.1 查询数据 (SELECT)

// 简单查询
const res = await supa.select('ml_products', null, {
    limit: 10,
    order: 'created_at.desc'
})

// 带过滤条件
const res = await supa.select('ml_products', {
    status: 1,
    category_id: categoryId
}, {
    limit: 20,
    order: 'sale_count.desc'
})

// 复杂过滤 (PostgREST 操作符)
const res = await supa.select('ml_products', {
    base_price: { gte: 100, lte: 500 },
    name: { ilike: '%商品%' },
    category_id: { in: [id1, id2, id3] }
}, {
    limit: 20
})

// 单条记录
const res = await supa.select('ml_products', { id: productId }, {
    single: true
})

// 选择特定字段
const res = await supa.select('ml_products', null, {
    columns: 'id,name,base_price,main_image_url',
    limit: 20
})

3.2.2 插入数据 (INSERT)

// 插入订单
const orderRes = await supa.insert('ml_orders', {
    user_id: userId,
    merchant_id: merchantId,
    total_amount: 100.00,
    order_status: 1,
    payment_status: 1,
    shipping_status: 1,
    shipping_address: {
        receiver_name: '张三',
        receiver_phone: '13800138000',
        address_detail: '北京市朝阳区xxx'
    }
})

// 批量插入
const items = [
    { order_id: orderId, product_id: productId1, quantity: 2 },
    { order_id: orderId, product_id: productId2, quantity: 1 }
]
const itemsRes = await supa.insert('ml_order_items', items)

3.2.3 更新数据 (UPDATE)

// 更新商品状态
await supa.update('ml_products', 
    { id: productId },  // 过滤条件
    { 
        status: 2,  // 下架
        updated_at: new Date().toISOString()
    }
)

// 更新订单状态
await supa.update('ml_orders',
    { id: orderId },
    {
        order_status: 2,  // 待发货
        updated_at: new Date().toISOString()
    }
)

3.2.4 删除数据 (DELETE)

// 删除收藏
await supa.delete('ml_user_favorites', { id: favoriteId })

// 删除购物车商品
await supa.delete('ml_shopping_cart', {
    user_id: userId,
    product_id: productId
})

3.2.5 调用数据库函数 (RPC)

// 计算购物车总金额
const totalRes = await supa.rpc('calculate_cart_total', {
    p_user_id: userId
})

// 生成订单号
const orderNoRes = await supa.rpc('generate_order_no')

// 获取用户默认地址
const addressRes = await supa.rpc('get_user_default_address', {
    p_user_id: userId
})

3.3 链式查询构建器

// 使用链式 API
const res = await supa
    .from('ml_products')
    .eq('status', 1)
    .gte('base_price', 100)
    .lte('base_price', 500)
    .like('name', '%商品%')
    .order('created_at', { ascending: false })
    .limit(20)
    .select()

四、调试工具和方法

4.1 浏览器开发者工具

网络请求调试

  1. 打开 Chrome DevTools (F12)

  2. Network 标签页

    • 查看所有 HTTP 请求
    • 检查请求 URL、Headers、Body
    • 查看响应状态码、数据
  3. Console 标签页

    • 查看 console.log() 输出
    • 查看错误信息
    • 执行调试代码

示例: 检查 API 请求

// 在代码中添加日志
console.log('请求商品列表:', {
    table: 'ml_products',
    filter: { status: 1 },
    options: { limit: 20 }
})

const res = await supa.select('ml_products', { status: 1 }, { limit: 20 })

console.log('API 响应:', {
    success: res.success,
    data: res.data,
    error: res.error,
    status: res.status
})

4.2 Supabase Dashboard

实时查看数据

  1. Table Editor

    • 查看表数据
    • 手动编辑数据
    • 验证数据是否正确
  2. SQL Editor

    • 执行 SQL 查询
    • 测试数据库函数
    • 验证 RLS 策略
  3. API Logs

    • 查看 API 请求日志
    • 检查错误信息
    • 分析性能问题

示例: 测试查询

-- 在 Supabase Dashboard SQL Editor 中执行
SELECT * FROM ml_products 
WHERE status = 1 
ORDER BY created_at DESC 
LIMIT 20;

-- 测试 RLS 策略
SET ROLE authenticated;
SET request.jwt.claim.sub = 'user-uuid-here';
SELECT * FROM ml_user_profiles;

4.3 Postman / Insomnia

直接测试 Supabase API

# 获取商品列表
GET https://your-project.supabase.co/rest/v1/ml_products?status=eq.1&limit=20
Headers:
  apikey: your-anon-key
  Authorization: Bearer your-jwt-token
  Content-Type: application/json

# 创建订单
POST https://your-project.supabase.co/rest/v1/ml_orders
Headers:
  apikey: your-anon-key
  Authorization: Bearer your-jwt-token
  Content-Type: application/json
  Prefer: return=representation
Body:
{
  "user_id": "user-uuid",
  "merchant_id": "merchant-uuid",
  "total_amount": 100.00,
  "order_status": 1
}

# 调用 RPC 函数
POST https://your-project.supabase.co/rest/v1/rpc/calculate_cart_total
Headers:
  apikey: your-anon-key
  Authorization: Bearer your-jwt-token
  Content-Type: application/json
Body:
{
  "p_user_id": "user-uuid"
}

4.4 数据库客户端工具

pgAdmin / DBeaver / DataGrip

-- 直接连接 PostgreSQL 数据库
-- Host: localhost (或 192.168.0.150)
-- Port: 5432
-- Database: postgres
-- User: postgres
-- Password: (从 supa.env 获取)

-- 查看表结构
SELECT * FROM information_schema.tables 
WHERE table_schema = 'public' AND table_name LIKE 'ml_%';

-- 查看数据
SELECT * FROM ml_products LIMIT 10;

-- 查看 RLS 策略
SELECT * FROM pg_policies WHERE tablename = 'ml_products';

4.5 uni-app-x 调试

HBuilderX 调试工具

  1. 控制台输出

    • 查看 console.log() 输出
    • 查看错误堆栈
  2. 网络请求监控

    • 查看所有网络请求
    • 检查请求参数和响应
  3. 断点调试

    • 在代码中设置断点
    • 单步执行
    • 查看变量值

五、常见联调场景

5.1 场景一: 查询商品列表失败

问题现象

// 前端代码
const res = await supa.select('ml_products', null, { limit: 20 })
// res.success = false
// res.error = "relation 'ml_products' does not exist"

排查步骤

  1. 检查数据库表是否存在

    SELECT table_name FROM information_schema.tables 
    WHERE table_schema = 'public' AND table_name = 'ml_products';
    
  2. 检查表是否已创建

    • 执行 complete_mall_database.sql 脚本
    • 验证脚本执行成功
  3. 检查连接配置

    console.log('Supabase URL:', SUPA_URL)
    console.log('Supabase Key:', SUPA_KEY)
    

解决方案

# 重新执行数据库脚本
psql -h localhost -U postgres -d postgres -f doc_mall/database/complete_mall_database.sql

5.2 场景二: RLS 策略阻止数据访问

问题现象

// 查询用户数据返回空
const res = await supa.select('ml_user_profiles', { user_id: userId })
// res.data = [] 或 null

排查步骤

  1. 检查用户是否已登录

    const session = await supa.getSession()
    console.log('当前用户:', session.user)
    
  2. 检查 RLS 策略

    -- 查看表的 RLS 策略
    SELECT * FROM pg_policies WHERE tablename = 'ml_user_profiles';
    
    -- 测试 RLS 策略
    SET ROLE authenticated;
    SET request.jwt.claim.sub = 'auth-user-id';
    SELECT * FROM ml_user_profiles;
    
  3. 检查 auth_id 关联

    -- 验证 ak_users.auth_id 是否正确
    SELECT id, auth_id FROM ak_users WHERE id = 'user-uuid';
    

解决方案

// 确保用户已登录
await supa.signIn('user@example.com', 'password')

// 或检查 Token
const token = AkReq.getToken()
console.log('JWT Token:', token)

5.3 场景三: 插入数据失败

问题现象

// 插入订单失败
const res = await supa.insert('ml_orders', orderData)
// res.success = false
// res.error = "new row violates row-level security policy"

排查步骤

  1. 检查必填字段

    console.log('订单数据:', JSON.stringify(orderData, null, 2))
    
  2. 检查外键约束

    -- 验证 user_id 和 merchant_id 是否存在
    SELECT id FROM ak_users WHERE id IN ('user-id', 'merchant-id');
    
  3. 检查 RLS INSERT 策略

    SELECT * FROM pg_policies 
    WHERE tablename = 'ml_orders' AND cmd = 'INSERT';
    

解决方案

// 确保数据完整
const orderData = {
    user_id: userId,  // 必须存在
    merchant_id: merchantId,  // 必须存在
    total_amount: 100.00,
    order_status: 1,
    payment_status: 1,
    shipping_status: 1,
    shipping_address: addressData  // 必须提供
}

// 确保用户有权限
await supa.signIn('user@example.com', 'password')

5.4 场景四: 实时数据同步不工作

问题现象

// 订阅订单状态更新,但没有收到推送
supa.realtime.subscribe('ml_orders', {
    filter: `id=eq.${orderId}`,
    event: 'UPDATE',
    callback: (payload) => {
        console.log('订单更新:', payload)  // 没有触发
    }
})

排查步骤

  1. 检查 WebSocket 连接

    console.log('WebSocket URL:', WS_URL)
    
  2. 检查表是否启用 Realtime

    -- 在 Supabase Dashboard 中检查
    -- Database -> Replication -> 确保 ml_orders 表已启用
    
  3. 检查网络连接

    • 确保 WebSocket 连接没有被防火墙阻止
    • 检查浏览器控制台是否有 WebSocket 错误

解决方案

// 确保 WebSocket URL 正确
export const WS_URL: string = 'wss://your-project.supabase.co/realtime/v1/websocket'

// 在 Supabase Dashboard 中启用表的 Realtime
// Database -> Replication -> 找到 ml_orders -> 启用

5.5 场景五: 数据库函数调用失败

问题现象

// 调用 RPC 函数失败
const res = await supa.rpc('calculate_cart_total', { p_user_id: userId })
// res.success = false
// res.error = "function calculate_cart_total does not exist"

排查步骤

  1. 检查函数是否存在

    SELECT routine_name FROM information_schema.routines 
    WHERE routine_schema = 'public' AND routine_name = 'calculate_cart_total';
    
  2. 检查函数参数

    -- 查看函数定义
    \df calculate_cart_total
    
  3. 测试函数

    SELECT calculate_cart_total('user-uuid-here');
    

解决方案

# 重新执行数据库脚本,确保函数已创建
psql -h localhost -U postgres -d postgres -f doc_mall/database/complete_mall_database.sql

六、问题排查

6.1 排查清单

连接问题

  • Supabase URL 是否正确
  • API Key 是否正确
  • 网络连接是否正常
  • 防火墙是否阻止连接

认证问题

  • 用户是否已登录
  • JWT Token 是否有效
  • Token 是否过期
  • auth_id 是否正确关联

数据问题

  • 表是否存在
  • 字段名是否正确
  • 数据类型是否匹配
  • 外键约束是否满足

权限问题

  • RLS 策略是否正确
  • 用户是否有权限
  • 策略条件是否满足

6.2 常用调试命令

前端调试

// 打印完整请求信息
console.log('请求详情:', {
    url: `${SUPA_URL}/rest/v1/ml_products`,
    headers: {
        apikey: SUPA_KEY,
        Authorization: `Bearer ${token}`
    },
    filter: filter,
    options: options
})

// 打印完整响应
console.log('响应详情:', {
    success: res.success,
    status: res.status,
    data: res.data,
    error: res.error,
    raw: res
})

数据库调试

-- 查看表结构
\d ml_products

-- 查看索引
\di ml_products*

-- 查看触发器
\d+ ml_products

-- 查看 RLS 策略
SELECT * FROM pg_policies WHERE tablename = 'ml_products';

-- 测试查询性能
EXPLAIN ANALYZE SELECT * FROM ml_products WHERE status = 1;

6.3 错误码参考

HTTP 状态码 含义 常见原因
200 成功 -
400 请求错误 参数错误、数据格式错误
401 未授权 Token 无效、未登录
403 禁止访问 RLS 策略阻止
404 未找到 表不存在、记录不存在
500 服务器错误 数据库错误、函数错误

6.4 日志收集

前端日志

// 创建日志工具
class DebugLogger {
    static log(module: string, action: string, data: any) {
        console.log(`[${module}] ${action}:`, data)
        // 可以发送到日志服务器
    }
}

// 使用
DebugLogger.log('MallAPI', '查询商品', { filter, options })

后端日志

-- 启用 PostgreSQL 日志
-- 在 postgresql.conf 中设置
log_statement = 'all'
log_duration = on
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

七、最佳实践

7.1 开发环境配置

  1. 使用环境变量

    // 开发环境
    const isDev = process.env.NODE_ENV === 'development'
    export const SUPA_URL = isDev 
        ? 'http://192.168.0.150:8080' 
        : 'https://ak3.oulog.com'
    
  2. 统一错误处理

    async function safeApiCall<T>(apiCall: () => Promise<AkReqResponse<T>>) {
        try {
            const res = await apiCall()
            if (!res.success) {
                console.error('API 调用失败:', res.error)
                uni.showToast({ title: '操作失败', icon: 'error' })
            }
            return res
        } catch (error) {
            console.error('API 调用异常:', error)
            uni.showToast({ title: '网络错误', icon: 'error' })
            throw error
        }
    }
    
  3. 请求重试机制

    async function retryApiCall<T>(
        apiCall: () => Promise<AkReqResponse<T>>,
        maxRetries = 3
    ) {
        for (let i = 0; i < maxRetries; i++) {
            try {
                const res = await apiCall()
                if (res.success) return res
            } catch (error) {
                if (i === maxRetries - 1) throw error
                await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
            }
        }
    }
    

7.2 联调流程

  1. 数据库准备

    • 执行数据库脚本
    • 插入测试数据
    • 验证表结构
  2. 前端配置

    • 配置 Supabase URL 和 Key
    • 测试连接
    • 验证认证
  3. 功能测试

    • 测试 CRUD 操作
    • 测试 RLS 策略
    • 测试实时同步
  4. 问题排查

    • 查看日志
    • 检查网络请求
    • 验证数据库数据

📚 相关文档


生成时间: 2025年1月
版本: v1.0
状态: 完整联调指南