浏览代码

代码codereview优化

admincjy 3 周之前
父节点
当前提交
7f5ba0914f
共有 2 个文件被更改,包括 181 次插入168 次删除
  1. 69 71
      public/js/reader.js
  2. 112 97
      server.js

+ 69 - 71
public/js/reader.js

@@ -78,6 +78,57 @@ function getDocDisplayName(docName) {
     return name || docName;
 }
 
+// ========== 工具函数 ==========
+
+// URL 编码路径(支持子目录)
+function encodeDocPath(docName) {
+    return docName.split('/').map(part => encodeURIComponent(part)).join('/');
+}
+
+// API 错误处理
+async function handleApiError(response, defaultMessage) {
+    const errorData = await response.json().catch(() => ({}));
+    throw new Error(errorData.error || `${defaultMessage} (${response.status})`);
+}
+
+// 确保 DOM 元素已缓存
+function ensureDOM(key, id) {
+    if (!DOM[key]) DOM[key] = document.getElementById(id);
+    return DOM[key];
+}
+
+// 通用防抖函数
+function debounce(func, wait) {
+    let timeout;
+    return function executedFunction(...args) {
+        clearTimeout(timeout);
+        timeout = setTimeout(() => func.apply(this, args), wait);
+    };
+}
+
+// 高亮代码块
+function highlightCodeBlock(block) {
+    block.classList.add('hljs');
+
+    // 如果已经高亮过了,跳过
+    if (block.querySelector('span')) return;
+
+    const lang = block.className.match(/language-(\w+)/)?.[1];
+
+    try {
+        const highlighted = (lang && hljs.getLanguage(lang))
+            ? hljs.highlight(block.textContent, { language: lang })
+            : hljs.highlightAuto(block.textContent);
+
+        block.innerHTML = highlighted.value;
+        if (highlighted.language) {
+            block.classList.add(`language-${highlighted.language}`);
+        }
+    } catch (err) {
+        console.error('Error highlighting code:', err);
+    }
+}
+
 // 加载文档列表
 async function loadDocList() {
     const { category } = getQueryParams();
@@ -165,21 +216,18 @@ function handleNavClick(e) {
 
 // 加载文档内容
 async function loadDocument(docName, scrollToText = null) {
-    // 使用 DOM 缓存
-    if (!DOM.loading) DOM.loading = document.getElementById('loading');
-    if (!DOM.content) DOM.content = document.getElementById('markdown-content');
+    ensureDOM('loading', 'loading');
+    ensureDOM('content', 'markdown-content');
 
     DOM.loading.style.display = 'flex';
     DOM.content.innerHTML = '';
 
     try {
-        // 对于包含子目录的文档名,需要分段编码
-        const encodedDocName = docName.split('/').map(part => encodeURIComponent(part)).join('/');
+        const encodedDocName = encodeDocPath(docName);
         const response = await fetch(`/api/doc/${encodeURIComponent(currentCategory)}/${encodedDocName}`);
 
         if (!response.ok) {
-            const errorData = await response.json().catch(() => ({}));
-            throw new Error(errorData.error || `加载失败 (${response.status})`);
+            await handleApiError(response, '加载失败');
         }
 
         const data = await response.json();
@@ -196,56 +244,17 @@ async function loadDocument(docName, scrollToText = null) {
         const html = marked.parse(data.content);
         DOM.content.innerHTML = html;
 
-        // 处理图片路径,将相对路径转换为正确的URL
+        // 处理图片路径(将相对路径转换为API路径)
         DOM.content.querySelectorAll('img').forEach(img => {
             const src = img.getAttribute('src');
-            // 如果是相对路径(不以 http/https 开头)
-            if (src && !src.startsWith('http://') && !src.startsWith('https://') && !src.startsWith('/')) {
-                // 使用新的API路径,避免中文路径问题
-                const newSrc = `/api/image/${encodeURIComponent(currentCategory)}/${src}`;
-                img.setAttribute('src', newSrc);
-                // 添加错误处理
-                img.onerror = function() {
-                    console.error('Failed to load image:', newSrc);
-                    // 显示占位图片或错误提示
-                    this.alt = `图片加载失败: ${src}`;
-                    this.classList.add('img-error');
-                };
+            if (src && !src.match(/^https?:\/\//)) {
+                img.setAttribute('data-original-src', src);
+                img.src = `/api/image/${encodeURIComponent(currentCategory)}/${src}`;
             }
         });
 
-        // 手动为所有代码块添加 hljs 类并确保高亮(修复 marked 高亮可能失败的问题)
-        DOM.content.querySelectorAll('pre code').forEach((block) => {
-            // 如果代码块没有 hljs 类,添加它
-            if (!block.classList.contains('hljs')) {
-                block.classList.add('hljs');
-            }
-            // 如果没有高亮的标记(没有 span 元素),尝试重新高亮
-            if (!block.querySelector('span')) {
-                const lang = block.className.match(/language-(\w+)/)?.[1];
-                if (lang && hljs.getLanguage(lang)) {
-                    try {
-                        const highlighted = hljs.highlight(block.textContent, { language: lang });
-                        block.innerHTML = highlighted.value;
-                        block.classList.add('hljs', `language-${lang}`);
-                    } catch (err) {
-                        console.error('Error re-highlighting:', err);
-                    }
-                } else {
-                    // 尝试自动检测
-                    try {
-                        const highlighted = hljs.highlightAuto(block.textContent);
-                        block.innerHTML = highlighted.value;
-                        block.classList.add('hljs');
-                        if (highlighted.language) {
-                            block.classList.add(`language-${highlighted.language}`);
-                        }
-                    } catch (err) {
-                        console.error('Error auto-highlighting:', err);
-                    }
-                }
-            }
-        });
+        // 代码块高亮
+        DOM.content.querySelectorAll('pre code').forEach(highlightCodeBlock);
 
         // 为所有代码块添加复制按钮
         addCopyButtonsToCodeBlocks();
@@ -280,15 +289,11 @@ async function loadDocument(docName, scrollToText = null) {
 
 // 生成 TOC
 function generateTOC() {
-    // 使用 DOM 缓存
-    if (!DOM.toc) DOM.toc = document.getElementById('toc');
-
-    // 确保 DOM.content 也被正确缓存
-    if (!DOM.content) DOM.content = document.getElementById('markdown-content');
+    ensureDOM('toc', 'toc');
+    ensureDOM('content', 'markdown-content');
 
-    // 先清空旧的TOC内容和事件监听器
+    // 先清空旧的TOC内容
     DOM.toc.innerHTML = '';
-    DOM.toc.removeEventListener('click', handleTocClick);
 
     const headings = DOM.content.querySelectorAll('h1, h2, h3, h4, h5, h6');
 
@@ -607,8 +612,7 @@ function initSearch() {
             );
 
             if (!response.ok) {
-                const errorData = await response.json().catch(() => ({}));
-                throw new Error(errorData.error || `搜索失败 (${response.status})`);
+                await handleApiError(response, '搜索失败');
             }
 
             const data = await response.json();
@@ -617,7 +621,6 @@ function initSearch() {
 
         } catch (err) {
             console.error('Search error:', err);
-            // 向用户显示错误信息
             displaySearchError(err.message || '搜索失败,请稍后重试');
         }
     };
@@ -667,10 +670,7 @@ function initSearch() {
     });
 
     // 输入时实时搜索(防抖) - 500ms 减少 API 调用
-    searchInput.addEventListener('input', () => {
-        clearTimeout(searchTimeout);
-        searchTimeout = setTimeout(performSearch, 500);
-    });
+    searchInput.addEventListener('input', debounce(performSearch, 500));
 
     // 点击搜索按钮
     searchBtn.addEventListener('click', performSearch);
@@ -1199,13 +1199,12 @@ async function saveDocument() {
     }
 
     // 禁用保存按钮,防止重复点击
-    if (!DOM.saveBtn) DOM.saveBtn = document.getElementById('save-btn');
+    ensureDOM('saveBtn', 'save-btn');
     DOM.saveBtn.disabled = true;
     DOM.saveBtn.textContent = '保存中...';
 
     try {
-        // 对于包含子目录的文档名,需要分段编码
-        const encodedDocName = currentDoc.split('/').map(part => encodeURIComponent(part)).join('/');
+        const encodedDocName = encodeDocPath(currentDoc);
         const response = await fetch(`/api/doc/${encodeURIComponent(currentCategory)}/${encodedDocName}`, {
             method: 'PUT',
             headers: {
@@ -1217,8 +1216,7 @@ async function saveDocument() {
         });
 
         if (!response.ok) {
-            const errorData = await response.json().catch(() => ({}));
-            throw new Error(errorData.error || `保存失败 (${response.status})`);
+            await handleApiError(response, '保存失败');
         }
 
         const result = await response.json();

+ 112 - 97
server.js

@@ -10,6 +10,13 @@ const PORT = 3000;
 // 硬编码的密码
 const PASSWORD = 'cjy@0526';
 
+// 目录常量
+const DIRS = {
+  public: path.join(__dirname, 'public'),
+  docs: path.join(__dirname, 'docs'),
+  index: path.join(__dirname, 'index.md')
+};
+
 // index.md 缓存
 let indexCache = null;
 let indexCacheTime = 0;
@@ -35,6 +42,40 @@ function validatePath(fullPath, baseDir) {
     return resolvedPath.startsWith(resolvedBaseDir);
 }
 
+// 检查是否已认证
+function isAuthenticated(req) {
+    return req.session && req.session.isAuthenticated === true;
+}
+
+// 统一的错误响应助手
+const ErrorResponse = {
+    badRequest: (res, message, details = null) => {
+        const response = { error: message };
+        if (details) response.details = details;
+        return res.status(400).json(response);
+    },
+
+    unauthorized: (res, message = '未授权') => {
+        return res.status(401).json({ error: message });
+    },
+
+    forbidden: (res, message = '拒绝访问') => {
+        return res.status(403).json({ error: message });
+    },
+
+    notFound: (res, message, details = null) => {
+        const response = { error: message };
+        if (details) response.details = details;
+        return res.status(404).json(response);
+    },
+
+    serverError: (res, message, details = null) => {
+        const response = { error: message };
+        if (details) response.details = details;
+        return res.status(500).json(response);
+    }
+};
+
 // 中间件
 // CORS 配置 - 允许前端携带凭证(cookies)
 app.use(cors({
@@ -62,13 +103,13 @@ app.use(session({
 
 // 登录验证中间件
 function requireAuth(req, res, next) {
-  if (req.session && req.session.isAuthenticated) {
+  if (isAuthenticated(req)) {
     return next();
   }
 
   // 如果是 API 请求,返回 401
   if (req.path.startsWith('/api')) {
-    return res.status(401).json({ error: '未登录,请先登录' });
+    return ErrorResponse.unauthorized(res, '未登录,请先登录');
   }
 
   // 如果是页面请求,重定向到登录页
@@ -77,73 +118,62 @@ function requireAuth(req, res, next) {
 
 // 根路径重定向处理
 app.get('/', (req, res) => {
-  console.log('访问首页 - Session状态:', req.session ? req.session.isAuthenticated : 'no session');
-
-  if (req.session && req.session.isAuthenticated) {
-    const indexPath = path.join(__dirname, 'public', 'index.html');
-    console.log('发送首页文件:', indexPath);
-
-    res.sendFile(indexPath, (err) => {
-      if (err) {
+  if (isAuthenticated(req)) {
+    res.sendFile(path.join(DIRS.public, 'index.html'), (err) => {
+      if (err && !res.headersSent) {
         console.error('发送首页文件失败:', err);
-        res.status(500).json({ error: '无法加载首页', details: err.message });
+        ErrorResponse.serverError(res, '无法加载首页', err.message);
       }
     });
   } else {
-    console.log('未登录,重定向到登录页');
     res.redirect('/login.html');
   }
 });
 
 // reader.html 需要登录
 app.get('/reader.html', (req, res) => {
-  if (req.session && req.session.isAuthenticated) {
-    res.sendFile(path.join(__dirname, 'public', 'reader.html'));
+  if (isAuthenticated(req)) {
+    res.sendFile(path.join(DIRS.public, 'reader.html'));
   } else {
     res.redirect('/login.html');
   }
 });
 
 // 静态文件服务(CSS、JS、图片等)
-app.use('/css', express.static(path.join(__dirname, 'public', 'css')));
-app.use('/js', express.static(path.join(__dirname, 'public', 'js')));
+app.use('/css', express.static(path.join(DIRS.public, 'css')));
+app.use('/js', express.static(path.join(DIRS.public, 'js')));
 
 // login.html 不需要登录
 app.get('/login.html', (req, res) => {
   // 如果已登录,重定向到首页
-  if (req.session && req.session.isAuthenticated) {
+  if (isAuthenticated(req)) {
     res.redirect('/');
   } else {
-    res.sendFile(path.join(__dirname, 'public', 'login.html'));
+    res.sendFile(path.join(DIRS.public, 'login.html'));
   }
 });
 
 // API: 登录
 app.post('/api/login', (req, res) => {
   const { password } = req.body;
-  console.log('登录尝试 - IP:', req.ip, 'Session ID:', req.sessionID);
 
   if (!password || typeof password !== 'string') {
-    console.log('登录失败: 密码格式错误');
-    return res.status(400).json({ error: '请输入密码' });
+    return ErrorResponse.badRequest(res, '请输入密码');
   }
 
   if (password === PASSWORD) {
     req.session.isAuthenticated = true;
-    console.log('登录成功 - Session ID:', req.sessionID, 'Session数据:', req.session);
 
     // 保存 session 后再响应
     req.session.save((err) => {
       if (err) {
         console.error('Session保存失败:', err);
-        return res.status(500).json({ error: '登录失败,请重试' });
+        return ErrorResponse.serverError(res, '登录失败,请重试');
       }
-      console.log('Session保存成功');
       res.json({ success: true, message: '登录成功' });
     });
   } else {
-    console.log('登录失败: 密码错误');
-    res.status(401).json({ error: '密码错误' });
+    return ErrorResponse.unauthorized(res, '密码错误');
   }
 });
 
@@ -151,7 +181,7 @@ app.post('/api/login', (req, res) => {
 app.post('/api/logout', (req, res) => {
   req.session.destroy((err) => {
     if (err) {
-      return res.status(500).json({ error: '登出失败' });
+      return ErrorResponse.serverError(res, '登出失败');
     }
     res.json({ success: true, message: '登出成功' });
   });
@@ -159,37 +189,31 @@ app.post('/api/logout', (req, res) => {
 
 // API: 检查登录状态
 app.get('/api/check-auth', (req, res) => {
-  if (req.session && req.session.isAuthenticated) {
-    res.json({ authenticated: true });
-  } else {
-    res.json({ authenticated: false });
-  }
+  res.json({ authenticated: isAuthenticated(req) });
 });
 
 // API: 获取图片资源(需要登录)
 app.get('/api/image/:category/*', requireAuth, async (req, res) => {
   try {
-    // 对分类名进行处理(移除危险字符但保留中文)
-    const category = req.params.category.replace(/\.\./g, '');
+    const category = sanitizePath(req.params.category);
     const imagePath = req.params[0]; // 获取剩余路径部分,如 'assets/test.png'
 
     if (!category || !imagePath) {
-      return res.status(400).json({ error: '无效的请求路径' });
+      return ErrorResponse.badRequest(res, '无效的请求路径');
     }
 
-    const docsDir = path.join(__dirname, 'docs');
-    const fullPath = path.join(docsDir, category, imagePath);
+    const fullPath = path.join(DIRS.docs, category, imagePath);
 
     // 验证路径安全性
-    if (!validatePath(fullPath, docsDir)) {
-      return res.status(403).json({ error: '拒绝访问' });
+    if (!validatePath(fullPath, DIRS.docs)) {
+      return ErrorResponse.forbidden(res, '拒绝访问');
     }
 
     // 检查文件是否存在
     try {
       await fs.access(fullPath);
     } catch (err) {
-      return res.status(404).json({ error: '图片不存在' });
+      return ErrorResponse.notFound(res, '图片不存在');
     }
 
     // 发送图片文件
@@ -197,7 +221,7 @@ app.get('/api/image/:category/*', requireAuth, async (req, res) => {
 
   } catch (error) {
     console.error('Error serving image:', error);
-    res.status(500).json({ error: '无法加载图片' });
+    return ErrorResponse.serverError(res, '无法加载图片');
   }
 });
 
@@ -209,8 +233,7 @@ async function getIndexStructure() {
     return indexCache;
   }
 
-  const indexPath = path.join(__dirname, 'index.md');
-  const content = await fs.readFile(indexPath, 'utf-8');
+  const content = await fs.readFile(DIRS.index, 'utf-8');
   indexCache = parseIndexMd(content);
   indexCacheTime = now;
   return indexCache;
@@ -222,7 +245,7 @@ app.get('/api/structure', requireAuth, async (req, res) => {
     const structure = await getIndexStructure();
     res.json(structure);
   } catch (error) {
-    res.status(500).json({ error: '无法解析文档结构', details: error.message });
+    return ErrorResponse.serverError(res, '无法解析文档结构', error.message);
   }
 });
 
@@ -232,19 +255,19 @@ app.get('/api/category/:category', requireAuth, async (req, res) => {
     const category = sanitizePath(req.params.category);
 
     if (!category) {
-      return res.status(400).json({ error: '无效的分类名称' });
+      return ErrorResponse.badRequest(res, '无效的分类名称');
     }
 
     const structure = await getIndexStructure();
     const categoryData = structure.find(cat => cat.name === category);
 
     if (!categoryData) {
-      return res.status(404).json({ error: '分类不存在' });
+      return ErrorResponse.notFound(res, '分类不存在');
     }
 
     res.json(categoryData);
   } catch (error) {
-    res.status(500).json({ error: '无法获取分类信息', details: error.message });
+    return ErrorResponse.serverError(res, '无法获取分类信息', error.message);
   }
 });
 
@@ -256,22 +279,21 @@ app.get('/api/doc/:category/*', requireAuth, async (req, res) => {
     const docName = req.params[0]; // 获取剩余的路径部分,支持子目录
 
     if (!category || !docName) {
-      return res.status(400).json({ error: '无效的分类或文档名称' });
+      return ErrorResponse.badRequest(res, '无效的分类或文档名称');
     }
 
-    const docsDir = path.join(__dirname, 'docs');
     // 直接使用 docName,它可能包含子目录路径
-    const docPath = path.join(docsDir, category, `${docName}.md`);
+    const docPath = path.join(DIRS.docs, category, `${docName}.md`);
 
     // 验证路径是否在 docs 目录内
-    if (!validatePath(docPath, docsDir)) {
-      return res.status(403).json({ error: '拒绝访问:无效的路径' });
+    if (!validatePath(docPath, DIRS.docs)) {
+      return ErrorResponse.forbidden(res, '拒绝访问:无效的路径');
     }
 
     const content = await fs.readFile(docPath, 'utf-8');
     res.json({ content, category, docName });
   } catch (error) {
-    res.status(500).json({ error: '无法读取文档', details: error.message });
+    return ErrorResponse.serverError(res, '无法读取文档', error.message);
   }
 });
 
@@ -285,27 +307,26 @@ app.put('/api/doc/:category/*', requireAuth, async (req, res) => {
 
     // 验证输入
     if (!category || !docName) {
-      return res.status(400).json({ error: '无效的分类或文档名称' });
+      return ErrorResponse.badRequest(res, '无效的分类或文档名称');
     }
 
     if (!content || typeof content !== 'string') {
-      return res.status(400).json({ error: '无效的文档内容' });
+      return ErrorResponse.badRequest(res, '无效的文档内容');
     }
 
-    const docsDir = path.join(__dirname, 'docs');
     // 直接使用 docName,它可能包含子目录路径
-    const docPath = path.join(docsDir, category, `${docName}.md`);
+    const docPath = path.join(DIRS.docs, category, `${docName}.md`);
 
     // 验证路径是否在 docs 目录内
-    if (!validatePath(docPath, docsDir)) {
-      return res.status(403).json({ error: '拒绝访问:无效的路径' });
+    if (!validatePath(docPath, DIRS.docs)) {
+      return ErrorResponse.forbidden(res, '拒绝访问:无效的路径');
     }
 
     // 检查文件是否存在
     try {
       await fs.access(docPath);
     } catch (error) {
-      return res.status(404).json({ error: '文档不存在' });
+      return ErrorResponse.notFound(res, '文档不存在');
     }
 
     // 保存文件
@@ -319,7 +340,7 @@ app.put('/api/doc/:category/*', requireAuth, async (req, res) => {
     });
   } catch (error) {
     console.error('Save document error:', error);
-    res.status(500).json({ error: '无法保存文档', details: error.message });
+    return ErrorResponse.serverError(res, '无法保存文档', error.message);
   }
 });
 
@@ -327,12 +348,11 @@ app.put('/api/doc/:category/*', requireAuth, async (req, res) => {
 app.get('/api/search/:category', requireAuth, async (req, res) => {
   try {
     const category = sanitizePath(req.params.category);
-    // currentDoc 可能包含子目录路径,不要使用 sanitizePath
     const currentDoc = req.query.currentDoc || '';
     const { q } = req.query;
 
     if (!category) {
-      return res.status(400).json({ error: '无效的分类名称' });
+      return ErrorResponse.badRequest(res, '无效的分类名称');
     }
 
     if (!q || q.trim().length === 0) {
@@ -340,12 +360,11 @@ app.get('/api/search/:category', requireAuth, async (req, res) => {
     }
 
     const query = q.toLowerCase();
-    const docsDir = path.join(__dirname, 'docs');
-    const categoryPath = path.join(docsDir, category);
+    const categoryPath = path.join(DIRS.docs, category);
 
     // 验证路径是否在 docs 目录内
-    if (!validatePath(categoryPath, docsDir)) {
-      return res.status(403).json({ error: '拒绝访问:无效的路径' });
+    if (!validatePath(categoryPath, DIRS.docs)) {
+      return ErrorResponse.forbidden(res, '拒绝访问:无效的路径');
     }
 
     // 从 index.md 获取当前分类下应该搜索的文档列表
@@ -353,67 +372,66 @@ app.get('/api/search/:category', requireAuth, async (req, res) => {
     const categoryData = structure.find(cat => cat.name === category);
 
     if (!categoryData) {
-      return res.status(404).json({ error: '分类不存在' });
+      return ErrorResponse.notFound(res, '分类不存在');
     }
 
-    // 只搜索 index.md 中列出的文档
-    const mdFiles = categoryData.docs.map(doc => {
-      // doc.name 可能包含子目录路径,如 "测试/11"
-      return doc.name + '.md';
-    });
-
-    const currentDocResults = [];
-    const otherDocsResults = [];
+    // 并行读取所有文档
+    const MAX_MATCHES_PER_DOC = 5;
+    const decodedCurrentDoc = decodeURIComponent(currentDoc).replace(/\\/g, '/');
 
-    // 搜索每个文档
-    for (const file of mdFiles) {
-      const docName = file.replace('.md', '').replace(/\\/g, '/'); // 统一使用正斜杠
-      const filePath = path.join(categoryPath, file.replace(/\//g, path.sep)); // 处理路径分隔符
+    const fileReadPromises = categoryData.docs.map(async (doc) => {
+      const docName = doc.name;
+      const filePath = path.join(categoryPath, `${docName}.md`);
 
-      // 检查文件是否存在(以防 index.md 中列出的文件实际不存在)
       try {
-        await fs.access(filePath);
+        const content = await fs.readFile(filePath, 'utf-8');
+        return { docName, content, exists: true };
       } catch (err) {
         console.warn(`文档不存在,跳过搜索: ${filePath}`);
-        continue;
+        return { docName, exists: false };
       }
+    });
+
+    const fileContents = await Promise.all(fileReadPromises);
+    const currentDocResults = [];
+    const otherDocsResults = [];
 
-      const content = await fs.readFile(filePath, 'utf-8');
+    // 搜索每个文档
+    for (const { docName, content, exists } of fileContents) {
+      if (!exists) continue;
 
-      // 搜索匹配的行
       const lines = content.split('\n');
       const matches = [];
 
-      lines.forEach((line, index) => {
+      // 搜索匹配的行,达到上限后提前退出
+      for (let index = 0; index < lines.length && matches.length < MAX_MATCHES_PER_DOC; index++) {
+        const line = lines[index];
         const lowerLine = line.toLowerCase();
+
         if (lowerLine.includes(query)) {
-          // 获取上下文(前后各50个字符)
           const startIndex = Math.max(0, lowerLine.indexOf(query) - 50);
           const endIndex = Math.min(line.length, lowerLine.indexOf(query) + query.length + 50);
           let snippet = line.substring(startIndex, endIndex);
 
-          // 如果不是从头开始,添加省略号
           if (startIndex > 0) snippet = '...' + snippet;
           if (endIndex < line.length) snippet = snippet + '...';
 
           matches.push({
             line: index + 1,
-            snippet: snippet,
+            snippet,
             fullLine: line
           });
         }
-      });
+      }
 
       if (matches.length > 0) {
         const result = {
           docName,
           matchCount: matches.length,
-          matches: matches.slice(0, 5) // 最多返回5个匹配
+          matches
         };
 
         // 区分当前文档和其他文档
-        // 处理 URL 解码后的 currentDoc(支持斜杠路径)
-        const decodedCurrentDoc = decodeURIComponent(currentDoc).replace(/\\/g, '/');
         if (docName === decodedCurrentDoc) {
           currentDocResults.push(result);
         } else {
@@ -429,7 +447,7 @@ app.get('/api/search/:category', requireAuth, async (req, res) => {
     });
 
   } catch (error) {
-    res.status(500).json({ error: '搜索失败', details: error.message });
+    return ErrorResponse.serverError(res, '搜索失败', error.message);
   }
 });
 
@@ -483,7 +501,6 @@ app.use((err, req, res, next) => {
 
 // 404 处理
 app.use((req, res) => {
-  console.log('404 未找到:', req.method, req.path);
   res.status(404).json({
     error: '页面不存在',
     path: req.path
@@ -493,6 +510,4 @@ app.use((req, res) => {
 // 启动服务器
 app.listen(PORT, () => {
   console.log(`服务器运行在 http://localhost:${PORT}`);
-  console.log(`密码: ${PASSWORD}`);
-  console.log(`Session 有效期: 7天`);
 });