Express.js 入门指南:从零开始构建 Web 应用

目录

[一、Express.js 简介](#一、Express.js 简介)

[二、安装 Express.js](#二、安装 Express.js)

[三、Express.js 核心概念](#三、Express.js 核心概念)

[1. 路由(Routes)](#1. 路由(Routes))

[2. 中间件(Middlewares)](#2. 中间件(Middlewares))

[3. 请求体解析](#3. 请求体解析)

[4. Express Router](#4. Express Router)

[5. 身份验证](#5. 身份验证)

[6. 错误处理](#6. 错误处理)

[四、Express.js 示例](#四、Express.js 示例)


一、Express.js 简介

Express.js 是一个基于 Node.js 的 Web 应用框架,它以简洁和灵活著称。它不强制使用特定的模板引擎或数据库,而是提供了一套强大的工具来处理 HTTP 请求、定义路由、管理中间件等。

Express.js 的主要特点包括:

  • 简单易用的路由系统

  • 灵活的中间件支持

  • 内置对 JSON、URL 编码等数据格式的支持

  • 轻量级,易于扩展

二、安装 Express.js

安装 Express.js 非常简单,只需使用 npm(Node.js 包管理器)即可。

javascript 复制代码
npm install express --save

在 Express 4.16.0 及更高版本中,Express 内置了 body-parser 的核心功能,因此不再需要额外安装 body-parser 包。只需使用 Express 内置的 express.json()express.urlencoded() 方法即可解析请求体。

三、Express.js 核心概念

1. 路由(Routes)

路由定义了 Express 应用如何响应客户端的 HTTP 请求。每个路由由一个 HTTP 方法(如 GET、POST、PUT、DELETE 等)和一个 URL 路径组成。

javascript 复制代码
// GET 请求根路径 
app.get('/', (req, res) => { res.send('Home Page'); }); 

// GET 请求 /hello 路径 
app.get('/hello', (req, res) => { res.send('Hello World'); });

2. 中间件(Middlewares)

中间件是 Express 应用的核心概念之一。它是一种可以在请求处理管道中执行的功能,可以访问请求和响应对象,并调用 next() 函数将控制权传递给下一个中间件。

javascript 复制代码
// 自定义日志记录中间件 
app.use((req, res, next) => {
 console.log(`${new Date().toISOString()} ${req.ip} ${req.method} ${req.path}`);
 next(); 
});

3. 请求体解析

在 Express 4.16.0 及更高版本中,Express 内置了 body-parser 的核心功能,因此可以直接使用 express.json()express.urlencoded() 方法来解析请求体。

javascript 复制代码
// 解析 JSON 请求体 
app.use(express.json()); 

// 解析 URL 编码的请求体 
app.use(express.urlencoded({ extended: true }));

4. Express Router

Express Router 允许你创建独立的路由模块,便于代码的组织和复用。你可以将路由逻辑拆分成不同的文件,然后通过 app.use() 将它们挂载到主应用上。

javascript 复制代码
// 创建一个路由模块 
const router = express.Router(); 

// 定义路由 
router.get('/', (req, res) => { 
    res.send('This is a sub-router'); 
}); 

// 将路由模块挂载到主应用 
app.use('/api', router);

5. 身份验证

你可以创建自定义的身份验证中间件,用于保护特定的路由。

javascript 复制代码
// 基础身份验证中间件
const authenticate = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  if (authHeader && authHeader.startsWith('Bearer ')) {
    // 在实际应用中,这里应该验证令牌的有效性
    req.user = { id: 1, name: 'Admin User' };
    next();
  } else {
    res.status(401).json({ error: 'Unauthorized' });
  }
};

6. 错误处理

Express 提供了专门的错误处理中间件,用于捕获和处理应用中的错误。

javascript 复制代码
// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something went wrong!' });
});

四、Express.js 示例

  • 项目结构
  • app.js (主应用文件)
javascript 复制代码
const express = require("express");
const path = require("path");
const app = express();
const PORT = 3000;

// 1. 中间件设置

// 解析 JSON 请求体
app.use(express.json());

// 解析 URL 编码的请求体
app.use(express.urlencoded({ extended: true }));

const logger = (req, res, next) => {
  console.log(
    `${new Date().toISOString()} ${req.ip} ${req.method} ${req.path}`
  );
  next();
};

// 应用日志中间件
app.use(logger);

// 静态文件服务
app.use(express.static(path.join(__dirname, "public")));

// 2. 路由设置

// 导入博客路由模块
const blogRoutes = require("./blogRoutes");

// 将 API 路由挂载到主应用
app.use("/api", blogRoutes);

// 3. 错误处理中间件

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: "Something went wrong!" });
});

// 4. 启动服务器

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});
  • blogRoutes.js (路由模块)
javascript 复制代码
const express = require("express");
const router = express.Router();

// 文章数据存储
let posts = [
  {
    id: 1,
    title: "Express.js 入门教程",
    content: "Express.js 是一个轻量级 Node.js Web 应用框架...",
  },
  {
    id: 2,
    title: "Node.js 基础",
    content: "Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境...",
  },
];

// 获取所有文章
router.get("/posts", (req, res) => {
  res.json(posts);
});

// 获取单篇文章
router.get("/posts/:id", (req, res) => {
  const postId = parseInt(req.params.id);
  const post = posts.find((post) => post.id === postId);

  if (post) {
    res.json(post);
  } else {
    res.status(404).json({ error: "Post not found" });
  }
});

// 创建新文章
router.post("/posts", (req, res) => {
  if (!req.body.title || !req.body.content) {
    return res.status(400).json({ error: "Title and content are required" });
  }

  const newPost = {
    id: posts.length + 1,
    title: req.body.title,
    content: req.body.content,
  };

  posts.push(newPost);
  res.status(201).json(newPost);
});

// 更新文章
router.put("/posts/:id", (req, res) => {
  const postId = parseInt(req.params.id);
  const updatedPost = {
    id: postId,
    title: req.body.title,
    content: req.body.content,
  };

  const index = posts.findIndex((post) => post.id === postId);
  if (index !== -1) {
    posts[index] = updatedPost;
    res.json(updatedPost);
  } else {
    res.status(404).json({ error: "Post not found" });
  }
});

// 删除文章
router.delete("/posts/:id", (req, res) => {
  const postId = parseInt(req.params.id);
  const initialLength = posts.length;

  posts = posts.filter((post) => post.id !== postId);

  if (posts.length < initialLength) {
    res.status(204).send();
  } else {
    res.status(404).json({ error: "Post not found" });
  }
});

module.exports = router;
  • public/index.html (静态页面)
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Express.js 应用</title>
    <link rel="stylesheet" href="/styles.css" />
  </head>
  <body>
    <div class="container">
      <h1>欢迎使用 Express.js</h1>
      <p>这是一个简单的 Express.js 示例应用</p>
      <ul>
        <li><a href="/api/posts">模拟请求文章列表</a></li>
        <li><a href="/api/posts/1">模拟请求文字详情</a></li>
      </ul>
    </div>
  </body>
</html>
  • public/styles.css (样式文件)
css 复制代码
body {
    font-family: Arial, sans-serif;
    background-color: #f0f0f0;
    margin: 0;
    padding: 0;
}

div.container {
    width: 80%;
    margin: 50px auto;
    padding: 20px;
    background-color: white;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

h1 {
    color: #333;
}

a {
    color: #007bff;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}
  • 页面展示
相关推荐
一只小风华~3 小时前
命名视图学习笔记
前端·javascript·vue.js·笔记·学习
编程点滴3 小时前
前端项目从 Windows 到 Linux:构建失败的陷阱
linux·前端
小高0073 小时前
🎯GC 不是 “自动的” 吗?为什么还会内存泄漏?深度拆解 V8 回收机制
前端·javascript·面试
RoyLin3 小时前
V8引擎与VM模块
前端·后端·node.js
Keepreal4964 小时前
React受控组件和非受控组件的区别,用法以及常见使用场景
前端·react.js
ITsheng_ge4 小时前
GitHub Pages 部署静态网站流程、常见问题以及解决方案
前端·github·持续部署
web3d5204 小时前
CSS水平垂直居中终极指南:从入门到精通
前端·css
1024小神4 小时前
前端css常用的animation动画效果及其简写
前端
小白菜学前端4 小时前
Vue 配置代理
前端·javascript·vue.js