React+Flask实现前后端交互

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

在最近工作中, 有一个小任务是需要前端发送一个请求去后端, 调用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下我一般只保留icoindex.html, src下全部删除, 然后手动创建App.jsindex.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

在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值