CF _worker搭建 WS01 Note，可设置私人日记或公开分享变量设置：1、帐号：USERNAME，默认：9527a2、密码：PASSWORD，默认：9527abc3、KV空间邦定：WS01_NOTE_KV// WS01 Note - Cloudflare Workers + KV 日记本应用 // 作者: WS01 // 功能: 基于Cloudflare Workers和KV数据库的简单日记本 export default { async fetch(request, env, ctx) { const url = new URL(request.url); const path = url.pathname; // 处理CORS const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }; if (request.method === 'OPTIONS') { return new Response(null, { status: 200, headers: corsHeaders }); } try { // 路由处理 if (path === '/' || path === '/login') { return new Response(getLoginPage(), { headers: { 'Content-Type': 'text/html; charset=utf-8', ...corsHeaders } }); } if (path === '/diary') { return new Response(getDiaryPage(), { headers: { 'Content-Type': 'text/html; charset=utf-8', ...corsHeaders } }); } // 查看具体日记页面 if (path.startsWith('/diary/') && path.split('/').length === 3) { const diaryId = path.split('/')[2]; return new Response(getDiaryDetailPage(diaryId), { headers: { 'Content-Type': 'text/html; charset=utf-8', ...corsHeaders } }); } // 分享日记目录页面路由 if (path === '/share') { return new Response(getShareIndexPage(), { headers: { 'Content-Type': 'text/html; charset=utf-8', ...corsHeaders } }); } // 分享页面路由 if (path.startsWith('/share/') && path.split('/').length === 3) { const shareId = path.split('/')[2]; return new Response(getSharePage(shareId), { headers: { 'Content-Type': 'text/html; charset=utf-8', ...corsHeaders } }); } if (path === '/api/auth') { return handleAuth(request, env, corsHeaders); } if (path === '/api/diary') { return handleDiaryAPI(request, env, corsHeaders); } // 添加分享相关API路由 if (path === '/api/diary/share' && (request.method === 'POST' || request.method === 'PUT')) { return handleShareDiary(request, env, corsHeaders); } // 获取分享日记API路由 if (path.startsWith('/api/share/') && path.split('/').length === 4) { const shareId = path.split('/')[3]; return handleGetSharedDiary(shareId, env, corsHeaders); } // 获取所有分享日记API路由 if (path === '/api/shares' && request.method === 'GET') { return handleGetAllShares(request, env, corsHeaders); } // 获取用户分享日记列表API路由 if (path === '/api/diary/shares' && request.method === 'GET') { return handleGetUserShares(request, env, corsHeaders); } // 删除分享日记API路由 if (path === '/api/diary/share' && request.method === 'DELETE') { return handleDeleteShare(request, env, corsHeaders); } // 添加备份相关API路由 if (path === '/api/diary/backup' && request.method === 'POST') { return handleCreateBackup(request, env, corsHeaders); } if (path === '/api/diary/backups' && request.method === 'GET') { return handleGetBackups(request, env, corsHeaders); } if (path === '/api/diary/restore' && request.method === 'POST') { return handleRestoreBackup(request, env, corsHeaders); } if (path === '/api/diary/backup' && request.method === 'DELETE') { return handleDeleteBackup(request, env, corsHeaders); } // 404处理 return new Response('页面未找到', { status: 404, headers: { 'Content-Type': 'text/plain; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('Worker错误:', error); return new Response('服务器内部错误', { status: 500, headers: { 'Content-Type': 'text/plain; charset=utf-8', ...corsHeaders } }); } } }; // 登录页面 function getLoginPage() { return ` WS01 Note - 登录 WS01 Note 您的私人日记本 用户名 密码 登录 `; } // 日记页面 function getDiaryPage() { return ` WS01 Note - 我的日记 WS01 Note 📂 🚪 写日记 12px 14px 16px 18px 20px 22px 💾 🔗 0 / 100000 × 我的日记 还没有日记，开始记录吧！ 分享日记 刷新分享列表 暂无分享日记 数据备份与恢复 创建备份 刷新备份列表 暂无备份 `; } // 日记详情页面 function getDiaryDetailPage(diaryId) { return ` WS01 Note - 日记详情 WS01 Note 12px 14px 16px 18px 20px 22px ← 返回 加载中... 内容已复制到剪贴板 `; } // 分享日记目录页面 function getShareIndexPage() { return ` WS01 Note - 分享目录 WS01 Note - 分享目录 分享文章目录 这里展示所有公开分享的文章，点击标题可查看完整内容。复制的分享内容可能有改变。 加载中... 上一页 下一页 跳转到 页 跳转 载入天数... <span | 本页总访问量 次 | 登录 `; } // 分享页面 function getSharePage(shareId) { return ` WS01 Note - 分享内容 WS01 Note - 分享内容 ← 返回分享目录 📢 这是一篇分享的文章，任何人都可以查看 加载中... 内容已复制到剪贴板 载入天数... <span | 本页总访问量 次 | 登录 `; } // 处理认证API async function handleAuth(request, env, corsHeaders) { if (request.method !== 'POST') { return new Response('方法不允许', { status: 405, headers: { 'Content-Type': 'text/plain; charset=utf-8', ...corsHeaders } }); } try { const { username, password } = await request.json(); // 验证用户名和密码（从环境变量获取） const validUsername = env.USERNAME || '9527a'; const validPassword = env.PASSWORD || '9527abc'; if (username === validUsername && password === validPassword) { // 生成简单的token（实际应用中应该使用更安全的方法） const token = btoa(username + ':' + Date.now()); return new Response(JSON.stringify({ success: true, token: token, message: '登录成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } else { return new Response(JSON.stringify({ success: false, message: '用户名或密码错误' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } catch (error) { return new Response(JSON.stringify({ success: false, message: '请求格式错误' }), { status: 400, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理日记API async function handleDiaryAPI(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } const token = authHeader.substring(7); try { if (request.method === 'GET') { // 获取日记列表 const diaries = await getDiaries(env); return new Response(JSON.stringify({ success: true, diaries: diaries }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } if (request.method === 'POST') { // 保存新日记 const { title, content, editShareId } = await request.json(); const diary = { id: Date.now().toString(), title: title, content: content, date: new Date().toISOString() }; await saveDiary(env, diary); // 如果是从分享日记编辑而来，需要从分享日记中删除 if (editShareId) { await env.WS01_NOTE_KV.delete(`shared_${editShareId}`); } return new Response(JSON.stringify({ success: true, message: '日记保存成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } // 添加: 处理更新日记 (PUT) if (request.method === 'PUT') { const { id, title, content } = await request.json(); // 获取现有日记 const diaries = await getDiaries(env); const diaryIndex = diaries.findIndex(d => d.id === id); if (diaryIndex === -1) { return new Response(JSON.stringify({ success: false, message: '日记不存在' }), { status: 404, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } // 更新日记内容 diaries[diaryIndex] = { ...diaries[diaryIndex], title, content, date: new Date().toISOString() // 更新时间 }; await env.WS01_NOTE_KV.put('diaries', JSON.stringify(diaries)); return new Response(JSON.stringify({ success: true, message: '日记更新成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } // 添加: 处理删除日记 (DELETE) if (request.method === 'DELETE') { const { id } = await request.json(); const diaries = await getDiaries(env); const filteredDiaries = diaries.filter(d => d.id !== id); if (filteredDiaries.length === diaries.length) { return new Response(JSON.stringify({ success: false, message: '日记不存在' }), { status: 404, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } await env.WS01_NOTE_KV.put('diaries', JSON.stringify(filteredDiaries)); return new Response(JSON.stringify({ success: true, message: '日记删除成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } return new Response('方法不允许', { status: 405, headers: { 'Content-Type': 'text/plain; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('日记API错误:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 获取日记列表 async function getDiaries(env) { try { const diariesJson = await env.WS01_NOTE_KV.get('diaries'); if (diariesJson) { const diaries = JSON.parse(diariesJson); return diaries.sort((a, b) => new Date(b.date) - new Date(a.date)); } return []; } catch (error) { console.error('获取日记失败:', error); return []; } } // 保存日记 async function saveDiary(env, diary) { try { const diaries = await getDiaries(env); diaries.unshift(diary); // 添加到开头 // 限制最多保存100篇日记 if (diaries.length > 100) { diaries.splice(100); } await env.WS01_NOTE_KV.put('diaries', JSON.stringify(diaries)); } catch (error) { console.error('保存日记失败:', error); throw error; } } // 处理创建备份 async function handleCreateBackup(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { // 获取当前所有日记 const diaries = await getDiaries(env); // 获取所有分享日记 const listResult = await env.WS01_NOTE_KV.list({ prefix: 'shared_' }); const shares = []; for (const key of listResult.keys) { try { const sharedDiaryJson = await env.WS01_NOTE_KV.get(key.name); if (sharedDiaryJson) { const sharedDiary = JSON.parse(sharedDiaryJson); shares.push(sharedDiary); } } catch (e) { console.error('读取分享日记失败:', e); } } // 创建备份数据 const backup = { id: Date.now().toString(), timestamp: new Date().toISOString(), data: diaries, shares: shares, count: diaries.length, shareCount: shares.length }; // 获取现有的备份列表 let backups = []; try { const backupsJson = await env.WS01_NOTE_KV.get('backups'); if (backupsJson) { backups = JSON.parse(backupsJson); } } catch (e) { console.error('读取备份列表失败:', e); } // 添加新备份到列表开头 backups.unshift(backup); // 限制最多5个备份 if (backups.length > 5) { backups = backups.slice(0, 5); } // 保存备份列表 await env.WS01_NOTE_KV.put('backups', JSON.stringify(backups)); return new Response(JSON.stringify({ success: true, message: '备份创建成功', backupId: backup.id }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('创建备份失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理获取备份列表 async function handleGetBackups(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { // 获取备份列表 let backups = []; try { const backupsJson = await env.WS01_NOTE_KV.get('backups'); if (backupsJson) { backups = JSON.parse(backupsJson); } } catch (e) { console.error('读取备份列表失败:', e); } // 只返回必要的信息 const backupInfo = backups.map(backup => ({ id: backup.id, timestamp: backup.timestamp, count: backup.count, shareCount: backup.shareCount || 0 })); return new Response(JSON.stringify({ success: true, backups: backupInfo }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('获取备份列表失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理恢复备份 async function handleRestoreBackup(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { const { backupId } = await request.json(); // 获取备份列表 let backups = []; try { const backupsJson = await env.WS01_NOTE_KV.get('backups'); if (backupsJson) { backups = JSON.parse(backupsJson); } } catch (e) { console.error('读取备份列表失败:', e); } // 查找指定的备份 const backup = backups.find(b => b.id === backupId); if (!backup) { return new Response(JSON.stringify({ success: false, message: '备份不存在' }), { status: 404, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } // 恢复个人日记数据 await env.WS01_NOTE_KV.put('diaries', JSON.stringify(backup.data)); // 恢复分享日记数据 if (backup.shares && backup.shares.length > 0) { // 先删除所有现有的分享日记 const existingShares = await env.WS01_NOTE_KV.list({ prefix: 'shared_' }); for (const key of existingShares.keys) { await env.WS01_NOTE_KV.delete(key.name); } // 恢复备份中的分享日记 for (const share of backup.shares) { await env.WS01_NOTE_KV.put(`shared_${share.id}`, JSON.stringify(share)); } } return new Response(JSON.stringify({ success: true, message: '数据恢复成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('恢复备份失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理分享日记 async function handleShareDiary(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { const { title, content, shareId, editDiaryId } = await request.json(); if (request.method === 'PUT' && shareId) { // 更新分享日记 const existingShareJson = await env.WS01_NOTE_KV.get(`shared_${shareId}`); if (!existingShareJson) { return new Response(JSON.stringify({ success: false, message: '分享日记不存在' }), { status: 404, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } const existingShare = JSON.parse(existingShareJson); const updatedShare = { ...existingShare, title: title, content: content, date: new Date().toISOString() // 更新修改时间 }; await env.WS01_NOTE_KV.put(`shared_${shareId}`, JSON.stringify(updatedShare)); return new Response(JSON.stringify({ success: true, message: '分享日记更新成功', shareId: shareId }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } else { // 创建新分享日记 const newShareId = Date.now().toString() + Math.random().toString(36).substr(2, 9); const sharedDiary = { id: newShareId, title: title, content: content, date: new Date().toISOString(), shared: true }; // 保存到KV存储 await env.WS01_NOTE_KV.put(`shared_${newShareId}`, JSON.stringify(sharedDiary)); // 如果是从我的日记编辑而来，需要从我的日记中删除 if (editDiaryId) { const diaries = await getDiaries(env); const filteredDiaries = diaries.filter(d => d.id !== editDiaryId); await env.WS01_NOTE_KV.put('diaries', JSON.stringify(filteredDiaries)); } return new Response(JSON.stringify({ success: true, message: '分享成功', shareId: newShareId }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } catch (error) { console.error('分享日记失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理获取分享日记 async function handleGetSharedDiary(shareId, env, corsHeaders) { try { // 从KV存储中获取分享日记 const sharedDiaryJson = await env.WS01_NOTE_KV.get(`shared_${shareId}`); if (!sharedDiaryJson) { return new Response(JSON.stringify({ success: false, message: '分享的日记不存在' }), { status: 404, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } const sharedDiary = JSON.parse(sharedDiaryJson); return new Response(JSON.stringify(sharedDiary), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('获取分享日记失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理获取所有分享日记（公开访问） async function handleGetAllShares(request, env, corsHeaders) { try { // 解析URL参数 const url = new URL(request.url); const page = parseInt(url.searchParams.get('page')) || 1; const limit = parseInt(url.searchParams.get('limit')) || 20; // 获取所有分享日记的键 const listResult = await env.WS01_NOTE_KV.list({ prefix: 'shared_' }); const shares = []; for (const key of listResult.keys) { try { const sharedDiaryJson = await env.WS01_NOTE_KV.get(key.name); if (sharedDiaryJson) { const sharedDiary = JSON.parse(sharedDiaryJson); shares.push({ id: sharedDiary.id, title: sharedDiary.title, content: sharedDiary.content, date: sharedDiary.date, shareUrl: `/share/${sharedDiary.id}` }); } } catch (e) { console.error('解析分享日记失败:', e); } } // 按日期排序（最新的在前） shares.sort((a, b) => new Date(b.date) - new Date(a.date)); // 计算分页 const totalCount = shares.length; const totalPages = Math.ceil(totalCount / limit); const startIndex = (page - 1) * limit; const endIndex = startIndex + limit; const paginatedShares = shares.slice(startIndex, endIndex); return new Response(JSON.stringify({ success: true, shares: paginatedShares, pagination: { currentPage: page, totalPages: totalPages, totalCount: totalCount, limit: limit, hasNext: page < totalPages, hasPrev: page > 1 } }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('获取所有分享日记失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理获取用户分享日记列表 async function handleGetUserShares(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { // 获取所有分享日记的键 const listResult = await env.WS01_NOTE_KV.list({ prefix: 'shared_' }); const shares = []; for (const key of listResult.keys) { try { const sharedDiaryJson = await env.WS01_NOTE_KV.get(key.name); if (sharedDiaryJson) { const sharedDiary = JSON.parse(sharedDiaryJson); shares.push({ id: sharedDiary.id, title: sharedDiary.title, content: sharedDiary.content, date: sharedDiary.date, shareUrl: `${request.url.split('/')[0]}//${request.headers.get('host')}/share/${sharedDiary.id}` }); } } catch (e) { console.error('解析分享日记失败:', e); } } // 按日期排序（最新的在前） shares.sort((a, b) => new Date(b.date) - new Date(a.date)); return new Response(JSON.stringify({ success: true, shares: shares }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('获取分享日记列表失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理删除分享日记 async function handleDeleteShare(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { const { shareId } = await request.json(); // 删除分享日记 await env.WS01_NOTE_KV.delete(`shared_${shareId}`); return new Response(JSON.stringify({ success: true, message: '分享日记删除成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('删除分享日记失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } } // 处理删除备份 async function handleDeleteBackup(request, env, corsHeaders) { // 验证token const authHeader = request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response(JSON.stringify({ success: false, message: '未授权' }), { status: 401, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } try { const { backupId } = await request.json(); // 获取备份列表 let backups = []; try { const backupsJson = await env.WS01_NOTE_KV.get('backups'); if (backupsJson) { backups = JSON.parse(backupsJson); } } catch (e) { console.error('读取备份列表失败:', e); } // 过滤掉要删除的备份 const filteredBackups = backups.filter(b => b.id !== backupId); if (filteredBackups.length === backups.length) { return new Response(JSON.stringify({ success: false, message: '备份不存在' }), { status: 404, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } // 保存更新后的备份列表 await env.WS01_NOTE_KV.put('backups', JSON.stringify(filteredBackups)); return new Response(JSON.stringify({ success: true, message: '备份删除成功' }), { headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } catch (error) { console.error('删除备份失败:', error); return new Response(JSON.stringify({ success: false, message: '服务器错误' }), { status: 500, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }); } }