JavaScript基础课程二十五、Node.js 后端基础

本课作为全栈开发入门课,聚焦Node.js后端基础,打通前端到后端的技术通道。Node.js让JavaScript具备后端开发能力,无需学习新语言即可上手服务端开发。课程围绕http、fs、path核心模块,讲解服务器搭建、文件操作、接口开发、跨域处理、路由判断等必备技能,贴合实战需求。通过单词接口案例,完整演示后端开发与前后端交互流程,降低全栈学习门槛。掌握本课内容,不仅能独立搭建简易后端服务、编写接口,更能理解数据流转逻辑,为后续学习Express框架、数据库操作、企业级全栈项目打下坚实基础,是前端开发者进阶全栈的关键一步。

一、课程学习目的

  1. 理解Node.js的核心定位与运行原理,打破前端与后端的技术壁垒,实现全栈入门。

  2. 掌握Node.js核心模块用法,能够搭建基础HTTP服务,处理接口请求与响应。

  3. 学会使用npm管理后端依赖,读取本地文件,搭建简易后端服务。

  4. 理解前后端交互流程,掌握接口开发、请求处理、数据返回的完整逻辑。

  5. 能够独立编写后端接口,对接前端页面,实现数据互通,完成全栈小项目。

  6. 建立后端开发思维,为后续Express、数据库学习打下扎实基础。

二、核心知识点讲解

1. Node.js 基础认知

Node.js是基于Chrome V8引擎的JavaScript运行环境,让JavaScript脱离浏览器,在服务器端运行,实现后端开发、文件操作、服务搭建等功能。

核心优势:使用JavaScript语法开发后端,上手门槛低;非阻塞异步I/O,性能优异;生态完善,npm依赖库丰富,适合快速开发接口与服务。

Node.js适合开发后端接口、中间层服务、工具脚本、实时通信项目,是前端进阶全栈的必备技术。

2. Node.js 核心模块

Node.js自带多种内置模块,无需额外安装,直接导入使用,支撑基础后端功能。

  • http模块:搭建HTTP服务器,处理前端请求,返回数据,实现接口服务。

  • fs模块:文件系统模块,用于读取、写入、修改本地文件,常用于存储数据。

  • path模块:处理文件路径,解决不同系统的路径兼容问题。

  • url模块:解析请求地址、获取请求参数,处理路由与传参。

3. 前后端交互基础

前端通过Ajax、fetch发送请求,Node.js后端监听端口、接收请求、处理逻辑、返回JSON数据,完成数据互通。

常见请求方式:GET(获取数据)、POST(提交数据),后端根据不同请求方式和地址,返回对应结果。

4. Node.js 运行与开发流程

  1. 安装Node.js环境,验证node -v、npm -v是否安装成功。

  2. 创建js文件,编写后端代码,导入核心模块。

  3. 终端执行node 文件名.js,启动服务。

  4. 前端发送请求,测试接口,接收返回数据。

5. 接口与路由基础

路由用于区分不同请求地址,根据不同URL返回不同数据,实现多接口管理。比如/word返回单词列表,/detail返回单词详情。

后端通过判断request.url,执行不同逻辑,返回对应数据。

三、示例程序(带详细注释)

示例1:搭建基础HTTP服务器(单词接口)

javascript 复制代码
// 导入http核心模块
const http = require('http');

// 定义单词数据
const wordList = [
  { en: 'apple', cn: '苹果' },
  { en: 'banana', cn: '香蕉' },
  { en: 'orange', cn: '橙子' }
];

// 创建服务器
const server = http.createServer((req, res) => {
  // 设置响应头,解决跨域,返回JSON格式
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Content-Type', 'application/json;charset=utf-8');

  // 判断请求地址与方式
  if (req.url === '/word' && req.method === 'GET') {
    // 返回单词数据
    res.end(JSON.stringify(wordList));
  } else {
    // 地址不存在,返回提示
    res.end(JSON.stringify({ msg: '接口不存在', code: 404 }));
  }
});

// 监听端口,启动服务
server.listen(3000, () => {
  console.log('服务器启动成功:http://localhost:3000');
});

示例2:fs模块读取文件数据

