Parcourir la source

🐛 fix(server): 增强错误响应信息

- 在500错误响应中包含错误堆栈信息,便于问题排查

✨ feat(utils): 添加异步数据解析工具函数

- 创建parseWithAwait工具函数,支持解析包含Promise的异步数据
- 实现路径解析和Promise自动等待功能,提升数据验证灵活性
- 添加getValueByPath和setValueByPath辅助函数,支持深层对象操作
yourname il y a 3 mois
Parent
commit
84a1d9c104
2 fichiers modifiés avec 60 ajouts et 1 suppressions
  1. 1 1
      server.js
  2. 59 0
      src/server/utils/parseWithAwait.ts

+ 1 - 1
server.js

@@ -295,7 +295,7 @@ app.use(async (c) => {
       vite.ssrFixStacktrace(e);
     }
     console.error('请求处理错误:', e.stack);
-    return c.text('服务器内部错误', 500);
+    return c.text('服务器内部错误' + e.stack, 500);
   }
 });
 

+ 59 - 0
src/server/utils/parseWithAwait.ts

@@ -0,0 +1,59 @@
+import { z } from '@hono/zod-openapi';
+
+export async function parseWithAwait<T>(schema: z.ZodSchema<T>, data: unknown): Promise<T> {  
+    // 先尝试同步解析,捕获 Promise 错误  
+    const syncResult = schema.safeParse(data);  
+      
+    if (!syncResult.success) {  
+      // 提取 Promise 错误的路径信息  
+      const promiseErrors = syncResult.error.issues.filter(issue =>   
+        issue.code === 'invalid_type' &&   
+        issue.message.includes('received Promise')  
+      );  
+        
+      if (promiseErrors.length > 0) {  
+        // 根据路径直接 await Promise  
+        const processedData = await resolvePromisesByPath(data, promiseErrors);  
+          
+        // 重新解析处理后的数据  
+        return schema.parse(processedData) as T;  
+      }  
+        
+      throw syncResult.error;  
+    }  
+      
+    return syncResult.data as T;  
+  }  
+    
+  async function resolvePromisesByPath(data: any, promiseErrors: any[]): Promise<any> {  
+    const clonedData = JSON.parse(JSON.stringify(data, (key, value) => {  
+      // 保留 Promise 对象,不进行序列化  
+      return typeof value?.then === 'function' ? value : value;  
+    }));  
+      
+    // 根据错误路径逐个处理 Promise  
+    for (const error of promiseErrors) {  
+      const path = error.path;  
+      const promiseValue = getValueByPath(data, path);  
+        
+      if (promiseValue && typeof promiseValue.then === 'function') {  
+        const resolvedValue = await promiseValue;  
+        setValueByPath(clonedData, path, resolvedValue);  
+      }  
+    }  
+      
+    return clonedData;  
+  }  
+    
+  function getValueByPath(obj: any, path: (string | number)[]): any {  
+    return path.reduce((current, key) => current?.[key], obj);  
+  }  
+    
+  function setValueByPath(obj: any, path: (string | number)[], value: any): void {  
+    const lastKey = path[path.length - 1];  
+    const parentPath = path.slice(0, -1);  
+    const parent = getValueByPath(obj, parentPath);  
+    if (parent) {  
+      parent[lastKey] = value;  
+    }  
+  }