文档章节

使用Express初体验

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:20
字数 2927
阅读 2
收藏 0
点赞 0
评论 0

十一小长假,学习了一下比较流行的网站开发技术:NodeJS+Express+MongoDB,记录一下初入门感觉。


我安装的软件版本是:

Node : v6.3.1
Express: 4.13.4
MongoDB: 3.2.4

接下来,我们新建一个工程,在命令行中输入:

$ express -e blog
$ cd blog && npm install

初始化一个 express 项目并安装所需模块,如下图所示:


然后运行:

DEBUG=blog:* npm start

但一般,我个人习惯我们会把运行程序的命令写到一个shell里面,如下:

#!/usr/bin/env bash

DEBUG=blog:* npm start

启动项目,此时命令行中会显示 blog Express server listening on port 3000 +0ms ,在浏览器里访问 localhost:3000,会显示如下图所示结果:


至此,我们用 express 初始化了一个项目工程,并指定使用 ejs 作为模板引擎(命令行中的 -e 参数),下面具体讲解工程的内部结构。

我们打开刚刚创建的 blog 文件夹,里面如图所示:


接下来,具体解释每一个文件在工程中的作用:

app.js: 启动文件,或者说入口文件。

package.json: 存储着工程的信息及模块依赖,当在 dependencies 中添加依赖的模块时, 运行 npm install ,npm 会检查当前目录下的 package.json,并自动安装所有指定的模块。

node_modules: 存放 package.json 中安装的模块,当你在 package.json 添加依赖的模块并安装后,存放在这个文件夹下。

public: 存放 image、css、js 等文件。

routes: 存放路由文件。

views: 存放视图文件或者说模板文件。

bin: 存放可执行文件。

现在,我们打开 app.js 文件,来看看里面具体有哪些代码:

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

这里我们通过 require() 加载了 express、path 等模块,以及 routes 文件夹下的 index.js 和 user.js 路由文件。下面解释每一行代码的含义:

(1) var app = express()

生成一个 express 实例 app。

(2) app.set('view', path.join(dirname, 'views'))

设置 views 文件夹为存放视图文件的目录,即存放模板文件的地方,dirname 为全局变量,存储当前正在执行的脚本所在的目录。

(3) app.set('view engine', 'ejs')

设置视图模板引擎为 ejs 。

(4) app.use(favicon(dirname + '/public/favicon.ico'))

设置 /public/favicon.ico 为 favicon 图标。

(5) app.use(logger('dev'))

加载日志中间件

(6) app.use(bodyParser.json())

加载解析 json 的中间件。

(7) app.use(bodyParser.urlencoded({ extended: false }))

加载解析 urlencoded 请求体的中间件。

(8) app.use(cookieParser())

加载解析 cookie 的中间件。

(9) app.use(express.static(path.join(dirname, 'public')))

设置 public 文件夹为存放静态文件的目录。

(10) app.use('/', routes)和app.use('/users', users)

路由控制。

(11)

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

捕获404错误,并转发到错误处理器。

(12)

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

开发环境下的错误处理器,将错误信息渲染 error 模板并显示到浏览器中。

(13)

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

生产环境下的错误处理器,将错误信息渲染 error 模板并显示到浏览器中。

(14) module.exports = app

导出 app 实例供其他模板调用。

接下来我们再看看 bin/www 文件:

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('blog: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);
}

接下来我们解释一下文件中的每一行代码:

(1) #!/usr/bin/env node

表明这是一个 node 可执行文件。

(2) var debug = require('debug')('blog:server')

引入 debug 模块,打印调试日志。

(3) var app = require('../app')

引入我们上面导出的 app 实例。

(4)

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

设置端口号。

(5) var server = http.createServer(app)

创建 HTTP 服务。

(6)

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

启动工程并监听 3000 端口。

接下来我们学习 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 模块,然后生成一个路由实例用来捕获访问主页的 GET 请求,导出这个路由并在 app.js 中通过 app.use('/', routes) 加载。这样,当访问主页时,就会调用 res.render('index', {title: 'Express'}) 渲染 views/index.ejs 模板并显示到浏览器中。

接下来,我们可以看看 views/index.ejs 文件:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