javascript 复制代码
// 导入fs、path模块
const fs = require('fs');
const path = require('path');

// 拼接文件路径
const filePath = path.join(__dirname, 'word.json');

// 异步读取文件
fs.readFile(filePath, 'utf8', (err, data) => {
  if (err) {
    console.log('读取失败', err);
    return;
  }
  // 转为JSON对象
  const wordData = JSON.parse(data);
  console.log('读取单词数据:', wordData);
});

// 同步读取(简单场景使用)
// const data = fs.readFileSync(filePath, 'utf8');

示例3:word.json数据文件

json 复制代码
[
  { "en": "book", "cn": "书" },
  { "en": "pen", "cn": "笔" },
  { "en": "desk", "cn": "桌子" }
]

四、掌握技巧与方法

  1. 编写Node.js代码后,用node 文件名.js启动服务,修改代码需重启服务生效。

  2. 处理跨域问题,在响应头添加Access-Control-Allow-Origin: *,允许前端访问。

  3. 返回数据必须用JSON.stringify转为字符串,前端才能正常解析。

  4. 文件路径使用path.join拼接,避免绝对路径报错,提升兼容性。

  5. 异步操作优先使用异步API,避免同步代码阻塞服务运行。

  6. 服务端口不要被占用,推荐使用3000、8080、9000等常用端口。

  7. 接口地址要语义化,便于区分和维护,比如/getWord、/addWord。

  8. 调试时查看终端报错,排查路径、语法、端口占用问题。

五、课后作业

基础作业

  1. 安装Node.js,验证node、npm版本,确认环境搭建成功。

  2. 编写基础HTTP服务,启动后访问地址,返回Hello World。

  3. 创建json文件,用fs模块读取文件内容,打印到终端。

进阶作业

  1. 搭建单词接口服务,访问/word地址,返回单词列表JSON数据。

  2. 添加路由判断,实现多个接口,返回不同数据。

  3. 配置跨域响应头,允许前端页面请求接口。

实战作业

  1. 使用Node.js搭建完整单词服务,包含获取单词列表、查询单个单词功能,读取本地json文件存储数据,接入前端页面实现前后端交互,纳入Git版本管理。

上一课:React Hooks 与实战 实战作业代码

代码功能说明

本实战代码基于React框架,深度运用Hooks完成单词搜索管理系统,贴合课程核心知识点。项目使用useState管理单词列表、输入框、加载状态,通过useEffect实现页面初始化时异步请求模拟数据,搭配useRef获取输入框DOM实现自动聚焦,封装自定义HookuseWordList统一管理数据逻辑。实现单词列表展示、搜索过滤、添加删除、加载提示等完整功能,用useMemo缓存搜索结果,避免重复计算,优化组件性能。代码结构清晰,逻辑模块化,覆盖主流Hooks用法,完美贴合实战需求,巩固React函数式开发与Hooks核心用法。

注意事项

  • Hooks必须在函数组件顶层调用,禁止在循环、条件判断、普通函数中使用。

  • useEffect需正确配置依赖项,防止出现死循环或逻辑不执行的问题。

  • React状态不可直接修改,必须用set方法返回新数据,数组/对象用展开语法更新。

  • 自定义Hook命名必须以use开头,符合React规范,才能正常调用其他Hooks。

  • useRef操作DOM时,需等待组件挂载完成,防止current为null报错。

  • 项目启动前需执行npm install安装依赖,修改代码后热更新生效,无需重启服务。

  • 列表渲染的key值需唯一,不建议只用index,避免渲染错乱。

  • 运行命令:npm install → npm run dev,关闭服务用Ctrl+C。

完整实战代码

项目结构

Plain 复制代码
react-hooks-word/
├── index.html
├── package.json
└── src/
    ├── main.jsx
    ├── App.jsx
    ├── hooks/useWordList.js
    └── index.css

src/hooks/useWordList.js(自定义Hook)

jsx 复制代码
import { useState, useEffect } from 'react'

