导读

如果你是第一次接触后端开发,可能会觉得"服务器"“API"“请求-响应"这些词很抽象。这篇文章的目标就是让你亲手写出一个能跑的 Web 服务。我们将从零开始:先安装 Node.js 运行环境,再学习它最基础的 HTTP 服务——几行代码就能让浏览器收到你返回的 JSON 数据。接着引入 Express 框架(行业标配),学会按路径分发请求(路由)、在请求经过时做统一处理(中间件)。最后,我们会给服务接上一个 AI 大模型 API,让你的网站能「说话」。

全文不依赖任何编辑器或 GUI 工具,只用命令行 + 文本文件就能完成。Windows 用户可以用 PowerShell 或 WSL(Windows Subsystem for Linux),macOS / Linux 用户直接用终端即可。


一、安装 Node.js(推荐 nvm)

为什么不用安装包?

官网 nodejs.org 提供 .msi(Windows)和 .dmg(Mac)安装包,装完就全局可用。但问题来了:一个项目可能需要 Node 18,另一个要 Node 22,换版本就要重新下载安装包,非常麻烦。

所以业界普遍使用 nvm(Node Version Manager —— Node 版本管理器)。它可以在同一个机器上同时装多个 Node 版本,用一行命令切换:

nvm use 22   # 切换到 22.x
nvm use 20   # 切到 20.x

国内安装步骤

Step 1:安装 nvm 本体

nvm 是一个 shell 脚本,运行在终端里。打开终端(PowerShell 不适合——推荐 WSL 或 cmd),执行:

# 下载并安装 nvm(自动写入 ~/.bashrc 或 ~/.zshrc)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

⚠️ 国内如果 github.com 慢? 可以把 URL 替换为 ghfast.top 镜像: curl -o- https://ghfast.top/https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

安装完成后需要新开终端窗口(或执行 source ~/.bashrc)让 nvm 生效。

Step 2:验证安装

command -v nvm    # 输出 "nvm" = 安装成功;无输出 = 没生效
nvm --version     # 应该输出版本号,如 "0.40.3"

Step 3:安装 LTS(长期支持版)

Node.js 有两大分支:LTS(长期稳定版)Current(最新试验版)。写教程和正经项目一律选 LTS。

