一、前言
在对接LLM大模型服务、后端业务接口开发中,HTTP接口调用是前端必备核心能力 。日常开发里主要分为两种调用方案:基于OpenAI官方SDK封装调用、原生fetch发起网络请求;同时前端原生还存在XMLHttpRequest老牌请求方案。本文围绕客户端-服务器架构、DNS与域名原理、本地Mock服务搭建、异步语法async/await、数据渲染全链路完整讲解,配套可运行实战项目。
二、前端发起HTTP请求的主流实现方案
2.1 两大原生请求API
前端浏览器环境原生提供两套发起HTTP请求的底层API,是所有请求库(axios、openai-sdk)的底层实现基础:
- XMLHttpRequest(XHR):早期JS异步请求标准,AJAX技术底层依托该API实现,兼容全量低版本浏览器;
- Fetch API:ES6推出新标准,基于Promise设计,语法更简洁,现代浏览器原生支持,也是对接LLM HTTP接口最常用原生方案。
| 请求方案 | 底层设计 | 优点 | 适用场景 |
|---|---|---|---|
| XMLHttpRequest | 回调设计 | 兼容性极强,IE可用 | 老旧项目维护、兼容低版本设备 |
| fetch | Promise+异步语法 | 语法精简、原生支持async/await | 新项目、对接LLM/后端REST接口 |
2.2 开发对应的编程架构模式
2.2.1 前后端分离架构
本文所有代码基于前后端分离模式:前端只负责页面渲染、交互逻辑,后端(Node/Java)专注接口开发、数据处理,通过约定的HTTP接口+JSON格式完成数据交互,也是目前对接OpenAI、各类LLM HTTP接口的主流架构。
2.2.2 异步编程:async/await语法
fetch本身基于Promise异步设计,async/await是ES2017推出的异步语法糖,可以把异步代码书写成同步代码的结构,解决多层Promise链式调用可读性差的问题,是LLM接口请求、后端接口数据拉取的标准写法。
核心作用:
await强制阻塞当前代码,等待接口请求、数据解析完成后,再向下执行渲染逻辑。
2.3 客户端/服务端(C/S)与浏览器/服务端(B/S)架构
- B/S(Browser/Server 浏览器-服务器):用户通过浏览器访问页面,前端代码运行在浏览器,本文HTML+JS项目属于该架构;
- C/S(Client/Server 客户端-服务器):Android、IOS原生App作为客户端,同样通过HTTP调用后端/LLM服务接口。
不管B/S还是C/S,客户端和服务端通信底层统一使用HTTP协议,对接LLM接口无架构区分。
三、Server服务基础原理
3.1 服务器组成
一台可提供接口服务的Server由两部分构成:
- 硬件:物理服务器/云服务器;
- 软件:后端运行环境,常见Java、Node.js、Go等开发语言。
3.2 IP地址 + 端口号
示例地址:http://127.0.0.1:3000
- IP地址 :网络中设备唯一标识,用来在互联网/局域网精准定位目标服务器;
127.0.0.1是本机回环地址,仅本地电脑可访问; - 端口号 :一台服务器可开启多个服务,端口用来区分同一机器上不同应用,示例
3000为自定义服务端口,取值范围0~65535。
3.3 域名与DNS解析
IP由一串数字组成难以记忆,因此出现域名 (如www.baidu.com);
DNS解析:域名系统自动将易记的域名翻译为对应的IP地址,浏览器才能通过IP找到目标服务器。对接线上LLM接口时,填写域名URL即可,底层自动完成DNS解析。
3.4 API URL(Endpoint接口终点)
Endpoint即接口请求终点,是后端预先定义好的接口地址(例如http://localhost:3000/friends、OpenAI大模型接口https://api.openai.com/v1/chat/completions)。
前端固定请求该地址,后端收到请求后处理逻辑、返回JSON数据,项目开发中所有接口地址统一配置管理,方便后期环境切换(测试/生产LLM地址)。
3.5 数据流转规则
后端接口统一返回JSON格式数组/对象 ,前端拿到数组后,通过Array.map()遍历数组,拼接HTML字符串,最终插入表格DOM完成页面渲染,也是本案例核心数据处理逻辑。
map() 方法创建一个新数组,这个新数组由原数组中的每个元素 都调用一次提供的函数后的返回值组成
示例:
javascript
const array1 = [1, 4, 9, 16];
const map1 = array1.map((x) => x * 2);
console.log(map1); // [2, 8, 18, 32]
开发查阅建议:原生Fetch、DOM操作细节优先参考MDN官方文档,API参数、异常处理最全。
四、本地Mock服务环境搭建(json-server)
项目使用json-server快速搭建本地RESTful模拟服务,无需编写后端代码,一键生成接口,用来模拟LLM/后端真实接口环境。
注:可以在终端中输入
pnpm i json-server
4.1 package.json配置文件
新建项目,初始化依赖配置,执行npm init -y安装依赖,npx json-server data.json启动3000端口服务。
json
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "json-server --watch data.json --port 3000"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"json-server": "1.0.0-beta.15"
}
}
--watch data.json:监听本地json文件,文件数据改动自动更新接口返回值;
注:这里data.json 是本地自己创建的,名字取决于我们自己定义--port 3000:指定服务运行在3000端口,和前端请求地址保持一致。
4.2 补充data.json模拟数据源
同目录新建data.json,接口http://localhost:3000/friends自动读取friends数据:
json
{
"friends": [
{"id":1,"name":"张三","age":22},
{"id":2,"name":"李四","age":24},
{"id":3,"name":"王五","age":21}
]
}
五、前端页面+业务JS完整实战代码
5.1 HTML页面结构(index.html)
搭建基础页面骨架,包含表格容器,JS动态向tbody插入数据,代码可直接新建html文件使用。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>前端HTTP请求实战</title>
</head>
<body>
<header>
<h1>前端发送http 请求渲染表格</h1>
</header>
<main>
<!-- 表格容器,tbody用来动态插入行 -->
<table border="1" cellpadding="6">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
</tr>
</thead>
<tbody></tbody>
</table>
</main>
<footer>
<!-- 引入业务脚本 -->
<script src="./main.js"></script>
</footer>
</body>
</html>
5.2 main.js 核心业务逻辑
功能拆分:数据请求函数loadData、页面渲染函数renderData、项目初始化init;两种fetch写法(async/await、原生.then链式)全部注释展示。
js
// 全局变量:存储接口返回的好友数据
let friends = [];
/**
* @description 请求后端接口获取friends列表数据
* @returns {Promise<Array>} 接口返回的数组数据
*/
async function loadData() {
// endpoint:接口请求终点URL
const endpoint = "http://localhost:3000/friends";
// await阻塞等待fetch发送请求,拿到服务端原始响应对象
const res = await fetch(endpoint);
// await等待二进制响应体解析为JS对象
const data = await res.json();// 得到friends.json 的数据
friends = data; // 赋值给全局数据
console.log("接口返回原始数据:", data);
return data;
// ========== 补充:原生Promise链式写法(不使用async/await)==========
// fetch(endpoint)
// .then(res => res.json())
// .then(data => {
// console.log(data);
// })
}
/**
* @description 根据数据渲染表格DOM
* @param {Array} friendsArr 好友数组数据
*/
function renderData(friendsArr) {
console.log('开始执行页面渲染');
// 获取表格tbodyDOM元素
const oBody = document.querySelector('table tbody');
// 数据非空才进行渲染
if(friendsArr.length > 0){
// map遍历数组,生成tr字符串数组,join拼接成完整html
oBody.innerHTML = friendsArr.map(function(friend){
return `
<tr>
<td>${friend.id}</td>
<td>${friend.name}</td>
<td>${friend.age}</td>
</tr>
`
}).join('');// .join('') 把数组转为字符串
}
}
/**
* @description 项目初始化入口函数
*/
async function init() {
console.log("项目初始化开始");
// 1. 等待接口数据请求完成
await loadData();
// 2. 拿到数据后执行页面渲染
renderData(friends);
}
// 启动项目
init();
5.3 项目启动步骤
- 终端进入项目目录,执行
pnpm i json-server安装json-server依赖; - 执行
npx json-server data.json启动本地3000端口服务; - 直接打开index.html文件,页面自动请求接口并渲染表格数据。
六、LLM接口调用方式
原生Fetch直接请求LLM HTTP接口
不引入SDK,原生fetch携带请求头、请求体,直接请求官方Endpoint,灵活可控:
js
// url + method + http 版本号 请求行
const endpoint =
'https://api.deepseek.com/chat/completions';
// headers 请求头
const headers = {
'Content-Type': 'application/json',
// api key 通过 Authorization带上
Authorization: `Bearer sk-783c7027777f44bfa4d2f67507acec99`
}
// 请求体
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,
// http 请求里面 传输的不可以是对象
// 只能传输字符串
body: JSON.stringify(payload)
})
const data = await response.json();
console.log(data);
document.getElementById('replay').innerHTML =
data.choices[0].message.content;
} catch (err) {
}
七、全文总结&知识点复盘&避坑指南
全文总结
- 前端HTTP请求两大原生API:
XMLHttpRequest(老式AJAX)、fetch(现代首选,对接LLM主流),基于前后端分离B/S架构完成前后端数据交互; - 网络通信基础:IP定位服务器、端口区分应用、DNS把域名转为IP、Endpoint是接口唯一请求地址;
async/await是异步请求核心语法,依托Promise改造,把异步请求同步化,简化LLM/业务接口代码;- 项目落地:json-server快速搭建Mock后端,前端fetch拉取JSON数组,
map拼接HTML字符串渲染页面,完整复刻真实LLM接口对接流程; - LLM接口调用:原生fetch手动组装参数调用。
核心知识点复盘
- 架构分类:B/S浏览器服务端、C/S客户端服务端,前后端分离是接口交互标准模式;
- 网络基础:IP+端口定位服务,DNS解析域名→IP,Endpoint=接口URL;
- 异步重点 :fetch基于Promise,
await等待请求和JSON解析,代码顺序执行; - 数据渲染 :后端返回JSON数组 →
Array.map生成HTML字符串 → innerHTML插入DOM; - LLM调用:原生fetch直接请求HTTP接口。
常见问题&避坑指南
- ❌ 接口请求地址端口错误:前端URL端口和json-server启动端口不一致,出现跨域/请求失败;
- ❌ 忘记
await res.json():fetch拿到的是原始响应对象,直接打印拿不到业务数据,必须解析json; - ❌ map后忘记
.join(''):map返回数组,直接赋值innerHTML会出现逗号分隔符,页面错乱; - ❌ LLM接口缺少请求头:POST请求大模型接口必须携带
Authorization密钥头、Content-Type,否则鉴权失败; - ❌ 同步代码顺序误区:去掉await后,
renderData优先执行,此时接口数据还未返回,表格渲染为空。