在渲染模板时,我们传入了一个变量 title 值为 express 字符串,模板引擎将所有 <%= title %> 替换为 express,然后将渲染后生成的html显示到浏览器中,如上图网页显示。

至此,我们大致了解了如何创建一个工程并且一些基础,接下来我们学习 express 的基本使用及路由控制。

路由控制

工作原理

先来查看一下 routes/index.js 文件中的主要路由分配代码:

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

这段代码的意思是当访问主页时,调用 ejs 模板引擎,来渲染 index.ejs 模板文件(即将 title 变量全部替换为字符串 Express),生成静态页面并显示在浏览器中。

接下来,我们学习一下路由添加规则,当我们访问 localhost:3000 时,会显示:


但是,当我们访问 localhost:3000/asdf 这种不存在的页面时,就会显示:


为什么会显示这个呢?因为我们在路由规则中,不存在 /asdf 的路由规则,而且它也不是一个 public 目录下的文件,所有 express 返回了 404 Not Found 的错误。下面我们来添加这条路由规则,使得当访问 localhost:3000/asdf 时,页面显示 Hello World! 。

注意:以下路由修改仅用于测试,看到效果后把代码还原回来。

修改 index.js,在路由规则中添加一条路由规则:

router.get('/asdf', function(req, res, next) {
  res.send('Hello World!');
});

重启之后,重新访问 localhost:3000/asdf 页面显示如下:


有没有感觉添加路由规则很简单啊,自己动手试试吧。

模板引擎

先来解释一下,什么是模板引擎:模板引擎(Template Engine)是一个将页面模板和要显示的数据结合起来生成HTML页面的工具。如果说上面讲到的 express 中的路由控制方法相当于 MVC 中的控制器的话,那模板引擎就相当于 MVC 中的视图。

模板引擎的功能是将页面模板和要显示的数据结合起来生成 HTML 页面。它既可以运 行在服务器端又可以运行在客户端,大多数时候它都在服务器端直接被解析为 HTML,解析完成后再传输给客户端,因此客户端甚至无法判断页面是否是模板引擎生成的。有时候模板引擎也可以运行在客户端,即浏览器中,典型的代表就是 XSLT,它以 XML 为输入,在客户端生成 HTML 页面。但是由于浏览器兼容性问题,XSLT 并不是很流行。目前的主流还是由服务器运行模板引擎。 在 MVC 架构中,模板引擎包含在服务器端。控制器得到用户请求后,从模型获取数据,调用模板引擎。模板引擎以数据和页面模板为输入,生成 HTML 页面,然后返回给控制器,由控制器交回客户端。
——《Node.js开发指南》

那么,什么是 ejs 呢?

ejs 是模板引擎的一种,也是我们这个教程中使用的模板引擎,因为它使用起来十分简单,而且与 express 集成良好。

使用模板引擎

前面我们通过以下两行代码设置了模板文件的存储位置和使用的模板引擎:

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

注意:我们通过 express -e blog 只是初始化了一个使用 ejs 模板引擎的工程而已,比如 node_modules 下添加了 ejs 模板,views 文件夹下有 index.ejs 。并不是说强制该工程只能使用 ejs 不能使用其他的模板引擎,比如 jade ,真正指定使用哪个模板引擎的是 app.set('view engine', 'ejs') 。

在 routes/index.js 中通过调用 res.render() 渲染模板,并将其产生的页面直接返回给客户端。它接受两个参数,第一个是模板的名称,即 views 目录下的模板文件名,扩展名 .ejs 可选。第二个参数是传递给模板的数据对象,用于模板翻译。

接下来,我们看看 views/index.ejs 中的代码:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

当我们 res.render('index', {title: 'Express'}); 时,模板引擎会把 <%= title %> 替换成 Express,然后把替换成的页面显示给用户。

渲染后生成的页面代码为:

<!DOCTYPE html>
<html>
  <head>
    <title>Express</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1>Express</h1>
    <p>Welcome to Express</p>
  </body>
</html>

注意:我们通过 app.use(express.static(path.join(__dirname, 'public'))) 设置了静态文件目录为 public 文件夹,所以上面代码中的 href = '/stylesheets/style.css' 就相当于 href = 'public/stylesheets/style.css' 。

