什么是异步请求?
异步请求的定义:
浏览器使用 JavaScript,在不刷新页面的前提下,主动向服务器发送 HTTP 请求,然后根据返回的数据 动态更新页面内容。
它本质上是两个部分:
- 请求数据:fetch() 发送 HTTP 请求(GET、POST 等)
- 处理响应:拿到服务器返回的数据(JSON、文本、文件等)后做处理
为什么不能只用 form 表单?
1. 页面刷新问题
- 传统表单提交:提交表单时,默认会导致整个页面刷新。这种行为会影响用户体验,尤其是在单页面应用(SPA)中,用户希望在不刷新页面的情况下加载或提交数据。
- 异步请求:通过 AJAX 或 Fetch API,可以在不重新加载页面的情况下提交数据,这样可以提供更流畅的用户体验。
2. 错误处理和反馈
- 传统表单:处理表单验证和错误时,您需要在服务器端进行验证,返回响应后再重定向到结果页面,用户可能会迷失在过程之中。
- 异步请求:可以立即在前端处理验证,在用户提交表单后,即使是输入错误也可以迅速给予反馈,而无需重新加载页面。
3. 动态加载和数据交互
- 传统表单:对于需要动态交互和数据更新的场景(如选项互相依赖的下拉框),使用标准表单提交可能会很不方便。
- 异步请求:可以在前端动态更新页面,例如根据用户输入实时更新下拉框内容,无需刷新页面。
4. 更好的用户体验
- 动态界面:在现代 Web 应用中,许多功能要求快速的无缝体验(如即时搜索、表单自动填充等)。通过异步请求,可以在用户交互的同时更新界面,增强用户体验。
- 部分更新:在异步请求中,您可以只更新页面的某个部分,而不影响其他部分。这种灵活性是传统表单提交所不具备的。
5. 前后端分离架构
- API导向:在现代 Web 开发中,尤其是使用前后端分离架构(例如 React、Vue、Angular 等)时,前端与后端通常通过 API 进行交互。使用标准的表单提交与 API 不一致,因此异步请求是更常见的选择。
示例比较
传统表单提交的简单示例:
<form action="/submit" method="POST">
<input type="text" name="username" required>
<button type="submit">提交</button>
</form>
用户提交后,页面将被重定向到 /submit
页面,表现为刷新的效果。
异步提交的示例:
<form id="ajaxForm">
<input type="text" name="username" required>
<button type="submit">提交</button>
</form>
<script>
document.getElementById('ajaxForm').addEventListener('submit', async (event) => {
event.preventDefault(); // 防止默认提交
const formData = new FormData(event.target);
const response = await fetch('/submit', {
method: 'POST',
body: formData
});
const result = await response.json();
console.log(result); // 处理返回的结果而不刷新页面
});
</script>
这里,表单数据通过 JavaScript 被异步提交,页面不会刷新,用户可以继续与其他部分进行交互,同时更新反馈信息。
Fetch API 基础语法
fetch(url, options)
.then(response => {
// 检查响应的状态
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
return response.json(); // 解析 JSON 数据
})
.then(data => {
// 处理返回的数据
console.log(data);
})
.catch(error => {
// 处理错误
console.error('Fetch error:', error);
});
处理响应类型
类型 | 方法 | 场景 |
---|---|---|
JSON | res.json() | 后端返回结构化数据 |
文本 | res.text() | 返回纯文本消息 |
文件 | res.blob() | 下载文件、图片 |
fetch('/api/info')
.then(res => {
if (!res.ok) throw new Error('请求失败')
return res.json()
})
.then(data => console.log(data))
.catch(err => console.error(err));
- url:要请求的资源的 URL。
- options:可选,可以指定方法(GET、POST、PUT、DELETE等)、头信息、请求体等。
GET 请求
js:
以下示例展示如何使用 Fetch API 发送 GET 请求,并提取用户数据:
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // 解析 JSON 数据
})
.then(users => {
// 处理返回的用户数据
users.forEach(user => {
console.log(`姓名: ${user.name}, 电子邮件: ${user.email}`);
});
})
.catch(error => {
console.error('Fetch error:', error);
});
POST 请求(发送 JSON 格式)
以下示例展示如何使用 Fetch API 发送 POST 请求以添加用户数据:
js:
const newUser = {
name: "Alice",
email: "alice@example.com"
};
fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // 指定请求体格式为 JSON
},
body: JSON.stringify(newUser) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // 解析 JSON 数据
})
.then(data => {
// 处理返回的数据
console.log('新用户添加成功:', data);
})
.catch(error => {
console.error('Fetch error:', error);
});
使用 Fetch API 的注意事项
- Promise 处理:Fetch API 返回一个 Promise,这意味着您可以使用
then()
和catch()
方法链式处理成功与错误。 - 状态检查:使用
response.ok
属性检查响应的状态,只有状态码在 200 到 299 范围内时才标记为成功。 - 默认不抛出错误:如果请求失败(如 404、500),Fetch API 不会抛出错误,除非您显式进行状态检查。
- 跨域请求:Fetch API 需要处理 CORS(跨源资源共享)情况。如果后端没有正确设置 CORS,您可能会收到跨域限制的错误。
- 使用 async/await:可以结合 async/await 语法使代码更加简洁。
async/await(进阶写法)
异步函数的现代写法:
async function loadData() {
try {
const res = await fetch('/data');
if (!res.ok) throw new Error('状态码异常');
const data = await res.json();
console.log(data);
} catch (err) {
console.error('出错了', err);
}
}
demo:
async function fetchUsers() {
try {
let response = await fetch('https://jsonplaceholder.typicode.com/users');
if (!response.ok) {
throw new Error('Network response was not ok');
}
let users = await response.json();
users.forEach(user => {
console.log(`姓名: ${user.name}, 电子邮件: ${user.email}`);
});
} catch (error) {
console.error('Fetch error:', error);
}
}
fetchUsers();
await
关键字会暂停 fetchData
函数的执行,直到 fetch
请求的 Promise 被解决(即请求完成)。但请注意,这并不会阻塞整个程序的执行,其他代码依然可以运行,异步 请求的结果会在完成后被处理。
FromData表单数据处理
FormData
是一个用于构造表单数据的 JavaScript 对象,通常用于在客户端以异步方式(例如通过 Fetch API 或 XMLHttpRequest)提交包含文件的表单。它提供了一种方便的方式来构建请求的 body,支持多种类型的数据(包括文本、文件等)。下面将详细介绍 FormData
的用法及其在不同场景下的处理。
1. 创建 FormData
对象
您可以通过传递 <form>
元素或通过构造函数来创建 FormData
对象。
示例 1: 从 <form>
元素创建
<form id="myForm">
<input type="text" name="username" required>
<input type="file" name="file" required>
<button type="submit">提交</button>
</form>
<script>
const form = document.getElementById('myForm');
const formData = new FormData(form); // 直接从表单创建 FormData 对象
</script>
示例 2: 使用构造函数创建
const formData = new FormData(); // 创建一个空的 FormData 对象
formData.append('username', 'Alice'); // 追加文本字段
formData.append('file', selectedFile); // 追加文件字段,selectedFile 是一个 File 对象
2. 向 FormData
中添加数据
您可以使用 append
方法向 FormData
中添加数据。append
方法可以添加多个字段,包括文本文件的上传。
formData.append('username', 'Alice'); // 添加用户名字段
formData.append('email', 'alice@example.com'); // 添加电子邮件字段
formData.append('file', fileInput.files[0]); // 添加文件字段,fileInput.files[0] 是选中的文件对象
3. 发送 FormData
的 GET/POST 请求
您可以使用 Fetch API 或 XMLHttpRequest 发送 FormData
。以下是使用 Fetch API 的示例:
fetch('http://example.com/upload', {
method: 'POST',
body: formData // 将 FormData 作为请求体
})
.then(response => {
if (!response.ok) {
throw new Error('网络响应错误');
}
return response.json(); // 解析 JSON 数据
})
.then(data => {
console.log(data); // 处理返回的数据
})
.catch(error => {
console.error('Fetch error:', error); // 处理错误
});
4. 处理 FormData
在服务器端
在后端(例如 Flask)处理来自 FormData
的请求数据时,您可以直接使用 request.form
和 request.files
来访问请求中的表单数据以及文件。
Flask 示例:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/upload', methods=['POST'])
def upload_file():
# 处理文本字段
username = request.form.get('username')
# 处理文件上传
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
# 保存文件
file.save(f"/path/to/save/{file.filename}")
return jsonify({'message': '文件上传成功', 'username': username}), 200
if __name__ == '__main__':
app.run(debug=True)
如何判断我该用哪种请求方式?
场景 | 方法 | 数据格式 |
---|---|---|
获取数据 | GET | URL 参数 |
登录 / 注册 | POST | JSON |
提交表单 | POST | FormData |
上传文件 | POST | FormData(带文件字段) |
前端和后端之间的通信流程
- 用户填写表单
- JS 构造 fetch 请求(method、headers、body)
- 浏览器发 HTTP 请求
- Flask 接收并解析 request.form / request.json / request.files
- Flask 返回 JSON 响应
- 前端解析 res.json(),更新页面 DOM
表单异步提交完整demo
Fetch API 通过 POST 请求发送一个包含表单数据和文件的 FormData
后端 Flask API
安装 Flask
pip install Flask Flask-CORS
创建 Flask 应用(app.py)
from flask import Flask, request, jsonify
from flask_cors import CORS
import os
app = Flask(__name__)
CORS(app)
# 创建一个文件上传目录
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
# 保存文件
file.save(os.path.join(UPLOAD_FOLDER, file.filename))
# 获取其他表单字段
user_name = request.form.get('name')
user_email = request.form.get('email')
# 返回成功响应
return jsonify({'message': 'File uploaded successfully', 'name': user_name, 'email': user_email}), 200
if __name__ == '__main__':
app.run(debug=True)
HTML 和 JavaScript
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>异步表单提交示例</title>
</head>
<body>
<h1>表单异步提交示例</h1>
<form id="uploadForm">
<label for="name">姓名:</label>
<input type="text" id="name" name="name" required><br><br>
<label for="email">电子邮件:</label>
<input type="email" id="email" name="email" required><br><br>
<label for="file">选择文件:</label>
<input type="file" id="file" name="file" required><br><br>
<button type="submit">提交</button>
</form>
<div id="response"></div>
<script>
const form = document.getElementById('uploadForm');
const responseDiv = document.getElementById('response');
form.addEventListener('submit', async (event) => {
event.preventDefault(); // 阻止默认提交
const formData = new FormData(form); // 创建 FormData 对象
try {
const response = await fetch('http://127.0.0.1:5000/upload', {
method: 'POST',
body: formData // 将 FormData 作为请求体
});
if (!response.ok) {
throw new Error('网络响应错误');
}
const result = await response.json();
// 显示成功信息
responseDiv.innerHTML = `<p>${result.message}</p><p>姓名: ${result.name}, 电子邮件: ${result.email}</p>`;
} catch (error) {
responseDiv.innerHTML = `<p>错误: ${error.message}</p>`;
}
});
</script>
</body>
</html>
运行和测试
1、启动 Flask 服务器:
在终端中导航到包含 app.py 的目录,然后运行:
python app.py
Flask 应该会在 http://127.0.0.1:5000/ 地址运行。
2、打开 HTML 文件:
进入到包含 index.html 的目录,然后 python -m http.server 8000
(使用 python -m http.server 8000 启动一个本地的 HTTP 服务器可以让您在开发和测试阶段轻松地提供静态文件,并避免潜在的 CORS 问题)
3、测试表单:
在浏览器中访问 http://localhost:8000/index.html。
填写表单中的姓名和电子邮件。
选择一个文件进行上传。
点击“提交”按钮,您应该能够看到文件上传并返回的成功消息。

发布者:LJH,转发请注明出处:https://www.ljh.cool/42784.html