在线试读

get_product_contenthtml

1章  安装和使用Express

Express是一个精简、灵活的Node.js的Web应用程序开发框架,为Web和移动应用程序提供了一组强大的功能。它是Node.js中流行的Web开发框架,被大多数开发人员所使用。使用Express可以快速地开发一个Web应用,其他的开发框架也都是基于Express构建的。

1.1  安装Express

要安装Express,首先要具备Node.js环境,也就是说你已经安装了Node.js。

安装Express非常简单,使用Node.js的配套工具npm命令即可安装:

$ npm install -g express-generator

npm命令运行完毕,再运行命令:

$ express --version

如果能够看到Express的版本号,证明Express已经安装成功。截至本书写完,Express的版本号是4.16.0。

$ express --version

$ 4.16.0

其实这里安装的是一个应用生成器工具——express-generator ,通过它可以快速创建一个应用的骨架,为快速创建Node.js项目提供便利。

1.2  使用Express创建项目

在安装完Express之后,就可以使用Express命令来创建一个新的项目了。

1.2.1  创建项目

使用Express创建项目非常简单,具体步骤如下:

(1)按WIN R键打开“运行”对话框,输入cmd命令,单击“确定”按钮打开命令行窗口,如图1-1所示。

图1-1  命令行窗口

(2)进入工作目录,可以自定义一个工作目录,如下:

$ e:

$ cd express/code

(3)执行,创建一个名为hello的Express项目:

$ express hello

(4)此时可以看到它会自动执行,图1-2代表创建成功。

图1-2  Express创建hello项目

(5)创建成功之后会在code目录下出现一个名叫hello的目录,进入hello目录,然后安装依赖包:

$ cd hello

$ npm install

(6)安装完毕之后,执行命令启动应用:

$ npm start

(7)应用启动后,在浏览器中输入http://localhost:3000/ 网址就可以看到名叫hello的这个应用了,如图1-3所示。

图1-3  Express默认应用启动界面

1.2.2  Express项目结构分析

项目正常启动后,我们用开发工具打开hello项目看一下它的目录结构,如图1-4所示。

图1-4  Express默认应用的目录结构

项目结构不太复杂是不是?相比较其他语言的框架来说很轻量,这也是Node.js快速开发的一个特色。

目录结构中的文件及其作用如表1-1所示。

表1-1  Express默认应用中的文件及其作用

目录名/文件名

类    型

作    用

bin

目录

服务器脚本默认目录

bin/www.js

文件

服务器默认脚本,即启动服务脚本

node_modules

目录

依赖包安装目录,用于存放依赖包

public

目录

静态资源目录,用于存放静态资源

routes

目录

路由目录,用于存放路由文件

routes/index.js

文件

首页路由文件

routes/users.js

文件

用户路由文件

views

目录

页面目录,用于存放页面文件

views/error.jade

文件

错误页面

views/index.jade

文件

首页

views/layout.jade

文件

页面共用布局

app.js

文件

应用主文件

package.json

文件

项目配置文件

package-lock.json

文件

锁定的项目配置文件

1.2.3  应用主文件app.js

app.js文件相当于项目启动的主入口文件,有一些公共方法和服务器配置等信息。代码分析如下:

var createError = require('http-errors');           // http错误处理模块

var express = require('express');                   // 引入Express

var path = require('path');                         // 引入path

var cookieParser = require('cookie-parser');        // 引入cookie处理对象

var logger = require('morgan');                     // 引入日志模块

var indexRouter = require('./routes/index');    // 引入路由目录中的index.js文件

var usersRouter = require('./routes/users');    // 引入路由目录中的users.js文件

var app = express();                                // 创建Express应用

app.set('views', path.join(__dirname, 'views'));    // 定义页面目录

app.set('view engine', 'jade');                     // 定义页面模板引擎

app.use(logger('dev'));                             // 定义日志打印级别

app.use(express.json());                            // 定义JSON格式处理数据

// 定义使用urlencode处理数据及querystring模块解析数据

app.use(express.urlencoded({ extended: false }));

app.use(cookieParser());                        // 定义使用cookie处理对象

// 定义静态资源目录public

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);                      // 定义指向index.js的路由

app.use('/users', usersRouter);                 // 定义指向users.js的路由

// 定义404错误处理

app.use(function(req, res, next) {

  next(createError(404));

});

// 定义其他错误处理

app.use(function(err, req, res, next) {

  // 设置locals,只在开发环境生效

  res.locals.message = err.message;

  res.locals.error = req.app.get('env') === 'development' ? err : {};

  res.status(err.status || 500);            // 返回错误http状态码

  res.render('error');                          // 渲染错误页面

});

module.exports = app;

1.3  Express路由

接触到一款框架,首先要熟悉的就是它的路由。路由是指应用程序的端点(URI)如何响应客户端请求。通俗来说,就是定义什么路径来访问。

1.3.1  GET请求路由

在Express中定义路由特别简单。首先来看一下routes目录中的index.js路由文件,也就是首页路由文件,它是一个GET请求路由,如下:

var express = require('express');           // 引入Express

var router = express.Router();              // 引入Express路由对象

//首页路由

router.get('/', function(req, res, next) {

  res.render('index', { title: 'Express' });

});

module.exports = router;                    // 导出路由

首页路由文件很简单,其中也只定义了一个根目录的路由。

将其中的代码:

res.render('index', { title: 'Express' });

更换成如下代码:

res.render('index', { title: Hello});

保存文件,重新运行npm start命令,用浏览器打开http://localhost:3000查看效果,因为在浏览器地址栏中输入地址发送的请求默认是GET请求,所以可以得到如图1-5所示的结果。

可以看到,之前的Express被换成了Hello。

