在最近工作中, 有一个小任务是需要前端发送一个请求去后端, 调用python并返回给前端结果. 因为只是一个小需求, 因此挑选了比较轻量化的flask来满足后端和前端的交互
以下是一个小小的示例
1. 配置所需的环境
1.1 构建前后端文件夹安装基础依赖
前端使用React.js, 如何安装就不再赘述, 使用如下命令创建一个React项目
# 创建 front-end 存放前端文件
create-react-app front-end
而在后端, 为了隔离开发环境, 我们首先安装virtualenv (这是官网所推荐的), 然后按照下方所示创建后端项目
# 安装pip依赖
pip install virtualenv
mkdir back-end # 创建文件夹
cd back-end # 进入文件夹
# 创建虚拟环境 venv
# 这一条命令执行的时候遇到了一点小问题, 提示virtualenv命令没有, 但是查询pip依赖是有的, 这个原因是virtualenv安装后, 并不会直接成为全局命令, 因此需要手动创建软链接. 如果是非root用户, virtualenv安装后可能会在 /home/$username/.local/bin/python* 下
virtualenv venv
# 进入虚拟环境
# 这里又有一个小问题, 在低版本中, 应该使用 ./venv/Script/activate 来激活虚拟环境
source ./venv/bin/activate
# 之后, 命令行应该变为了这样
(venv)xxx
1.2 前端环境搭建和测试
首先进入上一步创建好的front-end文件夹, public下我一般只保留ico和index.html, src下全部删除, 然后手动创建App.js 和index.js
-
index.js
import React, { StrictMode } from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <StrictMode> <App /> </StrictMode> )
使用命令npm start启动项目, 打开浏览器, 我们可以看到启动成功

1.3 后端环境搭建和测试
在virtualenv环境中, 我们使用命令pip install flask安装flask
之后, 我们在back-end文件夹中(注意,不是在venv目录下!), 新建文件hello.py如下
from flask import Flask
app = Flask(__name__)
@app.route('/')
def sayHello():
return 'Hello Python'
在虚拟环境中使用命令falsk --app hello run启动flask, 打开网页, 可以看到运行正常

这里, 我们做一点小的改进, 在hello.py文件下, 我们添加一些内容, 这样, 我们之后就可以使用python hello.py打开项目, 同时debug=Ture可以让我们的修改及时生效(而不是重启项目)
# from flask import Flask
# app = Flask(__name__)
# @app.route('/')
# def sayHello():
# return 'Hello Python'
if __name__ == "__main__":
app.run(debug=True)
我们做一个测试, 在hello.py中, 新增一条route
# from flask import Flask
# app = Flask(__name__)
# @app.route('/')
# def sayHello():
# return 'Hello Python'
@app.route('/hi')
def sayHi():
return ('<h1>Hi Flask</h1>')
# if __name__ == "__main__":
# app.run(debug=True)
打开网页, 在localhost:5000后添加/hi, 可以看到页面显示了最新内容

2. 最简单的前后交互
在上一章中, 我们已经成功的搭建起了前后端, 但此时, 前端和后端还是相互分离的, 两者之间并没有任何联系
现在, 让我们一步步为他们搭起桥梁
2.1 前端发送GET请求
我们在前端页面中添加一个button按钮, 当我们点击这个按钮时, 希望能从后台为我们返回一条数据
修改App.jsx如下
import React from 'react'
export default function App() {
const getData = async() => {
console.log('button is clicked')
await fetch('http://127.0.0.1:5000/message')
.then(response => console.log(response))
.catch(error => console.log(error))
};
return (
<div>
<button onClick={getData}>Click to get message</button>
</div>
)
}
打开页面, 并点击按钮后, 观察控制台

可以看到, 控制台出现了button is clicked, 证明我们的按钮点击成功, 但是紧接着出现了报错: 已拦截跨源请求:同源策略禁止读取位于http://127.0.0.1:5000/message的远程资源。(原因:CORS 头缺少 ‘Access-Control-Allow-Origin’)。状态码:404
这是因为我们的react在3000端口运行, 而他要去访问5000端口的flask, 因此出现了跨域错误. 哪里出错, 我们就调哪里, 在fetch中, 我们添加mode: cors, 来设置跨域访问
// 对应上述第7行
await fetch('http://127.0.0.1:5000/message', {mode: 'cors'})
刷新网页, 我们再次点击按钮

很不幸, 再次遇到了失败
虽然想放弃, 但是要冷静. 我们刚刚只配置了前端的跨域, 但却没有配置后端的跨域, 因此会出现失败, 接下来, 回到python进行一些修改
2.2 Python接受请求
在Flask中, 如果要配置跨域访问, 需要安装一个依赖
(venv)xxx: pip install flask-cors
然后修改hello.py文件如下
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, supports_credentials=True)
@app.route('/')
def sayHello():
return 'Hello Python'
@app.route('/hi')
def sayHi():
return ('<h1>Hi Flask</h1>')
@app.route('/message')
def message():
return 'This is a message from python'
if __name__ == "__main__":
app.run(debug=True)
再次回到页面, 点击button, 我们可以看到此时已经可以返回结果了