nvm install --lts   # 自动安装最新的 LTS 版本(通常是 v22.x)
nvm alias default lts/*   # 设置默认版本为新 LTS
node -v             # 看到类似 "v22.x.x" 就算搞定
npm -v              # npm 是随 Node 自带的包管理器,会显示对应版本号

💡 小白解释npm 是 Node.js 的"应用商店命令行”,用来安装别人写好的代码包(比如 Express 框架),也可以发布你自己写的包到公网。

配置国内 npm 镜像

npm 默认的包下载源在海外,国内下载慢。把它切到国内的 npmmirror(淘宝 NPM 镜像站):

npm config set registry https://registry.npmmirror.com
npm config get registry   # 确认输出含 "npmmirror"

💡 这是什么? npmmirror.com 由社区维护,同步了 npm 官方仓库的所有包。速度通常比官方快 5~10 倍。如果以后某个包恰好没同步到,临时切回官方源就行: npm config set registry https://registry.npmjs.org

到这里,你的开发环境已经就绪——可以开始写代码了。


二、模块系统:CommonJS(require) vs ESM(import)

Node.js 世界里有两个"组织代码"的规则体系。你可以把它们理解为两种整理文件夹的方法——决定你怎么把一个大项目拆成多个文件,又怎么把别的文件的代码请过来用。

特性CommonJS (require)ESM (import)
语法const fs = require('fs')import fs from 'fs'
状态Node.js 老标准,几乎所有库都用它ES2020 后成为 JS 国际标准
.js 扩展名默认行为当成 CommonJS需要在 package.json 里声明 "type": "module"
异步加载同步阻塞支持动态 import()

简单建议:新手先用 CommonJS(require),因为网上绝大部分教程和示例都是它。等你熟悉了,再慢慢转 ESM。

示例

// commonjs-demo.js(.cjs 扩展名也行,强制走 CommonJS)
const http = require('http');          // 引入 Node 内置的 http 模块
const port = 3000;                     // 端口号

// 创建服务器:每来一个请求,回调函数就会被调用一次
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });  // 200 = 正常响应
  res.end('Hello from CommonJS!');   // 发给浏览器的内容
});

server.listen(port, () => {            // 监听指定端口
  console.log(`服务已启动,访问 http://localhost:${port}`);
});

保存为 hello-cjs.js,然后终端里运行:

node hello-cjs.js

打开浏览器访问 http://localhost:3000,你会看到页面显示 “Hello from CommonJS!”。你刚刚亲手写出了第一个 Web 服务器!


三、用原生 http 写最小服务端

上节其实已经用原生 http 模块创建了一个能跑的服务。但它只有一个接口(返回同样的内容),不够灵活。下面我们加一些"真实感”——解析 URL、区分 GET/POST、返回 JSON。

// minimal-server.js
const http = require('http');

const server = http.createServer((req, res) => {
  // req.url 是浏览器请求的路径,比如 "/" 或 "/api/users"
  // req.method 是请求方法:GET、POST、DELETE ……
  const { pathname } = new URL(req.url, `http://${req.headers.host}`);

  if (pathname === '/' && req.method === 'GET') {
    // 首页:返回 HTML
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    res.end('<h1>我的 Node.js 小站</h1><p>试试 /api/hello</p>');

  } else if (pathname === '/api/hello' && req.method === 'GET') {
    // API 端点:返回 JSON
    const data = { message: '你好世界!', time: new Date().toISOString() };
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify(data));       // 对象 → JSON 字符串

  } else if (pathname === '/api/chat' && req.method === 'POST') {
    // POST 接收 body(注意:原生 http 不会自动解析 body,需手动拼接)
    let body = '';
    req.on('data', chunk => { body += chunk; });
    req.on('end', () => {
      try {
        const input = JSON.parse(body);   // 解析客户端发来的 JSON
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ echo: input.text || '你发了个空消息' }));
      } catch (e) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'JSON 解析失败' }));
      }
    });

  } else {
    // 未匹配到的路径:404
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('404 Not Found');
  }
});

server.listen(3000, () => console.log('最小服务已启动在 3000'));

运行后:

操作命令 / 地址说明
启动node minimal-server.js终端显示 “已启动”
首页浏览器打开 http://localhost:3000/看到 HTML
APIcurl http://localhost:3000/api/hello返回 JSON
发消息curl -X POST -H "Content-Type: application/json" -d '{"text":"嗨"}' http://localhost:3000/api/chat回显你发的内容

这个方案功能完整但写起来繁琐——每个路径都要手写 if/else,body 解析要自己处理流。Express 框架帮我们解决了这些问题。


四、Express 框架起步

Express 是 Node.js 最受欢迎的 Web 框架(上线 15 年,GitHub 超 6 万星)。它的核心思想很简单:用简洁的 API 代替手写的 if/else 路由判断

安装

mkdir express-starter && cd express-starter
npm init -y                        # 生成 package.json(项目的身份证)
npm install express                # 安装 Express

基本路由

// app.js
const express = require('express');
const app = express();

// 路由:当请求路径是 "/" 且方法是 GET 时执行的函数
app.get('/', (req, res) => {
  res.send('<h1>Hello Express!</h1>');
});

// API 端点:返回 JSON
app.get('/api/hello', (req, res) => {
  res.json({ greeting: '你好!' });  // .json() 自动设 Content-Type
});

// 带参数的路由:/api/user/张三 → req.params.name = "张三"
app.get('/api/user/:name', (req, res) => {
  res.json({ name: req.params.name, role: '游客' });
});

app.listen(3000, () => console.log('Express 跑了!'));

启动方式不变:node app.js

中间件(Middleware)——“过安检”

想象你去机场:所有旅客必须过安检才能登机。中间件就像安检口——每个请求在到达目标路由之前,都会先被中间件拦一下,可以做认证、日志记录、数据转换等事。

// 全局中间件:对所有请求生效
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.url}`);  // 打印访问日志
  next();   // ← 放行!不调 next() 请求就不会往下走
});

// 解析 JSON body 的中间件(没有它,req.body 永远是 undefined)
app.use(express.json());

app.post('/api/data', (req, res) => {
  // 有了 express.json(),这里可以直接读 req.body
  res.json({ received: req.body });
});

Express 内置了两款常用中间件:

  • express.json():自动把 POST body 里的 JSON 字符串解析为 JS 对象
  • cors(需额外安装 npm i cors):允许跨域请求,前端开发时经常用到

如果你需要 CORS 能力,只需 npm i cors,然后在入口添加 const cors = require('cors'); app.use(cors());


五、用 dotenv 管理环境变量

写接口时,Key(密钥)和密码绝对不能硬编码在代码里。比如 API Key、数据库密码——一旦上传到 GitHub 就被公开了。

dotenv 的作用很简单:从一个叫 .env 的文件里读取键值对,注入到进程的 process.env

安装与使用

npm install dotenv

在项目根目录创建 .env 文件:

# .env(不要把此文件提交到 Git!添加到 .gitignore)
LLM_API_KEY=sk-your-key-here
LLM_BASE_URL=https://api.openai.com/v1
PORT=3000

然后在代码开头加载:

// 必须在读 process.env 之前加载
const dotenv = require('dotenv');
dotenv.config();  // 从此 process.env.LLM_API_KEY 就有值了

const port = process.env.PORT || 3000;   // .env 里没有就用 3000 兜底
console.log('端口:', port);

🔒 .env 文件一定要加进 .gitignore 否则会被意外提交到代码仓库。.gitignore 告诉 Git “忽略这个文件”。一行搞定:

.env
node_modules/

六、接入 LLM API(OpenAI 兼容接口)

这是激动人心的部分——给你的服务接上人工智能。

现在绝大多数 AI 服务提供商都提供 OpenAI 兼容接口(即同样用 /v1/chat/completions 这个 URL 格式),你只需要改两个东西:base_url(请求地址)api_key(密钥),代码不用改。这意味着你随时可以切换供应商。

安装依赖

npm install openai dotenv

完整示例代码

// ai-chat.js —— 含 AI 调用的 Express 服务
require('dotenv').config();           // 加载 .env 文件
const express = require('express');
const { OpenAI } = require('openai'); // OpenAI SDK(兼容其他供应商)

const app = express();
app.use(express.json());              // 解析 JSON body

// 用环境变量构建 AI 客户端
// base_url 来自 .env,指向任意 OpenAI 兼容 API(OpenAI / 第三方)
const client = new OpenAI({
  baseURL: process.env.LLM_BASE_URL || 'https://api.openai.com/v1',
  apiKey: process.env.LLM_API_KEY,    // 从 .env 取 Key
});

// 聊天接口:前端传 user message,服务端调用 AI,返回结果
app.post('/api/chat', async (req, res) => {
  try {
    const result = await client.chat.completions.create({
      model: process.env.LLM_MODEL || 'gpt-4o-mini',   // 模型名称
      messages: [
        { role: 'system', content: '你是一个乐于助人的助手。请用简短中文回答。' },
        { role: 'user',   content: req.body.message },
      ],
      max_tokens: 500,
    });
    res.json({ answer: result.choices[0].message.content });
  } catch (err) {
    console.error('AI 调用出错:', err.message);
    res.status(500).json({ error: 'AI 服务暂时不可用' });
  }
});

app.listen(process.env.PORT || 3000, () => {
  console.log(`AI 聊天服务已启动于 http://localhost:${process.env.PORT || 3000}`);
  console.log(`正在使用的模型: ${process.env.LLM_MODEL || 'gpt-4o-mini'}`);
});

配合 .env 配置即可运行:

# .env
LLM_API_KEY=sk-xxxxxxxxxxxxxx
LLM_BASE_URL=https://api.openai.com/v1
LLM_MODEL=gpt-4o-mini
PORT=3000

启动后发送请求测试:

curl -X POST http://localhost:3000/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message":"用一句话介绍你自己"}'

费用省钱小技巧

上面这个 llm_chat.js 接的是 OpenAI 官方 API。新注册账户送 $5 额度,用完就要付费。对于学生党、个人开发者或者频繁实验的场景,有一个性价比极高的替代方案——云间 API 中转站

它是专为国内开发者设计的 API 中转平台,核心卖点:

  • OpenAI 兼容 + Anthropic 兼容:同样的代码,只改 base_urlapi_key 就能无缝切换
  • 90+ 模型覆盖:GPT-4o、Claude、Gemini、本地开源模型都有
  • 国内直连香港节点:延迟低,无需翻墙
  • 价格不到官方两折(最低 0.05x 起),按量计费无月租

如果你只是在学习 Node.js 过程中练手,或者想在个人项目里加一个 AI 功能但不想花太多钱,去 cloudzone-api.cyou 注册一个账号,拿到 Key 后把 .env 里的 LLM_BASE_URL 换成 https://cloudzone-api.cyou/v1 就行了。同样的代码,换个 Key 直接生效。

本文附带的一键脚本默认集成云间 API 配置选项——运行时选 Y 就会帮你跳转到注册页,拿 Key 后自动写入 .env。你也可以选 N,手动填自己的 Key。


总结 & 下一步

我们一起完成了 Node.js 后端开发的核心链路:

知识点做了什么
安装nvm 管理多版本 + npm 切换国内镜像
模块系统CommonJS require 引入模块
原生 HTTPhttp.createServer 写路由判断
Expressapp.get/post 替代 if/else + 中间件
环境变量dotenv 管理 Key,安全不硬编码
AI 集成OpenAI SDK 调 LLM,改 base_url 即可切换供应商

接下来你可以往深了走:学 MySQL 或 MongoDB 数据库连接、加 JWT 登录鉴权、用 PM2 部署到生产环境。也可以试试把我们刚才写的小服务和前面提到的 云间 API 深度结合,做一个智能客服网页或文档问答机器人——这些都是 Node.js 生态里非常常见的应用场景。


一键安装脚本

为方便快速搭建开发环境,下面提供 Windows + Linux/macOS 双版本的一键脚本。

📥 下载链接:也可从 https://cleanresolver.com/scripts/install-nodejs-guide.sh(对应 PowerShell 版为 .ps1)直接下载。

🔍 公开源码,欢迎审查:本脚本完全开源。你可以复制给任何 AI 工具审查,或直接查看每一行在做什么。不放心就不用——一切在你。

以下是完整源码。不方便复制的同学可以新建文本文档,粘贴后保存为 .sh.ps1 运行。

#!/usr/bin/env bash
set -u
# ============================================================
#  Node.js 后端开发实战 — 一键安装脚本(macOS / Linux / WSL)
#  公开源码,欢迎审查 —— 不放心可先复制给 AI 判断
#  默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
# ============================================================

GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
info()  { echo -e "${GREEN}[INFO]${NC} $1"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
step()  { echo -e "${CYAN}[STEP]${NC} $1"; }

detect_network() {
  step "检测网络环境(国内 / 国外)..."
  if curl -fsI --max-time 5 "https://claude.ai" >/dev/null 2>&1; then
    info "可直连 claude.ai,判定为海外网络"
    echo "overseas"
  else
    warn "无法直连 claude.ai,判定为国内网络环境(将自动切换镜像源)"
    echo "domestic"
  fi
}

install_nvm() {
  step "安装 nvm(Node 版本管理器)..."
  if command -v nvm >/dev/null 2>&1; then
    info "nvm 已安装,跳过"
    return 0
  fi

  step "下载 nvm 安装脚本(主源)..."
  local script_file="/tmp/install-nvm.sh"
  if curl -fsSL --max-time 30 "https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh" -o "$script_file"; then
    bash "$script_file"
    rm -f "$script_file"
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
    if nvm --version >/dev/null 2>&1; then
      info "nvm 安装成功:$(nvm --version)"
      return 0
    fi
  fi

  warn "主源安装失败,尝试 ghfast.top 镜像..."
  if curl -fsSL --max-time 30 "https://ghfast.top/https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh" -o "$script_file"; then
    bash "$script_file"
    rm -f "$script_file"
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
    if nvm --version >/dev/null 2>&1; then
      info "nvm 安装成功(镜像源):$(nvm --version)"
      return 0
    fi
  fi

  error "nvm 安装失败。请手动执行:"
  echo "  curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash"
  echo "  然后新开终端窗口或 source ~/.bashrc"
  return 1
}

install_node() {
  step "安装 Node.js LTS ..."
  export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
  [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

  nvm install --lts
  nvm alias default lts/*
  nvm use default

  if command -v node >/dev/null 2>&1; then
    info "Node.js 已安装:$(node --version)"
    info "npm 已安装:$(npm --version)"
    return 0
  fi
  error "Node.js 安装失败"
  return 1
}

setup_registry() {
  step "配置 npm 国内镜像 ..."
  npm config set registry https://registry.npmmirror.com
  info "npm registry → $(npm config get registry)"
}

install_express() {
  step "安装 Express ...(用于后续学习参考)"
  mkdir -p ~/nodejs-examples && cd ~/nodejs-examples || return 1
  npm init -y
  npm install express
  info "Express 安装完成"
}

configure_api() {
  step "配置 AI API Key ..."
  echo ""
  echo "下面的服务能让你的 Node.js 服务接入 AI 大模型,不需要自建服务器:"
  echo "  · 价格不足官方两折,国内直连无需翻墙"
  echo "  · 支持 90+ 模型(OpenAI / Anthropic / 开源模型均兼容)"
  echo ""
  echo "是否跳转注册并获取 API Key?"
  echo "  Y - 立即跳转至 https://cloudzone-api.cyou/"
  echo "  N - 我已有 Key,自行输入"
  read -r -p "请选择 [Y/N]: " choice

  local API_KEY=""
  if [ "${choice:-N}" = "Y" ] || [ "${choice:-N}" = "y" ]; then
    info "正在打开浏览器..."
    if command -v xdg-open >/dev/null 2>&1; then
      xdg-open "https://cloudzone-api.cyou" >/dev/null 2>&1
    elif command -v open >/dev/null 2>&1; then
      open "https://cloudzone-api.cyou" >/dev/null 2>&1
    else
      warn "无法自动打开浏览器,请手动访问:https://cloudzone-api.cyou"
    fi
    echo "注册后在「我的 API Key」页面复制 Key(以 sk- 开头)。"
    read -r -p "粘贴你的 API Key: " API_KEY
  else
    read -r -s -p "请输入你的 API Key (sk-...): " API_KEY
    echo
  fi

  if [ -z "${API_KEY:-}" ]; then
    error "未输入 API Key,跳过配置。可稍后手动设置。"
    return 1
  fi

  # 写入环境变量到 shell rc 文件
  local SHELL_RC=""
  case "${SHELL:/bin/bash}" in
    */zsh)  SHELL_RC="$HOME/.zshrc" ;;
    */bash) SHELL_RC="$HOME/.bashrc" ;;
    *)      SHELL_RC="$HOME/.profile" ;;
  esac

  info "写入环境变量到 $SHELL_RC"
  if [ -f "$SHELL_RC" ]; then
    sed -i.bak '/^export LLM_API_KEY/d; /^export LLM_BASE_URL/d' "$SHELL_RC"
  fi
  {
    echo ""
    echo "# Node.js AI 示例 - 云间 API 配置(一键脚本写入)"
    echo 'export LLM_API_KEY="'"$API_KEY"'"'
    echo 'export LLM_BASE_URL="https://cloudzone-api.cyou/v1"'
  } >> "$SHELL_RC"

  export LLM_API_KEY="$API_KEY"
  export LLM_BASE_URL="https://cloudzone-api.cyou/v1"

  info "配置完成!"
  echo "  API Key : ${API_KEY:0:10}********"
  echo "  Base URL: $LLM_BASE_URL"
  warn "新开终端后生效,或立即执行:source $SHELL_RC"
}

