从 AJAX 到 axios:前端与服务器通信实战指南

发布于:2025-06-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

直到现在我们小宁已经更新了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 插件介绍

1. 我们前⾯收集表单元素的值,是⼀个个标签获取的
2. 如果⼀套表单⾥有很多很多表单元素,如何⼀次性快速收集出来呢?
3. 使⽤ form-serialize 插件提供的 serialize 函数就可以办到
4. 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 包含空值)。
参数1:要获取的 form 表单标签对象(要求表单元素需要有 name 属性-⽤来作为收集的
数据中属性名)
参数2:配置对象
        hash:
                true - 收集出来的是⼀个 JS 对象结构
                false - 收集出来的是⼀个查询字符串格式
        empty:
                true - 收集空值
                false - 不收集空值
5. 需求:收集登录表单⾥⽤户名和密码
   <!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>
   


 


网站公告

今日签到

点亮在社区的每一天
去签到