直到現在我們小寧已經更新了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>
?