main() {
  echo "============================================"
  echo "  Node.js 后端开发实战 — 一键安装脚本"
  echo "  适用于 macOS / Linux / WSL"
  echo "  默认接入:云间 API 中转站"
  echo "============================================"
  echo ""

  local NET
  NET=$(detect_network)

  if ! install_nvm; then
    error "nvm 安装失败,脚本终止。请按上方提示手动处理后重跑。"
    exit 1
  fi

  if ! install_node; then
    error "Node.js 安装失败,脚本终止。"
    exit 1
  fi

  setup_registry
  install_express

  configure_api || warn "API Key 配置跳过,不影响 Node.js 运行"

  echo ""
  echo "============================================"
  info "全部完成!"
  echo "  Node.js: $(node --version)"
  echo "  npm:     $(npm --version)"
  echo "  nvm:     $(nvm --version)"
  echo "  项目目录: ~/nodejs-examples"
  echo "  运行示例: cd ~/nodejs-examples && node app.js"
  echo "============================================"
}

main "$@"
# ============================================================
#  Node.js 后端开发实战 — 一键安装脚本(Windows PowerShell)
#  公开源码,欢迎审查 -- 不放心可先复制给 AI 判断
#  说明:Windows 推荐使用 WSL 运行 Node.js,本脚本同时支持原生安装。
#  如需 WSL:管理员 PowerShell 执行 "wsl --install" 后重启。
# ============================================================
$ErrorActionPreference = "Stop"