前面的一段代码定义了首页的路由,这个路由定义的是GET请求,请求的是“/”路径,也就是根路径。接着后面跟着一个方法,当用户发送GET请求根路径的时候,就进入这个方法中,在这个方法中可以进行一些对请求的操作。

图1-5  将Express更改成Hello的运行效果

Express默认的首页方法中使用了res.render()方法,该方法的作用是渲染页面。其个参数就是页面的文件名,这里对应的就是views目录中的index.jade文件;第二个参数是传入到页面文件的对象,可以将数据渲染到页面上。

1.3.2  自定义路由

分析过首页路由之后,可以试着自己写一个路由。在index.js路由文件中添加如下代码:

// 定义一个GET请求“/world”的路由,执行方法

router.get('/world', function(req, res, next) {

  res.render('index', { title: 'Hello World' });    // 渲染index页面

});

将项目重新启动,打开浏览器请求地址http://localhost:3000/world,会看到新的页面,如图1-6所示。

图1-6  Hello World路由演示效果

新定义的路由生效了,是不是很简单呢?

但是每次更改过路由文件都要重新启动项目才会生效,如此,开发效率不太高。在这里,给大家推荐一个工具——nodemon,其安装方式也是利用npm命令:

npm install -g nodemon

安装完成之后,修改项目根目录中的package.json文件,将其中的

"scripts": {

  "start": "node ./bin/www"

},

修改成:

"scripts": {

  "start": "nodemon ./bin/www"                          // 使用nodemon运行

},

然后再执行npm start命令启动项目,这样在路由文件被更改并保存之后,会自动重启项目,并可以立刻在浏览器中看到更改后的运行结果。

1.3.3  其他请求方式的路由

HTTP请求方式除了GET之外,还有POST、PUT等其他方式。类似于GET请求的路由编写方式,其他请求方式也换成相应的router方法,如下:

// POST请求方式

router.post('/world', function(req, res, next) {

  res.render('index', { title: 'Hello World' });    // 渲染index页面

});

// PUT请求方式

router.put('/world', function(req, res, next) {

  res.render('index', { title: 'Hello World' });    // 渲染index页面

});

// DELETE请求方式

router.delete('/world', function(req, res, next) {

  res.render('index', { title: 'Hello World' });    // 渲染index页面

});

大家可以自己尝试一下相应的请求方式。

1.3.4  路由匹配规则

前面演示的路由匹配都是完整匹配,即定义“/world”,在浏览器中要输入“/world”才能匹配到。

在Express中,除了完整匹配,还支持模糊匹配,例如:

 

router.get('/wes?t', function(req, res, next) {

  res.render('index', { title: 'Hello World' });

});

在浏览器中查看,会发现当请求http://localhost:3000/west和http://localhost:3000/wet时都可以成功。

同样,模糊匹配还可以按如下处理:

// 能够匹配/west、/weest、/weeest等

router.get('/we st', function (req, res, next) {

  res.render('index', { title: 'Hello World' });

})

// 能够匹配/west、/wt

router.get('/w(es)?t', function (req, res, next) {

  res.render('index', { title: 'Hello World' });

})

// 能够匹配/west、/we123st、/wexxxst等

router.get('/we*st', function (req, res, next) {

  res.render('index', { title: 'Hello World' });

})

// 能够匹配/west、/we123st、/wexxxst等

router.get('/we*st', function (req, res, next) {

  res.render('index', { title: 'Hello World' });

})

同时,Express路由还支持正则表达式,如下:

// 能够匹配路径中包含west的任何内容,如/west、/aawest、/westee等

router.get(/west/, function (req, res, next) {

  res.render('index', { title: 'Hello World' });

})

1.3.5  中间件

在项目开发过程中,有时会需要用共同的方法来拦截请求,比如需要对请求做一些身份验证。

如果接口是一个或两个的话,可以在某个接口的处理方法中进行验证,但是如果很多接口都需要进行验证的话,就不可能在每一个需要验证的接口上都添加一套代码,那样既费时又费力。为了提高效率,需要将验证的方法单独提出来。

Express提供了一个很好的工具,即中间件。可以在中间件中定义一个验证方法,然后在需要验证的接口路由上添加验证中间件,完成接口的验证。

那么什么是中间件呢?这里的中间件是一些处理方法的合集。Express其实就是一个路由和中间件合成的Web框架。

在前面说过,当前端请求路由的时候,会进入后面的路由处理方法中打开前面的index.js路由文件,查看根路径的路由:

router.get('/', function(req, res, next) {

  res.render('index', { title: 'Express' });

});

当前端使用GET方法请求根路径的时候,会进入第二个参数function中,而这个路由处理方法就是Express中的中间件。

Express的中间件函数可以让我们访问请求对象Request、响应对象Response及下一个中间件函数。其中,下一个中间件函数通常声明为next。

在Express中,中间件会被Express传入3个参数,如表1-2所示。

表1-2  Express中间件的3个参数

参 数 顺 序

参    数

描    述

1

req

请求数据对象Request

2

res

返回数据对象Response

3

next

下一步函数

为了实现上述验证功能,可以在路由处理方法之前也就是中间件之前再加一个方法,例如:

// 定义一个GET请求

router.get('/car', function(req, res, next){

  console.log ('这里是中间件');           // 打印日志,方便查看

  next();                               // 继续下一步,下一个中间件

}, function(req, res, next) {

  res.send('这里是返回');                 // 向页面发送数据

});

在router.get()方法中,在前面定义的路由处理方法之前又传入了一个方法,这时使用浏览器访问http://localhost:3000/car,会看到控制台中打印出“这里是中间件”,同时浏览器的页面上展示出“这里是返回”。

在中间件中可以做很多事情,在后面的实战项目演示中大家将会经常见到它。