ejs 的标签系统非常简单,它只有以下三种标签:

  • <% code %>: JavaScript 代码。
  • <%= code %>: 显示替换过 HTML 特殊字符的内容。
  • <%- code %>: 显示原始 HTML 内容。

注意:<%= code %> 和 <%- code %> 的区别,当变量 code 为普通字符串时,两者没有区别。当 code 比如为 <h1> hello </h1> 这种字符串时,<%= code %> 会原样输出 <h1> hello </h1> ,而 <%- code %> 则会直接显示 H1 大小的 hello 字符串。

我们还可以在 <% %> 内使用 JavaScript 代码。下面是 ejs 的官网实例:

The Data
supplies: ['mop', 'broom', 'duster']
The Template
<ul>
<% for(var i=0; i<supplies.length; i++) {%>
   <li><%= supplies[i] %></li>
<% } %>
</ul>
The Result
<ul>
  <li>mop</li>
  <li>broom</li>
  <li>duster</li>
</ul>

我们可以用上述三种标签实现页面模板系统能实现的任何内容。

页面布局

这里我们不使用 layout 进行页面布局,而是使用更为简单灵活的 include 。include 的简单使用如下:

index.ejs

<%- include a %>
hello,world!
<%- include b %>

a.ejs

this is a.ejs

b.ejs

this is b.ejs

最终 index.ejs 会显示:

this is a.ejs
hello, world!
this is b.ejs

至此,我们学习完了模板引擎的相关知识。

接下来,我们利用Express实现一个简单的博客功能


Reference:

Express入门教程:一个简单的博客

本文转载自:http://www.jianshu.com/p/2c0ed2dcb768

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2139
码字总数 82983
作品 0
程序员
API网关express-gateway初体验

昨天朋友发来一个消息,问我express源码中的一个问题,我去看了一番源码以后,发现自己并不是很懂,只能看懂一些字面意思... 不过在聊天过程中,了解到他们公司在用express做api网关,什么是...

趁你还年轻233 ⋅ 04/03 ⋅ 0

微软数据库服务器--SQL Server

SQL Server Express Edition 是 MSDE 的下一个版本,它是免费、易于使用、可嵌入的 SQL Server 2005 轻型版本。可免费下载、重新发布、嵌入,便于新的开发人员立即使用。SQL Server Express ...

匿名 ⋅ 2009/03/23 ⋅ 3

Nodejs架构之Express初体验

参考:http://www.cnblogs.com/Darrencode/p/express4.html 本文是基于 node 0.12.7 express 4.13.1 1)安装 npm install -g expressnpm install -g express-generator 2)创建项目 express ......

cs_sharp ⋅ 2015/09/07 ⋅ 0

SQL SERVER FOR LINUX初体验

今天得空,就在Ubuntu17.04上安装了SQL SERVER 2017体验下,总体来说还是不错的。 SQL SERVER 2017 在Ubuntu上安装SQL SERVER 2017还是比较方便的,只需几条命令即可: 目前,在安装SQL SER...

雪飞鸿 ⋅ 2017/08/20 ⋅ 0

koahubjs 1.0.0 发布,基于 Koa.js 快速开发框架

