近期我完成了两套可以落地的前端小项目:一套依靠 json‑server 搭建轻量化后端,实现人员表格的数据渲染;另一套直接调用DeepSeek的大模型开放接口。开发过程里我踩了不少新手高频遇到的bug,非常适合刚接触的同学参考。
浏览器发起请求的两套原生方案
前端网页向后端发起网络请求,有两套原生的可选API:XMLHttpRequest和fetch。 XMLHttpRequest推出时间较早,兼容性拉满,可以适配老旧浏览器,但是回调写法繁琐,多层请求嵌套时极易出现回调地狱,开发体验较差。 当下绝大多数工程都会选用fetch完成请求开发,它基于Promise实现,搭配 async/await 语法就可以轻松管控异步代码的执行顺序。这里有一个非常容易踩坑的细节:fetch只会捕获网络断开类的底层异常,服务端返回的404、500状态错误不会被catch捕获,上线前需要手动校验响应状态码。
零后端编码:json‑server快速启动本地接口
前后端本地联调的场景下,我们不需要搭建完整的Node后端服务,json‑server工具仅依靠一份json文件,就可以对外提供全套的接口能力。 我的后端目录中存放了 data.json ,它相当于整套项目轻量化的数据库,存储人员基础信息:
{
"friends": [
{ "id":1, "name":"两只羊", "age": 19 },
{ "id":2, "name":"书包", "age": 19 }
]
}
我们在项目根目录的 package.json 内配置启动脚本,多余的 json‑serve 依赖可以直接移除:
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "json-server --watch data.json --port 3000"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"json-server": "1.0.0-beta.15"
}
}
终端运行 npm run dev 即可启动服务。 --watch 参数可以监听json文件的变更,文件更新之后接口返回的数据会同步刷新,3000是服务对外开放的端口。访问 http://localhost:3000/friends 就能够拿到全部人员数据。
人员表格页面的开发
后端服务运行完成之后,我们开始编写前端页面。首先完成 index.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>前端发送http 请求</h1>
</header>
<main>
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
</tr>
</thead>
<tbody></tbody>
</table>
</main>
<footer></footer>
<script src="./main.js"></script>
</body>
</html>
页面内置一张人员信息表格,表头定义id、name、age三个字段,tbody节点用于渲染后端返回的表格行。
let friends = [];
async function loadData() {
const endpoint = 'http://localhost:3000/friends';
const res = await fetch(endpoint);
const data = await res.json();
console.log(data);
return data;
}
function renderData(list) {
console.log('renderData');
const oBody = document.querySelector('table tbody');
if (list.length > 0) {
oBody.innerHTML = list.map(function(item) {
console.log(item);
return `
<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.age}</td>
</tr>
`
}).join('')
}
}
async function init() {
console.log('init start');
friends = await loadData();
renderData(friends);
console.log('init end')
}
init();
loadData函数负责发起网络请求、解析后端返回的json数据;renderData函数遍历数组,批量生成表格的DOM节点;init作为入口函数,统筹请求和页面渲染两个流程。
前端直连大模型的开放接口
本地人员表格项目调试完毕之后,我基于同样的fetch请求逻辑,实现了DeepSeek大模型接口的调用。大模型接口的底层通信逻辑和普通后端接口完全一致,仅在参数配置上有专属的规范。 我搭建了极简的展示页面 index.html :
<!DOCTYPE html>
<html lang="zh‑CN">
<head>
<meta charset="UTF‑8">
<meta name="viewport" content="width=device‑width, initial‑scale=1.0">
<title>DEEPSEEK接口调用</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="replay"></div>
<script type="module" src="script.js"></script>
</body>
</html>
页面只预留了一个id为replay的容器,用于展示大模型返回的回答,脚本开启模块模式规避全局变量污染。 完整的请求逻辑写在 script.js 当中:
const endpoint = 'https://api.deepseek.com/chat/completions';
const headers = {
'Content‑Type': 'application/json',
'Authorization': 'Bearer 你的api'
}
const payload = {
model: 'deepseek‑v4‑Flash',
messages: [
{ role: 'system', content: 'You are a helpful assistant'},
{ role: 'user', content: '你好,DeepSeek'}
]
}
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: headers,
body: JSON.stringify(payload)
})
const data = await response.json();
document.getElementById('replay').innerHTML = data.choices[0].message.content;
}catch(err){
console.log(err)
}
一份完整的大模型请求由三部分构成:
1. 接口地址,也就是大模型服务商提供的服务入口;
2. 请求头,需要声明传输数据的格式为json,同时携带API密钥完成身份校验;
3. 请求体,内部配置模型名称、对话上下文数组,system字段用来设定AI的基础人设,user字段填入用户的提问。
这个项目里我遇到了前端请求非常经典的坑:fetch的body参数无法直接传入JavaScript对象,一开始我直接把payload对象放入请求体,后端完全无法读取参数,最后确认需要调用 JSON.stringify 将对象转为字符串后端才可以正常解析。
开发总结与后续方向
做完两套完整的demo之后,我对HTTP请求的底层逻辑有了非常直观的认知:HTTP请求的本质就是前端客户端向后端发起申请,后端返回对应数据,前端完成页面渲染。前后端分离已经是当下前端开发的主流方案,async/await语法极大降低了异步代码的编写门槛。