前言
做前端的小伙伴谁没经历过?页面写得漂漂亮亮,一没数据瞬间变成静态废纸。从前靠 XHR 手写一大堆冗余代码,如今fetch搭配async/await直接封神,从本地后端拿表格数据、远程调用 DeepSeek 大模型全都能实现。本篇结合实战源码,从原理、基础实战、AI 接口实战、易错坑点四个维度完整拆解,干货 + 代码双在线。
一、基础知识铺垫:HTTP 请求与前后端架构
1. Client/Server 架构逻辑
日常网页、App 全部遵循 C/S(客户端 / 服务端)架构:
- 客户端:浏览器、安卓、IOS 小程序,负责页面展示、用户交互;
- 服务端:Java、Node.js 等语言开发,部署在服务器硬件上,存储业务数据;
- 通信桥梁 HTTP:客户端通过接口 URL(endpoint)发送请求,服务器接收后返回 JSON 格式数据。
2. IP 与域名、DNS 解析
访问地址http://127.0.0.1:3000/friends拆分:
127.0.0.1:本机 IP,网络中用来精准定位服务器;3000:端口号,一台服务器可开启多个服务,靠端口区分;www.baidu.com:域名,人类方便记忆,经过 DNS 域名解析自动转换成对应 IP。
3. 前端发送 HTTP 的两种方案
- XMLHttpRequest(XHR) :原生老牌接口,写法繁琐、回调嵌套多,早期 AJAX 底层实现;
- Fetch API :ES6 推出原生请求方案,基于 Promise,配合
async/await将异步代码写成同步样式,现在主流首选。
4. 前后端分离开发模式
前后端各司其职:后端专注编写接口、操作数据库;前端只需要调用 API 拿到 JSON,再通过map循环拼接 HTML 字符串渲染页面,互不干扰,也是当下企业主流开发模式。
二、实战一:Fetch 请求本地后端,表格渲染好友数据
后端本地启动服务,地址:http://localhost:3000/friends,接口返回好友数组 JSON 数据,前端通过 fetch 拉取数据、动态生成表格。
1. HTML 骨架代码
html
预览
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>好友信息管理表</title>
<style>
table{border-collapse: collapse;margin:20px 0;}
td,th{border:1px solid #333;padding:6px 12px;}
</style>
</head>
<body>
<h2>好友档案列表</h2>
<table>
<thead>
<tr>
<th>编号ID</th>
<th>姓名</th>
<th>年龄</th>
</tr>
</thead>
<tbody></tbody>
</table>
<!--引入业务JS-->
<script src="main.js"></script>
</body>
</html>
2. main.js 业务代码
javascript
运行
javascript
// 接口地址endpoint,后端请求终点
const endpoint = 'http://localhost:3000/friends';
let friends = [];
// 异步请求后端数据
async function loadData() {
try {
// await阻塞等待接口响应完成
const res = await fetch(endpoint);
// 判断接口请求状态码是否正常
if(!res.ok) throw new Error(`服务器异常:${res.status}`);
// 二进制响应体转为JS对象
const data = await res.json();
return data;
} catch (err) {
console.error('数据请求失败',err);
return [];
}
}
// 将数据渲染进表格
function renderData(list) {
const tbody = document.querySelector('table tbody');
// map遍历数组,拼接tr标签字符串,join去掉数组逗号分隔符
tbody.innerHTML = list.map(item => `
<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.age}</td>
</tr>
`).join('');
}
// 项目初始化入口
async function init() {
friends = await loadData();
renderData(friends);
}
init();
3. 逐行代码详细解析
async修饰函数:函数内部可以使用await关键字,函数返回值自动包装成 Promise;await fetch(url):发起 GET 请求,暂停代码执行,直到服务器返回响应结果再向下执行;res.json():接口返回原始二进制数据流,该方法异步解析为 JS 对象,必须加 await;Array.map():数组遍历,批量生成表格 HTML 字符串,join('')把数组拼接成完整字符串,直接赋值innerHTML渲染 DOM;- 执行顺序:
init() → loadData请求接口 → 获取JSON → renderData渲染页面,完全串行可控。
4. 运行前提
本地用 Node/Express 开启 3000 端口后端服务,/friends路由返回[{id:1,name:'张三',age:22},...]格式 JSON。
三、实战二:Fetch POST 请求,远程调用 DeepSeek 大模型 API
除请求自有后端,Fetch 还能对接各大 LLM 大模型接口,采用 POST 传参、Header 携带密钥鉴权,示例调用 DeepSeek 对话接口。
1. HTML 页面
html
预览
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>在线调戏DeepSeek AI</title>
<style>
#loading{color:#999;display:none;}
.err{color:red}
#apply{margin-top:15px;line-height:1.8}
</style>
</head>
<body>
<h3>AI智能问答</h3>
<div id="loading">正在请求AI思考中...</div>
<div id="apply"></div>
<script src="script.js"></script>
</body>
</html>
2. script.js 核心调用代码
javascript
运行
javascript
// 替换为自己在DeepSeek平台申请的密钥
const DEEPSEEK_API_KEY = 'sk-your-api-key-here';
// 获取DOM元素
const loadingEl = document.getElementById('loading');
const applyEl = document.getElementById('apply');
async function callDeepSeek() {
// 开启加载状态
loadingEl.style.display = 'block';
applyEl.innerHTML = '';
try {
// fetch第二个配置参数,定制POST请求
const response = await fetch('https://api.deepseek.com/chat/completions', {
method: 'POST', // 请求方式
headers: {
'Content-Type': 'application/json', // 告知后端请求体是JSON格式
Authorization: `Bearer ${DEEPSEEK_API_KEY}` // 接口身份凭证
},
// 请求体必须转为JSON字符串
body: JSON.stringify({
model: 'deepseek-chat',
messages: [
{ role: 'system', content: '你是简洁的AI助手,回答精简' },
{ role: 'user', content: '介绍下fetch请求的优势' }
]
})
});
// 接口非200状态抛出错误
if (!response.ok) {
const errInfo = await response.json();
throw new Error(errInfo.error?.message || `错误码:${response.status}`);
}
// 解析返回数据
const resData = await response.json();
applyEl.innerHTML = resData.choices[0].message.content;
} catch (error) {
applyEl.innerHTML = `<span class="err">调用失败:${error.message}</span>`;
console.error(error);
} finally {
// 无论成功失败,都关闭loading
loadingEl.style.display = 'none';
}
}
// 页面加载自动调用
callDeepSeek();
3. 接口知识点解析
- GET 与 POST 区别:GET 参数拼在 URL,多用于查询数据;POST 参数放在请求体 body,适合传大量数据、调用 AI 接口;
- 请求头 Content-Type:application/json:后端根据该标识解析 body 里的 JSON 参数,缺一不可;
- Bearer 鉴权:大模型接口通用鉴权方式,API KEY 相当于访问密码,泄露会产生扣费风险;
- finally 语句块:try 成功、catch 报错两种场景都会执行,用来统一关闭加载动画,优化用户体验;
- 返回结构:
choices[0].message.content是 AI 生成的回答内容,所有 LLM 接口返回格式思路一致。
四、Fetch 常见踩坑汇总
- 跨域问题 :前端页面打开文件直接本地
file://协议运行调用接口会跨域,需要后端配置 CORS 跨域,或开启本地服务预览页面; - 忘记 await res.json () :直接打印得到 Promise 对象,拿不到真实数据;
- POST 忘记 JSON.stringify:body 直接传 JS 对象,后端无法解析参数;
- 不校验 response.ok:接口 404/500 报错不会进入 catch,导致代码异常。
五、拓展:前端两种 HTTP 请求方式对比
表格
| 请求方式 | 优点 | 缺点 |
|---|---|---|
| XMLHttpRequest | 兼容性极强,兼容老旧 IE | 代码冗余、异步嵌套繁琐 |
| Fetch API | 语法简洁、Promise 封装、搭配 async/await 可读性高 | 低版本浏览器需要垫片兼容 |
六、文末总结
- Fetch+async/await 是现代前端网络请求标配,是实现前后端分离的数据通信核心;
- 本地接口用于业务数据渲染,远程 LLM 接口用于 AI 功能开发,二者请求逻辑完全相通,仅请求参数不同;
- 开发规范:所有网络请求统一加
try/catch异常捕获,增加页面容错,优化用户体验; - 拓展方向:学会后可以自行封装通用请求工具函数,统一处理请求头、错误拦截,适配项目开发。
实操小提示:调用 DeepSeek 接口务必替换个人 API Key,密钥错误会直接返回鉴权失败报错。