本课作为全栈开发入门课,聚焦Node.js后端基础,打通前端到后端的技术通道。Node.js让JavaScript具备后端开发能力,无需学习新语言即可上手服务端开发。课程围绕http、fs、path核心模块,讲解服务器搭建、文件操作、接口开发、跨域处理、路由判断等必备技能,贴合实战需求。通过单词接口案例,完整演示后端开发与前后端交互流程,降低全栈学习门槛。掌握本课内容,不仅能独立搭建简易后端服务、编写接口,更能理解数据流转逻辑,为后续学习Express框架、数据库操作、企业级全栈项目打下坚实基础,是前端开发者进阶全栈的关键一步。
一、课程学习目的
-
理解Node.js的核心定位与运行原理,打破前端与后端的技术壁垒,实现全栈入门。
-
掌握Node.js核心模块用法,能够搭建基础HTTP服务,处理接口请求与响应。
-
学会使用npm管理后端依赖,读取本地文件,搭建简易后端服务。
-
理解前后端交互流程,掌握接口开发、请求处理、数据返回的完整逻辑。
-
能够独立编写后端接口,对接前端页面,实现数据互通,完成全栈小项目。
-
建立后端开发思维,为后续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 运行与开发流程
-
安装Node.js环境,验证node -v、npm -v是否安装成功。
-
创建js文件,编写后端代码,导入核心模块。
-
终端执行node 文件名.js,启动服务。
-
前端发送请求,测试接口,接收返回数据。
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": "桌子" }
]
四、掌握技巧与方法
-
编写Node.js代码后,用node 文件名.js启动服务,修改代码需重启服务生效。
-
处理跨域问题,在响应头添加Access-Control-Allow-Origin: *,允许前端访问。
-
返回数据必须用JSON.stringify转为字符串,前端才能正常解析。
-
文件路径使用path.join拼接,避免绝对路径报错,提升兼容性。
-
异步操作优先使用异步API,避免同步代码阻塞服务运行。
-
服务端口不要被占用,推荐使用3000、8080、9000等常用端口。
-
接口地址要语义化,便于区分和维护,比如/getWord、/addWord。
-
调试时查看终端报错,排查路径、语法、端口占用问题。
五、课后作业
基础作业
-
安装Node.js,验证node、npm版本,确认环境搭建成功。
-
编写基础HTTP服务,启动后访问地址,返回Hello World。
-
创建json文件,用fs模块读取文件内容,打印到终端。
进阶作业
-
搭建单词接口服务,访问/word地址,返回单词列表JSON数据。
-
添加路由判断,实现多个接口,返回不同数据。
-
配置跨域响应头,允许前端页面请求接口。
实战作业
- 使用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
作业验收标准
-
项目正常启动,无控制台报错,页面加载流畅。
-
useState、useEffect、useRef、useMemo、自定义Hook使用规范无误。
-
支持单词搜索过滤、添加、删除功能,数据响应及时。
-
加载状态、空数据提示展示正常,交互体验完整。
-
代码逻辑清晰,模块化拆分合理,符合React Hooks开发规范。