Skip to Content
Handbook第 5 章:🎯 实战项目开发5.4 做一个带后端服务的页面

5.4 做一个带后端服务的页面

目标:把「可点击的前端」和「在服务器上跑逻辑」组合起来,输出一个对外可用的小产品。

到目前为止,你做的都是纯前端项目或脚本。这一节将带你进入全栈开发,理解前后端分离架构,掌握 API 设计和部署。

典型案例:上传 Word/PPT 自动转换为 Markdown、批量生成 Banner、图片识别返回结果、文本转语音等。

🎯 成品要求

  • 后端有清晰的接口文档(Swagger / Postman / README)
  • 前端可以调用后端、展示结果并给出状态反馈
  • 至少有一个部署在公网可访问的地址(Replit、Render、自建服务器等)
  • 有基础的安全措施(鉴权、限流、日志)

🧰 准备工作

1. 后端运行环境

选择一个你熟悉的平台:

  • Replit(推荐新手):在线编辑+一键部署,免费额度足够学习使用
  • Render:支持 Docker,有免费套餐
  • 自建服务器(进阶):AWS EC2、DigitalOcean、阿里云等

2. 参考项目

微软开源的 Markitdown

3. 前端技术栈

  • Next.js:适合 SEO 友好的页面
  • SvelteKit:轻量快速
  • 纯 HTML + Tailwind:最简单,适合快速验证

🛠️ 实践步骤

步骤 1:部署基础服务

1.1 在 Replit 创建项目

  1. 访问 https://replit.com/ 
  2. 登录后点击 + Create Repl
  3. 选择 Import from GitHub
  4. 填入仓库地址:https://github.com/microsoft/markitdown
  5. 等待依赖自动安装

或者:选择 Python 模板,手动克隆仓库:

git clone https://github.com/microsoft/markitdown.git cd markitdown pip install -r requirements.txt

1.2 测试基础功能

在 Replit 的 Shell 中运行:

# 测试命令行工具 python -m markitdown test.docx # 应该输出 Markdown 格式的文本

步骤 2:描述后端需求

现在需要把这个命令行工具封装成 Web API。

完整 Prompt 示例:

请基于 Markitdown 库创建一个 FastAPI 后端服务: ## 核心功能 1. 文件上传接口:支持上传 .docx、.pptx、.pdf、.xlsx、.jpg/.png 等文件 2. URL 转换接口:提供 URL,服务端下载后转换 3. 转换结果处理: - 生成 Markdown 文件 - 存储到 /public/output 目录 - 返回可下载的链接(如 /download/{file_id}.md) - 30 分钟后自动清理文件 ## 技术架构 - 使用 FastAPI 框架 - 支持异步处理(大文件转换可能较慢) - 文件 ID 使用 UUID 生成 - 添加 /docs 路由(自动生成的 Swagger 文档) ## 接口设计 POST /convert/file - 请求:multipart/form-data,包含文件 - 响应:{file_id, download_url, status} POST /convert/url - 请求:{url: "https://example.com/file.pdf"} - 响应:{file_id, download_url, status} GET /download/{file_id} - 返回 Markdown 文件 - 设置 Content-Disposition 头让浏览器下载 GET /health - 健康检查接口 - 返回:{status: "ok", version: "1.0.0"} ## 错误处理 - 文件类型不支持:返回 400 Bad Request - 文件过大(>10MB):返回 413 Payload Too Large - 转换失败:返回 500 并记录详细错误日志 请生成完整的可运行代码,包括 main.py 和必要的配置文件。

步骤 3:运行与联调

3.1 启动服务

在 Replit 中点击 Run 按钮,或在终端运行:

uvicorn main:app --host 0.0.0.0 --port 8000 --reload

3.2 访问 Swagger 文档