koahubjs 发布 1.0.0 正式版,基于 Koa.js 的快速开发框架。 KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架。可以直接在项目里使用 ES6/7(Generator Function, Class, Async ...

einsqing ⋅ 2017/01/07 ⋅ 6

Cody 更新到 Express 4.x

Cody 更新到 Express 4.x,cody 是一个使用 Node.js 开发的CMS系统,这是一个由 比利时 根特大学 布鲁日校区howest(猜测是一个学院的名称)的教授和学生开发的一个项目,他们已经把这个项目...

糊涂茶 ⋅ 2014/08/25 ⋅ 1

Angular2

angular 可重用结构建议 angular 可重用结构建议,非常用价值 掌握 Angular2 的服务 (service) step by step 使用 Angular 构建 Progressive Web Apps(Google 开发者大会演讲 PPT & 视频) ...

掘金官方 ⋅ 01/05 ⋅ 0

基于 Node.js 的内容管理系统--DoraCMS

DoraCMS 使用的技术栈: 1、vue + vuex + vue-router 全家桶 2、webpack 2 3、nodejs 8.0 + express 4 4、mongodb 3+ 演示地址: 前端开发俱乐部 后台登录: https://www.html-js.cn/dr-admi...

doramart ⋅ 2015/08/18 ⋅ 2

IBM软件开发协作平台--Jazz

Jazz 是 IBM Rational 面向软件交付技术的下一代协作平台。Jazz 平台专门面向全球化和跨地域团队开发,通过这一全新的平台,地理上分隔的开发人员将能互相协作,共同构建软件。从而使得软件交...

匿名 ⋅ 2010/03/16 ⋅ 2

Windows 8 - 安装Visual Studio 11(硬盘吃紧)

I:Visual Studio 11 开发者预览版下载(附离线下载) Web安装下载, 离线安装下载 分块1 分块2 分块3 II:安装Visual Studio 11 开发者预览版 安装前磁盘大小情况 下面开始点击Web安装文件了(建议...

晨曦之光 ⋅ 2012/06/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

开启Swarm集群以及可视化管理

在搭建的两台coreos服务器上开启swarm集群 前置条件: docker均开启2375端口 同一个局域网内 主服务器上安装Portainer容器 安装Portainer容器执行: docker run -d -p 9000:9000 --restart=a...

ykbj ⋅ 6分钟前 ⋅ 0

单例设计模式

1、单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例 2、饿汉式单例类 在这个类被加载时,静态变量instance会被初始化,此时类的私有构造子会被调用 饿汉式是典型...

职业搬砖20年 ⋅ 11分钟前 ⋅ 0

前端基础(四):前端国际规范收集

字数:1142 阅读时间:5分钟 前言 由于前端技术的灵活性和杂乱性,导致网上的许多解决方案不够全面甚至是完全错误,容易起到误导作用。所以,我对搜索到的解决方案往往是存疑态度。那么,如何...

老司机带你撸代码 ⋅ 14分钟前 ⋅ 0

Failed to open/create Network-VirtualBox Host-Only

虚拟机版本 : Oracle Vm VirtualBox 5.2.12 报错时机:开网卡二,重启虚拟机报错 "Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Ada......

p至尊宝 ⋅ 17分钟前 ⋅ 0

三分钟学会如何在函数计算中使用 puppeteer

摘要: 使用 puppeteer 结合函数计算,可以快速的构建弹性的服务完成各种功能,包括:生成网页截图或者 PDF、高级爬虫,可以爬取大量异步渲染内容的网页、模拟键盘输入、表单自动提交、登录网...

阿里云云栖社区 ⋅ 20分钟前 ⋅ 0

springMVC接收表单时 Bean对象有Double Int Char类型的处理

前台ajax提交表单price为double类型 后台controller就介绍不到 400错误 前台 实体类: public class ReleaseMapIconConfig{ private String id; private long maxValue; private long minVal......

废柴 ⋅ 22分钟前 ⋅ 0

ZOOKEEPER安装

工作需要在ubuntu上配置了一个zookeeper集群,有些问题记录下来。 1. zookeeper以来java,所以首先要安装java。但是ubuntu系统有自带的jdk,需要通过命令切换java版本: $ sudo update-alter...

恰东 ⋅ 25分钟前 ⋅ 0

linux 进程地址空间的一步步探究

我们知道,在32位机器上linux操作系统中的进程的地址空间大小是4G,其中0-3G是用户空间,3G-4G是内核空间。其实,这个4G的地址空间是不存在的,也就是我们所说的虚拟内存空间。 那虚拟内存空间...

HelloRookie ⋅ 26分钟前 ⋅ 0

myatis #{}与${}区别及原理

https://blog.csdn.net/wo541075754/article/details/54292751

李道福 ⋅ 29分钟前 ⋅ 0

三分钟学会如何在函数计算中使用 puppeteer

摘要: 使用 puppeteer 结合函数计算,可以快速的构建弹性的服务完成各种功能,包括:生成网页截图或者 PDF、高级爬虫,可以爬取大量异步渲染内容的网页、模拟键盘输入、表单自动提交、登录网...

猫耳m ⋅ 30分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部