Easton Notes
知识八股Express

启动与入口:服务先怎么跑起来

Express 中的 app.listen() 方法有什么作用?

回答重点

在 Express 框架中,app.listen() 方法的主要作用是启动一个 HTTP 服务器,并使应用程序侦听特定的端口连接。通过app.listen()方法,Express 应用程序将开始接收来自客户端的请求。

const express = require('express');
const app = express();
const PORT = 3000;

// 启动服务器,并监听指定的端口号
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

在上面的代码中,app.listen(PORT, callback) 方法启动一个服务器并使其监听端口 3000,启动成功后会执行回调函数并输出提示信息。

扩展知识

1)HTTP 服务器的基本概念: 当我们使用 app.listen() 时,Express 会在后台创建一个 HTTP 服务器实例。这个实例能够处理 HTTP 请求,并根据请求路径和方法,将请求分发到相应的路由处理函数。

2)参数解释

  • PORT:表示服务器监听的端口号,这是一个必填参数,指定了程序需要在哪个端口上接收请求。
  • callback:这是一个可选的回调函数,会在服务器成功启动并开始监听时执行。通常我们会在回调函数中添加一些日志输出,方便我们知道服务器是否成功启动。

3)与原始 HTTP 模块的关系: 在 Node.js 中,我们可以使用原生的 HTTP 模块创建服务器:

const http = require('http');
const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
}
);
server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
}
);

Express 的 app.listen() 则是对原生 HTTP 模块进行了封装,使得启动服务器更为简洁和直观。

4)错误处理: 有时候,服务器启动可能会遇到错误,这些错误可以通过 try-catch 块或者服务器监听的 error 事件来捕获和处理:

const express = require('express');
const app = express();
const PORT = 3000;

app.listen(PORT, (err) => {
  if (err) {
    console.error(`Error occurred: ${err.message}`);
    return;
  }

  console.log(`Server is running on http://localhost:${PORT}`);
});

5)利用中间件和路由更好地管理请求: Express 不仅让服务器搭建变得简单,还提供了中间件和路由机制:

const express = require('express');
const app = express();

// 中间件示例
app.use((req, res, next) => {
  console.log('Request received at:', new Date().toLocaleString());
  next();
});

// 路由示例
app.get('/', (req, res) => {
  res.send('Hello World');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

什么是 Express Generator,如何使用它?

回答重点

Express Generator 是一个官方的命令行工具,用于生成基于 Express 框架的应用骨架。它可以帮助我们快速创建一个Express 应用,并生成标准化的目录结构和基础代码,从而提高开发效率。

使用 Express Generator 的步骤如下: 1)确保安装了 Node.js 和 npm。 2)通过 npm 安装 Express Generator:npm install -g express-generator 3)使用 Express Generator 生成新项目:express myapp 4)切换到新项目目录:cd myapp 5)安装项目依赖:npm install 6)启动应用:npm start

通过以上步骤,我们可以快速地开始基于 Express 框架的 Web 开发。

扩展知识

在深入了解 Express Generator 之后,下面扩展了解以下相关知识点:

1)自定义项目模板:除了默认模板,我们还可以创建和使用自己的项目模板。这样可以进一步定制生成的项目结构,以满足特定的开发需求。比如,我们可以集成某些中间件,一些常用的模块等。

2)目录结构解析:理解 Express Generator 生成的目录结构有助于我们更高效地开发和维护代码。通常包含的目录和文件有:

  • bin/:用于存放应用的可执行文件,比如 www 文件。
  • public/:用于存放静态文件(CSS、JavaScript、图片等)。
  • routes/:用于存放路由文件,定义应用的路由规则。
  • views/:用于存放视图文件,比如 EJS、Pug 模板文件。
  • app.js:应用入口文件,配置中间件和路由。

3)集成其他组件:在生成的基础项目上,我们可以集成其他需要的中间件和功能模块。例如,我们可以集成数据库(如 MongoDB、MySQL),认证模块,日志模块等。

4)理解 Express 中间件:Express 的中间件在整个开发过程中非常重要。理解中间件的原理和如何编写自定义中间件,将极大地提升你的开发效率。中间件是指在请求处理过程中,可以对请求和响应对象进行操作的函数。

如何在 Express 中使用环境变量和配置文件?

回答重点

在 Express 中使用环境变量和配置文件主要涉及以下几个步骤:

