前言
在设计网络程序时,前后端的分离设计已经是一门成熟的技术,在之前我所做的网络程序中,并未将前后端分离,比如之前的一系列Flask
文章,更多是侧重于网络后端的开发,甚至会将原本需要在前端做的工作,比如校验数据等,都提交给服务器来实现,这加大了前后端的交互,也使得在实际部署后,增大了网络通信成本。
本着不断学习的理念,现计划学习一下前后端分离技术,前端采用三大框架之一的Vue.js
,后端则采用Python
的FastAPI
框架。
关于这两个框架,都有十分详细的中文文档,照着做没有什么问题,只是将前后端合在一起实现通信时,会有一点小麻烦,就目前网上查找到的各种示例来看,要么过于复杂,期间夹杂了太多的数据逻辑,要么语焉不详,看起来似乎能完成,但实际跟着操作时错误频出,再或是介绍了过多的Vue2
与FastAPI
的通信,对于Vue3
的介绍很少涉及。
有鉴于此,本文仅就完成前后端最基本的通信问题来详细说明如何设置前端和后端。
一、前端设计
对于绝大多数同学而言,其实最好的方式是借助于官方的自动生成框架,新建一个文件夹,比如mydemo
,然后切换到该目录,运行下面命令:
npm init vue@latest
这个命令会自动调用create-vue
,这是vue
的官方脚手架工具,为了区分前后端,在该项目下,建议新手将所要创建的工程名设置为frontend
,以区分同一个目录下的后端文件夹backend
(目前该文件夹还未创建),运行截图如下:
![](https://img6.php1.cn/3cdc5/982b/61b/b17afccae00b65be.png)
上图中红色方框内的即是接下来要运行的三条命令,按要求运行完最后一条命令后,你应该在命令窗口看到以下内容 (注意:你的端口有可能是5173):
![](https://img6.php1.cn/3cdc5/982b/61b/12fb89ef87b36471.png)
此时在浏览器中输入上述网址:http://127.0.0.1:5174/
,即会看到以下页面:
![](https://img6.php1.cn/3cdc5/982b/61b/a311be279f8e62e9.png)
这样我们就实现了一个最基本的前端程序,整个过程中,并未输入一行代码!
接下来我们来看一下官方的脚手架工具自动生成的文件是怎样的结构:
![](https://img6.php1.cn/3cdc5/982b/61b/eafa4fc99c6fd1c5.png)
上图中生成的东西虽然很多,但实际上我们主要工作只是对其中红色方框中的src
目录下文件编辑即可,为了实现最简化说明问题,现将其中App.vue
的内容减少为如下代码:
<script>
export default {
data() {
return {
msg: "你好,世界!",
};
},
};
script>
<template>
<button >第一个按钮button>
<p>{{ msg }}p>
template>
只需要保存,页面即会变成如下这样:
![](https://img6.php1.cn/3cdc5/982b/61b/d44c17b39a152432.png)
上述代码添加了一个按钮和文本。
至此,我们完成了前端的一个示例。
二、后端设计
安装FastAPI
是容易的,在命令窗口运行如下代码:
pip install fastapi
pip install "uvicorn[standard]"
以上代码完成了FastAPI
的基本安装,接下来在mydemo
文件夹下创建一个backend
文件夹,用以存放后端文件:
在backend
文件夹中创建一个main.py
文件,其中代码如下:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
保存后,在backend
路径的命令窗口运行以下代码:
uvicorn main:app --reload --port 8001
则启动了后端服务器,命令窗口显示如下:
![](https://img6.php1.cn/3cdc5/982b/61b/db506f92449c33da.png)
在浏览器地址栏输入http://127.0.0.1:8001
即可看到后端服务器返回的页面:
![](https://img6.php1.cn/3cdc5/982b/61b/169cf22aa612d4d0.png)
至此,后端服务器的最小例子也建立了。
三、前端获取后端的数据
为了让前后端通信,需要在两者之间建立桥梁,毕竟两个服务器运行的是不同的网址,因此,一个基本的思路是要让前端知道从哪个网址获取信息,同时也要让后端知道请求方来自何处。
这时需要用到两个包,即前端需要用到axios
这个包,后端则要用到CORS
这个中间件。
前端的设置
安装axios
,在frontend
文件夹的命令窗口下运行以下命令:
修改frontend/src/main.js
文件如下图所示:
![](https://img6.php1.cn/3cdc5/982b/61b/8b1c7272a5b22a8d.png)
上图中,红色方框中是需要添加的代码,其目的是导入axios
,并且告诉前端要将数据发送的地址是http://127.0.0.1:8001
。
接着在frontend/src/App.vue
中,添加获取数据的代码,如下所示:
<script>
import axios from "axios";
export default {
data() {
return {
msg: "你好,世界!",
};
},
methods: {
getMessage() {
axios.get("/").then((res) => {
this.msg = res.data;
});
},
},
};
script>
<template>
<button @click="getMessage">第一个按钮button>
<p>{{ msg }}p>
template>
在上述代码中,给按钮绑定了一个click
事件,当这个按钮被点击时,它会调用getMessage()
函数,该函数中用axios
去获得后端根目录下的数据,然后将要显示的文字更改为相应的返回值{hello:world}
。
至此,前端配置完成,当然,此时点击页面按钮不会有任何反应,如果打开网页开发工具中的控制台,你会看到以下错误信息:
![](https://img6.php1.cn/3cdc5/982b/61b/02600c0e8c99a7d9.png)
上述错误信息提示跨域访问不成功,这需要在服务器后端来配置。
后端的设置
在FastAPI
中,设置CORS
是很简单的,只不过要注意的是,当前端的axios.defaults.withCredentials
设置为true
时,后面的响应地址就必须明确为字符串,而不能是一个列表,这里的意思是,当跨域访问需要带session
时,只能响应确定的地址请求。
添加中间件CORS
的代码如下:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins= "http://127.0.0.1:5174/",
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
def read_root():
return {"Hello": "World"}
至此,后端代码修改完毕。
此时,当点击一下页面的按钮,其下方的文字将变成后端FastAPI
发送的信息,如下图所示:
![](https://img6.php1.cn/3cdc5/982b/61b/dba7af8ac1f53cf2.png)
这就完成了从服务器端获取数据的过程。
前端向后端发送数据
当我们在客户端填写或是更改某个数据之后,往往需要将数据发送给服务器端,此时就需要用到数据的发送功能。
客户端设置
先在frontend/src/App.vue
中添加一个发送的方法,同时添加一个按钮,当用户点击该按钮时,调用axios
发送数据给服务器端,修改代码如下:
<script>
import axios from "axios";
export default {
data() {
return {
msg: "你好,世界!",
};
},
methods: {
sendMessage () {
axios.post(
"/update_item/",
{name: "张无忌", age:24},
).then((res) => {
console.log(res.data);
});
},
getMessage() {
axios.get("/").then((res) => {
this.msg = res.data;
});
},
},
};
script>
<template>
<button @click="getMessage">第一个按钮button>
<button @click="sendMessage">发送信息给服务器button>
<p>{{ msg }}p>
template>
这里要注意的是,axios
发送数据时,其数据是以字典
的形式发送,当然也可以看作是json
格式。
在这里,axios
提交的路径是/update_item/
,因此服务器端必须建立该路由。
服务器端设置
为了接受客户端提交过来的数据,要进行两步操作:一是设立相应的路由地址,二是设置接受数据的模型,此时用到pydantic
,该包会在安装fastAPI
时同步安装,该包的主要功能是对接口数据进行定义、检查与管理。
在下面示例中,我们定义一个Item
类来接受客户端提交的数据,backend/main.py
的代码修改如下:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Union
class Item(BaseModel):
name: str
age: float
is_TrueMan: Union[bool, None]=None
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins= "http://127.0.0.1:5174/",
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.post("/update_item/")
def update_item(item: Item):
item.age += 10
print(item)
return {'item':item}
这里将接受到的人员年龄增加10后,打印在服务器端的控制台上,并将修改的结果返回给客户端,由客户端打印在浏览器的控制台上,运行截图如下:
![](https://img6.php1.cn/3cdc5/982b/61b/888daad3eeb272ff.png)
从上图可以看出,服务器接受并修改了客户端传送过来的数据,客户端也接受到了修改后的数据。
至此,我们完成了一个客户端与服务器端完整的通信程序。
小结
本文对FastAPI
和Vue3
的通信问题进行了介绍,从整个流程看,设置并不复杂,但由于各自借用了一个第三方包,因此会对初学者造成困扰,记此仅供参考。