一、动机
通过 React(前端框架)和 Flask(后端框架)构建一个初始网站,可以结合它们的优势,前端负责交互界面,后端提供 API 接口。
二、准备环境
2.1 安装必要工具
- 确保安装了 Node.js 和 npm,用于管理 React 项目。
- 确保安装了 Python(推荐 3.8 及以上版本)和 pip,用于管理 Flask 项目。
npm是什么?
npm 是 Node Package Manager(节点包管理器)的缩写,它是 JavaScript 运行时环境 Node.js 的默认包管理器。
npm 用于管理和安装 Node.js 应用程序所需的各种代码库和工具,这些代码库和工具被称为“包”或“模块”。
以下是 npm 的一些主要功能:
- 依赖管理:npm 允许你为你的项目定义依赖关系,并通过
package.json
文件来管理这些依赖。这使得项目可以轻松地在不同的开发环境中共享和部署。- 包安装:你可以使用 npm 来安装项目所需的包。这些包可以是第三方库,也可以是你自己的代码模块。
- 版本控制:npm 支持语义化版本控制,允许你指定依赖的版本范围,以确保兼容性。
- 包发布:开发者可以将自己的包发布到 npm 的公共仓库,供其他开发者使用。
- 全局安装:npm 允许你全局安装包,这样你就可以在任何地方使用这些工具,而不需要在每个项目中单独安装。
- 脚本:
package.json
文件中的scripts
字段允许你定义自定义脚本,这些脚本可以通过npm run <script-name>
来执行。- 工作区:npm 支持工作区,允许你在多个包之间共享配置和依赖。
三、创建 Flask 后端
3.1 创建 Flask 项目
初始化 Flask 项目目录:
mkdir flask-backend
cd flask-backend
3.2 创建虚拟环境并激活
conda 或 venv
3.2.1 anaconda
3.2.2 venv
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
3.2.3 安装 Flask
pip install flask
3.2.4 创建 app.py
文件
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/api/message', methods=['GET'])
def get_message():
return jsonify({"message": "Hello from Flask!"})
if __name__ == '__main__':
app.run(debug=True)
3.2.5 启动 Flask 服务器
python app.py
访问 http://127.0.0.1:5000/api/message
:
四、创建 React 前端
4.1 初始化 React 项目
在另一个目录中创建 React 项目
npx create-react-app react-frontend
cd react-frontend
- 命令解析:
**
npx
**是 npm 的一部分,用于运行 npm 包而无需全局安装它们。**
create-react-app
**是 React 官方提供的脚手架工具,用于快速搭建 React 项目的初始结构。**
react-frontend
**是项目的目录名称,你可以根据需要自定义,例如my-react-app
。
报错:
![]()
try:
npm config set legacy-peer-deps true npm i
npm config set legacy-peer-deps true
这条命令用于配置 npm 使用 “legacy peer dependencies” 机制来解决依赖冲突。具体来说:
peer dependencies
是指某个 npm 包对其他包的版本要求,它并不直接安装这些依赖,而是由使用该包的项目来安装。它用于确保在多个包中共享同一版本的依赖。- “legacy peer dependencies”
在 npm 7 版本及之后,npm 会强制执行严格的peer dependencies
规则。若存在不兼容的版本,npm 会拒绝安装。这可能导致一些旧项目的依赖安装失败,特别是一些老旧的 npm 包没有更新以适应这些新规则。npm config set legacy-peer-deps true
这条命令设置 npm 配置,指示 npm 在安装时忽略peer dependencies
的严格检查,允许安装不完全匹配的版本。这对于那些依赖较旧的 npm 包(或者在升级后依赖有冲突的情况)特别有用。
npm i
(或npm install
)**这是用于安装项目依赖的命令,它会按照项目根目录下的
package.json
文件来安装所有列出的依赖。
- 在执行
npm i
时,npm 会下载并安装依赖到项目的node_modules
目录。- 如果你在之前执行过
npm config set legacy-peer-deps true
,npm 会在安装过程中忽略peer dependencies
的严格检查,允许版本冲突的依赖继续安装。
启动服务并访问测试:
bug处理:
![]()
![]()
安装缺失的库。
npm install --save-dev web-vitals
重新运行npm start启动前端项目。
4.2 修改 React 项目以调用 Flask API
4.2.1 安装 axios
(用于发起 HTTP 请求)
npm install axios
4.2.2 在 src/App.js
中编辑代码
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [message, setMessage] = useState('');
useEffect(() => {
// 调用 Flask API
axios.get('http://127.0.0.1:5000/api/message')
.then(response => setMessage(response.data.message))
.catch(error => console.error("Error fetching data:", error));
}, []);
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h1>React + Flask 初始页面</h1>
<p>{message || "Loading..."}</p>
</div>
);
}
export default App;
- 代码解析:
这段代码是一个简单的 React 组件,它使用 axios 库从一个 Flask API 获取数据。下面是代码的逐行解释:
import React, { useState, useEffect } from ‘react’;
这行代码从 react 库中导入了 React 对象、useState 钩子和 useEffect 钩子。useState 用于在函数组件中添加状态,useEffect 用于处理副作用(例如,数据获取、订阅或手动更改 React 组件中的 DOM)。import axios from ‘axios’;
这行代码导入了 axios,这是一个基于 Promise 的 HTTP 客户端,用于浏览器和 node.js,用于向后端发送请求。function App() { … }
定义了一个名为 App 的函数组件。const [message, setMessage] = useState(‘’);
使用 useState 钩子创建了一个名为 message 的状态变量和一个名为 setMessage 的函数,用于更新这个状态。初始值设置为空字符串。useEffect(() => { … }, []);
useEffect 钩子用于在组件加载后执行副作用。这里的效果是调用 Flask API 获取消息。空数组 [] 作为第二个参数表示这个效果仅在组件首次渲染时运行。axios.get(‘http://127.0.0.1:5000/api/message‘)
使用 axios 发送一个 GET 请求到 http://127.0.0.1:5000/api/message 这个 URL。这个 URL 应该是你的 Flask 应用提供的 API 端点。.then(response => setMessage(response.data.message))
如果请求成功,.then 方法会处理响应。这里将响应中的 message 数据赋值给状态变量 message。.catch(error => console.error(“Error fetching data:”, error));
如果请求失败,.catch 方法会捕获错误,并在控制台打印错误信息。return ( … );
这是 React 组件的返回语句,它定义了组件的 JSX 结构,即组件在页面上呈现的内容。<div style={{ textAlign: 'center', marginTop: '50px' }}> ... </div>
+ 在 div 内部,有一个标题元素 h1,显示文本 “React + Flask 初始页面”。+ 返回一个 div 元素,其中包含一些内联样式:文本居中和上边距为 50px。 11. ```html <h1>React + Flask 初始页面</h1>
<p>{message || "Loading..."}</p>
+ 一个段落元素 p 显示 message 状态的值。如果 message 是空的(即正在加载中),则显示 “Loading…”。 整体来看,这段代码创建了一个 React 组件,该组件在加载时从 Flask API 获取一条消息,并将其显示在页面上。如果消息尚未加载,页面将显示 “Loading…”。 <img src="React+Flask%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E5%BC%80%E5%8F%91/%E6%88%AA%E5%B1%8F2024-12-10%2009.49.10.png" alt="截屏2024-12-10 09.49.10" style="zoom:50%;" /> ### 4.2.3 访问测试  前端执行成功,但是后端的message数据请求失败。 原因:同源策略限制(React端口3000,Flask端口5000)。 # 五、跨域请求设置 ## 5.1 设置 Flask 支持跨域请求 安装 Flask-CORS: ```bash pip install flask-cors
修改 app.py
:
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # 允许跨域请求
5.2 测试验证
六、部署优化
开发环境:前后端分开运行。
生产环境:可以使用 Flask 提供 React 构建后的静态文件。
6.1 构建 React 项目
npm run build
输出:
npm run build
react-frontend@0.1.0 build
react-scripts buildCreating an optimized production build…
One of your dependencies, babel-preset-react-app, is importing the
“@babel/plugin-proposal-private-property-in-object” package without
declaring it in its dependencies. This is currently working because
“@babel/plugin-proposal-private-property-in-object” is already in your
node_modules folder for unrelated reasons, but it may break at any time.babel-preset-react-app is part of the create-react-app project, which
is not maintianed anymore. It is thus unlikely that this bug will
ever be fixed. Add “@babel/plugin-proposal-private-property-in-object” to
your devDependencies to work around this error. This will make this message
go away.Compiled successfully.
File sizes after gzip:
73.28 kB build/static/js/main.7d3412ba.js
2.7 kB build/static/js/488.ee97bdc1.chunk.js
264 B build/static/css/main.e6c13ad2.cssThe project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.The build folder is ready to be deployed.
You may serve it with a static server:npm install -g serve
serve -s buildFind out more about deployment here:
6.2 设置 Flask 提供静态文件服务
6.2.1 将 build
文件夹复制到 Flask 项目目录
6.2.3 设置 Flask 提供静态文件服务
from flask import Flask, jsonify, send_from_directory
from flask_cors import CORS
app = Flask(__name__, static_folder='build')
CORS(app)
@app.route('/')
def serve():
return send_from_directory(app.static_folder, 'index.html')
@app.route('/api/message', methods=['GET'])
def get_message():
return jsonify({"message": "Hello from Flask!"})
if __name__ == '__main__':
app.run(debug=True)
6.2.4 访问测试
启动 Flask 项目后,直接访问根路径 http://127.0.0.1:5000
。
首页为空,静态资源下载失败。
6.2.5 修改 package.json
"homepage": "."
重新构建项目:
npm run build
重新测试:
仍然失败。
6.2.6 问题进一步分析
http://127.0.0.1:5000/build/static/css/main.e6c13ad2.css
添加build目录能够成功访问。
6.2.7 问题解决
app = Flask(__name__, static_folder='build', static_url_path='')
添加配置:static_url_path=’’
6.3 访问测试
至此,成功完成一个Flask+React的Demo系统。
进阶技能,后续继续加以学习。
目录结构总结
前端:
react-frontend/
├── public/
├── src/
│ ├── App.js
│ ├── index.js
├── package.json
后端:
flask-backend/
├── app.py
├── venv/
├── build/ (React 构建的静态文件)