在建立第一个Demo后,我们引入一个开发框架实现前面的功能;引入开发框架有以下几个主要原因:
在Node.js生态中,流行的框架包括Express、Koa、NestJS等,它们各有特点,适用于不同的开发场景和需求。选择合适的框架可以大大提升开发效率和项目质量。
npm install -g express-generator
express Demo4Express //在当前目录下创建Demo4Express目录,同时在该目录下创建Demo4Express项目及相应的子文件夹
cd Demo4Express npm install //
命令说明:
express Demo4Express //这将在当前目录下创建一个名为Demo4Express的新目录,并在其中生成项目的骨架文件;子文件夹结构如下:
├── app.js `app.js`: 这是主应用程序文件,它启动了 Express 服务器,并设置了一些基本的中间件和路由。
├── bin/
│ └── www `bin/www`: 这个文件是一个启动脚本,它启动了 `app.js` 中的服务器。你可以通过运行 `node bin/www` 来启动你的应用程序。
├── node_modules/ `node_modules/`: 这个文件夹包含了所有通过 npm 安装的依赖包。
├── package.json `package.json`: 这个文件列出了项目的依赖包,以及一些其他的元数据,如项目名称、版本、描述等。
├── public/ `public/`: 这个文件夹包含了所有的静态资源,如图片、样式表和 JavaScript 文件。
│ ├── images/
│ ├── javascripts/
│ └── stylesheets/
│ └── style.css
├── routes/ `routes/`: 这个文件夹包含了路由文件,这些文件定义了应用程序的不同 URL 路径如何响应 HTTP 请求。
│ ├── index.js
│ └── users.js
└── views/ `views/`: 这个文件夹包含了应用程序的视图模板。默认情况下,`express-generator` 使用 Pug 模板引擎,但你可以使用其他模板引擎,如 EJS 或 Handlebars。
├── error.pug
├── index.pug
└── layout.pug
完成后,你可以启动项目:
npm start
在浏览器中输入“http://127.0.0.1:3000/”浏览默认实现;
(二)代码说明
1. package.json,这个文件列出了项目的依赖包,以及一些其他的元数据,如项目名称、版本、描述等。你可以使用 `npm install` 命令根据这个文件来安装所有必要的依赖包。其内容如下:
{
"name": "demo4express", //项目名称
"version": "0.0.0", //项目版本号
"private": true, //是否为私有
"scripts": { //脚本文件
"start": "node ./bin/www" //指定当执行npm start命令时 执行的命令
},
"dependencies": { //所有依赖包
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"jade": "~1.11.0",
"morgan": "~1.9.1"
}
}
2. App.js,它是使用 Express.js 框架的基本 Node.js 应用程序的入口点。下面是对每行代码的逐行注释:
// 导入内置的 http-errors 模块,用于创建各种 HTTP 错误。
var createError = require('http-errors');
// 导入 express 模块,这是 Express 应用程序的核心。
var express = require('express');
// 导入 path 模块,用于处理文件路径。
var path = require('path');
// 导入 cookie-parser 中间件,用于解析 Cookie 头部信息。
var cookieParser = require('cookie-parser');
// 导入 morgan 中间件,用于日志记录 HTTP 请求。
var logger = require('morgan');
// 导入 index 路由器,它处理根 URL (/) 的请求。
var indexRouter = require('./routes/index');
// 导入 users 路由器,它处理与用户相关的 URL (/users) 的请求。
var usersRouter = require('./routes/users');
// 创建一个 Express 应用实例。
var app = express();
// 设置视图模板的存放目录,__dirname 是当前文件所在的目录。
app.set('views', path.join(__dirname, 'views'));
// 设置视图模板引擎为 Jade(现在称为 Pug)。
app.set('view engine', 'jade');
// 使用 morgan 中间件来记录每个请求的信息到控制台,'dev' 是一种预定义的格式。
app.use(logger('dev'));
// 解析 JSON 格式的请求体。
app.use(express.json());
// 解析 URL 编码的请求体。
app.use(express.urlencoded({ extended: false }));
// 使用 cookieParser 中间件来解析请求中的 Cookie。
app.use(cookieParser());
// 设置静态文件服务的目录为 public 文件夹。
app.use(express.static(path.join(__dirname, 'public')));
// 将根 URL (/) 的请求路由到 indexRouter。
app.use('/', indexRouter);
// 将与用户相关的 URL (/users) 的请求路由到 usersRouter。
app.use('/users', usersRouter);
// 如果前面的路由都没有处理请求,则创建一个 404 错误并传递给错误处理器。
app.use(function(req, res, next) {
next(createError(404));
});
// 错误处理器,用于处理所有路由和中间件中抛出的错误。
app.use(function(err, req, res, next) {
// 设置本地变量,只在开发环境下提供错误详情。
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// 渲染错误页面。
res.status(err.status || 500);
res.render('error');
});
// 导出 app 实例,以便在其他文件中(如启动脚本)使用。
module.exports = app;
这段代码设置了一个基本的 Express 应用程序,包括中间件、路由和错误处理。它还定义了视图引擎和静态文件服务的目录。最后,它导出了应用程序实例,以便可以将其传递给 HTTP 服务器并在端口上监听。
3. bin\www ,启动脚本
#!/usr/bin/env node
/**
* 这行代码是 Shebang,它告诉系统使用 env 来查找 node 解释器,并使用它来执行这个脚本。
*/
/**
* Module dependencies.
*/
var app = require('../app');
// 导入位于父目录中的 app.js 文件,它导出了 Express 应用实例。
var debug = require('debug')('demo4express:server');
// 导入 debug 模块,并创建一个名为 'demo4express:server' 的调试器实例。
var http = require('http');
// 导入 Node.js 内置的 http 模块,用于创建 HTTP 服务器。
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
// 获取环境变量中的端口,如果没有设置,则使用默认端口 3000,并规范化端口。
app.set('port', port);
// 将端口存储在 Express 应用实例中,以便可以在应用中使用。
/**
* Create HTTP server.
*/
var server = http.createServer(app);
// 使用 Express 应用实例创建一个 HTTP 服务器。
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
// 服务器开始监听指定端口。
server.on('error', onError);
// 为服务器注册一个错误事件监听器。
server.on('listening', onListening);
// 为服务器注册一个监听事件监听器。
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
// 尝试将端口转换为整数。
if (isNaN(port)) {
// 如果转换失败(不是数字),则假设它是一个命名管道。
return val;
}
if (port >= 0) {
// 如果转换成功且是有效端口,则返回端口数字。
return port;
}
return false;
// 如果端口无效,则返回 false。
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
// 如果错误不是监听错误,则抛出错误。
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// 根据端口类型创建一个友好的错误消息。
// 处理特定的监听错误,并显示友好的错误消息。
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
// 获取服务器正在监听的地址。
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
// 根据地址类型创建一个友好的监听消息。
debug('Listening on ' + bind);
// 使用 debug 调试器输出服务器正在监听的消息。
}
这个脚本首先导入了必要的模块,然后从环境变量中获取端口号,创建一个 HTTP 服务器,并为该服务器添加了错误和监听事件的处理函数。如果服务器启动失败,它会输出错误信息并退出进程。如果服务器成功启动,它会输出监听的信息。
4. Index.js 路由器模块,它处理对主页的 GET 请求。
var express = require('express');
// 导入 Express 框架,用于创建和管理 HTTP 服务器和路由。
var router = express.Router();
// 创建一个 Express 路由器实例,它是一个中间件和路由的集合,可以用于路由特定的请求。
/* GET home page. */
// 这是一条注释,说明下面的路由处理的是对主页的 GET 请求。
router.get('/', function(req, res, next) {
// 为路由器添加一个处理 GET 请求的路由。当用户访问根 URL (/) 时,这个函数会被调用。
res.render('index', { title: 'Express' });
// 使用 res.render 方法渲染名为 'index' 的视图模板,并传递一个包含标题的对象作为模板变量。
// 假设 Express 已经配置了视图引擎(如 Jade/Pug、EJS 等),这里会将模板渲染成 HTML 并发送给客户端。
});
module.exports = router;
// 导出这个路由器模块,以便在其他文件中(如应用程序的主文件)可以 require 它并使用它来处理请求。
这个路由器模块定义了一个路由,当用户访问主页时,它会渲染一个名为 index 的视图,并将 title 变量设置为 'Express'。这个模块可以被包含在一个更大的 Express 应用程序中,作为处理主页请求的一部分。
5.index.jade、index.jade
在 Express 应用程序中使用 Jade(或 Pug)作为模板引擎时,layout.jade 文件和 index.jade 文件通常用于定义应用程序的布局和主页内容。
layout.jade
layout.jade 文件是一个布局模板,它定义了应用程序的公共部分,比如页头、导航栏、页脚等。这个文件通常包含一个或多个块(blocks),这些块可以在继承它的其他模板中填充具体内容。
例如,layout.jade 文件的内容可能如下所示:
html
head
title My Express App
link(rel='stylesheet', href='/stylesheets/style.css')
body
header
h1 My Express App
nav
// 导航栏代码
section.container
block content
footer
p Copyright © 2023
在这个例子中,block content 是一个占位符,它表示子模板可以插入自己的内容。其他模板通过 extends 关键字继承 layout.jade 并在 block content 中填充自己的内容。
index.jade
index.jade 文件是主页的模板文件,它继承了 layout.jade 文件,并在 block content 中定义了主页特有的内容。这样,当用户访问主页时,他们会看到 layout.jade 中定义的公共布局,以及 index.jade 中定义的主页特定内容。
例如,index.jade 文件的内容可能如下所示:
extends layout
block content
h1 Home Page
p Welcome to the home page of My Express App.
// 其他主页特定的 HTML 和数据
在这个例子中,extends layout 表示 index.jade 继承自 layout.jade。block content 中的内容会替换 layout.jade 中的 block content,从而在主页上显示特定的标题和段落。
通过这种方式,layout.jade 和 index.jade 文件共同工作,提供了一个结构化的方式来创建和维护网页的布局和内容。这种模式可以减少代码重复,使得更新和维护变得更加容易。
在使用 Express 框架时,app.js 和 index.js 文件通常都存在于项目的根目录中,但它们的职责有所不同。这些文件的角色可能会根据项目的规模和结构而有所变化,但以下是一些常见的职责分配:
app.js 文件通常作为应用程序的入口点,它负责设置 Express 应用程序的基本配置和中间件,以及启动服务器。在这个文件中,你会看到以下的操作:
var express = require('express');
var app = express();
// 设置视图引擎等中间件
app.set('view engine', 'ejs');
// 静态文件服务等
app.use(express.static('public'));
// 路由
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
// 错误处理
app.use(function(err, req, res, next) {
// ...
});
// 启动服务器
var port = process.env.PORT || 3000;
app.listen(port, function() {
console.log('Express server listening on port ' + port);
});
index.js 文件在不同的上下文中可能有不同的用途。在一些项目中,index.js 可能是整个应用程序的入口点,而在其他项目中,它可能是一个路由模块的入口点。以下是两种常见的使用方式:
var express = require('express');
var router = express.Router();
// 定义主页路由
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
在实际项目中,app.js 和 index.js 的职责可能会根据项目的具体需求和开发者的个人偏好而有所不同。重要的是要保持一致性并确保项目的其他开发者能够理解文件的结构和职责。
在 Express 应用程序中,app.js 文件通常负责创建和配置 Express 应用实例,以及将路由器连接到应用的路由系统中。index.js 文件通常是一个路由器模块,它定义了特定的路由和处理函数。
app.js 文件中的这两行代码:
var indexRouter = require('./routes/index');
app.use('/', indexRouter);
index.js 文件中也有类似的代码:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
下面解释它们之间的关系:
这里,index.js 文件创建了一个路由器实例 router,并为根路径定义了一个 GET 请求的处理函数。当用户访问根 URL (/) 时,这个处理函数会被调用,并且使用 res.render 方法来渲染一个名为 index 的视图,同时传递一个包含 title 属性的对象作为视图渲染时的数据。
总结来说,app.js 文件通过 require 导入 index.js 文件中定义的路由器,并通过 app.use 将其绑定到应用的路由系统中。这样,当用户发起特定的 HTTP 请求时,请求会被路由到正确的处理函数。这是 Express 中常见的路由和组织代码的方式,有助于保持代码的模块化和可维护性。