5 个 Step,让你的前端代码连上 AI 大模型
🔗 项目源码:gitee.com/zhou-wenqia...
前言
"前端不就是切页面的吗?"
如果你也被这样问过,这篇文章就是你的反击武器。从请求后端数据,到调用 AI 大模型,前端能做的事远比你想象的多------而这一切,只需要掌握一个 API:fetch。
本文通过 5 个 Step,带你从零做到这件事:
| Step | 做什么 | 核心技能 |
|---|---|---|
| 1 | 理解 HTTP 请求 | 请求行、请求头、请求体 |
| 2 | 搭建后端 | json-server、REST API |
| 3 | fetch GET 获取数据 | async/await、DOM 渲染 |
| 4 | fetch POST 调用 AI | Headers、Body、认证 |
| 5 | 用 SDK 简化代码 | OpenAI SDK、baseURL 切换 |
读完你会发现:会用 fetch,你就能连接整个互联网。
Step 1:理解 HTTP 请求
在写代码之前,先搞清楚 HTTP 请求长什么样。
1.1 请求的三要素
每次 fetch 发出的请求,都由三部分组成:
bash
请求行:去哪里、做什么 → POST /v1/chat/completions
请求头:携带的附加信息 → Content-Type: application/json
请求体:发送的数据 → { "model": "mimo-v2.5-pro", ... }
用浏览器打开任意网页,按 F12 → Network 面板,你能看到每一个请求的这三部分。
1.2 Endpoint(端点)
bash
http://localhost:3000/friends ← 本机服务器
https://api.xiaomimimo.com/v1/chat/completions ← 远程 AI 服务
Endpoint 就是 API 请求的终点------一个"服务窗口",你告诉它你要什么,它返回对应的数据。
localhost:3000→ 你本机运行的服务器api.xiaomimimo.com→ 远程部署的 AI 服务- 域名通过 DNS 解析翻译成 IP 地址,帮你找到对应的服务器
1.3 为什么选 fetch?
前端发 HTTP 请求有三种方式:
| 方式 | 特点 |
|---|---|
| fetch | 浏览器原生,返回 Promise,推荐 |
| XMLHttpRequest | 老牌 API,回调风格,逐渐被淘汰 |
| Axios 等库 | 封装了 fetch,功能更丰富,需安装 |
本文全程用 fetch------零依赖,够用且优雅。
Step 2:搭建后端(json-server)
我们先搭一个本地后端,提供数据接口。
2.1 项目结构
kotlin
demo1/
├── backend/ ← 后端
│ ├── data.json ← 数据源
│ └── package.json
└── frontend/ ← 前端
├── index.html
└── main.js
2.2 创建数据文件
在 backend 目录下创建 data.json:
data.json:
json
{
"friends": [
{ "id": 1, "name": "小金", "age": 17 },
{ "id": 2, "name": "大金", "age": 17 }
]
}
2.3 安装并启动服务
bash
# 创建项目目录并进入
mkdir backend && cd backend
# 初始化项目并安装 json-server
pnpm init
pnpm add json-server@1.0.0-beta.15
然后在 package.json 中添加启动脚本:
json
{
"scripts": {
"dev": "json-server --watch data.json --port 3000"
},
"dependencies": {
"json-server": "1.0.0-beta.15"
}
}
如果从零创建,直接运行:
bash
pnpm dev
如果克隆了项目源码,先安装依赖再启动:
bash
cd demo1/backend
pnpm install
pnpm dev
看到以下输出说明启动成功:
bash
\{^_^}/ hi!
Loading data.json
Done
Resources
http://localhost:3000/friends
Home
http://localhost:3000
json-server 会把一个 JSON 文件变成完整的 REST API:
bash
GET /friends → 获取所有朋友
GET /friends/1 → 获取 id 为 1 的朋友
POST /friends → 新增朋友
PUT /friends/1 → 修改朋友信息
DELETE /friends/1 → 删除朋友
💡 这就是前后端分离的核心:后端只管数据(JSON),前端只管展示(HTML/CSS/JS),两者通过 HTTP 接口通信。
Step 3:fetch GET 获取数据
确保 Step 2 的后端已启动(
pnpm dev),然后继续。
后端有了,现在用前端代码把数据"拿"过来。
3.1 HTML 页面
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<header><h1>Friends List</h1></header>
<main>
<table>
<thead>
<tr><th>id</th><th>name</th><th>age</th></tr>
</thead>
<tbody>
<!-- 数据由 JS 动态填充 -->
</tbody>
</table>
</main>
<footer><p>Powered by json-server + fetch</p></footer>
<script src="./main.js"></script>
</body>
</html>
3.2 核心 JS 代码
js
// 1. 获取数据
async function loadData() {
const endpoint = 'http://localhost:3000/friends';
const res = await fetch(endpoint); // 发送 GET 请求
if (!res.ok) { // fetch 不会因 4xx/5xx 报错,必须手动检查
throw new Error(`请求失败: ${res.status}`);
}
const data = await res.json(); // 响应体是二进制流,要转成 JS 对象
return data;
}
// 2. 渲染到页面
function renderData(friends) {
const oBody = document.querySelector('table tbody');
if (friends.length > 0) {
// 数据来自本地 json-server(可信来源),用 innerHTML 渲染表格
// 如果数据来自用户输入或外部 API,应使用 textContent 防止 XSS
oBody.innerHTML = friends.map(friend => `
<tr>
<td>${friend.id}</td>
<td>${friend.name}</td>
<td>${friend.age}</td>
</tr>
`).join("");
}
}
// 3. 入口:先加载,再渲染
async function init() {
try {
const friends = await loadData();
renderData(friends);
} catch (err) {
console.error('加载数据失败:', err);
}
}
init();
3.3 关键点拆解
await fetch(endpoint) 做了什么?
scss
init() 被调用
→ loadData() 开始执行
→ fetch 发出请求(JS 不阻塞,继续执行其他代码)
→ 响应返回,await 拿到 res
→ res.json() 解析数据
→ await 拿到 data
→ loadData() 返回 data
→ renderData(data) 渲染到 DOM
为什么要检查 res.ok?
fetch只有在网络错误时才会 reject。HTTP 404、500 这些状态码不会抛异常------你必须自己判断。
为什么要 await res.json()?
res的 body 是二进制流 ,不是 JS 对象。.json()把它解析为数组/对象,这一步也是异步的。
async/await 会阻塞浏览器吗?
js
console.log('A: 先执行');
const data = await loadData(); // 暂停当前函数,让出线程
console.log('B: 数据到了'); // 数据返回后才执行
// 输出:A → (等待) → B
// 不是 A → B → (等待)
await只是暂停了当前 async 函数,主线程继续执行其他代码,所以不会卡住浏览器。
3.4 运行效果
用 Live Server 打开 demo1/frontend/index.html,表格自动渲染:
| id | name | age |
|---|---|---|
| 1 | 小金 | 17 |
| 2 | 大金 | 17 |
Step 4:fetch POST 调用 AI
现在来玩点更刺激的------用前端代码直接调用 AI 大模型。
4.1 项目结构
demo/
├── index.html
├── script.js
└── style.css ← 可选样式,不影响核心逻辑
4.2 核心代码
前往 api.xiaomimimo.com 注册并获取 API Key,替换下方代码中的
your-api-key-here。
js
// endpoint
const endpoint = 'https://api.xiaomimimo.com/v1/chat/completions'
// API Key(生产环境应从环境变量获取,不要硬编码)
const apiKey = 'your-api-key-here'
// 请求头:声明格式 + 身份认证
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`
}
// 请求体:模型 + 对话内容
const payload = {
model: "mimo-v2.5-pro",
messages: [
{ role: 'system', content: 'You are a helpful assistant' },
{ role: 'user', content: 'hello' }
]
}
try {
const response = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(payload) // body 必须是字符串,不能是对象
})
if (!response.ok) {
throw new Error(`请求失败: ${response.status}`)
}
const data = await response.json();
document.getElementById('reply').textContent = data.choices[0].message.content;
} catch (err) {
console.error('请求出错:', err);
document.getElementById('reply').textContent = '请求失败,请查看控制台';
}
4.3 和 Step 3 的三个区别
对比两个 Step 的 fetch 调用:
js
// Step 3:GET(最简形式)
fetch('http://localhost:3000/friends')
// Step 4:POST(完整形式)
fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(payload)
})
区别一:请求方法
| 方法 | 语义 | 有无请求体 |
|---|---|---|
| GET | 获取资源 | 无 |
| POST | 提交数据 | 有 |
| PUT | 更新资源 | 有 |
| DELETE | 删除资源 | 无 |
区别二:请求头
js
const headers = {
'Content-Type': 'application/json', // 告诉服务器:我发的是 JSON
Authorization: `Bearer ${apiKey}` // 告诉服务器:我是合法用户
}
Content-Type:服务器据此决定如何解析 bodyAuthorization:身份认证,大部分 AI API 都需要
区别三:请求体
HTTP 协议传输的只能是字符串 。
JSON.stringify()把 JS 对象序列化为 JSON 字符串。
4.4 请求与响应对照
请求:
bash
POST /v1/chat/completions HTTP/1.1
Content-Type: application/json
Authorization: Bearer sk-xxxxxxxx
{
"model": "mimo-v2.5-pro",
"messages": [
{ "role": "system", "content": "You are a helpful assistant" },
{ "role": "user", "content": "hello" }
]
}
响应:
css
HTTP/1.1 200 OK
Content-Type: application/json
{
"choices": [{
"message": {
"content": "Hello! How can I help you today?"
}
}]
}
4.5 运行
bash
# 1. 替换 script.js 中的 apiKey 为你的实际 Key
# 2. 用 Live Server 打开 demo/index.html(type="module" 不支持 file:// 协议)
# 3. 打开浏览器控制台查看完整响应,页面上会显示 AI 的回复
运行后,页面上会显示:
bash
Hello! How can I help you today?
Step 5:用 SDK 简化代码
Step 4 的代码能跑,但有不少重复:手动写 Headers、JSON.stringify、状态码检查......
在实际项目中,大多数开发者会选择 OpenAI SDK 。现在很多大模型服务都兼容 OpenAI 的接口格式,一套 SDK 就能调用多种模型。
5.1 安装
bash
npm install openai
# 或
pnpm add openai
5.2 代码对比
同样的功能,用 SDK 只需要:
js
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'your-api-key-here',
baseURL: 'https://api.xiaomimimo.com/v1'
});
try {
const response = await client.chat.completions.create({
model: "mimo-v2.5-pro",
messages: [
{ role: 'system', content: 'You are a helpful assistant' },
{ role: 'user', content: 'hello' }
]
});
console.log(response.choices[0].message.content);
} catch (err) {
console.error('请求失败:', err.message);
}
没有 Headers、没有 JSON.stringify、没有 res.ok 检查------SDK 全帮你搞定了。
5.3 fetch vs SDK
| fetch(手动) | OpenAI SDK | |
|---|---|---|
| 安装依赖 | 无 | 需要 npm install openai |
| Headers | 手动写 | 自动处理 |
| 请求体 | 手动 JSON.stringify | 自动序列化 |
| 状态码检查 | 手动 res.ok | 自动抛出错误 |
| 类型提示 | 无 | 完整 TypeScript 类型 |
| 流式输出 | 手动解析 SSE | 内置 .stream() |
| 适合场景 | 学习原理、简单脚本 | 生产项目、多模型切换 |
5.4 什么时候用什么?
- 学习阶段 → 用
fetch,理解底层原理(本文的重点) - 生产项目 → 用 SDK,省心省力,错误处理更完善
- 调用多个模型 → 改一下
baseURL和apiKey就能无缝切换
💡 DeepSeek、Moonshot、智谱、百川等国产大模型都提供 OpenAI 兼容接口,一套代码适配多个服务。
总结
5 个 Step 回顾
vbnet
Step 1: HTTP 请求 = 请求行 + 请求头 + 请求体
Step 2: json-server 把 JSON 文件变成 REST API
Step 3: fetch GET + async/await → 从后端拿数据,渲染到页面
Step 4: fetch POST + Headers + Body → 调用 AI 大模型
Step 5: OpenAI SDK → 一行代码搞定,多模型通用
核心范式
js
const res = await fetch(url, options); // 发请求
const data = await res.json(); // 解响应
从获取本地朋友列表,到调用远程 AI 大模型,变化的是 URL、Headers 和 Body,不变的是 fetch + async/await 这套范式。
掌握了这个范式,前端就不再只是"切页面"------你可以连接任何服务,构建真正有生命力的应用。
下一步
- 🔄 流式输出 :AI 场景的核心体验,用 SSE 或
ReadableStream实现 - 🔐 安全:API Key 放后端代理,不要暴露在前端代码中
- 📦 封装 :把 fetch 封装成自己的
request工具函数,统一错误处理 - 🌐 更多 API:天气、地图、支付......万物皆可 fetch
📚 参考资料
👨💻 作者:zhou-wenqiang-c | 欢迎 Star ⭐
如果这篇文章对你有帮助,点个赞 👍 收藏 ⭐ 不迷路!有问题欢迎评论区交流~