从 0 到 1:用 Bun + axios 快速搭建 LLM API 客户端

为什么我放弃了 npm,投入 Bun 的怀抱

作为一个常年跟 JavaScript 打交道的开发者,我对 npm install 的速度已经麻木了。每次安装依赖,我都得去泡杯茶,回来可能还在转圈圈。直到有一天,我在 GitHub 上看到了 Bun 的介绍:"比 npm 快 30 倍"------这不就是我梦寐以求的工具吗?

抱着试试看的心态,我用 bun init -y 创建了一个新项目。结果让我震惊:从命令执行到项目初始化完成,前后不到 200 毫秒。那一刻,我仿佛看到了新世界的大门。

bash 复制代码
$ bun init -y
bun init v1.3.14 (285c09e8)
✓ Created package.json
✓ Created tsconfig.json
✓ Created .gitignore
✓ Created README.md
✓ Created index.ts

  Done! You can now run:
    bun run index.ts

没有任何多余的提问,没有漫长的等待,一切都那么丝滑。这就是我决定把新项目都迁移到 Bun 的原因------效率就是生产力

几行代码搞定 LLM API 调用

项目创建好了,接下来要实现核心功能:调用 DeepSeek 的大模型 API。这看似复杂,其实用 axios 几行代码就能搞定。

typescript 复制代码
import axios from "axios";