// 自定义Hook,封装单词列表逻辑
export function useWordList() {
  const [wordList, setWordList] = useState([])
  const [loading, setLoading] = useState(false)

  // 异步获取单词数据
  useEffect(() => {
    const fetchWords = async () => {
      setLoading(true)
      // 模拟接口请求
      await new Promise(resolve => setTimeout(resolve, 1000))
      const data = [
        { en: 'apple', cn: '苹果', id: 1 },
        { en: 'banana', cn: '香蕉', id: 2 },
        { en: 'react', cn: '框架', id: 3 },
        { en: 'hook', cn: '钩子', id: 4 }
      ]
      setWordList(data)
      setLoading(false)
    }
    fetchWords()
  }, [])

  // 添加单词
  const addWord = (newWord) => {
    setWordList([...wordList, { ...newWord, id: Date.now() }])
  }

  // 删除单词
  const delWord = (id) => {
    setWordList(wordList.filter(item => item.id !== id))
  }

  return {
    wordList,
    loading,
    addWord,
    delWord
  }
}

src/App.jsx

jsx 复制代码
import { useState, useRef, useMemo } from 'react'
import { useWordList } from './hooks/useWordList'
import './index.css'

function App() {
  const { wordList, loading, addWord, delWord } = useWordList()
  const [searchKey, setSearchKey] = useState('')
  const [inputEn, setInputEn] = useState('')
  const [inputCn, setInputCn] = useState('')
  const inputRef = useRef(null)

  // 缓存搜索结果,只有wordList或searchKey变化时重新计算
  const filterList = useMemo(() => {
    return wordList.filter(item =>
      item.en.includes(searchKey.toLowerCase()) || item.cn.includes(searchKey)
    )
  }, [wordList, searchKey])

  // 提交添加单词
  const handleAdd = () => {
    if (!inputEn.trim() || !inputCn.trim()) return
    addWord({ en: inputEn, cn: inputCn })
    setInputEn('')
    setInputCn('')
    inputRef.current.focus()
  }

  return (
    <div className="app">
      <h2>React Hooks 单词管理器</h2>

      {/* 搜索框 */}
      <div className="search-box">
        <input
          type="text"
          placeholder="搜索单词"
          value={searchKey}
          onChange={(e) => setSearchKey(e.target.value)}
        />
      </div>

      {/* 添加单词 */}
      <div className="add-box">
        <input
          ref={inputRef}
          type="text"
          placeholder="英文"
          value={inputEn}
          onChange={(e) => setInputEn(e.target.value)}
        />
        <input
          type="text"
          placeholder="中文"
          value={inputCn}
          onChange={(e) => setInputCn(e.target.value)}
        />
        <button onClick={handleAdd}>添加</button>
      </div>

      {/* 列表展示 */}
      <div className="list-box">
        {loading && <p className="tip">加载中...</p>}
        {!loading && filterList.length === 0 && (
          <p className="tip">暂无数据</p>
        )}
        {filterList.map(item => (
          <div className="word-item" key={item.id}>
            <span>{item.en} --- {item.cn}</span>
            <button onClick={() => delWord(item.id)}>删除</button>
          </div>
        ))}
      </div>
    </div>
  )
}

export default App

src/main.jsx

jsx 复制代码
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

src/index.css

css 复制代码
.app {
  max-width: 650px;
  margin: 30px auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}
.search-box,
.add-box {
  margin: 15px 0;
  display: flex;
  gap: 8px;
}
input {
  padding: 8px 12px;
  flex: 1;
  border: 1px solid #ddd;
  border-radius: 4px;
}
button {
  padding: 8px 16px;
  background: #61dafb;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.tip {
  color: #666;
  text-align: center;
  padding: 20px 0;
}
.word-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  margin: 8px 0;
  background: #f7f7f7;
  border-radius: 4px;
}

运行命令

bash 复制代码
npm install
npm run dev

作业验收标准

  1. 项目正常启动,无控制台报错,页面加载流畅。

  2. useState、useEffect、useRef、useMemo、自定义Hook使用规范无误。

  3. 支持单词搜索过滤、添加、删除功能,数据响应及时。

  4. 加载状态、空数据提示展示正常,交互体验完整。

  5. 代码逻辑清晰,模块化拆分合理,符合React Hooks开发规范。