Flask个人博客 V1.3 全栈搭建记录原生前端FlaskSQLite从本地部署到PythonAnywhere上线项目地址谁暖了冬季 · 个人博客站 V1.3线上体验https://xue12.pythonanywhere.com版本V1.3 | 作者谁暖了冬季 | 类型自研轻量个人站点无前端框架、零MySQL依赖环境清单可复现Python3.12Flask3.x前端原生HTML/CSS/JS marked.js数据库SQLite3Python内置外网穿透ngrok本地开发/ PythonAnywhere生产部署PWAmanifest.json Service Worker项目展示一、项目背景 开发初衷我是一名全栈开发者同时爱好硬件开发日常开发Java智慧校园系统、ESP32-LVGL界面、树莓派ROS2小车长期在CSDN沉淀技术笔记。长期使用CSDN写作有几个无法回避的痛点平台约束强广告较多页面排版固定不方便集中展示自研Github项目想要一个完全自主可控的空间发布技术文章、项目展示、动态相册、评论交互不想使用Hexo/Hugo依赖Node环境构建流程繁琐不想使用WordPress后台臃肿、冗余功能多学习和维护成本高因此决定自研原生手写前端 Flask轻量后端 SQLite单文件数据库不引入重型框架一个页面一个HTML文件结构干净、方便二次迭代。核心定位轻量自建博客面向自己的项目展示与技术笔记支持公网访问。二、技术选型层选型选型理由前端原生 HTML CSS JavaScript无打包框架加载速度快自由度高风格对标CSDN两栏布局Markdown渲染marked.js在浏览器前端直接完成MD转HTML减轻后端压力后端FlaskPython轻量web框架开发速度快适合小型个人站点数据库SQLitePython内置、零配置、单文件存储无需单独部署MySQL服务登录认证邮箱注册 GitHub OAuth个人开发者无法申请微信登录CSDN无开放登录接口公网访问PythonAnywhere ngrokPythonAnywhere免费永久在线ngrok本地开发临时穿透PWAmanifest.json sw.js手机可添加到主屏幕离线缓存资源视觉素材樱花/银河/风铃mp4视频 银发精灵静态图Hero全屏动态轮播背景主题配色粉色系#ff6b9d视觉柔和和我CSDN博客的风格统一三、页面结构my_blog_V1.3/ ├── index.html # 首页两栏布局、Hero轮播、模块预览 ├── blog.html # 博客文章列表、MD编辑器、文章详情、评论、排序弹窗 ├── projects.html # 项目页同步拉取GitHub仓库、README渲染、文件树 ├── personal.html # 个人记录页技能栈、开发时间线 ├── space.html # 空间动态页朋友圈动态 相册网格 ├── app.py # Flask后端主程序 ├── site.db # SQLite数据库文件 ├── manifest.json # PWA配置 ├── sw.js # Service Worker ├── assets/ # 图片、视频、头像等静态素材 └── README.md # 项目文档项目启动入口app.py基础骨架fromflaskimportFlask,request,jsonify,send_from_directory,sessionimportsqlite3,os,secrets BASEos.path.dirname(os.path.abspath(__file__))appFlask(__name__,static_folderBASE,static_url_path)app.secret_keysecrets.token_hex(16)app.config[MAX_CONTENT_LENGTH]20*1024*1024# 20MBDBos.path.join(BASE,site.db)defget_db():connsqlite3.connect(DB)conn.row_factorysqlite3.Rowreturnconnif__name____main__:# 启动自动拉起 ngrokimportsubprocess subprocess.Popen([ngrok,http,5000])app.run(host0.0.0.0,port5000,debugFalse)⚠️ 重要提醒debugTrue 仅本地开发使用生产环境必须关闭。四、V1.3 核心新增功能4.1 博客文章编辑功能像CSDN一样发布过的文章可以直接编辑修改// 点击编辑按钮加载原文到编辑器asyncfunctioneditPost(id){constresawaitfetch(/api/posts/${id});constpostawaitres.json();document.getElementById(md-editor).valuepost.content;document.getElementById(post-title).valuepost.title;document.getElementById(post-cat).valuepost.category;document.getElementById(save-btn).onclick()updatePost(id);}// 保存修改asyncfunctionupdatePost(id){awaitfetch(/api/posts/${id},{method:PUT,headers:{Content-Type:application/json},credentials:include,body:JSON.stringify({title:document.getElementById(post-title).value,category:document.getElementById(post-cat).value,content:document.getElementById(md-editor).value})});loadPosts();}4.2 文章排序⇅ 弹窗调节右下角悬浮排序按钮点击弹出文章列表点上下箭头调整顺序数据库持久化asyncfunctionopenSortModal(){constresawaitfetch(/api/posts);constpostsawaitres.json();constlistEldocument.getElementById(sort-list);listEl.innerHTMLposts.data.map((p,i)div classsort-item>${p.id} span classidx${i1}/span span classtitle${p.title}/span button onclickmoveSort(${p.id}, -1)↑/button button onclickmoveSort(${p.id}, 1)↓/button /div).join();document.getElementById(sort-modal).style.displayflex;}asyncfunctionsaveSort(orderedIds){awaitfetch(/api/posts/sort,{method:POST,headers:{Content-Type:application/json},credentials:include,body:JSON.stringify({ids:orderedIds})});}数据库加了sort字段查询时按 sort 排序SELECT*FROMpostsORDERBYsortASC,created_atDESC4.3 CSDN 视频自动转 iframe 播放器从CSDN复制的MD文章里带的视频标签自动转成可播放的iframefunctionconvertCsdnVideo(html){constregex/\[video\([^)]*url-(https:\/\/live\.csdn\.net\/v\/embed\/\d)\)[^\]]*\]/g;returnhtml.replace(regex,(match,url)iframe src${url} width100% height400 frameborder0 allowfullscreen/iframe);}4.4 CSDN 图片防盗链处理CSDN图片直接引用会403加referrerpolicyno-referrer解决imgsrchttps://i-blog.csdnimg.cn/direct/xxx.pngreferrerpolicyno-referrer4.5 PWA 支持手机可以添加到主屏幕像APP一样打开{name:谁暖了冬季 · 博客,short_name:博客,start_url:/index.html,display:standalone,background_color:#fdf7f9,theme_color:#ff6b9d,icons:[{src:/assets/avatar.png,sizes:192x192,type:image/png}]}self.addEventListener(install,e{e.waitUntil(caches.open(v1.3).then(cc.addAll([/,/index.html,/blog.html,/assets/avatar.png])));});4.6 启动自动 ngrok 公网穿透运行python app.py自动拉起ngrokimportsubprocess,time ngrok_processsubprocess.Popen([ngrok,http,5000])time.sleep(2)importurllib.request resurllib.request.urlopen(http://127.0.0.1:4040/api/tunnels)print(公网地址:,json.loads(res.read())[tunnels][0][public_url])五、核心功能详解5.1 首页首页采用CSDN风格两栏布局左栏顶部Hero全屏动态背景4个素材轮播樱花视频 / 银河视频 / 风铃视频 / 银发精灵图页面向下滚动时Banner自动收缩4个导航卡片入口博客 / 项目 / 记录 / 空间预览板块精选博客文章、GitHub最新项目底部联系区域GitHub、CSDN、邮箱右栏个人信息卡片圆形头像、昵称、个人格言文章分类统计、归档统计右下角设置按钮自定义首页展示的文章、展示仓库5.2 博客模块博客页面核心能力右上角「✎ 写文章」弹窗编辑器支持粘贴Markdown文本、上传md文件marked.js实时预览自定义分类、填写标题数据写入后端SQLite持久化分页列表每页4篇文章文章编辑、排序、删除Hash路由跳转到文章详情页完整渲染表格、代码块、图片、CSDN视频登录用户可在文章底部发布评论5.3 项目模块项目页对接Github开放API自动拉取本人仓库列表按更新时间排序卡片展示仓库名称、简介、star、fork数量Hash路由进入仓库详情左侧文件树、中间README渲染、右侧仓库元信息localStorage缓存10分钟避免API限流5.4 个人记录页记录页用来展示技能栈和开发成长时间线5.5 空间动态页朋友圈风格动态模块发布文字、图片、短视频动态分页展示每页4条Tab切换动态流 / 相册相册自动收集所有图片三列网格布局点击放大预览数据持久化存入SQLite六、后端API与数据库设计接口汇总接口方法说明/api/registerPOST邮箱注册/api/loginPOST邮箱登录/api/logoutPOST退出登录/api/meGET获取当前登录用户信息/auth/githubGETGitHub OAuth跳转授权/auth/github/callbackGETGitHub OAuth回调/api/postsGET/POST获取文章列表 / 新增文章/api/posts/idGET/PUT/DELETE获取单篇 / 编辑 / 删除文章/api/posts/sortPOST保存文章排序/api/momentsGET/POST获取动态列表 / 发布动态/api/moments/idDELETE删除动态/api/comments/type/idGET/POST获取评论 / 新增评论建表SQLCREATETABLEIFNOTEXISTSusers(idINTEGERPRIMARYKEYAUTOINCREMENT,emailTEXTUNIQUENOTNULL,nickTEXTNOTNULL,pwdTEXTNOTNULL);CREATETABLEIFNOTEXISTSposts(idINTEGERPRIMARYKEYAUTOINCREMENT,titleTEXTNOTNULL,categoryTEXT,contentTEXT,sortINTEGERDEFAULT0,created_atTEXTDEFAULT(datetime(now)));CREATETABLEIFNOTEXISTSmoments(idINTEGERPRIMARYKEYAUTOINCREMENT,contentTEXT,mediaTEXT,typeTEXTDEFAULTtext,created_atTEXTDEFAULT(datetime(now)));CREATETABLEIFNOTEXISTScomments(idINTEGERPRIMARYKEYAUTOINCREMENT,target_typeTEXTNOTNULL,target_idTEXTNOTNULL,contentTEXTNOTNULL,created_atTEXTDEFAULT(datetime(now)));七、部署到 PythonAnywhere免费上线V1.3 最终部署到了 PythonAnywhere 免费版永久在线7.1 部署步骤注册 PythonAnywhere 账号免费版即可打开 Bash 控制台clone 代码gitclone https://github.com/Wasd2490/my_blog_V1.3.git创建 Web App选 Flask 框架配置 WSGI 文件importsys path/home/xue12/my_blog_V1.3ifpathnotinsys.path:sys.path.insert(0,path)fromappimportappasapplicationReload 网页完成7.2 踩坑记录flask_cors 装不上PythonAnywhere Python 3.10 环境找不到 flask_cors直接删掉这个依赖解决同源部署不需要CORS中文乱码导致 SyntaxErrorapp.py 里三处中文字符串乱码全部改成正常中文后跑通免费版每月要续期每月登录点一下「Run until 1 month from today」就行八、开发踩坑记录8.1 CSDN图片防盗链 403现象在自己网站直接引用CSDN图片链接图片全部加载失败控制台403 Forbidden。解决加referrerpolicyno-referrer或者下载到本地 assets 目录。8.2 localStorage 存视频触发 QuotaExceededError现象上传视频转base64存入localStorage大视频写入失败刷新后动态丢失。解决核心数据持久化交给后端SQLitelocalStorage仅做离线缓存。8.3 JS 嵌套反引号模板字符串语法报错现象使用嵌套${a ?:}写法浏览器JS解析报错页面直接无交互。解决取消嵌套反引号改用普通字符串拼接。8.4 GitHub API 限流 403现象短时间多次刷新项目页仓库列表加载失败返回403 rate limit。解决增加localStorage缓存10分钟内复用缓存数据。8.5 Hero轮播JS在无Hero的页面报错现象blog.html、projects.html页面没有hero-layer元素轮播代码执行时layers[i]为undefined。解决获取dom后增加空值判断if (!layers[i]) return;。8.6 PythonAnywhere 部署乱码现象clone下来的app.py中文乱码直接SyntaxError。解决在本地修复后重新push到GitHub服务器上git pull。九、本地运行教程# 安装依赖pipinstallflask# 启动后端服务python app.py浏览器打开 http://127.0.0.1:5000启动后自动拉起 ngrok控制台会打印公网地址。十、后续迭代规划自动生成文章右侧目录锚点完善评论通知、评论互通优化图片存储方案改为文件服务器减少数据库体积增加文章标签检索功能对接更多第三方登录渠道十一、项目开源地址https://github.com/Wasd2490/my_blog_V1.3线上体验https://xue12.pythonanywhere.com如果这个项目对你有帮助欢迎Star收藏评论区交流问题联系我GitHubhttps://github.com/Wasd2490CSDNhttps://blog.csdn.net/wjcjjsjs邮箱3287316014qq.com开源协议MIT协议仅供学习交流可自由修改二次开发分发时保留原作者出处。著作权归 谁暖了冬季 所有