2.3 显示数据
现在, 前后端已经可以返回数据了, 但是还没有正常显示python返回的数据, 我们进一步对App.jsx进行修改
// 其余不变
const getData = async() => {
console.log('button is clicked')
await fetch('http://127.0.0.1:5000/message', {mode: 'cors'})
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log(error))
};
再次在页面测试, 可以看到已经成功

不过在实际工作中, 这种直接返回string的方式极少, 大部分都需要json格式, 我们再创建一个方法试一下
- App.jsx
const getJson = async() => {
await fetch('http://127.0.0.1:5000/json', {mode: 'cors'})
.then(response => response.json())
.then(result => {
console.log(result);
console.log(result.today)
})
.catch(error => {console.log(error)})
}
- hello.py
@app.route('/json')
def giveJson():
data = {'today': 'Fifth'}
return data
在页面测试一下, 可以看到已经成功了

3. 很简单的应用示例
现在, 让我们完成一个简单的应用, 当我们点击第三个按钮时, 它会为我们展示三名同学的成绩单(原谅我界面十分简单)

在python中, 我们的功能很简单, 就是将写好的json文件读出来, 当受到请求时发送给前端
@app.route('/grades')
def giveGrades():
return getGrades('./grades.json')
def getGrades(jsonFile):
with open(jsonFile) as inf:
grades = json.load(inf)
return grades
在App.js中, 我们添加方法和渲染的结构
const [info, setInfo] = useState([]);
const getGrades = async () => {
await fetch("http://127.0.0.1:5000/grades", { mode: "cors" })
.then((response) => response.json())
.then((result) => {
setInfo(result.students);
})
.catch((error) => console.log(error));
};
return (
<div className="outerbox">
<ul>
{info.map((item) => {
return (
<li key={item.name}>
<p>{item.name}</p>
<p>His/Her class is: {item.class}</p>
<p>His/Her grades is: </p>
<ul >
{item.grades.map((kind) => {
return (
<li style={{listStyleType:"square"}} key={kind.name}>{kind.classname}:{kind.score}</li>
)
})}
</ul>
</li>
);
})}
</ul>
</div>
)
json文件如下:
{
"students": [
{
"name": "xiaoming",
"class": "One",
"grades": [
{ "classname": "Chinese", "score": 95 },
{ "classname": "Math", "score": 95 },
{ "classname": "English", "score": 95 }
]
},
{
"name": "Lihua",
"class": "Two",
"grades": [
{ "classname": "Chinese", "score": 90 },
{ "classname": "Math", "score": 90 },
{ "classname": "English", "score": 90 }
]
},
{
"name": "HanMeimei",
"class": "Three",
"grades": [
{ "classname": "Chinese", "score": 85 },
{ "classname": "Math", "score": 85 },
{ "classname": "English", "score": 85 }
]
}
]
}
4. 一点补充
在实际工作中, 我们还会遇到需要前端带着参数向后端发送请求的, 这个时候, 我们上面用的GET请求就不再合适, 下面我们再来看一个案例
我们再次新建一个按钮, 当点击时, 它将向后端发送一条问候语, 而后端会在前面添加修饰后返回
-
App.jsx
const getModify = async() => { await fetch("http://127.0.0.1:5000/modify", { method: 'POST', mode: 'cors', body: 'what a nice day' }) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log(error)) } -
hello.py
@app.route('/modify', methods=['POST']) def giveModify(): data = request.get_data(as_text=True) data = "I have recived this message from you: " + data return data
可以看到, 我们发送的what a nice day已经成功被python修饰后返回

除了发送字符串, 更常用的方式是发送一些json数据. 我们将上述使用的json数据, 通过js传到后端, 将第一个学生的名称从XiaoMing修改为Xiaogang
-
App.jsx
const getModifyJson = async () => { await fetch("http://127.0.0.1:5000/modifyjson", { method: "POST", mode: "cors", headers: { "content-type": "application/json", }, body: JSON.stringify(jsonData), // 将json格式化为string }) .then((response) => response.json()) .then((result) => console.log(result)) .catch((error) => console.log(error)); }; -
hello.py
@app.route('/modifyjson', methods=['POST']) def giveModifyJson(): jsonData = request.get_data(as_text=True) jsonData = json.loads(jsonData) # 将字符串解析为json jsonData['students'][0]['name'] = 'XiaoGang' return json.dumps(jsonData)
从返回的数据可以看到, 学生的名字已经成为了XiaoGang

本文详细介绍了如何使用React.js和Flask搭建前后端交互环境,包括环境配置、前后端基础依赖安装、环境搭建和测试。通过逐步解决跨域问题,实现了前端发送GET请求、后端接收和响应数据,最终展示了一个简单的成绩单应用示例,并讨论了带参数的请求处理。
110

被折叠的 条评论
为什么被折叠?



