JavaScript Fetch API请求源代码:GET与POST实例详解
深入讲解JavaScript原生Fetch API的使用方法,提供规范可运行的GET与POST请求源代码实例,涵盖查询参数拼接、JSON载荷提交、状态码校验及错误处理机制。
在现代Web开发中,与后端服务器进行异步数据通信是核心需求。传统的 XMLHttpRequest 由于回调嵌套繁琐、配置冗长,已被原生的 Fetch API 普遍替代。Fetch API 基于现代 Promise 机制设计,语法更加简洁直接,且天然契合 async/await 异步编程范式。本文将聚焦于 Fetch API 最常用的两种 HTTP 方式——GET 与 POST,提供规范的源代码实例,并系统梳理参数装配、JSON 解析、状态码校验以及网络错误拦截的完整实现流程。
一、Fetch API 的工作流程与核心机制
Fetch API 的核心入口是全局函数 fetch()。调用该函数会发起一个网络请求,并立即返回一个 Promise 对象。要写出稳健的请求代码,开发者必须首先明确 Fetch 在处理机制上与旧技术的一个关键差异:无论 HTTP 状态码是 200、404 还是 500,只要服务端返回了响应,Fetch 返回的 Promise 都将被判定为 resolved(已完成)状态。
只有当发生真正的底层网络故障(例如断网、DNS解析失败、跨域CORS被完全阻断或请求被主动中止)时,Promise 才会进入 rejected 状态并被 catch 捕获。因此,在业务代码中检查响应成功与否,必须依赖 response.ok 属性或检查 response.status 状态码。
二、GET 请求详解与完整源代码实例
GET 请求用于从服务器获取指定的资源。按照 HTTP 规范,GET 请求主要依靠 URL 中的查询参数(Query Parameters)传递过滤条件,不能包含请求体(Body)。
1. 基础 GET 请求:使用 async/await 语法
以下示例展示了获取用户信息的标准写法,代码中包含了完整的状态校验与错误捕获结构:
/**
* 基础 GET 请求示例
* @param {string} url 目标接口地址
* @returns {Promise<object>} 解析后的 JSON 数据
*/
async function fetchUserProfile(url) {
try {
// 默认即为 GET 请求,无需显式设置 method
const response = await fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
// 重点:检查 HTTP 状态码是否在 200-299 范围内
if (!response.ok) {
throw new Error(`网络响应不符合预期,HTTP 状态码: ${response.status} (${response.statusText})`);
}
// 解析 JSON 响应体(注意:此过程也是异步的)
const data = await response.json();
return data;
} catch (error) {
console.error('获取用户数据失败:', error.message);
throw error;
}
}
// 调用示例
// fetchUserProfile('https://jsonplaceholder.typicode.com/users/1')
// .then(user => console.log('用户信息:', user))
// .catch(err => console.error('处理异常:', err));
2. 带查询参数的 GET 请求:安全构建 Query String
在实际业务中,GET 请求通常需要附加诸如分页、分类、关键字检索等查询条件。手动拼接字符串极易引发空格、中文或特殊符号的编码错误。使用浏览器内置的 URL 和 URLSearchParams 对象是最高效且规范的实现方式。
/**
* 携带查询参数的 GET 请求通用函数
* @param {string} baseUrl 接口基础地址
* @param {Record<string, string | number>} queryParams 查询参数对象
* @returns {Promise<object>}
*/
async function fetchWithParams(baseUrl, queryParams = {}) {
try {
// 实例化 URL 对象(若为相对路径需指定 window.location.origin)
const targetUrl = new URL(baseUrl, window.location.origin);
// 将对象遍历追加到 searchParams 中,底层自动处理转义编码
Object.keys(queryParams).forEach(key => {
const val = queryParams[key];
if (val !== undefined && val !== null) {
targetUrl.searchParams.append(key, String(val));
}
});
const response = await fetch(targetUrl.toString(), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Cache-Control': 'no-cache' // 可选:避免浏览器强缓存 GET 结果
}
});
if (!response.ok) {
throw new Error(`请求失败: 状态码 ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('参数化 GET 请求发生错误:', error);
throw error;
}
}
// 调用示例
// fetchWithParams('https://jsonplaceholder.typicode.com/posts', {
// userId: 1,
// keyword: '教程指南'
// }).then(list => console.log('文章列表:', list));
三、POST 请求详解与完整源代码实例
POST 请求用于向服务器提交数据,通常用于创建新记录、提交表单或执行复杂的查询操作。与 GET 请求相比,POST 请求包含三个必须明确的要素:
- 明确指定请求方法:在配置项中显式设置
method: 'POST'。 - 设置正确的请求头:通过
headers告知后端载荷的媒体类型,提交 JSON 数据时必须包含'Content-Type': 'application/json'。 - 序列化请求体:将 JavaScript 内存对象通过
JSON.stringify()转换为符合规范的 JSON 文本字符串传入body。
1. 提交 JSON 数据的标准 POST 源码
这是前后端分离架构中最常见的请求模式。代码中完整体现了请求参数配置、响应状态判断和数据反序列化:
/**
* 发送 JSON 格式数据的 POST 请求
* @param {string} url 接口地址
* @param {object} payload 需提交的业务对象
* @returns {Promise<object>} 后端响应结果
*/
async function postJsonData(url, payload = {}) {
try {
const response = await fetch(url, {
method: 'POST',
headers: {
// 关键头信息:告知服务器请求体内容为 JSON 字符串
'Content-Type': 'application/json',
// 声明客户端希望接收的响应格式
'Accept': 'application/json'
},
// 将 JS 对象序列化为标准 JSON 字符串
body: JSON.stringify(payload)
});
// 状态码校验:处理 400 Bad Request、401 Unauthorized、500 等异常
if (!response.ok) {
// 尝试读取后端返回的具体错误信息 JSON
let errorDetails = null;
try {
errorDetails = await response.json();
} catch (parseErr) {
// 若后端返回的不是标准 JSON,则回退读取纯文本
errorDetails = await response.text();
}
throw new Error(`POST 请求未成功: ${response.status} - ${JSON.stringify(errorDetails)}`);
}
// 成功获取服务端返回的创建结果
const result = await response.json();
return result;
} catch (error) {
console.error('执行 postJsonData 失败:', error.message);
throw error;
}
}
// 调用示例
// const newArticle = {
// title: 'JavaScript Fetch API 实践',
// body: '这是一篇深入探讨 GET 与 POST 请求的教程。',
// userId: 1
// };
//
// postJsonData('https://jsonplaceholder.typicode.com/posts', newArticle)
// .then(response => console.log('发布成功,返回新记录:', response))
// .catch(err => console.error('发布失败:', err));
防错提醒:切勿省略 JSON.stringify() 直接向 body 传入普通 JavaScript 对象。如果传入普通对象,浏览器会自动将其转换为 "[object Object]" 字符串发送,导致后端解析报出 400 格式错误。
2. 提交表单数据(FormData 格式)
当涉及图片文件上传或传统 Form 表单提交时,应使用 FormData 对象。需要特别注意的是,使用 FormData 时,千万不要手动设置 Content-Type 头,因为浏览器会自动补齐对应的 multipart/form-data 及其专属的 boundary 随机分隔符:
/**
* 使用 FormData 提交表单或包含文件的 POST 请求
* @param {string} url 目标接口
* @param {HTMLFormElement | FormData} formElement 表单节点或数据对象
*/
async function submitFormData(url, formElement) {
try {
const formData = formElement instanceof FormData
? formElement
: new FormData(formElement);
const response = await fetch(url, {
method: 'POST',
// 注意:不要在此处手动设置 'Content-Type'
body: formData
});
if (!response.ok) {
throw new Error(`表单提交失败,状态码: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('表单提交发生异常:', error);
throw error;
}
}
四、进阶模式:统一请求封装、超时与取消机制
在生产级项目中,单纯依靠散落的 fetch() 调用难以满足网络超时控制、用户切页主动取消请求以及公共请求头统一注入的需求。现代浏览器提供了 AbortController 接口,通过配合 signal 属性,可以优雅地为请求增加超时中止能力。
/**
* 生产级统一 Fetch 请求包装器
* 支持:自动超时中止、自定义请求头注入、统一错误格式
* @param {string} url 请求地址
* @param {object} options 配置参数
* @param {number} [options.timeout=8000] 超时时间(毫秒)
*/
async function request(url, { method = 'GET', data = null, headers = {}, timeout = 8000 } = {}) {
// 1. 实例化 AbortController 用于超时自动取消
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
// 2. 组装请求配置
const fetchOptions = {
method: method.toUpperCase(),
headers: {
'Accept': 'application/json',
...headers
},
signal: controller.signal
};
// 3. 处理请求体与 Content-Type
if (data && ['POST', 'PUT', 'PATCH'].includes(fetchOptions.method)) {
if (data instanceof FormData) {
fetchOptions.body = data;
} else {
fetchOptions.headers['Content-Type'] = 'application/json';
fetchOptions.body = JSON.stringify(data);
}
}
try {
const response = await fetch(url, fetchOptions);
clearTimeout(timer); // 响应到达,清除超时计时器
if (!response.ok) {
const errBody = await response.text();
throw new Error(`HTTP 异常 ${response.status}: ${errBody}`);
}
// 默认按照 JSON 解析
return await response.json();
} catch (error) {
clearTimeout(timer);
if (error.name === 'AbortError') {
throw new Error(`请求超时:在 ${timeout}ms 内未能完成与服务器的通信`);
}
throw error;
}
}
// 实际使用示例:
// request('https://jsonplaceholder.typicode.com/posts', {
// method: 'POST',
// data: { title: '封装测试', body: '统一封装实战' },
// timeout: 5000
// }).then(res => console.log('请求成功:', res))
// .catch(err => console.error('统一处理异常:', err.message));
五、Fetch API 核心要点总结与避坑对照
为了让开发者在实际使用时能迅速排查问题,下表列出了日常开发中最常见的典型误区与标准实践原则:
| 对比维度 | 常见错误做法 | 正确规范做法 |
|---|---|---|
| 状态码判断 | 仅靠 try...catch 捕获 404/500 错误 |
显式检查 response.ok 或 response.status |
| GET 参数拼装 | 直接手写 url + '?a=' + a + '&b=' + b |
使用 new URLSearchParams() 自动进行安全编码 |
| POST JSON 数据 | 直接写 body: myObject,未转字符串 |
必须使用 body: JSON.stringify(myObject) |
| POST 头部声明 | 遗漏 Content-Type: application/json |
显式声明内容类型,后端方可正确反序列化 |
| FormData 提交 | 手动指定 Content-Type: multipart/form-data |
不设置该头,由浏览器自动生成 boundary 分隔符 |
| 数据多次读取 | 先后调用 response.json() 与 response.text() |
Response 数据流为一次性消耗,多次读取会报错 |
掌握 Fetch API 的本质在于透彻理解其基于 Promise 的异步流转规则以及 HTTP 报文协议的标准构成。通过合理配置请求头、严密校验 response.ok、妥善编码查询参数与载荷,并在外层引入 AbortController 超时控制机制,开发者便能用原生 JavaScript 写出高效、可靠且易于维护的网络请求层。
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
相关标签:








