从零搭建:json-server+Bootstrap+OpenAI 全栈 AI 小项目

作者:有意义日期:2025/11/9

在前后端分离与大模型应用日益普及的当下,我搭建了这个集模拟后端、交互前端、AI 响应于一体的实战项目。

本笔记将详细记录从项目结构搭建、依赖安装,到接口模拟、页面开发、大模型对接的完整流程,核心技术涵盖 json-server 后端模拟、Bootstrap 前端布局、JavaScript fetch 数据交互及 OpenAI API 集成。

通过这个轻量化项目,可快速掌握前后端通信逻辑与大模型的实际应用,适合作为入门级全栈 + AI 开发的实践参考。

初步准备

在启动项目开发前,需完成基础环境与工具的准备,确保后续开发流程顺畅:

  1. 环境配置:安装 Node.js(推荐 v16+ 版本)及包管理器 pnpm(可通过 npm install -g pnpm 全局安装),用于项目初始化、依赖安装与脚本执行。
  2. 工具准备:选择代码编辑器(如 VS Code),搭配终端工具(系统自带终端或 VS Code 集成终端),方便执行命令与编写代码。
  3. 资源准备:获取 OpenAI API Key(用于大模型服务调用),可通过 OpenAI 官方平台或合法第三方代理平台申请。
  4. 网络环境:确保网络通畅,能够正常访问 npm 镜像源(用于安装依赖)与大模型 API 服务地址。

后端backand

后端初始化详细步骤

  1. 创建项目目录结构
    • 首先,在你选择的存储位置创建一个名为 project 的文件夹。这将作为整个项目的根目录,用于组织所有相关文件和文件夹。
    • 进入 project 文件夹,在其中分别创建 backendfrontendllm 三个文件夹。backend 文件夹将专门用于存放后端相关代码及配置,frontend 用于前端代码,llm 文件夹可用于存放与大语言模型(Large Language Model)相关的文件或代码。
  2. 初始化后端项目并安装依赖
    • 使用终端(Terminal)进入 backend 目录。这是后续后端开发操作的主要工作目录。
    • 在终端中执行 npm init -y 命令。该命令会快速初始化一个 package.json 文件,它是 Node.js 项目的配置文件, -y 参数表示采用默认配置,无需手动确认各项设置。
    • 接着执行 pnpm i json - server 命令。pnpm 是一个快速高效的 Node.js 包管理器,此命令会安装 json - server 这个工具。json - server 能够根据提供的 JSON 文件快速搭建一个 RESTful API 服务器,方便后端开发时模拟数据接口。
1pnpm i json - server
2
1pnpm i json - server
2
  1. 准备模拟数据
    • backend 目录下创建一个名为 users.json 的文件,并在其中添加一些自定义数据。例如:
1{
2    "users":[
3        {
4            "id":1,
5            "username":"刘",
6            "hometown":"萍乡"
7        },
8        {
9            "id":2,
10            "username":"徐",
11            "hometown":"上饶"
12        },
13        {
14            "id":3,
15            "username":"薛",
16            "hometown":"赣州"
17        },
18        {
19            "id":4,
20            "username":"瞿",
21            "hometown":"宜春"
22        }
23    ]
24}
25

这里的数据结构和内容你可以根据实际需求随意调整,它将作为模拟 API 的数据来源。

4. 配置启动脚本

  • 打开 backend 目录下的 package.json 文件,找到 "scripts" 字段。在其中添加一个新的脚本配置 "dev":"json - server --watch users.json --port 3001"。此脚本定义了通过 json - server 启动模拟服务器的方式,--watch 参数表示监听 users.json 文件的变化,一旦文件内容更新,服务器会自动重新加载数据;--port 3001 则指定服务器运行在端口 3001 上。

后端2.png完成以上步骤后,你就初步完成了后端的初始化设置,一个基于 json - server 的简单后端模拟服务器已准备就绪,可以为前端开发提供数据接口模拟服务。

前端代码实现解析

前端代码构建了一个具有用户数据展示和问题提交功能的页面,利用了 Bootstrap 框架进行页面布局,并通过 JavaScriptfetch 方法与后端进行数据交互。以下是详细的代码分析:

1<!DOCTYPE html>
2<html lang="en">
3
4<head>
5    <meta charset="UTF - 8">
6    <!-- 设置视口,确保页面在不同设备上正确显示 -->
7    <meta name="viewport" content="width=device - width, initial - scale = 1.0">
8    <title>Users Chatbot</title>
9    <!-- 引入Bootstrap CSS文件,为页面提供预定义的样式和布局类 -->
10    <link href="https://cdn.bootcdn.net/ajax/libs/twitter - bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
11</head>
12
13<body>
14    <!-- Bootstrap的.container类创建一个响应式的固定宽度容器,用于包裹页面主要内容 -->
15    <div class="container">
16        <!-- 创建一个.row类的行容器,用于水平排列其子元素 -->
17        <div class="row">
18            <!--.col - md - 6表示在中等及以上屏幕宽度时占6列宽度,.col - md - offset - 3表示偏移3列,使表格在页面中居中 -->
19            <div class="col - md - 6 col - md - offset - 3">
20                <table class="table table - striped" id="user_table">
21                    <!-- 表格头部,定义了表格各列的标题 -->
22                    <thead>
23                        <tr>
24                            <th>ID</th>
25                            <th>姓名</th>
26                            <th>家乡</th>
27                        </tr>
28                    </thead>
29                    <tbody>
30                        <!-- 表格主体部分,后续将通过JavaScript动态填充用户数据 -->
31                    </tbody>
32                </table>
33            </div>
34        </div>
35        <div class="row">
36            <!-- 定义一个表单,用户可在其中输入问题并提交 -->
37            <form name="aiForm">
38                <div class="form - group">
39                    <label for="questionInput">请输入问题:</label>
40                    <!-- 文本输入框,用于用户输入问题,required属性确保输入框不能为空 -->
41                    <input type="text" class="form - control" id="questionInput" name="question" required
42                        placeholder="请输入问题">
43                </div>
44                <div class="form - group">
45                    <!-- 提交按钮,样式为Bootstrap的primary风格 -->
46                    <button type="submit" class="btn btn - primary">提交</button>
47                </div>
48            </form>
49        </div>
50        <!-- 用于显示后端返回回答消息的区域 -->
51        <div class="row" id="message"></div>
52    </div>
53    <script>
54        // 获取名为aiForm的表单元素,用于监听提交事件
55        const oForm = document.forms["aiForm"];
56        // 获取id为user_table的表格中的tbody元素,用于动态添加用户数据行
57        const oBody = document.querySelector('#user_table tbody');
58        // 获取页面中的按钮元素,用于在提交过程中禁用和启用
59        const oBtn = document.querySelector(".btn");
60        // 声明一个变量users,用于存储从后端获取的用户数据
61        let users;
62
63        // 为表单的提交事件添加监听器
64        oForm.addEventListener("submit", (event) => {
65            // 阻止表单的默认提交行为,防止页面刷新
66            event.preventDefault();
67            // 获取用户在表单中输入的问题
68            const question = oForm["question"].value;
69
70            // 检查用户是否输入了问题,如果没有则提示并终止后续操作
71            if (!question) {
72                alert("请输入问题");
73                return;
74            }
75
76            // 禁用提交按钮,避免用户重复提交
77            oBtn.disabled = true;
78
79            // 构造请求URL,包含用户输入的问题以及从后端获取的用户数据(若有)
80            const requestUrl = [`http://localhost:1314/?question=${question}&data=${JSON.stringify(users)}`](http://localhost:1314/?question=${question}&data=${JSON.stringify(users)});
81            // 在控制台打印请求URL,方便调试
82            console.log(requestUrl);
83
84            // 使用fetch API发送GET请求到指定的后端URL
85            fetch(requestUrl)
86               .then(res => res.json())
87               .then(data => {
88                    // 在控制台打印后端返回的数据,方便调试
89                    console.log(data);
90                    // 启用提交按钮,允许用户再次提交
91                    oBtn.disabled = false;
92                    // 将后端返回数据中的result字段内容显示在页面的message区域
93                    document.getElementById('message').innerHTML = data.result;
94                });
95        });
96
97        // 使用fetch API发送GET请求到后端获取用户数据
98        fetch('http://localhost:3001/users')
99           .then(res => res.json())
100           .then(data => {
101                // 将从后端获取的用户数据存储在users变量中
102                users = data;
103                // 使用map方法遍历用户数据数组,为每个用户生成一行HTML表格行
104                const tableRows = data.map(user => `
105                    <tr>
106                        <td>${user.id}</td>
107                        <td>${user.username}</td>
108                        <td>${user.hometown}</td>
109                    </tr>
110                `).join("");
111                // 将生成的表格行添加到表格的tbody元素中,实现用户数据的动态展示
112                oBody.innerHTML = tableRows;
113            });
114    </script>
115</body>
116
117</html>
118

代码说明:

  1. HTML 部分
    • 头部:设置了页面的字符编码、视口以及引入了 Bootstrap 的 CSS 文件,为页面提供基本样式和布局支持。
    • 主体: 使用 Bootstrapcontainerrowcol - md - * 类创建了一个响应式布局。表格用于展示用户数据,表单用于用户输入问题并提交,message 区域用于显示后端返回的回答。
  2. JavaScript 部分
    • 变量声明:获取表单、表格主体和按钮元素,并声明一个变量 users 用于存储从后端获取的用户数据。
    • 表单提交事件
      * 阻止表单默认提交行为,获取用户输入的问题。若问题为空,提示用户并终止操作。
      * 禁用提交按钮,构造请求 URL 并发送 fetch 请求。接收到后端响应后,将数据解析为 JSON 格式,启用按钮,并将后端返回的结果显示在页面上。
    • 获取用户数据:发送 fetch 请求到后端获取用户数据,将数据解析为 JSON 格式后存储在 users 变量中,并动态生成表格行添加到表格主体,实现用户数据的展示。

通过上述前端代码,实现了页面的布局、用户交互以及与后端的数据通信功能。

大模型项目llm

本项目结合了 HTTP 服务与 OpenAI 的大语言模型(LLM)服务,通过设置环境变量来配置 API Key 和基础 URL,并利用 http 模块创建一个简单的 HTTP 服务器,以接收前端发送的请求并返回基于大模型生成的响应。

  1. 项目初始化与依赖安装
    • 首先,通过 pnpm 安装所需的依赖包:openai 用于与 OpenAI 的 API 进行交互,dotenv 用于加载环境变量。
    • 命令:pnpm i openai dotenv
  2. 环境变量配置
    • 创建一个 .env 文件,用于存储敏感信息,如 OpenAI 的 API Key。
    • .env 文件中添加 OPENAI_API_KEY = your_api_key_here,将 your_api_key_here 替换为你实际的 OpenAI API Key。同时,也可以配置 baseURL,如在代码中设置为 https://api.agicto.cn/v1
  3. index.mjs 代码解析
    • 引入模块
1import http from 'http';
2import OpenAI from 'openai';
3import url from 'url';
4import { config } from 'dotenv';
5

这里引入了 http 模块用于创建 HTTP 服务器,OpenAI 模块来自 openai 包用于与 OpenAI 服务交互,url 模块用于解析 URL,config 函数来自 dotenv 包用于加载环境变量。

  • 加载环境变量
1config({
2  path: '.env'
3});
4console.log(process.env.OPENAI_API_KEY, '////');
5

config 函数加载 .env 文件中的环境变量。console.log 用于调试,打印出加载的 OPENAI_API_KEY,确保环境变量正确加载。

  • 初始化 OpenAI 客户端
1const client = new OpenAI({
2  apiKey: process.env.OPENAI_API_KEY,
3  baseURL: 'https://api.agicto.cn/v1'
4});
5

创建一个 OpenAI 客户端实例,传入从环境变量中获取的 API Key 和自定义的 baseURL

  • 定义获取模型响应的函数
1// aigc
2const getCompletion = async (prompt, model = 'gpt - 3.5 - turbo') => {
3  const messages = [{
4    role: 'user',
5    content: prompt
6  }];
7  const result = await client.chat.completions.create({
8    model,
9    messages,
10    temperature: 0.1
11  });
12  return result.choices[0].message.content;
13};
14

getCompletion 函数是一个异步函数,它接受一个 prompt(提示信息)和一个可选的 model(模型名称,默认为 gpt - 3.5 - turbo)。函数构建一个包含用户角色和提示内容的消息数组,然后使用 client.chat.completions.create 方法向 OpenAI 发送请求,获取模型的回复。temperature 参数控制生成文本的随机性,值越低越确定。

  • 创建 HTTP 服务器
1http.createServer(async (req, res) => {
2  res.setHeader('Access - Control - Allow - Origin', '*');
3  // req, question  data
4  const parsedUrl = url.parse(req.url, true);
5  // console.log(parsedUrl);
6  const prompt = `
7  ${parsedUrl.query.data}
8  请根据上面的 JSON 数据, 回答${parsedUrl.query.question} 这个问题。
9  `;
10  const result = await getCompletion(prompt);
11  let info = {
12    result
13  };
14  res.status = 200;
15  res.setHeader('Content - Type', 'application/json');
16  res.end(JSON.stringify(info));
17}).listen(1314);
18

创建一个 HTTP 服务器,监听在端口 1314。对于每个请求,设置响应头允许跨域访问(Access - Control - Allow - Origin: *)。通过 url.parse 解析请求的 URL,获取其中的 dataquestion 参数。构建一个提示信息,将 dataquestion 包含在内,然后调用 getCompletion 函数获取模型的回答。将回答包装在一个对象中,设置响应状态码为 200,响应头 Content - Typeapplication/json,最后将响应数据以 JSON 字符串的形式发送回客户端。

  1. 开发过程中的辅助工具安装与启动
    • 安装 nodemonnodemon 是一个工具,它可以在文件更改时自动重启 Node.js 应用程序,方便开发调试。
    • 命令:npm i -g nodemon-g 表示全局安装)
    • 启动项目:安装完成后,使用 nodemon index.mjs 命令启动项目。nodemon 会监控 index.mjs 文件及相关依赖文件的变化,一旦有更改,自动重启服务器,无需手动停止和启动。

总结

本项目由后端、前端和大模型三部分构成:

  • 后端:在 project 下的 backend 目录,用 npm init -y 初始化,pnpm i json - server 安装依赖,创建 users.json 模拟数据,在 package.json 配置脚本启动 JSON 服务器。
  • 前端:基于 Bootstrap 布局,通过 fetch 获取后端 users 数据展示表格。表单提交问题,fetch 向大模型服务请求并展示回答。
  • 大模型(LLM) :在 llm 目录,pnpm 安装 openaidotenv.env 配置 API 密钥等。index.mjs 创建 HTTP 服务器,接收前端请求,调用 OpenAI 模型生成回答并返回。

从零搭建:json-server+Bootstrap+OpenAI 全栈 AI 小项目》 是转载文章,点击查看原文


相关推荐


Redis(109)Redis的Pipeline如何使用?
Victor3562025/11/7

Redis 的 Pipeline 机制允许客户端在一次网络请求中发送多个命令,并在一次网络响应中接收所有命令的结果。这种机制可以显著提高批量操作的性能,因为它减少了每个命令的网络往返延迟。 1. Pipeline 的基本使用 在 Jedis 客户端中,使用 Pipeline 可以通过 Jedis.pipelined() 方法实现。 示例代码 import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; public


Python 的内置函数 frozenset
IMPYLH2025/11/2

