直到现在我们小宁已经更新了44作品了,其中和大家介绍了Python入门基础、Fast API框架、SQLite数据库,以及前端的知识都已经学习完了,总的来说现在前端、后端、数据库已经都学习了,那大家是否有这样的疑问,前端后端到底应该怎么联系起来使用呢?
在现代 Web 开发中,网页不再是静态的信息展示板,而是能与服务器实时交互的动态应用。实现这一功能的核心技术就是 AJAX,而 axios 则是简化 AJAX 操作的利器。本文从基础概念到实战案例,带你掌握前端与服务器通信的全流程。
一、认识 AJAX:让数据 “动” 起来
1. 什么是 AJAX?
AJAX(Asynchronous JavaScript and XML)是一种通过浏览器的 XMLHttpRequest
对象与服务器异步通信的技术。它能让网页在不刷新的情况下,向服务器请求数据并更新页面内容。
例如,当你在网页上点击 “查询省份” 按钮时,浏览器通过 AJAX 向服务器发送请求,服务器返回省份列表数据,前端直接将数据展示在页面上,整个过程无需刷新页面。
2. 为什么需要 AJAX?
传统网页的数据是固定写在代码中的,无法实时更新。有了 AJAX,数据可以从服务器动态获取,让页面内容 “活” 起来。比如:实时显示最新的省份 / 城市列表、用户登录状态验证等。
3. 为什么选择 axios?
AJAX 底层依赖 XMLHttpRequest
对象,但语法繁琐。axios 是一个基于 Promise 的 HTTP 客户端,语法简洁,且在 Vue 等框架中被广泛使用,能让我们更专注于业务逻辑而非底层通信细节。
二、URL:定位服务器资源的 “地址”
要与服务器通信,首先需要知道资源的位置 ——URL(统一资源定位符)。
1. URL 的核心组成
一个完整的 URL 包含三个关键部分:
- 协议:如
http://
,规定浏览器与服务器的通信规则; - 域名 / IP:如
127.0.0.1:8000
,标记服务器在网络中的位置; - 资源路径:如
/api/province
,指定服务器上具体资源的位置。
例如,http://127.0.0.1:8000/api/province
表示:通过 HTTP 协议,访问本地服务器(127.0.0.1:8000
)上的省份列表资源。
2. axios 中携带查询参数
在 axios 中,通过 params
选项设置查询参数,无需手动拼接 URL:
// 获取辽宁省的城市列表
axios({
url: 'http://127.0.0.1:8000/api/city',
params: {
pname: '辽宁省' // 参数名与服务器要求一致(课件中服务器约定参数名为pname)
}
}).then(result => {
// 服务器返回的数据格式为 { list: [城市1, 城市2, ...] }
console.log('辽宁省城市列表:', result.data.list);
// 渲染到页面:将城市列表转为li标签
document.querySelector('ul').innerHTML = result.data.list.map(city => `<li>${city}</li>`).join('');
});
三、请求方法和常见报错:与服务器的 “交互方式”
HTTP 协议定义了多种请求方法,用于表示对服务器资源的操作。常用方法如下:
请求方法 | 作用 | 示例 |
---|---|---|
GET | 获取资源(如查询数据) | 查询省份列表 |
POST | 提交数据(如注册、登录) | 用户注册 |
PUT | 全量更新资源 | 修改用户所有信息 |
DELETE | 删除资源 | 删除一条记录 |
HTTP 常见响应状态码(错误码)说明
状态码 | 类别 | 含义说明 | 常见场景示例 |
---|---|---|---|
200 | 成功 | 请求成功,服务器正常返回数据 | 登录成功、查询数据成功 |
400 | 客户端错误 | 请求参数错误或格式不正确 | 用户名不符合规则(如长度不足) |
401 | 客户端错误 | 未授权,需要验证身份(如登录失效) | 密码错误、未登录访问需要权限的资源 |
404 | 客户端错误 | 请求的资源不存在 | 访问了错误的 URL(如 /api/xxx 拼写错误) |
500 | 服务器错误 | 服务器内部出错,无法处理请求 | 服务器代码报错、数据库连接失败 |
403 | 客户端错误 | 服务器拒绝请求(如权限不足) | 普通用户尝试删除管理员数据 |
408 | 客户端错误 | 请求超时 | 网络延迟导致服务器未及时收到请求 |
503 | 服务器错误 | 服务器暂时不可用(如维护中) | 服务器负载过高、正在重启 |
四、综合案例
1、axios的使用步骤
①引入axios.js文件到自己的网页中:axios 在线引入地址(复制直接使用)
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.2/axios.min.js"></script>
②明确axios函数的使⽤语法
综合语句1:
axios({
// 配置项
url: '目标地址',
method: '请求方法', // 默认为 get
params: {}, // GET 参数
data: {} // POST 参数
})
.then(result => {
// 成功回调:处理服务器返回的数据
})
.catch(error => {
// 失败回调:处理错误信息
});
综合语句2:
axios.请求方法(url:'目标地址',{
参数名1:值1;
.......
}).then(result => {
// 成功回调:处理服务器返回的数据
})
.catch(error => {
// 失败回调:处理错误信息
});
2、综合案例代码
province_API.py:这里有后续网页对应的API接口
from fastapi import FastAPI
# 浏览器出于安全考虑,默认会阻止跨域请求(例如前端运行在 http://localhost:3000,
# 而 API 服务在 http://localhost:8000),这时就需要后端设置 CORS 来允许跨域访问。
from fastapi.middleware.cors import CORSMiddleware
# 用于创建数据库引擎,常用于同步数据库连接
from sqlalchemy import create_engine,Column,Integer,String
# 用于创建数据库会话,用于执行数据库操作
from sqlalchemy.orm import sessionmaker, declarative_base
# 创建FastAPI应用
app = FastAPI()
# 添加CORS中间件,允许跨域传输
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许所有源
allow_credentials=True, # 是否允许发送 Cookie
allow_methods=["*"], # 允许所有HTTP方法
allow_headers=["*"], # 允许所有HTTP头部
)
# 定义数据库连接URL
DATABASE_URL = "sqlite:///province.db"
# 创建数据库引擎,设置连接参数以允许在多线程环境中使用(地址)
engine = create_engine(DATABASE_URL,connect_args={"check_same_thread": False})
# 创建会话,绑定数据库引擎
SessionLocal = sessionmaker(bind=engine)
# 创建基类
Base = declarative_base()
# 创建数据库表结构(可以创建数据库表结构)
class Province(Base):
__tablename__ = "province"
code = Column(String)
id = Column(Integer, primary_key=True, index=True)
name = Column(String, unique=True, index=True)
# 执行创建数据库表结构
Base.metadata.create_all(bind = engine)
@app.get("/api/all_province")
def get_all_provinces():
"""
获取所有省份列表
返回格式与前端期望的格式一致,包含list属性
"""
db = SessionLocal()
try:
provinces = db.query(Province).all()
province_list = [province.name for province in provinces]
return {"list": province_list}
finally:
db.close()
@app.get("/api/find_province")
def find_province(name: str):
"""
根据名称查询省份
返回格式与前端期望的格式一致,包含list属性
"""
db = SessionLocal()
try:
find_province = db.query(Province).filter(Province.name == name).first()
if find_province:
return find_province.name
return "未找到该省份"
finally:
db.close()
# 实现城市查询API接口
@app.get("/api/city")
def get_cities(pname: str = None):
"""
根据省份名称获取城市列表
参数:
- pname: 省份名称
"""
# 这里简化处理,实际应该查询数据库中的城市数据
# 为演示目的,返回一些示例城市
cities = {
"辽宁省": ["沈阳市", "⼤连市", "鞍⼭市", "抚顺市", "本溪市"],
"上海": ["上海市"],
"⼴东省": ["⼴州市", "深圳市", "珠海市", "汕头市", "佛⼭市"],
"北京": ["北京", "东城", "西城", "朝阳", "海淀", "丰台", "石景山", "门头沟", "房山", "通州", "顺义", "昌平"],
"天津": ["天津", "和平", "河北", "河东", "河西", "南开", "河北", "和平", "宁河", "东丽", "西青", "津南", "北辰"],
}
if pname and pname in cities:
return {"list": cities[pname]}
return {"list": []}
# 实现地区查询API接口
@app.get("/api/area")
def get_areas(cname: str = None):
"""
根据省份和城市名称获取地区列表
参数:
- pname: 省份名称
- cname: 城市名称
"""
# 这里简化处理,实际应该查询数据库中的地区数据
# 为演示目的,返回一些示例地区
areas = {
"北京市": ["东城区", "西城区", "朝阳区", "海淀区", "丰台区", "石景山区"],
"上海市": ["黄浦区", "徐汇区", "长宁区", "静安区", "普陀区", "虹口区"],
"广州市": ["越秀区", "荔湾区", "海珠区", "天河区", "白云区", "黄埔区"],
"深圳市": ["福田区", "罗湖区", "南山区", "宝安区", "龙岗区", "盐田区"]
}
if cname and cname in areas:
return {"list": areas[cname]}
return {"list": []}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8080)
data.py:主要用于创建数据库,插入数据库的省份数据
import sqlite3
# 创建数据库连接
conn = sqlite3.connect('province.db')
# 创建数据库游标:游标能够对数据库进行操作
cursor = conn.cursor()
# 创建表
sql = '''
CREATE TABLE IF NOT EXISTS province (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
code TEXT NOT NULL
)'''
cursor.execute(sql)
sql = '''
insert into province(name,code)values
('北京', '110000'),
('天津', '120000'),
('河北', '130000'),
('⼭⻄', '140000'),
('内蒙古', '150000'),
('辽宁', '210000'),
('吉林', '220000'),
('⿊⻰江', '230000'),
('上海', '310000'),
('江苏', '320000'),
('浙江', '330000'),
('安徽', '340000'),
('福建', '350000'),
('江⻄', '360000')
'''
cursor.execute(sql)
conn.commit()
conn.close()
all_province.html:这个页面主要是对应 province_API里面的第一个接口,使用get的请求方式,不带参数来获取数据库的所有省份信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>所有的省份信息</title>
</head>
<body>
<h1>这里是所有的省份信息</h1>
<p id="all_province"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.2/axios.min.js"></script>
<script>
axios({
url: 'http://127.0.0.1:8080/api/all_province'
}).then(result => {
// 对服务器返回的数据做后续处理
console.log(result)
console.log(result.data)
console.log(result.data.list)
let all_province = document.getElementById('all_province')
all_province.innerHTML = result.data.list.join('<br/>')
})
</script>
<p></p>
</body>
</html>
find_city.html:这个页面主要是对应 province_API里面的第二个接口,使用post的请求方式,带查询城市名称参数来获取地区信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>显示城市的各个区</title>
</head>
<body>
<h1>显示城市的各个区</h1>
城市:<input type="text" id="input" placeholder="请输入你要查找的城市">
<button id = "btn">查找</button>
<h2>以下是查找的结果:</h2>
省份:<p id="sf"></p>
区:<p id="city"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.2/axios.min.js"></script>
<script>
let input = document.getElementById('input');
let btn = document.getElementById('btn');
let sf = document.getElementById('sf');
let city = document.getElementById('city');
btn.addEventListener('click', function () {
if (input.value) {
axios({
url: 'http://127.0.0.1:8080/api/city',
params: {
pname: input.value
}
}).then(result => {
// 对服务器返回的数据做后续处理
// console.log(result)
// console.log(result.data)
console.log(result.data.list)
if (result.data.list.length != 0){
sf.innerHTML = input.value
city.innerHTML = result.data.list.join('<br/>')
}
else {
sf.innerHTML = '没有找到该城市'
}
})
}
})
</script>
</body>
</html>
find_area.html:这个页面主要是对应 province_API里面的第三个接口,使用post的请求方式,带查询城市名称参数来获取地区信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查找地区列表</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>案例_地区查询</title>
</head>
<body>
<h1>显示城市的各个区</h1>
城市:<input type="text" id="input" placeholder="请输入你要查找的城市">
<button id = "btn">查找</button>
<h2>以下是查找的结果:</h2>
城市:<p id="sf"></p>
区:<p id="city"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.2/axios.min.js"></script>
<script>
const input = document.getElementById('input');
const btn = document.getElementById('btn');
const sf = document.getElementById('sf');
const city = document.getElementById('city');
btn.addEventListener('click', function () {
if (input.value) {
axios({
url: 'http://127.0.0.1:8080/api/area',
params: {
cname: input.value
}
}).then(result => {
// 对服务器返回的数据做后续处理
// console.log(result)
// console.log(result.data)
console.log(result.data.list)
if (result.data.list.length != 0){
sf.innerHTML = input.value
city.innerHTML = result.data.list.join('\n')
}
else {
sf.innerHTML = '没有找到该城市'
}
})
}
})
</script>
</body>
</html>
find_province.html:这个页面主要是对应 province_API里面的第四个接口,使用post的请求方式,带查询数据库中是否存在该城市
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查找城市是否存在</title>
</head>
<body>
<input type="text" id="input">
<button id="btn">查找</button>
<p id="find_province"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.2/axios.min.js"></script>
<script>
let input = document.getElementById('input');
let btn = document.getElementById('btn');
let find_province = document.getElementById('find_province');
btn.addEventListener('click', function () {
if (input.value) {
axios({
url: 'http://127.0.0.1:8080/api/find_province',
params: {
name: input.value
}
}).then(result => {
// 对服务器返回的数据做后续处理
console.log(result)
console.log(result.data)
find_province.innerText = result.data
})
}
})
</script>
</body>
</html>
五、综合案例 2:用户登录(结合 form-serialize)
需求:实现用户登录功能,包含表单验证、数据提交和结果提示,并使用 form-serialize
插件简化表单数据收集。
1. form-serialize 插件介绍
- 引入插件:
<script src="https://unpkg.com/form-serialize@0.7.2/form-serialize.min.js"></script>
; - 调用
serialize
函数:serialize(表单元素, { hash: true, empty: true })
(hash: true
返回对象,empty: true
包含空值)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>form-serialize插件使⽤</title>
</head>
<body>
<form action="javascript:;" class="example-form">
<input type="text" name="username"><br>
<input type="text" name="password"><br>
<input type="button" class="btn" value="提交">
</form>
<!--/
2. 使⽤serialize函数,快速收集表单元素的值
参数1:要获取哪个表单的数据
表单元素设置name属性,值会作为对象的属性名
建议name属性的值,最好和接⼝⽂档参数名⼀致
参数2:配置对象
hash 设置获取数据结构
- true:JS对象(推荐)⼀般请求体⾥提交给服务器
- false: 查询字符串
empty 设置是否获取空值
- true: 获取空值(推荐)数据结构和标签结构⼀致
- false:不获取空值
/-->
<!-- 引入 serialize.js 插件 -->
<script src="https://unpkg.com/form-serialize@0.7.2/form-serialize.min.js"></script>
<script>
document.querySelector('.btn').addEventListener('click', () => {
const form = document.querySelector('.example-form');
const data = serialize(form, { hash: true, empty: true });
// const data = serialize(form, { hash: false, empty: true });
// const data = serialize(form, { hash: true, empty: false });
console.log(data);
});
</script>
</body>
</html>