一、前言
在模块化烹饪小程序的开发体系中,后端服务是支撑前端数据交互、数据持久化以及AI解析功能的核心载体。前序开发完成了小程序前端页面的基础搭建与样式优化,本日的核心工作聚焦于Flask后端项目的完整初始化、MySQL数据库的自动化配置、全局跨域处理、自定义业务日志系统的搭建,同时完成了菜谱核心业务接口、图片静态资源服务以及AI菜谱解析接口的开发。
本次开发彻底解决了小程序前后端跨域请求报错、数据库手动创建繁琐、接口调用无日志溯源、静态大图导致小程序包体积超标等核心问题,搭建出一套可稳定迭代、可调试、可扩展的轻量化后端服务架构,为后续小程序菜谱数据的增删查改、AI智能解析、图片资源托管等功能提供了坚实的底层支撑。

二、项目技术栈与整体架构
本次后端开发采用轻量化、易部署且适配小程序开发的技术栈。整体架构采用前后端分离模式,后端专注于数据处理、数据库交互、日志记录以及AI接口对接,前端则专注于页面渲染与用户交互。
核心技术栈如下:Python Flask作为Web框架,Flask-SQLAlchemy作为ORM数据库映射工具,Flask-CORS处理跨域问题,PyMySQL作为MySQL驱动,DeepSeek AI接口提供智能解析能力。核心能力涵盖项目初始化配置、数据库自动创建与ORM映射、全局跨域放行、全接口自定义日志、图片上传与静态资源托管、菜谱数据CRUD操作以及AI结构化菜谱解析。
示例代码:项目依赖安装
bash
pip install flask flask-sqlalchemy flask-cors pymysql requests
三、Flask项目基础初始化配置
项目初始化是后端开发的基础工作,主要完成Flask应用实例的创建、全局插件的引入、文件上传目录的自动创建以及服务运行参数的配置。统一的初始化配置能够为后续功能开发奠定稳定的基础运行环境,避免出现环境适配问题。
核心知识点包括:Flask应用实例的初始化方法、静态资源目录的自动化创建方式、服务局域网开放的具体配置。在初始化过程中,需要通过CORS组件全局开启跨域支持,同时创建用于存储上传图片的uploads目录,使用os.makedirs的exist_ok参数可以确保目录存在时不报错,实现幂等性创建。
示例代码:Flask应用初始化与跨域配置
python
from flask import Flask, request, jsonify, send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import os
import json
import requests
from datetime import datetime
import pymysql
from pymysql.constants import CLIENT
app = Flask(__name__)
CORS(app)
DB_USER = "root"
DB_PASSWORD = "your_password"
DB_HOST = "127.0.0.1"
DB_NAME = "recipe_db"
DEEPSEEK_API_KEY = "your_api_key"
app.config['UPLOAD_FOLDER'] = "uploads"
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
上述代码完成了项目基础环境的搭建工作。通过os.makedirs实现了上传目录的自动创建,无需手动新建文件夹。配置CORS(app)全局解决了前后端跨域问题,能够适配小程序前端的各类请求。统一管理数据库连接信息、AI密钥等核心配置参数,方便后续进行统一的修改和维护。
四、MySQL数据库自动化连接与模型映射
传统Flask项目开发中,数据库需要手动创建,这一操作较为繁琐且不利于项目的迁移。本次开发实现了数据库自动创建与ORM模型映射的双重机制,程序启动时会自动检测并创建数据库,同时定义菜谱数据表结构,实现数据的持久化存储。
核心知识点涵盖:PyMySQL自动建库的实现原理、SQLAlchemy ORM数据模型的定义方法、数据表的自动生成机制。通过PyMySQL连接MySQL服务器后,执行CREATE DATABASE IF NOT EXISTS语句可以安全地创建数据库。使用utf8mb4字符集能够完整支持中文和特殊符号的存储,避免出现乱码问题。
示例代码:数据库自动创建与ORM模型定义
python
try:
conn = pymysql.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASSWORD,
client_flag=CLIENT.MULTI_STATEMENTS
)
cursor = conn.cursor()
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {DB_NAME} DEFAULT CHARACTER SET utf8mb4")
cursor.close()
conn.close()
except Exception as e:
print(f"数据库创建失败: {e}")
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Food(db.Model):
__tablename__ = 'foods'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(200), nullable=False)
image_url = db.Column(db.String(500))
desc = db.Column(db.Text)
structured_data = db.Column(db.Text)
create_time = db.Column(db.DateTime, default=datetime.now)
该模块实现了零手动操作的建库流程。Food模型涵盖了菜谱名称、图片地址、描述信息、结构化AI数据以及创建时间等核心字段,完全满足小程序菜谱展示、详情查询和数据存储的全部需求。
五、全局跨域处理方案
小程序前端与后端通常运行在不同的端口和域名下,这会导致浏览器默认的跨域拦截机制被触发,使得接口请求失败。本次开发采用Flask-CORS实现全局跨域放行,无需对单个接口进行单独配置,能够适配所有前后端数据交互的场景。
核心知识点包括:Flask全局跨域的配置方法、小程序跨域请求的适配原理。CORS(跨域资源共享)通过在响应头中添加Access-Control-Allow-Origin字段来告知浏览器允许跨域访问。设置为*表示允许任意域名访问,这在开发阶段非常便捷。
示例代码:全局CORS配置
python
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={
r"/api/*": {
"origins": "*",
"methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"allow_headers": ["Content-Type", "Authorization"]
}
})
相较于局部跨域配置方式,全局CORS配置更加简洁高效。它可以放行小程序本地开发环境和线上环境的所有请求,彻底解决开发阶段常见的跨域报错问题,保障前后端数据交互的顺畅进行。
六、自定义全业务日志系统搭建
Flask默认的日志记录仅包含基础的请求信息,无法精准定位业务层面的问题。本次开发自主搭建了可视化业务日志系统,对所有核心接口的请求、读取、写入和异常信息进行结构化打印。日志内容包含时间戳、接口地址、请求数据、返回条数和异常提示等核心信息,极大提升了调试效率。
核心知识点包括:自定义业务日志的规范设计、接口全链路日志的记录方法、异常日志的捕获机制。通过统一的分隔线格式,可以清晰地区分不同请求的日志边界。在开发模式下使用print输出日志可以实时查看,生产环境则可以替换为专业的logging模块。
示例代码:带完整日志的接口实现
python
@app.route('/api/food/list', methods=['GET'])
def food_list():
print("\n" + "="*80)
print("日志: 获取菜谱列表 /api/food/list")
print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
foods = Food.query.order_by(Food.id.desc()).all()
data = []
for f in foods:
img_url = f"http://127.0.0.1:5000/uploads/{os.path.basename(f.image_url)}" if f.image_url else ""
item = {
"id": f.id,
"name": f.name,
"image": img_url,
"desc": f.desc
}
data.append(item)
print("列表查询完成,共返回:", len(data), "条数据")
print("="*80 + "\n")
return jsonify({"code": 200, "data": data})
@app.route('/api/food/detail/<int:food_id>', methods=['GET'])
def food_detail(food_id):
print("\n" + "="*80)
print("日志: 获取菜谱详情 /api/food/detail")
print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print("请求ID:", food_id)
food = Food.query.get(food_id)
if not food:
print("未找到对应菜谱,ID:", food_id)
print("="*80 + "\n")
return jsonify({"code": 404, "msg": "菜谱不存在"})
result = {
"id": food.id,
"name": food.name,
"image_url": food.image_url,
"desc": food.desc,
"structured_data": json.loads(food.structured_data) if food.structured_data else None,
"create_time": food.create_time.strftime("%Y-%m-%d %H:%M:%S")
}
print("详情查询完成,菜谱:", food.name)
print("="*80 + "\n")
return jsonify({"code": 200, "data": result})
日志系统覆盖了菜谱列表、详情查询、数据新增、图片上传和AI解析等所有核心接口。统一的分隔线格式能够区分正常请求与异常请求,开发者可以清晰追溯每一次数据读写操作,快速定位参数缺失、数据查询为空、AI解析失败等开发和线上问题。
七、静态资源托管与图片上传接口实现
针对小程序代码包体积超标的问题,本次搭建了后端静态资源托管服务。将小程序中的本地大图和GIF动图迁移至后端的uploads目录,通过网络URL加载资源,大幅缩减小程序包的体积,有效解决了官方80051体积超标的报错问题。
核心知识点包括:Flask静态资源路由的配置方法、文件重命名防止覆盖的策略、小程序网络资源的适配方式。通过send_from_directory函数可以安全地从指定目录提供文件服务。使用时间戳对上传文件进行重命名,可以有效避免文件名冲突导致的资源覆盖问题。
示例代码:静态资源服务与图片上传接口
python
@app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
@app.route('/api/upload', methods=['POST'])
def upload_image():
print("\n" + "="*80)
print("日志: 图片上传 /api/upload")
print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
if 'image' not in request.files:
print("错误: 未选择图片")
print("="*80 + "\n")
return jsonify({"code": 400, "msg": "请选择图片"})
file = request.files['image']
if file.filename == '':
print("错误: 图片文件名为空")
print("="*80 + "\n")
return jsonify({"code": 400, "msg": "图片不能为空"})
ext = file.filename.rsplit('.', 1)[1].lower() if '.' in file.filename else 'jpg'
filename = datetime.now().strftime("%Y%m%d%H%M%S_%f") + '.' + ext
save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(save_path)
file_url = f"/uploads/{filename}"
print("图片上传成功,保存路径:", save_path)
print("访问URL:", file_url)
print("="*80 + "\n")
return jsonify({"code": 200, "url": file_url, "msg": "上传成功"})
通过微秒级时间戳对上传文件进行重命名,能够彻底避免同名文件被覆盖的问题。后端统一托管静态资源后,小程序端仅需保留小图标资源即可,完美适配微信小程序2MB代码包体积的限制,同时保证了图片的正常加载和展示。
八、菜谱数据读写与AI解析接口开发
本日完成了核心业务接口的开发工作,实现了菜谱数据的新增、详情查询以及AI自然语言转结构化菜谱数据的功能。同时通过详细的日志记录每一次数据写入与读取过程,保障了数据的可追溯性。
核心知识点包括:SQLAlchemy数据提交的事务机制、JSON结构化数据的存储方式、AI大模型接口的对接流程。使用db.session.add和db.session.commit完成数据的持久化操作。structured_data字段以JSON字符串形式存储,可以灵活保存步骤、食材、工具等复杂结构信息。
示例代码:菜谱新增与AI解析接口
python
@app.route('/api/food/add', methods=['POST'])
def add_food():
print("\n" + "="*80)
print("日志: 新增菜谱 /api/food/add")
print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
data = request.get_json()
print("接收到的数据:", json.dumps(data, ensure_ascii=False, indent=2))
if not data.get('name'):
print("错误: 菜名不能为空")
print("="*80 + "\n")
return jsonify({"code": 400, "msg": "菜名不能为空"})
structured_data = data.get('structured_data')
if isinstance(structured_data, dict):
structured_data = json.dumps(structured_data, ensure_ascii=False)
food = Food(
name=data.get('name'),
desc=data.get('desc'),
image_url=data.get('image_url'),
structured_data=structured_data
)
db.session.add(food)
db.session.commit()
print("数据写入成功,ID:", food.id)
print("="*80 + "\n")
return jsonify({"code": 200, "msg": "菜谱发布成功", "id": food.id})
@app.route('/api/ai/parse', methods=['POST'])
def ai_parse_recipe():
print("\n" + "="*80)
print("日志: AI菜谱解析 /api/ai/parse")
print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
data = request.get_json()
raw_text = data.get('raw_text', '')
if not raw_text:
print("错误: 待解析文本为空")
print("="*80 + "\n")
return jsonify({"code": 400, "msg": "请输入菜谱描述"})
headers = {
"Authorization": f"Bearer {DEEPSEEK_API_KEY}",
"Content-Type": "application/json"
}
prompt = f"请将以下菜谱描述解析为结构化JSON,包含菜名、食材列表、步骤列表三个字段:\n{raw_text}"
payload = {
"model": "deepseek-chat",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.7
}
try:
response = requests.post(
"https://api.deepseek.com/v1/chat/completions",
headers=headers,
json=payload,
timeout=30
)
result = response.json()
parsed_content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
print("AI解析成功,返回内容长度:", len(parsed_content))
print("="*80 + "\n")
return jsonify({"code": 200, "data": parsed_content})
except Exception as e:
print("AI解析失败:", str(e))
print("="*80 + "\n")
return jsonify({"code": 500, "msg": f"AI解析失败: {str(e)}"})
该接口能够接收前端传入的结构化菜谱数据,将JSON格式的步骤、食材、工具信息存入数据库。同时对接DeepSeek AI接口,实现了自然语言菜谱的自动标准化解析功能,为小程序的动画分步烹饪功能提供了可靠的数据支撑。
九、服务启动配置与项目总结
服务启动是后端项目的最后环节,需要在启动时完成数据表的自动创建,并将服务监听在指定端口上。开启调试模式可以在代码修改后自动重载,提高开发效率。开放局域网访问则允许手机等设备在同一个网络下进行调试。
核心知识点包括:Flask应用上下文的正确使用方式、数据表自动创建的触发时机、调试模式与生产模式的区别。使用with app.app_context()可以确保在应用上下文环境中执行数据库操作。host='0.0.0.0'表示监听所有网络接口,允许外部设备访问。
示例代码:服务启动配置
python
if __name__ == "__main__":
with app.app_context():
db.create_all()
print("\n后端服务启动成功,监听地址: http://0.0.0.0:5000")
print("API文档:")
print(" GET /api/food/list - 获取菜谱列表")
print(" GET /api/food/detail - 获取菜谱详情")
print(" POST /api/food/add - 新增菜谱")
print(" POST /api/upload - 上传图片")
print(" POST /api/ai/parse - AI解析菜谱")
print("日志系统已开启,可监控所有接口请求\n")
app.run(host='0.0.0.0', port=5000, debug=True)
本日完成了烹饪小程序后端的全套基础架构搭建工作,实现了Flask项目的初始化配置、MySQL自动化配置、全局跨域处理、自定义业务日志系统、静态资源托管、核心业务接口与AI解析接口的开发。成功解决了小程序包体积超标、前后端跨域报错、数据库部署繁琐、接口问题无法溯源等开发痛点。
整套后端架构具备轻量化、易调试、易扩展的特点。所有业务操作均有详细的日志记录,数据读写稳定可靠,完全满足模块化烹饪小程序的业务需求,为后续的前端接口对接、功能迭代和线上部署奠定了坚实的后端基础。
十、明日开发计划
明日将继续推进项目开发,主要工作计划包括以下几个方面:
第一,完成小程序前端与后端所有接口的全面对接工作,实现菜谱列表和详情页的动态数据渲染,确保前端能够正确展示从后端获取的菜谱数据。
第二,优化静态资源的加载速度,适配小程序线上环境的HTTPS域名配置,确保图片资源能够在小程序生产环境中正常访问。
第三,完善AI菜谱解析的容错机制,增强数据解析的稳定性,处理AI接口返回格式不一致等边界情况。
第四,新增菜谱收藏功能和浏览记录业务接口,丰富小程序的核心功能模块,提升用户体验。
想要解锁更多小程序组件化封装、JSON 结构化菜谱解析、Lottie/GIF 动画适配、全栈项目落地实战干货、零基础入门避坑教程吗?
持续关注,后续将更新云端部署、跨端适配、样式统一美化、历史菜谱收藏功能等硬核内容,手把手带你吃透小程序全栈开发流程!