在这个Express初学者教程中,我们可以下载并安装Express.js到我们的系统中,看看如何设置和配置一个超级基本的骨架应用程序。值得庆幸的是,有一个专门的工具可以自动创建一个新的Express项目,叫做Express Generator,这让我们的工作变得相当容易。让我们来看看完全的初学者如何能够马上使用Express.js来运行。
什么是Express.js,我们为什么要使用它?
所以在这一点上,我们已经花了一些时间来习惯在非常基本的水平上使用Node.js。我们了解了什么是Node.js,如何从文件系统中写入和读取数据,处理一些请求和响应,以及建立我们自己的基本路由系统。如果你看一下路由教程中的代码,你会注意到,仅靠我们自己建立一些路由是有点费劲的。此外,如果我们想添加多个路由,它的规模就不会那么大了。以纯粹的形式使用Node.js,需要我们自己编写所有的东西。这很容易出错,很可能不安全,而且只是普通的大量工作。你猜怎么着?就像软件开发中的大多数其他事情一样,你想做的事情很可能已经有了稳定的、经过测试的解决方案。这就是为什么我们现在要看一下Express.js。Express将允许你专注于你的业务逻辑和你的应用程序的需求。像解析尿液和设置手动路由这样的重复性任务可以由该框架来处理。Express建立在Node的基础上,提供了许多工具,使Node的工作更容易。有了Express,配置路由变得轻而易举。由TJ Holowaychuk创建的Express框架为许多常见的任务提供了方便的方法和语法糖,否则这些任务将是乏味和多余的。
如何设置和配置Express.js
我们需要做的第一件事是在我们的系统上安装Express生成器模块。这是很简单的事情。只要在你的命令行中输入npm install -g express-generator ,这将为你安装它。
C:node>npm install -g express-generator
接下来,让我们继续使用我们新安装的Express Generator创建一个新的Express项目。你所要做的就是输入express ,然后再输入你要创建的项目的名称。我们将创建一个名为expressjs-tutorial 的项目。你会看到,当生成器工作时,它会给你一些输出,告诉你它为你的项目创建的确切文件和文件夹。
C:node>express expressjs-tutorial
warning: the default view engine will not be jade in future relea
warning: use `--view=jade' or `--help' for additional options
create : expressjs-tutorial
create : expressjs-tutorialpublic
create : expressjs-tutorialpublicjavascripts
create : expressjs-tutorialpublicimages
create : expressjs-tutorialpublicstylesheets
create : expressjs-tutorialpublicstylesheetsstyle.css
create : expressjs-tutorialroutes
create : expressjs-tutorialroutesindex.js
create : expressjs-tutorialroutesusers.js
create : expressjs-tutorialviews
create : expressjs-tutorialviewserror.jade
create : expressjs-tutorialviewsindex.jade
create : expressjs-tutorialviewslayout.jade
create : expressjs-tutorialapp.js
create : expressjs-tutorialpackage.json
create : expressjs-tutorialbin
create : expressjs-tutorialbinwww
change directory:
> cd expressjs-tutorial
install dependencies:
> npm install
run the app:
> SET DEBUG=expressjs-tutorial:* & npm start
在这个例子中,我们现在使用Visual Studio Code,选择 "Open Folder "选项来打开刚刚创建的文件夹。

Package.json
作为项目创建的一部分,Express Generator填写了一个package.json文件,该文件提供了在Express中创建一个骨架程序所需的依赖性列表。
package.json
{
"name": "expressjs-tutorial",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.3",
"debug": "~2.6.9",
"express": "~4.16.0",
"http-errors": "~1.6.2",
"jade": "~1.11.0",
"morgan": "~1.9.0"
}
}
这些依赖项还没有安装,所以你需要换到存放package.json的目录中,并运行 npm install来完成这一过程。
C:node>cd expressjs-tutorial
C:nodeexpressjs-tutorial>npm install
一旦这个步骤完成,你现在就会有一个node_modules文件夹,它实际上保存了所有这些刚刚用npm下载到你机器上的依赖项。

启动Express!
你已经准备好启动Express应用程序了。要做到这一点,只需在项目的根部输入npm start。
C:nodeexpressjs-tutorial>npm start
> expressjs-tutorial@0.0.0 start C:nodeexpressjs-tutorial
> node ./bin/www
现在,继续打开你的浏览器,在http://localhost:3000/,看看吧

bin/www 和app.js 文件
这两个文件在Express应用程序中是非常重要的,所以让我们快速看一下它们为我们做什么。
www 服务器文件
/bin/www 文件是 Express 的应用程序入口。它所做的第一件事就是要求() "真正的 "应用程序入口,也就是app.js,它设置并返回 express() 应用程序对象。下面是该文件中包含的代码。
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('expressjs-tutorial:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* 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)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return 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;
// handle specific listen errors with friendly messages
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);
}
下面是Express中的bin/www服务器文件的一些快速启示。
var app = require('.../app');app文件在这里被加载。
var debug = require('debug')('expressjs-tutorial:server');设置服务器调试和名称。
var http = require('http');Load the http module that we learned about in thehtml rendering tutorial.
var port = normalizePort(process.env.PORT || '3000');将'3000'的字符串值变成一个整数。
app.set('port', port);设置应用程序应使用的监听端口。
var server = http.createServer(app);像我们在Node路由教程中看到的那样创建服务器。
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);设置了监听以及错误和监听事件。
app.js 文件
app.js文件创建了一个Express应用程序对象,按惯例命名为app,并通过各种设置和中间件设置了该应用程序。然后,它从模块中导出应用程序。下面是app.js文件中的代码。
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
在文件的顶部,有几个导入,Express需要它们来进行工作。
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
这是Express在你第一次用Express Generator创建项目时提供的两个示例路由。
var app = express();
应用程序在这里被创建。
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');在这里你可以配置使用的模板引擎。默认情况下,它使用Jade。

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser());这里是指定logger、json、urlencoded和cookie解析器的中间程序。
**app.use(express.static(path.join(__dirname, 'public')));**如何在Express中设置公共文件夹。