function Write-Info  { Write-Host "[INFO] $args" -ForegroundColor Green }
function Write-Warn  { Write-Host "[WARN] $args" -ForegroundColor Yellow }
function Write-Err   { Write-Host "[ERROR] $args" -ForegroundColor Red }
function Write-Step  { Write-Host "[STEP] $args" -ForegroundColor Cyan }

function Detect-Network {
    Write-Step "检测网络环境(国内 / 国外)..."
    try {
        $null = Invoke-WebRequest -Uri "https://claude.ai" -Method Head -TimeoutSec 5 -UseBasicParsing
        Write-Info "可直连 claude.ai,判定为海外网络"
        return "overseas"
    } catch {
        Write-Warn "无法直连 claude.ai,判定为国内网络环境(将自动切换镜像源)"
        return "domestic"
    }
}

function Install-NvmOrScoop {
    Write-Step "检查 Node.js 安装..."
    # 优先用 scoop 包管理器安装(Windows 推荐的轻量包管理器)
    if (Get-Command scoop -ErrorAction SilentlyContinue) {
        Write-Info "scoop 已安装"
    } else {
        Write-Step "安装 scoop(Windows 轻量包管理器,仅需一步)..."
        Set-ExecutionPolicy -Scope Process Bypass -Force
        # 仅当前会话生效,关闭窗口即恢复,不动系统全局策略
        irm https://get.scoop.sh | iex
        Write-Info "scoop 安装完成"
    }

    if (Get-Command scoop -ErrorAction SilentlyContinue) {
        scoop install nodejs-lts
        if ($LASTEXITCODE -eq 0) {
            Write-Info "通过 scoop 安装 Node.js LTS 成功"
            return $true
        }
    }

    # fallback:用 winget(Windows 10/11 自带)
    if (Get-Command winget -ErrorAction SilentlyContinue) {
        Write-Warn "scoop 安装失败,尝试 winget(系统自带)..."
        winget install OpenJS.NodeJS.LTS --accept-source-agreements --silent 2>$null
        if ($LASTEXITCODE -eq 0) {
            Write-Info "通过 winget 安装 Node.js LTS 成功"
            return $true
        }
    }

    Write-Err "自动安装失败。请手动下载:"
    Write-Host "  海外: https://nodejs.org/dist/latest/node.msi"
    Write-Host "  国内: https://npmmirror.com/mirrors/node/latest/node.msi"
    return $false
}