Python 内建函数列表 > Python 的内置函数 frozenset def frozenset(x): ''' 类型转换为 frozenset :param x: 一个变量 :return: 转换为 frozenset 后的值 ''' Python 的内置函数 frozenset 用于创建一个不可变的集合对象,它继承了普通集合(set)的所有特性,如无序性、元素唯一性等,但关键区别在于 frozenset 一旦创建就不能被修改,因此它是可


MySQL 复合查询全解析:从单表到多表的实战进阶
藤椒味的火腿肠真不错2025/10/31

目录 1. 单表查询回顾:夯实基础操作 1.1 多条件筛选查询 1.2 自定义排序查询 1.3 聚合与筛选结合查询 2. 多表查询:关联多张表取数 2.1 两表关联查询 2.2 三表关联查询 3. 自连接:同一张表的 “自我关联” 4. 子查询:嵌套查询的灵活应用 4.1 单行子查询(返回 1 行结果) 4.2 多行子查询(返回多行结果) 4.3 子查询嵌入 from 子句 5. 合并查询:union 与 union all 在 MySQL 日常使用中,单表查询仅能满


面试自述:从单体到微服务的实践之路
360_go_php2025/10/28

​ 在最近的项目中,我负责从零搭建一个基于 Spring Boot + Dubbo + Redis + RocketMQ 的分布式微服务系统。整个项目大约持续一个多月,代码量较大,是我第一次完整实践从后端架构设计到部署上线的全过程。   1. 自我介绍 略 2. 项目介绍 略 3. 为什么要做微服务?   做微服务的核心原因是为了解耦与扩展性。单体项目后期难以维护,功能耦合严重、部署困难、影响面大。  ​编辑 微服务将系统拆分成多个独立模块(如用户、订单、支付、库存等),每个服务可以独立开发、


