前后端交互是现代 Web 开发的核心概念,它描述了前端(客户端)和后端(服务器端)之间的数据交换和通信方式。本章将介绍前后端分离架构、数据交换格式、AJAX 技术等关键概念。
浏览器 → 服务器 → 数据库
↑ ↓
← HTML 页面 ←
特点:
- 服务器生成完整的 HTML 页面
- 页面刷新时重新加载整个页面
- 前后端耦合度高
- 开发效率相对较低
前端应用 ←→ API 服务器 ←→ 数据库
↓ ↓
HTML/CSS/JS JSON/XML
特点:
- 前端和后端独立开发
- 通过 API 进行数据交换
- 支持单页应用(SPA)
- 更好的用户体验
- 开发效率:前后端可以并行开发
- 技术栈灵活:前端和后端可以使用不同的技术栈
- 可维护性:代码结构清晰,职责分离
- 可扩展性:支持多端应用(Web、移动端、桌面端)
- 用户体验:支持无刷新交互
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。
{
"string": "字符串",
"number": 123,
"boolean": true,
"null": null,
"array": [1, 2, 3],
"object": {
"name": "张三",
"age": 25
}
}import json
# Python 对象转 JSON 字符串
data = {
"name": "张三",
"age": 25,
"skills": ["Python", "JavaScript", "Vue.js"]
}
json_string = json.dumps(data, ensure_ascii=False, indent=2)
print(json_string)
# JSON 字符串转 Python 对象
json_data = '{"name": "李四", "age": 30}'
python_obj = json.loads(json_data)
print(python_obj["name"])// JavaScript 对象转 JSON 字符串
const data = {
name: "张三",
age: 25,
skills: ["Python", "JavaScript", "Vue.js"]
};
const jsonString = JSON.stringify(data, null, 2);
console.log(jsonString);
// JSON 字符串转 JavaScript 对象
const jsonData = '{"name": "李四", "age": 30}';
const jsObj = JSON.parse(jsonData);
console.log(jsObj.name);AJAX(Asynchronous JavaScript and XML)是一种在无需重新加载整个页面的情况下,能够更新部分网页的技术。
// 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();
// 配置请求
xhr.open('GET', '/api/users', true);
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');
// 处理响应
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log('用户列表:', response);
} else {
console.error('请求失败:', xhr.status);
}
}
};
// 发送请求
xhr.send();
// POST 请求示例
const xhrPost = new XMLHttpRequest();
xhrPost.open('POST', '/api/users', true);
xhrPost.setRequestHeader('Content-Type', 'application/json');
xhrPost.onreadystatechange = function() {
if (xhrPost.readyState === 4 && xhrPost.status === 201) {
const newUser = JSON.parse(xhrPost.responseText);
console.log('新用户:', newUser);
}
};
const userData = {
name: "王五",
email: "wangwu@example.com"
};
xhrPost.send(JSON.stringify(userData));Fetch API 是现代浏览器提供的更简洁的 HTTP 请求接口。
// GET 请求
fetch('/api/users')
.then(response => {
if (!response.ok) {
throw new Error('网络响应错误');
}
return response.json();
})
.then(data => {
console.log('用户列表:', data);
})
.catch(error => {
console.error('请求失败:', error);
});
// POST 请求
const userData = {
name: "王五",
email: "wangwu@example.com"
};
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
})
.then(response => response.json())
.then(data => {
console.log('新用户:', data);
})
.catch(error => {
console.error('请求失败:', error);
});
// 使用 async/await
async function fetchUsers() {
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error('网络响应错误');
}
const users = await response.json();
console.log('用户列表:', users);
return users;
} catch (error) {
console.error('请求失败:', error);
}
}
async function createUser(userData) {
try {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error('创建用户失败');
}
const newUser = await response.json();
console.log('新用户:', newUser);
return newUser;
} catch (error) {
console.error('请求失败:', error);
}
}CORS(Cross-Origin Resource Sharing)是一种安全机制,用于控制不同源之间的资源访问。
同源策略要求协议、域名、端口都相同:
http://localhost:3000和http://localhost:8000→ 不同源https://example.com和http://example.com→ 不同源http://api.example.com和http://www.example.com→ 不同源
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# 允许所有域名访问
CORS(app)
# 或者指定允许的域名
CORS(app, origins=['http://localhost:3000', 'https://example.com'])
# 或者针对特定路由
@app.route('/api/users')
@cross_origin(origins=['http://localhost:3000'])
def get_users():
return jsonify(users)from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# 添加 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "https://example.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)// 在请求中添加凭证
fetch('/api/users', {
credentials: 'include', // 包含 cookies
headers: {
'Content-Type': 'application/json',
}
});
// 使用代理解决开发环境跨域
// 在 package.json 中添加
{
"proxy": "http://localhost:8000"
}// 在请求头中添加认证信息
fetch('/api/protected', {
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json',
}
});// 存储 token
localStorage.setItem('token', 'your-jwt-token');
// 获取 token
const token = localStorage.getItem('token');
// 删除 token
localStorage.removeItem('token');
// 检查 token 是否有效
function isTokenValid() {
const token = localStorage.getItem('token');
if (!token) return false;
// 检查 token 是否过期
try {
const payload = JSON.parse(atob(token.split('.')[1]));
return payload.exp > Date.now() / 1000;
} catch (error) {
return false;
}
}<!DOCTYPE html>
<html>
<head>
<title>用户管理</title>
<style>
.user-list {
margin: 20px 0;
}
.user-item {
padding: 10px;
border: 1px solid #ddd;
margin: 5px 0;
}
.form-group {
margin: 10px 0;
}
.form-group label {
display: inline-block;
width: 80px;
}
</style>
</head>
<body>
<h1>用户管理</h1>
<!-- 添加用户表单 -->
<div>
<h2>添加用户</h2>
<form id="addUserForm">
<div class="form-group">
<label>姓名:</label>
<input type="text" id="name" required>
</div>
<div class="form-group">
<label>邮箱:</label>
<input type="email" id="email" required>
</div>
<button type="submit">添加用户</button>
</form>
</div>
<!-- 用户列表 -->
<div>
<h2>用户列表</h2>
<button onclick="loadUsers()">刷新列表</button>
<div id="userList" class="user-list"></div>
</div>
<script>
const API_BASE = 'http://localhost:8000/api';
// 加载用户列表
async function loadUsers() {
try {
const response = await fetch(`${API_BASE}/users`);
const users = await response.json();
const userList = document.getElementById('userList');
userList.innerHTML = users.map(user => `
<div class="user-item">
<strong>${user.name}</strong> - ${user.email}
<button onclick="deleteUser(${user.id})">删除</button>
</div>
`).join('');
} catch (error) {
console.error('加载用户失败:', error);
}
}
// 添加用户
document.getElementById('addUserForm').addEventListener('submit', async (e) => {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
try {
const response = await fetch(`${API_BASE}/users`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, email })
});
if (response.ok) {
alert('用户添加成功!');
document.getElementById('addUserForm').reset();
loadUsers();
} else {
alert('添加失败');
}
} catch (error) {
console.error('添加用户失败:', error);
alert('添加失败');
}
});
// 删除用户
async function deleteUser(userId) {
if (!confirm('确定要删除这个用户吗?')) return;
try {
const response = await fetch(`${API_BASE}/users/${userId}`, {
method: 'DELETE'
});
if (response.ok) {
alert('用户删除成功!');
loadUsers();
} else {
alert('删除失败');
}
} catch (error) {
console.error('删除用户失败:', error);
alert('删除失败');
}
}
// 页面加载时获取用户列表
loadUsers();
</script>
</body>
</html>// 统一的 API 请求函数
class ApiClient {
constructor(baseURL) {
this.baseURL = baseURL;
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('API 请求失败:', error);
throw error;
}
}
async get(endpoint) {
return this.request(endpoint);
}
async post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
async put(endpoint, data) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
});
}
async delete(endpoint) {
return this.request(endpoint, {
method: 'DELETE'
});
}
}
// 使用示例
const api = new ApiClient('http://localhost:8000/api');
// 显示加载状态
function showLoading(elementId) {
const element = document.getElementById(elementId);
element.innerHTML = '<div>加载中...</div>';
}
// 显示错误信息
function showError(elementId, message) {
const element = document.getElementById(elementId);
element.innerHTML = `<div style="color: red;">错误: ${message}</div>`;
}
// 使用 API 客户端
async function loadUsersWithStatus() {
const userList = document.getElementById('userList');
try {
showLoading('userList');
const users = await api.get('/users');
userList.innerHTML = users.map(user => `
<div class="user-item">
<strong>${user.name}</strong> - ${user.email}
<button onclick="deleteUser(${user.id})">删除</button>
</div>
`).join('');
} catch (error) {
showError('userList', error.message);
}
}完成本节学习后,请检查是否掌握:
- 理解前后端分离架构的优势
- 掌握 JSON 数据格式的使用
- 能够使用 AJAX 和 Fetch API
- 理解 CORS 跨域问题及解决方案
- 掌握基本的认证和授权机制
- 能够处理 API 请求的错误和加载状态
上一节:1.2 Web 框架入门 | 下一节:1.4 实践项目