function Setup-Registry {
    Write-Step "配置 npm 国内镜像 ..."
    npm config set registry https://registry.npmmirror.com
    Write-Info "npm registry -> $(npm config get registry)"
}

function Install-Express {
    Write-Step "安装 Express (用于后续学习参考)..."
    $dir = "$HOME\nodejs-examples"
    New-Item -ItemType Directory -Path $dir -Force | Out-Null
    Set-Location $dir
    npm init -y
    npm install express
    Write-Info "Express 安装完成"
}

function Configure-Api {
    Write-Step "配置 AI API Key ..."
    Write-Host ""
    Write-Host "下面的服务能让你的 Node.js 服务接入 AI 大模型,不需要自建服务器:"
    Write-Host "  · 价格不足官方两折,国内直连无需翻墙"
    Write-Host "  · 支持 90+ 模型(OpenAI / Anthropic / 开源模型均兼容)"
    Write-Host ""
    Write-Host "是否跳转注册并获取 API Key?"
    Write-Host "  Y - 立即跳转至 https://cloudzone-api.cyou/"
    Write-Host "  N - 我已有 Key,自行输入"
    $choice = Read-Host "请选择 [Y/N]"

    $apiKey = ""
    if ($choice -eq "Y" -or $choice -eq "y") {
        Write-Info "正在打开浏览器..."
        try {
            Start-Process "https://cloudzone-api.cyou"
        } catch {
            Write-Warn "无法自动打开浏览器,请手动访问:https://cloudzone-api.cyou"
        }
        Write-Host "注册后在「我的 API Key」页面复制 Key(以 sk- 开头)。"
        $sec = Read-Host "粘贴你的 API Key" -AsSecureString
        $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
        $apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
        [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
    } else {
        $sec = Read-Host "请输入你的 API Key (sk-...)" -AsSecureString
        $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
        $apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
        [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
    }

    if ([string]::IsNullOrWhiteSpace($apiKey)) {
        Write-Err "未输入 API Key,跳过配置。可稍后手动设置。"
        return $false
    }

    # 写入用户级环境变量(永久),并导出到当前会话
    [Environment]::SetEnvironmentVariable("LLM_API_KEY", $apiKey, "User")
    [Environment]::SetEnvironmentVariable("LLM_BASE_URL", "https://cloudzone-api.cyou/v1", "User")
    $env:LLM_API_KEY = $apiKey
    $env:LLM_BASE_URL = "https://cloudzone-api.cyou/v1"

    Write-Info "配置完成!"
    Write-Host "  API Key : $($apiKey.Substring(0, [Math]::Min(10, $apiKey.Length)))********"
    Write-Host "  Base URL: https://cloudzone-api.cyou/v1"
    Write-Host ""
    Write-Warn "新开终端窗口后生效(或当前会话已立即生效)"
    return $true
}

Write-Host "============================================"
Write-Host "  Node.js 后端开发实战 — 一键安装脚本"
Write-Host "  适用于 Windows"
Write-Host "  默认接入:云间 API 中转站"
Write-Host "============================================"
Write-Host ""

$net = Detect-Network

if (-not (Install-NvmOrScoop)) {
    Write-Err "Node.js 安装失败,脚本终止。"
    exit 1
}

Setup-Registry
Install-Express

if (Get-Command express -ErrorAction SilentlyContinue) {
    Write-Info "Express 已在项目目录安装"
}

Configure-Api | Out-Null

Write-Host ""
Write-Host "============================================"
Write-Info "全部完成!"
Write-Host "  Node.js: $(node --version)"
Write-Host "  npm:     $(npm --version)"
Write-Host "  项目目录: $HOME\nodejs-examples"
Write-Host "  运行示例: cd `$HOME\nodejs-examples && node app.js"
Write-Host "============================================"

以上内容为完整脚本源码。不方便下载的同学可以直接复制上方代码块,新建文本文档粘贴后改后缀为 .sh.ps1 运行。也欢迎复制给任何 AI 工具审查安全性——脚本公开透明,没有任何隐藏操作。