打开浏览器,访问 Replit 提供的预览地址(如 https://your-repl.username.repl.co),然后访问:

https://your-repl.username.repl.co/docs

你会看到自动生成的 API 文档界面。

3.3 测试接口

方式一:通过 Swagger UI

  1. /docs 页面找到 POST /convert/file
  2. 点击 Try it out
  3. 上传一个测试文件(如 test.docx
  4. 点击 Execute
  5. 查看响应,应该包含 download_url

方式二:通过 curl

# 上传文件 curl -X POST https://your-repl.username.repl.co/convert/file \ -F "[email protected]" # 响应示例 { "file_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "download_url": "/download/a1b2c3d4-5678-90ab-cdef-1234567890ab.md", "status": "success" } # 下载结果 curl https://your-repl.username.repl.co/download/a1b2c3d4-5678-90ab-cdef-1234567890ab.md \ -o output.md

方式三:通过 Python 脚本

import requests # 上传文件 with open('test.docx', 'rb') as f: response = requests.post( 'https://your-repl.username.repl.co/convert/file', files={'file': f} ) print(response.json())

3.4 调试常见问题

问题症状解决方案
ImportError提示找不到模块检查 requirements.txt,运行 pip install -r requirements.txt
权限错误无法写入 /public/output创建目录 mkdir -p public/output,检查文件权限
转换失败返回 500 错误查看 Replit Console 的详细错误日志,检查文件格式是否支持
CORS 错误前端调用时报跨域在 FastAPI 中添加 CORS 中间件(见下方代码)

添加 CORS 支持:

from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["*"], # 生产环境改为具体域名 allow_methods=["*"], allow_headers=["*"], )

步骤 4:加上鉴权与监控

4.1 简单的 API Key 鉴权

from fastapi import Header, HTTPException async def verify_api_key(x_api_key: str = Header(...)): if x_api_key != os.getenv("API_KEY"): raise HTTPException(status_code=401, detail="Invalid API Key") return x_api_key @app.post("/convert/file", dependencies=[Depends(verify_api_key)]) async def convert_file(...): ...

在 Replit 的 Secrets 中添加环境变量:

API_KEY=your_secret_key_here

前端调用时带上 Header:

fetch('/convert/file', { headers: { 'X-API-Key': 'your_secret_key_here' }, ... })

4.2 添加请求日志

import logging from datetime import datetime logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @app.post("/convert/file") async def convert_file(file: UploadFile, request: Request): client_ip = request.client.host logger.info(f"[{datetime.now()}] {client_ip} - Upload: {file.filename}") # 转换逻辑 ... logger.info(f"[{datetime.now()}] {client_ip} - Success: {file_id}")

4.3 限流(防止滥用)

使用 slowapi

pip install slowapi
from slowapi import Limiter, _rate_limit_exceeded_handler from slowapi.util import get_remote_address limiter = Limiter(key_func=get_remote_address) app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) @app.post("/convert/file") @limiter.limit("5/minute") # 每分钟最多 5 次请求 async def convert_file(request: Request, ...): ...

步骤 5:构建前端控制台

5.1 在 Cursor 创建前端项目

npx create-next-app@latest markitdown-frontend cd markitdown-frontend

5.2 给 AI 描述前端需求

Prompt 示例:

请创建一个文件转换的前端界面,使用 Next.js + Tailwind CSS: ## 功能需求 1. 文件上传区域: - 支持拖拽上传 - 显示文件名、大小、类型 - 限制文件大小(最大 10MB) - 支持的格式:.docx, .pptx, .pdf, .xlsx, .jpg, .png 2. URL 输入区域: - 输入框 + 提交按钮 - 验证 URL 格式 3. 进度显示: - 上传进度条 - 转换状态(上传中/转换中/完成/失败) - 预计剩余时间(可选) 4. 结果展示: - 转换成功:显示下载按钮 + 预览区(显示 Markdown 内容) - 转换失败:显示错误原因 5. 历史记录: - 显示最近 10 次转换记录 - 支持重新下载 ## 技术要求 - 使用 Next.js App Router - Tailwind CSS 样式 - 调用 API:`https://your-backend.repl.co` - API Key 存储在 .env.local - 响应式设计,支持移动端 请生成完整的代码。

5.3 配置环境变量

创建 .env.local

NEXT_PUBLIC_API_URL=https://your-backend.repl.co NEXT_PUBLIC_API_KEY=your_secret_key_here

5.4 前后端联调

  1. 启动前端开发服务器:

    pnpm run dev
  2. 打开 http://localhost:3000 

  3. 测试功能:

    • 上传文件
    • 输入 URL
    • 查看转换结果
    • 下载 Markdown
  4. 遇到问题时:

    • 打开浏览器 DevTools → Network 标签
    • 查看请求和响应
    • 检查 CORS、鉴权、参数格式

步骤 6:部署

6.1 后端部署(Replit)

  1. 在 Replit 点击 Deploy
  2. 选择 Autoscale deploymentReserved VM
  3. 部署后会得到固定域名(如 https://your-app.username.repl.co

或者使用 Render:

  1. 登录 https://render.com/ 
  2. 点击 New → Web Service
  3. 连接 GitHub 仓库
  4. 设置启动命令:uvicorn main:app --host 0.0.0.0 --port $PORT
  5. 添加环境变量(API_KEY 等)
  6. 点击 Create Web Service

6.2 前端部署(Vercel)

# 确保前端可以正常构建 pnpm run build # 初始化 Git git init git add . git commit -m "feat: frontend for markitdown service" # 推送到 GitHub gh repo create markitdown-frontend --public --source=. --push # 在 Vercel 部署 # 登录 https://vercel.com/ → New Project → 选择仓库 → Deploy

6.3 更新环境变量

部署后,在 Vercel 项目设置中更新环境变量:

NEXT_PUBLIC_API_URL=https://your-backend.repl.co NEXT_PUBLIC_API_KEY=your_secret_key_here

✅ 质量检查

功能完整性

  • Swagger 文档完整,可直接测试
  • 支持的文件类型都能正常转换
  • 大文件处理有进度反馈

错误处理

  • 不支持的格式返回友好提示
  • 文件过大时给出明确错误
  • 网络错误时有重试机制

安全性

  • 有 API Key 或其他鉴权机制
  • 限制请求频率(如 5 次/分钟)
  • 敏感信息不暴露在前端代码中
  • 上传的文件会定期清理

性能

  • 大文件转换不阻塞其他请求
  • 有合理的超时设置
  • 临时文件自动清理(避免磁盘满)

🔁 进阶练习

练习 1:增加 Webhook 回调

转换完成后通知用户:

import requests @app.post("/convert/file") async def convert_file(file: UploadFile, callback_url: str = None): # 转换逻辑 ... # 完成后回调 if callback_url: requests.post(callback_url, json={ "file_id": file_id, "status": "success", "download_url": download_url })

练习 2:记录调用日志到数据库

使用 Supabase 或 PlanetScale:

from supabase import create_client supabase = create_client( os.getenv("SUPABASE_URL"), os.getenv("SUPABASE_KEY") ) @app.post("/convert/file") async def convert_file(...): ... # 记录到数据库 supabase.table("conversion_logs").insert({ "file_id": file_id, "filename": file.filename, "file_size": file.size, "client_ip": request.client.host, "created_at": datetime.now().isoformat() }).execute()

练习 3:做成 SaaS 产品

  1. 添加用户注册登录(NextAuth.js)
  2. 设计定价计划(免费 10 次/月,付费无限制)
  3. 接入支付(Stripe / Lemon Squeezy)
  4. 添加使用统计仪表盘
  5. 结合 5.5 SEO 网站 做营销页面

💡 常见问题

Q:Replit 部署后一段时间不访问就停止了? A:免费版会休眠。升级到付费版或使用 Render/Railway 等平台。

Q:如何调试后端代码? A:在代码中添加 print()logger.info(),查看 Replit Console 的输出。也可以在 VS Code 中用 Remote SSH 连接 Replit。

Q:前端如何显示上传进度? A:使用 XMLHttpRequestfetch 配合 ReadableStream,监听 progress 事件。

Q:如何处理大文件上传超时? A:

  1. 增加服务器超时时间
  2. 改为分片上传
  3. 使用对象存储(如 S3、Cloudflare R2)直传

🎯 本节小结

完成这个项目后,你应该掌握了:

✅ 如何设计和实现 RESTful API ✅ 如何使用 FastAPI 构建后端服务 ✅ 如何实现前后端分离架构 ✅ 如何部署全栈应用到公网 ✅ 基础的安全措施(鉴权、限流、日志)

把这个服务分享给朋友,收集真实反馈! 接下来进入 5.5 SEO 友好的网站,学习如何搭建可以获取搜索流量的网站。

Last updated on