Redis(82)如何解决Redis的缓存雪崩问题?
Victor3562025/10/25

缓存雪崩的概念 缓存雪崩(Cache Avalanche)指的是在某一时刻大量缓存数据同时过期或者缓存服务器宕机,导致大量请求直接打到数据库,从而使数据库瞬时压力剧增,甚至可能导致数据库崩溃。 解决缓存雪崩问题的方法 为了解决缓存雪崩问题,可以采取以下策略: 缓存数据的过期时间设置为随机值:避免在同一时间大量缓存数据同时失效。 加锁或队列:在缓存失效时,通过机制控制对数据库的访问,避免大量请求同时打到数据库。 双写策略:更新缓存的同时也更新数据库,保证数据的一致性。 数据预热:在系统启动时,预


猿辅导MySQL面试常见问题解析(一)
360_go_php2025/10/23

​ 在进行MySQL相关的面试时,尤其是在如猿辅导这样注重技术底层实现的公司,面试官往往会问一些关于数据库优化、事务管理、锁机制等方面的问题。以下是一些常见的MySQL面试问题及其详细解答,帮助你更好地准备面试。​编辑 1. MySQL建立索引的原则​编辑 在MySQL中,索引是提升查询性能的重要工具。然而,索引虽然能加速查询,但也会占用额外的空间,并且会影响写操作的性能。因此,建立索引时需要遵循一些原则: 选择性高的列:选择性高的列,指的是该列的唯一值多,数据分布较为均匀。对于这些列建立索


Swift 字符串与字符完全导读(二):Unicode 视图、索引系统与内存陷阱
unravel20252025/10/22

Unicode 的三种编码视图 Swift 把同一个 String 暴露成 4 种迭代方式: 视图元素类型单位长度典型用途StringCharacter人眼“一个字符”业务逻辑utf8UInt81~4 字节网络/文件 UTF-8 流utf16UInt162 或 4 字节与 Foundation / Objective-C 交互unicodeScalarsUnicodeScalar21-bit精确到标量,做编码分析 代码一览 l


AWS EKS 集成Load Balancer Controller 对外暴露互联网可访问API [AWS 中国宁夏区]
thinktik2025/10/20

本文主要介绍AWS EKS和AWS Elastic Load Balancing的集成;我们可以通过AWS ELB将运行在EKS中的服务暴露出去,供互联网访问。 AWS ELB提供的负载均衡,高可用,按流量自动弹性和自带的安全性服务(比如基础版的AWS Shield)给为我们的网络服务提供了高质量的保证。虽然我们也可以直接让K8S Service服务直接以public ip的方式来对外服务,但是一般技术和成本等综合来考虑不如AWS ELB。 如下图,AWS ELB充当运行在AWS上的动态API服


AI环境下的网络安全人才的发展方向
Mr_Meng_De2025/10/19

2025年9月16日,2025年国家网络安全宣传周分论坛上发布《AI时代网络安全产业人才发展报告(2025)》。 《报告》由工业和信息化部教育与考试中心、安恒信息、中国联合网络通信有限公司软件研究院、全国数字安全行业产教融合共同体、中国网络空间新兴技术安全创新论坛、智联招聘、中国网络空间安全人才教育论坛联合编制。 AI驱动网络安全领域岗位革新与挑战升级 随着人工智能技术与网络安全行业的深度融合,当代大学生对这一技术变革带来的就业影响形成了较为全面的认知。约三分之一(33.5%)的学生表现出


策略模式:让算法选择像点菜一样简单
太过平凡的小蚂蚁2025/10/18

什么是策略模式? ​策略模式(Strategy Pattern)​​ 是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。 简单来说:​定义策略家族,让客户端自由选择。​​ 现实世界类比 想象你去餐厅吃饭: ​策略接口​:点菜这个行为 ​具体策略​:中餐、西餐、日料等不同菜系 ​上下文​:餐厅(提供点菜环境) ​客户端​:你(根据心情选择今天吃什么) 模式结构 classDiagra

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0