1)安装 dotenv 包:这是一个常用的包,用来加载环境变量。

2)创建 .env 文件:在项目根目录下创建一个 .env 文件,用于存储环境变量。

3)在项目中加载 .env 文件:在您的应用入口文件(比如 app.jsserver.js)中添加 dotenv 配置代码。

具体步骤如下:

npm install dotenv
# 或者
yarn add dotenv

.env 示例:

PORT=3000
DATABASE_URL=mongodb://localhost/mydatabase

app.js 示例:

require('dotenv').config();

const express = require('express');
const app = express();

const port = process.env.PORT || 3000;

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

扩展知识

1)为什么使用环境变量? 环境变量使我们可以在不同环境(开发、测试、生产)中使用不同的配置,而无需修改代码。例如,在开发环境下用的是本地数据库连接,而在生产环境下用的是远程数据库连接。

2)使用配置文件的好处:

  • 集中管理配置:所有的配置信息集中在一个地方,修改起来方便。
  • 提高安全性:将敏感信息存储在环境变量中,避免这些信息写在代码中,提高应用安全性。

3)如何安全管理环境变量:

  • 使用 .env.example 文件:在仓库中存储一个 .env.example 文件,列出需要的环境变量,但不包含实际的值。这样其他开发者在克隆项目时知道需要哪些变量。
  • 将 .env 文件加入 .gitignore:确保 .env 文件不会被提交到版本控制系统中。

4)举一反三:

  • 其他 Node.js 配置管理工具nconfconfig 以及 convict 也是常见的配置管理工具。
  • 替代方案:在复杂的项目中,可以把配置分成多个文件,例如 config/development.jsconfig/production.js,并使用模块化的方式来加载不同的配置文件。

Express 如何与 TypeScript 集成,需注意哪些问题?

要将 Express 与 TypeScript 集成,主要可以分为以下几个步骤:

1)初始化 TypeScript 项目:

  • 在项目根目录下执行 tsc --init,来生成 tsconfig.json 文件。

2)安装必要的依赖:

  • 用 npm 安装 Express、TypeScript 和类型定义(@types/express):
npm install express
npm install typescript @types/node @types/express ts-node-dev

3)创建项目结构:

  • 通常在项目根目录下创建一个 src 文件夹,并在里面放置 TypeScript 文件,占位一个入口文件如 index.ts

4)配置 tsconfig.json

  • 确保 tsconfig.json 文件配置正确,常见的设置如下:
{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

5)创建 TypeScript 版的 Express 服务器:

  • 在 src/index.ts 中编写简单的 Express 服务器代码:
import express from 'express';

const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, Express with TypeScript!');
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

6)启动服务器:

  • 使用 ts-node-dev 进行开发服务器启动,这样可以实时监听 TypeScript 代码的变化并自动重启:
"scripts": {
  "start": "ts-node-dev --respawn --transpile-only src/index.ts"
}

扩展知识

在上面提到的核心步骤之外,还有一些细节和最佳实践可以进一步提升项目的质量和开发体验:

1)使用 ESLint 和 Prettier

  • 配置静态代码检查和格式化工具,保持代码风格一致,提升代码质量。
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
npm install prettier eslint-config-prettier eslint-plugin-prettier --save-dev

2)环境变量管理

  • 使用 dotenv 包来管理环境变量,防止硬编码敏感信息。需要安装相关的依赖,并在代码中加载:
npm install dotenv
并在 `src/index.ts` 顶部添加:
import dotenv from 'dotenv';
dotenv.config();

3)组织项目结构

  • 随着项目的扩大,将路由、控制器、服务等模块化管理,例如创建 routescontrollersservices 文件夹,来分别存放对应的代码内容。

4)使用 Dependency Injection

  • 引入依赖注入框架,如 InversifyJS,提升代码的可维护性和测试性。

5)搭建测试环境

  • 为了确保代码的稳定性,集成 Jest 做单元测试和集成测试。安装相关依赖,并编写测试用例:
npm install jest ts-jest @types/jest --save-dev

6)打包和部署

  • 使用 Webpack 或 Rollup 进行代码打包,将类型和源码分开部署。确保在生产环境中代码是最小化和优化的。

Express 4 相比老版本有哪些区别,升级需要注意什么

回答重点

Express 4 是一个大升级版本,相比老版本(如 Express 3)有几个显著的区别。最关键的变化包括以下几点:

1)拆分中间件:Express 4 把核心功能和第三方中间件分开,使得框架更加模块化。大部分曾经在 Express 3 中集成的中间件(例如 body-parsercookie-parser 等)在 Express 4 中被移除了,需要单独安装。

2)路由变更:Express 4 实现了更灵活的路由,在定义路由时可以使用更先进的语法和特性。路由的功能是增强了。

3)移除了 Connect 依赖:Express 4 移除了对 Connect 的依赖,这意味着中间件的实现更独立了。

4)性能优化和架构改进:Express 4 对内部架构进行了更多优化,使框架在性能和可扩展性上有所提升。

升级注意事项

1)依赖安装:确定你项目中使用的所有中间件都已单独安装,并且版本与 Express 4 兼容。

2)路由重构:审查并更新路由定义,遵循 Express 4 的新语法和特性。

3)中间件更新:确保所有中间件的使用方法都按照新版本的调用方式修改。

扩展知识

1)拆分中间件:拆分中间件意味着你需要主动管理和更新每一个中间件。虽然增加了一点配置开销,但优点是可以更自由选择第三方中间件,而不是盲从框架带来的固定选择。例如,你可以选择更适合自己项目需求的 body-parser 版本。

2)路由的增强:Express 4 提供了更强大的路由匹配能力,可以定义基于特定条件的路由映射,提高代码的灵活性和可维护性。例如,支持正则表达式路由和动态参数路由:

app.get('/user/:id',
function (req, res) {
  res.send('user ' + req.params.id);
}
);

3)移除 Connect 依赖:Connect 是 Express 在老版本中的底层中间件框架,虽然 Connect 本身非常强大,但移除依赖使得 Express 4 在更新和维护上更加灵活独立。你可以选择最适合自己项目的替代中间件,或者简化项目依赖。

4)性能优化:Express 4 通过改进底层架构使得性能更好,还引入了异步操作的更好支持。你可以放心在高并发场景下使用 Express 4,结合现代 Node.js 的异步特性,例如 async/await,可以使代码更加简洁和高效。

Express.js 和 Koa.js 框架有什么区别?

回答重点

Express.js 和 Koa.js 的主要区别在于:

1)中间件机制:

  • Express 使用回调方式处理中间件
  • Koa 使用 async/await 处理中间件,更优雅地处理异步流程

2)核心设计:

  • Express 功能集成度高,内置了很多功能
  • Koa 更轻量,仅提供核心功能,其他功能通过中间件扩展

3)错误处理:

  • Express 使用 try-catch 和 next(error) 处理错误
  • Koa 可以使用 try-catch 直接处理异步错误

扩展知识

1)中间件实现对比

1)Express 中间件:

app.use((req, res, next) => {
  // 处理请求 next();
}
);

2)Koa 中间件:

app.use(async (ctx, next) => {
  // 处理请求
  await next();
}
);

2)路由处理

1)Express 路由:

app.get('/users', (req, res) => {
  res.json({
    users: []
  }
  );
}
);

2)Koa 路由:

router.get('/users', async ctx => {
  ctx.body = {
    users: []
  }
  ;
}
);

3)错误处理方式

1)Express 错误处理:

app.use((err, req, res, next) => {
  res.status(500).json({
    error: err.message
  }
  );
}
);

2)Koa 错误处理:

app.use(async (ctx, next) => {
  try {
    await next();
  }
  catch (err) {
    ctx.status = 500;
    ctx.body = {
      error: err.message
    }
    ;
  }
}
);

4)上下文对象

1)Express:

  • req 和 res 分离
  • 需要手动处理响应
  • 扩展性较差

2)Koa:

  • ctx 统一上下文
  • 自动处理响应
  • 更易扩展

5)性能对比

1)内存占用:

  • Koa 更轻量
  • Express 集成更多功能,占用更多内存

2)响应速度:

  • Koa 异步处理更快
  • Express 在简单场景下性能相当

6)使用场景

1)Express 适合:

快速开发,团队熟悉 callback,需要大量现成中间件

2)Koa 适合:

追求代码简洁,项目需要定制化,大量异步操作

通过以上对比,可以看出 Express 和 Koa 各有特色。选择哪个框架主要取决于:

1)项目需求的复杂度 2)团队的技术栈偏好 3)对异步处理的要求 4)对扩展性的需求

建议在选择框架时,根据实际情况做出判断,而不是盲目追求某个特定框架。

On this page