在现代 AI 应用开发中,我们经常需要在浏览器端直接调用大语言模型(LLM)的 API。虽然有 OpenAI SDK 等封装工具,但使用原生 fetch 发送 HTTP 请求是一种更灵活、可控且易于理解的方式。
本文将结合你提供的代码和笔记,深入解析 如何在前端通过 fetch 调用 DeepSeek 的聊天接口,并逐行解释每一个关键步骤。
🧩 一、完整的调用代码
javascript
// llm api 地址
const endpoint = 'https://api.deepseek.com/chat/completions';
// 请求头
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${import.meta.env.VITE_DEEPSEEK_API_KEY}`
};
// 请求体
const payload = {
model: 'deepseek-chat',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: '你好 Deepseek' }
]
};
// 发起请求
const response = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(payload)
});
// 解析响应
const data = await response.json();
console.log(data);
// 显示结果
document.getElementById('reply').textContent = data.choices[0].message.content;
这段代码实现了从用户输入到模型回复的完整流程。下面我们逐部分拆解。
🔍 二、HTTP 请求结构解析(结合你的笔记)
1. 请求行(Request Line)
bash
POST /chat/completions HTTP/1.1
Host: api.deepseek.com
POST:必须使用 POST 方法,因为 API 接口要求;/chat/completions:DeepSeek 的聊天接口路径;HTTP/1.1:标准版本,浏览器自动处理。
2. 请求头(Headers)
css
{
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-xxxxxx'
}
'Content-Type': 'application/json'
告诉服务器请求体是 JSON 格式,这是必需的。'Authorization': 'Bearer <key>'
认证方式,Bearer是固定前缀,后面跟你的 API Key。
⚠️ 注意:API Key 不能硬编码在前端代码中,应通过 Vite 的环境变量管理:
ini// .env 文件 VITE_DEEPSEEK_API_KEY=sk-xxxxxxxx在代码中使用
import.meta.env.VITE_DEEPSEEK_API_KEY获取。
3. 请求体(Body)
css
{
model: 'deepseek-chat',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: '你好 Deepseek' }
]
}
-
model:指定使用的模型名称; -
messages:对话历史,支持多轮交互;role: "system":设定助手行为;role: "user":用户的提问内容。
✅ 注意:请求体必须是字符串化后的 JSON ,所以要用
JSON.stringify()。
4. 使用 fetch 发送请求
javascript
const response = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(payload)
});
method: 'POST':发送 POST 请求;headers:设置请求头;body: JSON.stringify(payload):将 JS 对象转为字符串,不能直接传对象。
💡
await比.then()更直观,适合异步操作。
5. 处理响应
ini
const data = await response.json();
console.log(data);
response.json()将响应体解析为 JavaScript 对象;data.choices[0].message.content是模型返回的文本。
6. 显示结果
ini
document.getElementById('reply').textContent = data.choices[0].message.content;
- 将模型回复显示在页面上(假设有一个 id 为
reply的元素)。
🔄 三、异步处理:.then vs await
你提到:
- await 异步变同步比 then 更方便
✅ 完全正确!
| 方式 | 特点 |
|---|---|
.then() |
链式调用,适合复杂逻辑 |
await |
代码像同步一样,更易读 |
推荐使用 await,尤其是在处理多个异步操作时。
🔐 四、安全建议:API Key 的存放位置
❌ 不推荐(前端暴露)
ini
const apiKey = 'sk-xxxxxxxx'; // 直接写在代码里 → 容易泄露
✅ 推荐(后端代理)
javascript
// 后端路由
app.post('/api/chat', async (req, res) => {
const response = await fetch('https://api.deepseek.com/chat/completions', {
headers: {
'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}` // 后端环境变量,安全!
},
body: JSON.stringify(req.body)
});
res.json(result);
});
然后前端只调用自己的 /api/chat,永远看不到真实 API Key。
✅ 五、总结:前端调用 LLM 的核心要点
| 要点 | 说明 |
|---|---|
✅ 使用 fetch 发送 POST 请求 |
标准方式,兼容性强 |
✅ 设置 Content-Type: application/json |
必须 |
✅ 添加 Authorization: Bearer <key> |
认证必要 |
✅ 使用 JSON.stringify() 处理请求体 |
不能直接发送 JS 对象 |
✅ 使用 await 处理异步 |
更简洁 |
| ✅ 环境变量管理 API Key | Vite 支持 VITE_ 开头变量 |
| ⚠️ 不要在生产环境中暴露 API Key | 必须走后端代理 |
🎯 结语
技术的本质是解决问题,而不是追求"高大上"的工具。
当你理解了 fetch 的工作原理,就能轻松对接任何符合 OpenAI 协议的 LLM 服务。无论是 DeepSeek、Qwen 还是其他模型,只要你知道它的 API 地址和参数格式,就可以用这段代码快速接入。
希望这篇文章帮你彻底搞懂了前端调用 LLM 的全过程!
如果你正在做项目,我可以帮你封装一个通用的 AI 调用模块 😊