# 🔧 前端与后端联调指南 ## 📋 目录 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` ```typescript // 开发环境 - 本地 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` ```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 (推荐) ```bash # 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:8000` 或 `http://192.168.0.150:8080` - **PostgreSQL**: `localhost:5432` - **Dashboard**: `http://localhost:3000` #### 方式二: Supabase CLI ```bash # 1. 安装 Supabase CLI npm install -g supabase # 2. 初始化项目 supabase init # 3. 启动本地实例 supabase start # 4. 查看服务信息 supabase status ``` ### 2.2 数据库初始化 ```bash # 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 前端开发环境 ```bash # 1. 安装依赖 (如果使用 npm) npm install # 2. 启动 uni-app-x 开发服务器 # 在 HBuilderX 中: # - 运行 -> 运行到浏览器/手机模拟器 # - 或使用命令行工具 # 3. 配置开发环境 # 修改 ak/config.uts 中的 SUPA_URL 和 SUPA_KEY ``` --- ## 三、前端连接后端 ### 3.1 Supabase 客户端初始化 #### 全局单例模式 **文件**: `components/supadb/aksupainstance.uts` ```typescript 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 = (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 ``` #### 在页面中使用 ```typescript // pages/mall/consumer/index.uvue ``` ### 3.2 API 调用方式 #### 3.2.1 查询数据 (SELECT) ```typescript // 简单查询 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) ```typescript // 插入订单 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) ```typescript // 更新商品状态 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) ```typescript // 删除收藏 await supa.delete('ml_user_favorites', { id: favoriteId }) // 删除购物车商品 await supa.delete('ml_shopping_cart', { user_id: userId, product_id: productId }) ``` #### 3.2.5 调用数据库函数 (RPC) ```typescript // 计算购物车总金额 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 链式查询构建器 ```typescript // 使用链式 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 请求 ```typescript // 在代码中添加日志 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 请求日志 - 检查错误信息 - 分析性能问题 #### 示例: 测试查询 ```sql -- 在 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 ```http # 获取商品列表 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 ```sql -- 直接连接 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 场景一: 查询商品列表失败 #### 问题现象 ```typescript // 前端代码 const res = await supa.select('ml_products', null, { limit: 20 }) // res.success = false // res.error = "relation 'ml_products' does not exist" ``` #### 排查步骤 1. **检查数据库表是否存在** ```sql SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'ml_products'; ``` 2. **检查表是否已创建** - 执行 `complete_mall_database.sql` 脚本 - 验证脚本执行成功 3. **检查连接配置** ```typescript console.log('Supabase URL:', SUPA_URL) console.log('Supabase Key:', SUPA_KEY) ``` #### 解决方案 ```bash # 重新执行数据库脚本 psql -h localhost -U postgres -d postgres -f doc_mall/database/complete_mall_database.sql ``` ### 5.2 场景二: RLS 策略阻止数据访问 #### 问题现象 ```typescript // 查询用户数据返回空 const res = await supa.select('ml_user_profiles', { user_id: userId }) // res.data = [] 或 null ``` #### 排查步骤 1. **检查用户是否已登录** ```typescript const session = await supa.getSession() console.log('当前用户:', session.user) ``` 2. **检查 RLS 策略** ```sql -- 查看表的 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 关联** ```sql -- 验证 ak_users.auth_id 是否正确 SELECT id, auth_id FROM ak_users WHERE id = 'user-uuid'; ``` #### 解决方案 ```typescript // 确保用户已登录 await supa.signIn('user@example.com', 'password') // 或检查 Token const token = AkReq.getToken() console.log('JWT Token:', token) ``` ### 5.3 场景三: 插入数据失败 #### 问题现象 ```typescript // 插入订单失败 const res = await supa.insert('ml_orders', orderData) // res.success = false // res.error = "new row violates row-level security policy" ``` #### 排查步骤 1. **检查必填字段** ```typescript console.log('订单数据:', JSON.stringify(orderData, null, 2)) ``` 2. **检查外键约束** ```sql -- 验证 user_id 和 merchant_id 是否存在 SELECT id FROM ak_users WHERE id IN ('user-id', 'merchant-id'); ``` 3. **检查 RLS INSERT 策略** ```sql SELECT * FROM pg_policies WHERE tablename = 'ml_orders' AND cmd = 'INSERT'; ``` #### 解决方案 ```typescript // 确保数据完整 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 场景四: 实时数据同步不工作 #### 问题现象 ```typescript // 订阅订单状态更新,但没有收到推送 supa.realtime.subscribe('ml_orders', { filter: `id=eq.${orderId}`, event: 'UPDATE', callback: (payload) => { console.log('订单更新:', payload) // 没有触发 } }) ``` #### 排查步骤 1. **检查 WebSocket 连接** ```typescript console.log('WebSocket URL:', WS_URL) ``` 2. **检查表是否启用 Realtime** ```sql -- 在 Supabase Dashboard 中检查 -- Database -> Replication -> 确保 ml_orders 表已启用 ``` 3. **检查网络连接** - 确保 WebSocket 连接没有被防火墙阻止 - 检查浏览器控制台是否有 WebSocket 错误 #### 解决方案 ```typescript // 确保 WebSocket URL 正确 export const WS_URL: string = 'wss://your-project.supabase.co/realtime/v1/websocket' // 在 Supabase Dashboard 中启用表的 Realtime // Database -> Replication -> 找到 ml_orders -> 启用 ``` ### 5.5 场景五: 数据库函数调用失败 #### 问题现象 ```typescript // 调用 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. **检查函数是否存在** ```sql SELECT routine_name FROM information_schema.routines WHERE routine_schema = 'public' AND routine_name = 'calculate_cart_total'; ``` 2. **检查函数参数** ```sql -- 查看函数定义 \df calculate_cart_total ``` 3. **测试函数** ```sql SELECT calculate_cart_total('user-uuid-here'); ``` #### 解决方案 ```bash # 重新执行数据库脚本,确保函数已创建 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 常用调试命令 #### 前端调试 ```typescript // 打印完整请求信息 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 }) ``` #### 数据库调试 ```sql -- 查看表结构 \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 日志收集 #### 前端日志 ```typescript // 创建日志工具 class DebugLogger { static log(module: string, action: string, data: any) { console.log(`[${module}] ${action}:`, data) // 可以发送到日志服务器 } } // 使用 DebugLogger.log('MallAPI', '查询商品', { filter, options }) ``` #### 后端日志 ```sql -- 启用 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. **使用环境变量** ```typescript // 开发环境 const isDev = process.env.NODE_ENV === 'development' export const SUPA_URL = isDev ? 'http://192.168.0.150:8080' : 'https://ak3.oulog.com' ``` 2. **统一错误处理** ```typescript async function safeApiCall(apiCall: () => Promise>) { 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. **请求重试机制** ```typescript async function retryApiCall( apiCall: () => Promise>, 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. **问题排查** - 查看日志 - 检查网络请求 - 验证数据库数据 --- ## 📚 相关文档 - [模块分析报告](./MODULE_ANALYSIS.md) - [数据库创建报告](./database/database_creation_report.md) - [完整部署指南](./database/complete_deployment_guide.md) - [Supabase 官方文档](https://supabase.com/docs) --- **生成时间**: 2025年1月 **版本**: v1.0 **状态**: ✅ 完整联调指南