async function chat() {
    try {
        const res = await axios.post(
            `${process.env.DEEPSEEK_BASE_URL}/chat/completions`,
            {
                model: "deepseek-v4-flash",
                messages: [{
                    role: "user",
                    content: "你好,介绍一下 bun"
                }]
            },
            {
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${process.env.DEEPSEEK_API_KEY}`
                }
            }
        );
        
        console.log(res.data.choices[0].message.content);
    } catch (err: any) {
        console.error("请求失败:", err.message);
    }
}

chat();

让我拆解一下这段代码的精妙之处:

HTTP 请求的三层结构

一个完整的 HTTP 请求就像一封书信:

  1. 请求行POST /chat/completions ------ 告诉服务器要做什么
  2. 请求头Content-TypeAuthorization ------ 信封上的寄件人信息
  3. 请求体:模型参数和消息内容 ------ 信件正文

async/await 的魔法

async/await 是 JavaScript 史上最伟大的发明之一。它让异步代码看起来像同步代码:

  • await axios.post(...) 会暂停执行,直到请求完成
  • 不需要嵌套的回调函数(告别"回调地狱")
  • 错误处理用熟悉的 try-catch 语法

axios 的优势

为什么选择 axios 而不是原生的 fetch?

特性 axios fetch
自动 JSON 解析 ❌ 需要手动 .json()
拦截器支持
请求取消
超时处理 需手动实现
浏览器兼容性 现代浏览器

环境变量管理的正确姿势

API 密钥这种敏感信息,绝对不能硬编码在代码里!这是每个开发者都应该知道的基本原则。

.env 文件的秘密

项目根目录下的 .env 文件是存放敏感配置的最佳位置:

env 复制代码
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
DEEPSEEK_API_KEY=sk-your-secret-key-here

然后在代码中通过 process.env.xxx 访问:

typescript 复制代码
const baseUrl = process.env.DEEPSEEK_BASE_URL;
const apiKey = process.env.DEEPSEEK_API_KEY;

为什么不用 dotenv?

你可能会疑惑,为什么代码里没有 require('dotenv').config()

因为 Bun 内置支持 .env 文件 !当你用 bun run 执行脚本时,它会自动加载项目根目录下的 .env 文件,无需任何额外配置。这又是 Bun 超越 Node.js 的一个细节。

.gitignore 的重要性

一定要确保 .env 文件在 .gitignore 中:

gitignore 复制代码
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

想象一下,如果把 API 密钥提交到 GitHub,后果不堪设想------你的账户可能被恶意使用,产生巨额费用。

TypeScript 配置的最佳实践

项目中的 tsconfig.json 配置非常讲究,让我逐行解读:

json 复制代码
{
  "compilerOptions": {
    "lib": ["ESNext"],
    "target": "ESNext",
    "module": "Preserve",
    "jsx": "react-jsx",
    "allowJs": true,
    "types": ["bun"],
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true
  }
}

关键配置解析

  1. "lib": ["ESNext"] ------ 启用最新的 ES 特性,告别 polyfill
  2. "module": "Preserve" ------ 保持模块语法不变,让 Bun 处理打包
  3. "types": ["bun"] ------ 添加 Bun 的类型定义,获得更好的 IDE 支持
  4. "moduleResolution": "bundler" ------ 使用打包器风格的模块解析
  5. "allowImportingTsExtensions": true ------ 可以直接 import .ts 文件
  6. "strict": true ------ 开启所有严格类型检查,提前发现潜在问题

为什么这些配置很重要

良好的 TypeScript 配置能带来:

  • 更好的代码提示:IDE 能智能推断类型
  • 更早的错误发现:编译时就能发现类型错误
  • 更好的团队协作:统一的代码规范

从开发到生产:项目结构优化建议

当前项目结构非常简单,但如果要投入生产环境,还需要做一些优化。

当前结构

bash 复制代码
axios-demo/
├── .gitignore
├── .env
├── README.md
├── bun.lock
├── index.ts
├── package.json
└── tsconfig.json

生产级结构建议

csharp 复制代码
axios-demo/
├── src/
│   ├── api/
│   │   └── llm.ts          # LLM API 封装
│   ├── config/
│   │   └── index.ts        # 配置管理
│   └── index.ts            # 入口文件
├── .env.example            # 环境变量模板
├── .gitignore
├── README.md
├── bun.lock
├── package.json
└── tsconfig.json

API 封装示例

把 API 调用封装成独立模块:

typescript 复制代码
// src/api/llm.ts
import axios from "axios";

const client = axios.create({
    baseURL: process.env.DEEPSEEK_BASE_URL,
    headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${process.env.DEEPSEEK_API_KEY}`
    },
    timeout: 30000
});

export async function chatWithAI(message: string): Promise<string> {
    const response = await client.post("/chat/completions", {
        model: "deepseek-v4-flash",
        messages: [{ role: "user", content: message }]
    });
    
    return response.data.choices[0].message.content;
}

这样做的好处:

  • 代码复用:多个地方调用只需 import
  • 易于测试:可以轻松 mock
  • 统一配置:集中管理超时、拦截器等

坑点总结与避坑指南

在开发过程中,我遇到了几个值得分享的坑:

坑一:Bun 与 dotenv 的冲突

刚开始我同时使用了 dotenv 包和 Bun 的内置 .env 支持,结果出现了 injected env (0) 的提示------环境变量没有被正确加载。

解决方案 :删除 dotenv 依赖和相关代码,完全信任 Bun 的内置能力。

坑二:API 地址错误

一开始我把 API 地址写成了 https://api.deepseek.cn/v1,结果一直报 ECONNREFUSED。后来改成 https://api.deepseek.com/v1 就正常了。

解决方案:仔细核对官方文档的 API 地址。

坑三:async 函数忘记调用

写好 chat() 函数后,忘记在文件末尾调用,结果运行后什么都没发生。

解决方案:养成在文件末尾调用主函数的习惯,或者使用 IIFE:

typescript 复制代码
(async () => {
    await chat();
})();

坑四:环境变量未定义

如果 .env 文件不存在或变量名拼写错误,process.env.xxx 会返回 undefined,导致请求失败。

解决方案:添加环境变量检查:

typescript 复制代码
if (!process.env.DEEPSEEK_BASE_URL || !process.env.DEEPSEEK_API_KEY) {
    console.error("请配置环境变量");
    process.exit(1);
}

结语

这个看似简单的项目,其实包含了很多现代 JavaScript 开发的最佳实践:

  1. 使用 Bun 替代 npm:提升开发效率
  2. axios 处理 HTTP 请求:简洁优雅
  3. 环境变量管理:安全第一
  4. TypeScript 严格模式:提前发现错误
  5. async/await 语法:异步代码同步化

技术的本质是解决问题,而好的工具能让我们更专注于解决问题本身。Bun + axios 的组合,就是这样一个让开发变得更轻松的工具链。

如果你也想体验飞一般的开发速度,不妨试试这个项目模板,然后告诉我你的感受!

相关推荐
子午1 小时前
基于DeepSeek的酒店客房管理系统~Python+DeepSeek智能问答+Vue3+Web网站系统
开发语言·前端·python
bkspiderx1 小时前
Boa Web服务器HTTPS支持的源码改造方案
服务器·前端·https·web服务器·boa·https支持
贺今宵1 小时前
Vue 3 + Capacitor 使用jeep-sqlite,web端使用本地sqlite数据库
前端·数据库·vue.js·sqlite·web
taocarts_bidfans1 小时前
Google Indexing API 外贸独立站主动推送收录实战开发
前端·独立站·外贸独立站·taoify
lichenyang4532 小时前
鸿蒙 Stage 模型到底是什么?一篇讲清 Ability、EntryAbility 和入口文件为什么这么设计
前端
JSMSEMI112 小时前
JSM12N60C 600V N沟道增强型功率MOSFET
开发语言·javascript·ecmascript
ihuyigui2 小时前
国际商超零售短信接口
大数据·前端·后端·架构·零售
Yan-英杰2 小时前
从零玩转搜索引擎 API: 多引擎整合实战
服务器·前端·microsoft
Spider_Man2 小时前
Claude Code Hooks:给 AI 助手装上"安全带"
前端·ai编程·claude