app.use('/', indexRouter);
app.use('/users', usersRouter);这里指定了/ 和/users 的基本路由。
检查index.js 和users.js 路由文件
我们可以看到,在app.js文件中,如果一个用户请求/ 路由,那么indexRouter就会被这个代码使用app.use('/', indexRouter); 。现在indexRouter实际上持有index.js中包含的内容。这是由var indexRouter = require('./routes/index'); ,让我们看一下那个文件。
routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
这里是行动开始发生的地方。在文件的顶部,express router被要求并被初始化到router 这个变量中。之后,我们可以看到,一个get()函数被调用。该函数接受两个参数。
第一个参数是路由的路径。当然,在这种情况下,它只是/ 或主页。
第二个参数是一个函数,它本身需要三个参数。这个函数接收请求、响应和下一个参数。
在这个函数中,对render()进行了调用。我们可以看到,"index "是第一个参数。这是说要在views文件夹中寻找一个扩展名为index的文件。在views文件夹中,有一个index.jade文件。这就是被引用的文件。render()函数的第二个参数是一个JavaScript对象。正是在这个对象中,变量数据可以在渲染过程中传递给视图。事实上,让我们对这个文件做一个快速的修改。
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'I am learning Express!' });
});
module.exports = router;
在命令行中输入ctrl-c,重新启动应用程序。
Terminate batch job (Y/N)? y
用npm start重新启动
C:nodeexpressjs-tutorial>npm start
一旦服务器重启,你可以看到,通过更新JavaScript对象的标题属性,我们的数据在网络浏览器中被更新。

关键的概念是,我们正在渲染一个模板文件,并将动态数据传入该文件,以便在视图中使用。这个概念在许多不同的框架和许多不同的编程语言中都是一样的。
子路线
现在我们可以看一下 users.js 文件。
users.js
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
注意到什么了吗?users.js文件使用的是相同的/ 路径。这怎么可能呢?这是因为在app.js中,已经定义了/users 将使用 users.js。因此,在users.js中,我们不需要指定完整的/users路径。事实上,如果我们这样做,那就等于/users/users ,这不是我们想要的。关键是在实际路由文件中看到的路径是相对于app.js中指定的路径。为了了解这一点,我们可以向users.js添加另一个路由。
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function (req, res, next) {
res.send('respond with a resource');
});
router.get('/stats', function (req, res, next) {
res.send('Stats about the user');
});
module.exports = router;
这样做的目的是建立一个新的路由,可以访问http://localhost:3000/users/stats

单一文件路由
我们现在看到了路由在新安装的Express.js上是如何工作的。也许你更希望有一个单一的入口,把你所有的路由放在一个文件中。如果你愿意,你也可以这样做。让我们来看看怎么做。
首先,从app.js中删除var usersRouter = require('./routes/users'); 。

接下来,从app.js中删除app.use('/users', usersRouter); 。

最后,你可以像这样把所有的路由合并到index.js文件中。
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', {
title: 'I am learning Express!'
});
});
/* GET users listing. */
router.get('/users', function (req, res, next) {
res.send('respond with a resource');
});
router.get('/users/stats', function (req, res, next) {
res.send('Stats about the user');
});
module.exports = router;
但是请注意,当把所有的路由放在同一个文件中时,我们需要指定完整的路径,而不是把每个路由放在自己的文件中。这两种方法都可以,这取决于什么对你和你的需求最有意义。我们现在看到了一个基本骨架的Express应用程序是如何设置的,以及它是如何工作的。
Express.js初学教程总结
你现在已经使用Express Generator创建了一个骨架网站项目,并确认它使用node运行。通过查看为我们创建的文件和文件夹,你也明白了一个Express应用程序是如何结构化的。这里有一些关于Express和Node的关键话题需要记住。
- Express通过遵循请求处理管道架构来工作
- 一个Express应用程序主要是一个中间件函数的集合,所有的中间件函数都在一起工作。
- 一个中间件函数是一个接受请求对象的函数,它要么终止请求/响应周期,要么将控制权传递给另一个中间件函数。
- Express有几个内置的中间件功能
- json(): 用来解析带有JSON有效载荷的请求正文。
- urlencoded(): 用来解析带有URL编码的有效载荷的请求正文。
- static(): 用来提供静态文件
- 任何人都可以创建自定义中间件并在请求处理管道中使用它
// Custom middleware (applied on all routes)
app.use(function(req, res, next)) {
// …
next();
}
// Custom middleware (applied on routes starting with /api/v1)
app.use(‘/api/v1’, function(req, res, next)) {
// …
next();
}