# UTS AkReq HEAD 请求支持说明 ## 概述 为了正确支持 Supabase 的 `head: true` 选项,我们对 `ak-req.uts` 进行了增强,使其能够正确处理 HEAD 请求的特殊响应格式。 ## HEAD 请求的特点 ### HTTP 标准 - HEAD 请求与 GET 请求相同,但**只返回响应头,不返回响应体** - 适用于只需要元数据而不需要实际内容的场景 - 用于检查资源状态、获取缓存信息、计算文件大小等 ### Supabase 中的应用 - `{ head: true }` 选项会使用 HEAD 请求 - 响应体为空,但 `Content-Range` header 包含 count 信息 - 极大减少网络传输量 ## AkReq 的增强实现 ### 修改前的问题 ```typescript // 原始实现:不区分 HEAD 和 GET success: (res) => { // 总是尝试解析 res.data,即使是 HEAD 请求 let data: UTSJSONObject | Array | null; if (typeof res.data == 'string') { // ... 解析逻辑 } } ``` ### 修改后的正确处理 ```typescript success: (res) => { // HEAD 请求特殊处理:没有响应体,只有 headers if (options.method === 'HEAD') { const result = { status: res.statusCode, data: null, // HEAD 请求没有数据 headers: res.header as UTSJSONObject, error: null } as AkReqResponse resolve(result); return; } // 其他请求正常解析 data // ... } ``` ## 完整的数据流 ### 1. 发起 HEAD 请求 ```typescript const result = await supa .from('ak_assignments') .select('*', { count: 'exact', head: true }) .eq('teacher_id', userId) .execute() ``` ### 2. AkSupa 构建请求 ```typescript // aksupa.uts let httpMethod = 'GET'; if (options != null && options.head == true) { httpMethod = 'HEAD'; // 使用 HEAD 方法 } let reqOptions: AkReqOptions = { url, method: httpMethod, // 'HEAD' headers: { 'Prefer': 'count=exact,return=minimal' } } ``` ### 3. AkReq 处理响应 ```typescript // ak-req.uts if (options.method === 'HEAD') { return { status: 200, data: null, // HEAD 请求没有响应体 headers: { // 重要信息在 headers 中 'content-range': '0-0/42', // count 信息 'content-type': 'application/json' }, error: null } } ``` ### 4. AkSupa 解析 count ```typescript // aksupa.uts // 从 content-range header 解析 count let contentRange = res.headers?.get('content-range') if (contentRange != null) { const match = /\/(\d+)$/.exec(contentRange); if (match != null) { total = parseInt(match[1] ?? "0"); // 提取 count } } // HEAD 模式返回 count if (this._options.head == true) { return { data: null, count: total, // 解析出的 count total, // ... }; } ``` ### 5. 应用层使用 ```typescript // dashboard.uvue const result = await supa.from('ak_assignments') .select('*', { count: 'exact', head: true }) .execute() const count = result.total // 42 ``` ## 网络请求对比 ### GET 请求(大量数据传输) ``` Request: GET /rest/v1/ak_assignments?select=*&count=exact&teacher_id=eq.123 Response: HTTP/1.1 200 OK Content-Range: 0-9/42 Content-Type: application/json [ {"id": 1, "title": "作业1", "description": "...", ...}, {"id": 2, "title": "作业2", "description": "...", ...}, // ... 更多数据 ] ``` ### HEAD 请求(最小数据传输) ``` Request: HEAD /rest/v1/ak_assignments?select=*&count=exact&teacher_id=eq.123 Response: HTTP/1.1 200 OK Content-Range: 0-0/42 Content-Type: application/json (无响应体) ``` ## 性能优势 ### 传输量对比 | 请求类型 | 响应体大小 | 网络传输 | 解析开销 | |---------|-----------|---------|---------| | GET | ~50KB | 大 | 高 | | HEAD | 0KB | 小 | 极低 | ### 实际场景 ```typescript // 统计查询场景 const stats = await Promise.all([ supa.from('assignments').select('*', { count: 'exact', head: true }).execute(), supa.from('students').select('*', { count: 'exact', head: true }).execute(), supa.from('courses').select('*', { count: 'exact', head: true }).execute() ]) // 如果用 GET:可能传输几百KB数据 // 使用 HEAD:只传输几KB headers ``` ## 错误处理 ### HEAD 请求可能的错误 ```typescript const safeHeadRequest = async (queryBuilder: any) => { try { const result = await queryBuilder.execute() // HEAD 请求成功但没有 count 信息 if (result.data === null && result.total === 0) { console.warn('HEAD 请求可能没有正确解析 count') } return result.total ?? 0 } catch (error) { console.error('HEAD 请求失败:', error) return 0 } } ``` ### 调试 HEAD 请求 ```typescript const debugHeadRequest = async () => { const result = await supa .from('ak_assignments') .select('*', { count: 'exact', head: true }) .execute() console.log('HEAD 请求结果:') console.log('- Status:', result.status) console.log('- Data:', result.data) // 应该为 null console.log('- Total:', result.total) // 应该有数值 console.log('- Headers:', result.headers) // 包含 content-range return result } ``` ## 最佳实践 ### 1. 统计查询使用 HEAD ```typescript // ✅ 推荐:统计查询使用 HEAD const getAssignmentCount = async (teacherId: string) => { const result = await supa .from('ak_assignments') .select('*', { count: 'exact', head: true }) .eq('teacher_id', teacherId) .execute() return result.total ?? 0 } ``` ### 2. 数据查询使用 GET ```typescript // ✅ 推荐:需要数据时使用 GET const getAssignmentList = async (teacherId: string) => { const result = await supa .from('ak_assignments') .select('*', { count: 'exact' }) // 不使用 head .eq('teacher_id', teacherId) .limit(10) .execute() return { data: result.data, total: result.total } } ``` ### 3. 混合场景 ```typescript // 先获取总数,再按需获取数据 const loadDashboard = async (teacherId: string) => { // 1. 快速获取统计(HEAD) const [totalCount, completedCount] = await Promise.all([ supa.from('ak_assignments').select('*', { count: 'exact', head: true }).eq('teacher_id', teacherId).execute(), supa.from('ak_assignments').select('*', { count: 'exact', head: true }).eq('teacher_id', teacherId).eq('status', 'completed').execute() ]) // 2. 根据需要获取具体数据(GET) const recentData = await supa .from('ak_assignments') .select('*') .eq('teacher_id', teacherId) .order('created_at', { ascending: false }) .limit(5) .execute() return { stats: { total: totalCount.total, completed: completedCount.total }, recent: recentData.data } } ``` ## 总结 通过增强 `ak-req.uts` 对 HEAD 请求的支持: 1. **正确处理**:HEAD 请求不解析响应体,直接返回 `data: null` 2. **性能优化**:大幅减少网络传输量 3. **符合标准**:遵循 HTTP HEAD 请求规范 4. **无缝集成**:与现有 Supabase count 功能完美配合 这使得 UTS 应用能够高效地进行数据统计查询,特别适合仪表板、统计页面等场景。