直到现在我们小宁已经更新了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: '请求方法', // 默认为 getparams: {}, // 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, # 是否允许发送 Cookieallow_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.namereturn "未找到该省份"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 uvicornuvicorn.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.valuecity.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.valuecity.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>