logo
0
0
WeChat Login

MoeFocalors' Blog

个人博客站点,Next.js 15 前端 + FastAPI 代理层 + Flask 后端。

怎么跑起来

前端

npm install NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8000 npm run dev

访问 http://localhost:30010

代理服务

pip install -r requirements.txt FLASK_BACKEND=http://127.0.0.1:5000 ZHIPU_API_KEY=your_key uvicorn proxy_server:app --reload

构建部署

1. 本地构建

# 设置生产环境变量后构建 NEXT_PUBLIC_API_BASE_URL=https://your-api-server.com \ NEXT_PUBLIC_ADMIN_REGISTER_KEY=your_register_key \ npm run build

构建脚本会做两件事:next build 生成静态导出到 out/,然后复制到 .cnb.build/

产物是纯静态 HTML+JS+CSS,不依赖 Node.js 运行时,随便找个 Web 服务器托管就行。

2. 部署静态文件

Nginx(推荐)

server { listen 80; server_name your-domain.com; root /var/www/.cnb.build; index index.html; # SPA fallback:前端路由全走 index.html location / { try_files $uri $uri/ /index.html; } # 静态资源缓存 location /_next/static/ { expires 1y; add_header Cache-Control "public, immutable"; } }

CNB 云原生流水线

项目已集成 Cloud Native Build 流水线,.cnb.build/ 就是产物目录。推送到对应分支后自动触发构建和部署。

其他托管方案

平台说明
Vercel直接导入仓库即可,注意在 Settings 里设 NEXT_PUBLIC_API_BASE_URL
GitHub Pagesnext build 后把 out/ 推到 gh-pages 分支
CDN / OSS上传整个 .cnb.build/ 到对象存储,配置 SPA fallback
Docker基于 nginx 镜像,COPY 产物进去

关键点:不管用什么托管,动态路由(/post/[id]/tag/[tag]/archive/...)必须配置 SPA fallback——所有未匹配的路径都返回 index.html,否则刷新 404。

3. 同步快照数据(可选但推荐)

如果后端 API 不可用时需要离线降级展示内容:

npm run fetch:snapshot # 从 API 拉取最新数据到 public/snapshots/ npm run sync:snapshot # 同步更新已有快照

建议在 CI 流水线的构建阶段执行一次 fetch:snapshot,确保每次部署都带最新的数据备份。

4. 部署代理服务

代理层是 Python 服务,需要单独部署:

pip install -r requirements.txt # 生产环境启动(用 gunicorn 或 uvicorn) FLASK_BACKEND=http://your-flask-backend:5000 \ ZHIPU_API_KEY=your_key \ ALLOWED_ORIGINS=https://your-domain.com \ PROXY_TIMEOUT=30 \ uvicorn proxy_server:app --host 0.0.0.0 --port 8000

推荐用 systemd / supervisor 守护进程,或打包成 Docker 镜像:

FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY proxy_server.py . EXPOSE 8000 CMD ["uvicorn", "proxy_server:app", "--host", "0.0.0.0", "--port", "8000"]

环境变量清单(部署前确认)

阶段变量必填
前端构建NEXT_PUBLIC_API_BASE_URL
前端构建NEXT_PUBLIC_ADMIN_REGISTER_KEY管理功能必填
代理运行FLASK_BACKEND
代理运行ZHIPU_API_KEYAI 功能必填
代理运行ALLOWED_ORIGINS生产环境建议设具体域名
代理运行PROXY_TIMEOUT否,默认 30s

架构一览

浏览器 → CDN / 静态托管 (HTML+JS+CSS) ↓ API 请求 FastAPI 代理 (proxy_server.py) ↙ ↘ Flask 后端 智谱 GLM-4 /api/v1/* /api/ai/v1/* /api/v0/glm/* (兼容旧路由)

前端完全静态导出(output: 'export'),不依赖 Node.js 运行时。API Key 全部由代理层持有,前端不暴露任何密钥。

技术选型

层面用了什么
框架Next.js 15 (App Router) + React 18
语言TypeScript (strict mode)
样式Tailwind CSS v4
状态Zustand,持久化到 localStorage
实时通信SSE(@microsoft/fetch-event-source
AI 能力智谱 GLM-4,流式对话 + 输入建议
代理FastAPI + httpx
部署CNB 流水线 → 静态站 + 代理服务

环境变量

构建时注入前端:

变量干嘛的默认值
NEXT_PUBLIC_API_BASE_URL代理服务地址""
NEXT_PUBLIC_ADMIN_REGISTER_KEY管理员注册密钥""

FastAPI 代理运行时:

变量干嘛的默认值
FLASK_BACKENDFlask 后端地址http://127.0.0.1:5000
ZHIPU_API_KEY智谱 AI 密钥""
ALLOWED_ORIGINSCORS 白名单,逗号分隔*
PROXY_TIMEOUT代理超时秒数30

路由表

/ 首页 /post/[id] 文章详情 /archive 归档总览 /archive/[year]/[month] 按年月归档 /tag/[tag] 标签聚合页 /category/[category] 分类聚合页 /glmchat AI 对话 /music 音乐播放器 /contact 联系页 /control/* 管理后台(需登录)

项目结构

src/ ├── app/ 页面路由(App Router) │ ├── layout.tsx 根布局 │ ├── page.tsx 首页 │ ├── post/[id]/ 文章(客户端渲染) │ ├── tag/, archive/, category/ │ └── control/ 管理后台 ├── components/ 组件 │ ├── ui/ 通用 UI(通知、侧边栏) │ ├── MusicPlayer/ 播放器组件族 │ ├── Comment/ 评论组件 │ └── v1/ 聊天 UI(旧版) ├── hooks/ 自定义 Hooks │ ├── useAppStore.ts 全局状态(Zustand) │ ├── useSiteStats.ts 站点统计 │ ├── useAudioPlayer.ts 音频播放控制 │ └── useSnapshotData.ts SSG 数据降级策略 ├── lib/ 核心模块 │ ├── apiService.ts API 调用封装 │ ├── apiEndpoints.ts 端点定义(自动生成) │ ├── ai.ts AI 服务对接 │ ├── auth.ts 认证管理 │ ├── fetcher.ts HTTP 请求基础库 │ ├── crypto.ts 加密工具 │ ├── pluginManager.ts 插件系统 │ └── security.ts 安全相关 ├── services/ 业务服务 │ ├── statsService.ts 统计数据查询 │ └── statsStreamService.ts SSE 实时统计流 ├── types/ 类型定义 ├── config/ 配置(主题、封面图) └── utils/ 工具函数 proxy_server.py FastAPI 代理入口 requirements.txt Python 依赖 next.config.ts 静态导出配置

开发规范要点

  • 类型安全:strict 模式,禁止 as any,API 响应统一在边界处做类型转换
  • 无生产日志:不向用户环境输出 console.log/debug/error
  • DRY:公共类型统一定义在 types/,重复逻辑提取为共享模块
  • 命名:不用版本后缀(V0/V1),语义化命名
  • 错误处理:同模块内策略一致,不静默吞错
  • 文件大小:单文件不超过 500 行,超限考虑拆分

License

Apache-2.0

About

预计 2026.4.15 前上线 www.focalors.online

Language
HTML82.9%
TypeScript8.9%
JavaScript6.6%
CSS1.1%
Others0.5%