876 lines
19 KiB
Markdown
876 lines
19 KiB
Markdown
# 🔧 前端与后端联调指南
|
|
|
|
## 📋 目录
|
|
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<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
|
|
```
|
|
|
|
#### 在页面中使用
|
|
|
|
```typescript
|
|
// 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)
|
|
|
|
```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<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. **请求重试机制**
|
|
```typescript
|
|
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. **问题排查**
|
|
- 查看日志
|
|
- 检查网络请求
|
|
- 验证数据库数据
|
|
|
|
---
|
|
|
|
## 📚 相关文档
|
|
|
|
- [模块分析报告](./MODULE_ANALYSIS.md)
|
|
- [数据库创建报告](./database/database_creation_report.md)
|
|
- [完整部署指南](./database/complete_deployment_guide.md)
|
|
- [Supabase 官方文档](https://supabase.com/docs)
|
|
|
|
---
|
|
|
|
**生成时间**: 2025年1月
|
|
**版本**: v1.0
|
|
**状态**: ✅ 完整联调指南
|