Express使用手记:核心入门
入门简介
Express是基于nodejs的web开发框架。优点是易上手、高性能、扩展性强。
- 易上手:nodejs最初就是为了开发高性能web服务器而被设计出来的,然而相对底层的API会让不少新手望而却步。express对web开发相关的模块进行了适度的封装,屏蔽了大量复杂繁琐的技术细节,让开发者只需要专注于业务逻辑的开发,极大的降低了入门和学习的成本。
- 高性能:express仅在web应用相关的nodejs模块上进行了适度的封装和扩展,较大程度避免了过度封装导致的性能损耗。
- 扩展性强:基于中间件的开发模式,使得express应用的扩展、模块拆分非常简单,既灵活,扩展性又强。
环境准备
首先,需要安装nodejs,这一步请自行解决。接着,安装express的脚手架工具express-generator
,这对于我们学习express很有帮助。
npm install -g express-generator
第一个demo
利用之前安装的脚手架工具,初始化我们的demo项目。
/tmp mkdir express-demo
/tmp cd express-demo
express-demo express
create : .
create : ./package.json
create : ./app.js
create : ./public
create : ./public/javascripts
create : ./public/images
create : ./public/stylesheets
create : ./public/stylesheets/style.css
create : ./routes
create : ./routes/index.js
create : ./routes/users.js
create : ./views
create : ./views/index.jade
create : ./views/layout.jade
create : ./views/error.jade
create : ./bin
create : ./bin/www
install dependencies:
$ cd . && npm install
run the app:
$ DEBUG=express-demo:* npm start
按照指引,安装依赖。并启动服务
npm install
然后,启动服务器。
express-demo npm start
> ex1@0.0.0 start /private/tmp/ex1
> node ./bin/www
访问浏览器,迈出成功的第一步。
目录结构介绍
看下demo应用的目录结构。大部分时候,我们的应用目录结构跟这个保持一致就可以了。也可以根据需要自行调整,express并没有对目录结构进行限制。
从目录结构可以大致看出,express应用的核心概念主要包括:路由
、中间件
、模板引擎
。
express-demo tree -L 1
.
├── app.js # 应用的主入口
├── bin # 启动脚本
├── node_modules # 依赖的模块
├── package.json # node模块的配置文件
├── public # 静态资源,如css、js等存放的目录
├── routes # 路由规则存放的目录
└── views # 模板文件存放的目录
5 directories, 2 files
核心概念简介
上面提到,express主要包含三个核心概念:路由、中间件、模板引擎。
注意,笔者这里用的是
核心概念
这样的字眼,而不是核心模块
,为什么呢?这是因为,虽然express的中间件有它的定义规范,但是express的内核源码中,其实是没有所谓的中间件这样的模块的。
言归正传,三者简要的来说就是。
中间件
:可以毫不夸张的说,在express应用中,一切皆中间件。各种应用逻辑,如cookie解析、会话处理、日志记录、权限校验等,都是通过中间件来完成的。路由
:地球人都知道,负责寻址的。比如用户发送了个http请求,该定位到哪个资源,就是路由说了算。模板引擎
:负责视图动态渲染。下面会介绍相关配置,以及如何开发自己的模板引擎。
核心概念:路由
路由分类
粗略来说,express主要支持四种类型的路由,下面会分别举例进行说明
- 字符串类型
- 字符串模式类型
- 正则表达式类型
- 参数类型
分别举例如下,细节可参考官方文档。
var express = require('express');
var app = express();
// 路由:字符串类型
app.get('/book', function(req, res, next){
res.send('book');
});
// 路由:字符串模式
app.get('/user/*man', function(req, res, next){
res.send('user'); // 比如: /user/man, /user/woman
});
// 路由:正则表达式
app.get(/animals?$/, function(req, res, next){
res.send('animal'); // 比如: /animal, /animals
});
// 路由:命名参数
app.get('/employee/:uid/:age', function(req, res, next){
res.json(req.params); // 比如:/111/30,返回 {"uid": 111, "age": 30}
});
app.listen(3000);
路由拆分
当你用的应用越来越复杂,不可避免的,路由规则也会越来越复杂。这个时候,对路由进行拆分是个不错的选择。
我们分别看下两段代码,路由拆分的好处就直观的体现出来了。
路由拆分前
var express = require('express');
var app = express();
app.get('/user/list', function(req, res, next){
res.send('/list');
});
app.get('/user/detail', function(req, res, next){
res.send('/detail');
});
app.listen(3000);
这样的代码会带来什么问题呢?无论是新增还是修改路由,都要带着/user
前缀,这对于代码的可维护性来说是大忌。这对小应用来说问题不大,但应用复杂度一上来就会是个噩梦。
路由拆分后
可以看到,通过express.Router()
进行了路由拆分,新增、修改路由都变得极为便利。
var express = require('express');
var app = express();
var user = express.Router();
user.get('/list', function(req, res, next){
res.send('/list');
});
user.get('/detail', function(req, res, next){
res.send('/detail');
});
app.use('/user', user); // mini app,通常做应用拆分
app.listen(3000);
核心概念:中间件
一般学习js的时候,我们都会听到一句话:一切皆对象。而在学习express的过程中,很深的一个感受就是:一切皆中间件。比如常见的请求参数解析、cookie解析、gzip等,都可以通过中间件来完成。
工作机制
贴上官网的一张图镇楼,图中所示就是传说中的中间件了。
首先,我们自己编写一个极简的中间件。虽然没什么实用价值,但中间件就长这样子。
参数
:三个参数,熟悉http.createServer()
的同学应该比较眼熟,其实就是req(客户端请求实例)、res(服务端返回实例),只不过进行了扩展,添加了一些使用方法。next
:回调方法,当next()被调用时,就进入下一个中间件。
function logger(req, res, next){
console.log('here comes request');
next();
}
来看下实际例子:
var express = require('express');
var app = express();
app.use(function(req, res, next) {
console.log('1');
next();
});
app.use(function(req, res, next) {
console.log('2');
next();
});
app.use(function(req, res, next) {
console.log('3');
res.send('hello');
});
app.listen(3000);
请求 http://127.0.0.1:3000,看下控制台输出,以及浏览器返回内容。
middleware git:(master) node chains.js
1
2
3
应用级中间件 vs 路由级中间件
根据作用范围,中间件分为两大类:
- 应用级中间件
- 路由级中间件。
两者的区别不容易说清楚,因为从本质来讲,两类中间件是完全等同的,只是使用场景不同。同一个中间件,既可以是应用级中间件、也可以是路由级中间件。
直接上代码可能更直观。参考下面代码,可以简单粗暴的认为:
- 应用级中间件:
app.use()
、app.METHODS()
接口中使用的中间件。 - 路由级中间件:
router.use()
、router.METHODS()
接口中使用的中间件。
var express = require('express');
var app = express();
var user = express.Router();
// 应用级
app.use(function(req, res, next){
console.log('收到请求,地址为:' + req.url);
next();
});
// 应用级
app.get('/profile', function(req, res, next){
res.send('profile');
});
// 路由级
user.use('/list', function(req, res, next){
res.send('/user/list');
});
// 路由级
user.get('/detail', function(req, res, next){
res.send('/user/detail');
});
app.use('/user', user);
app.listen(3000);
开发中间件
上面也提到了,中间件的开发是是分分钟的事情,不赘述。
function logger(req, res, next){
doSomeBusinessLogic(); // 业务逻辑处理,比如权限校验、数据库操作、设置cookie等
next(); // 如果需要进入下一个中间件进行处理,则调用next();
}
常用中间件
包括但不限于如下。更多常用中间件,可以点击 这里
- body-parser
- compression
- serve-static
- session
- cookie-parser
- morgan
核心概念:模板引擎
模板引擎大家不陌生了,关于express模板引擎的介绍可以参考官方文档。
下面主要讲下使用配置、选型等方面的内容。
可选的模版引擎
包括但不限于如下模板引擎
- jade
- ejs
- dust.js
- dot
- mustache
- handlerbar
- nunjunks
配置说明
先看代码。
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
有两个关于模版引擎的配置:
views
:模版文件放在哪里,默认是在项目根目录下。举个例子:app.set('views', './views')
view engine
:使用什么模版引擎,举例:app.set('view engine', 'jade')
可以看到,默认是用jade
做模版的。如果不想用jade
怎么办呢?下面会提供一些模板引擎选择的思路。
选择标准
需要考虑两点:实际业务需求、个人偏好。
首先考虑业务需求,需要支持以下几点特性。
- 支持模版继承(extend)
- 支持模版扩展(block)
- 支持模版组合(include)
- 支持预编译
对比了下,jade
、nunjunks
都满足要求。个人更习惯nunjunks
的风格,于是敲定。那么,怎么样使用呢?
支持nunjucks
首先,安装依赖
npm install --save nunjucks
然后,添加如下配置
var nunjucks = require('nunjucks');
nunjucks.configure('views', {
autoescape: true,
express: app
});
app.set('view engine', 'html');
看下views/layout.html
<!DOCTYPE html>
<html>
<head>
<title>
{% block title %}
layout title
{% endblock %}
</title>
</head>
<body>
<h1>
{% block appTitle %}
layout app title
{% endblock %}
</h1>
<p>正文</p>
</body>
</html>
看下views/index.html
{% extends "layout.html" %}
{% block title %}首页{% endblock %}
{% block appTitle %}首页{% endblock %}
开发模板引擎
通过app.engine(engineExt, engineFunc)
来注册模板引擎。其中
- engineExt:模板文件后缀名。比如
jade
。 - engineFunc:模板引擎核心逻辑的定义,一个带三个参数的函数(如下)
// filepath: 模板文件的路径
// options:渲染模板所用的参数
// callback:渲染完成回调
app.engine(engineExt, function(filepath, options, callback){
// 参数一:渲染过程的错误,如成功,则为null
// 参数二:渲染出来的字符串
return callback(null, 'Hello World');
});
比如下面例子,注册模板引擎 + 修改配置一起,于是就可以愉快的使用后缀为tmpl
的模板引擎了。
app.engine('tmpl', function(filepath, options, callback){
// 参数一:渲染过程的错误,如成功,则为null
// 参数二:渲染出来的字符串
return callback(null, 'Hello World');
});
app.set('views', './views');
app.set('view engine', 'tmpl');
相关链接
模板引擎对比:点击这里
express模版引擎介绍:点击这里
开发模版引擎:点击这里
更多内容
前面讲了一些express的入门基础,感兴趣的同学可以查看官方文档。篇幅所限,有些内容在后续文章展开,比如下面列出来的内容等。
- 进程管理
- 会话管理
- 日志管理
- 性能优化
- 调试
- 错误处理
- 负载均衡
- 数据库支持
- HTTPS支持
- 业务实践
- 。。。
相关链接
express官网:http://expressjs.com/
Express使用手记:核心入门的更多相关文章
- Node.js核心入门
前言: 因为以前学习Node.js并没有真正意义上的去学习它,而是粗略的学习了npm的常用命令和Node.js一些模块化的语法,因此昨天花了一天的时间看了<Node.js开发指南>一书.通 ...
- Express NodeJs Web框架 入门笔记
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...
- Node.js、Express、Socket.io 入门
前言 周末断断续续的写了第一个socket.io Demo.初次接触socket.io是从其官网看到的,看着get started做了一遍,根据官网的Demo能提供简单的服务端和客户端通讯. 这个De ...
- JAVA手记 JAVA入门(安装+Dos下运行)
JAVA入门特供= =,今天设置环境变量后用dos运行的时候发现出现“找不到或无法加载主类”,索性查了些资料重新看了看JAVA入门的部分. 声明:我的笔记本暂时用的是Win10系统,Windows其他 ...
- 谈谈 React.js 的核心入门知识
近来React.js变得越来越流行,本文就来谈一谈React.js的入门实践,通过分析一些常用的概念,以及提供一些入门 的最佳编程编程方式,仅供参考. 首先需要搞懂的是,React并不是一个框架,Re ...
- Express 3.0新手指南入门教程
在确认已经安装了node之后(下载), 在你的机器上创建一个目录,让我们来开始你的第一个应用程序吧 $ mkdir hello-world 在这个目录中你首先得定义一下你的应用程序“包”文件,它和其它 ...
- 随手记-egg入门
egg 入门 https://eggjs.org/zh-cn/intro/quickstart.html 1.建立项目目录2. npm i egg --save && npm i ...
- node的express框架,核心第三方模块body-parser 获取我们所有post请求传过来数据
- 安装 body-parser模块- npm install body-parser -S - 调用- let bodyParser=require('body-parser'); - 设置中间件- ...
- Express + Mongoose 极简入门
今天尝试使用express + mongoose,构建了一个简单的Hello world,实现以下功能: 定义mongodb使用的Schema,一个User 访问/输出Hello world 访问/i ...
随机推荐
- HTTPS(SSL/TLS) 原理之深入浅出
注:本文参考自网络上的多篇HTTPS相关文章,本人根据自己的理解,进行一些修改,综合. 1. 必要的加密解密基础知识 1)对称加密算法:就是加密和解密使用同一个密钥的加密算法.因为加密方和解密方使用的 ...
- mysql管理(一)
创建数据库,并指定默认字符集和排序规则:help create database;create {database|schema} [if not exists] db_name [character ...
- andriod增、删、改、查
将数据库的增删改查单独放进一个包 */ package com.itheima28.sqlitedemo.dao; import java.util.ArrayList; import java.ut ...
- 迅为iTOP-4412核心板调整电压
本文转自:http://www.topeetboard.com iTOP-4412核心板使用的电源管理芯片是三星专门针对4412研发的S5M8767,8767提供9路BUCK和28路LDO输出,每路电 ...
- WordCount Analysis
1.Create a new java project, then copy examples folder from /home/hadoop/hadoop-1.0.4/src; Create a ...
- IIS关于“ 配置错误 不能在此路径中使用此配置节”的解决办法
IIS关于“ 配置错误 不能在此路径中使用此配置节”的解决办法 原文链接:http://www.cnblogs.com/200325074/p/3679316.html 今天刚安装好IIS8.5, 我 ...
- codeforces 484B B. Maximum Value(二分)
题目链接: B. Maximum Value time limit per test 1 second memory limit per test 256 megabytes input standa ...
- CSS3 Filter详解(改变模糊度 亮度 透明度等方法)
CSS3 Filter(滤镜)属性提供了提供模糊和改变元素颜色的功能.CSS3 Fitler 常用于调整图像的渲染.背景或边框显示效果. -webkit-filter是css3的一个属性,Webkit ...
- div中的内容垂直居中的五种方法
一.行高(line-height)法 如果要垂直居中的只有一行或几个文字,那它的制作最为简单,只要让文字的行高和容器的高度相同即可,比如: p { height:30px; line-height:3 ...
- 2014 UESTC 暑前集训队内赛(3) 部分解题报告
B.Battle for Silver 定理:完全图Kn是平面图当且仅当顶点数n<=4. 枚举所有完全图K1,K2,K3,K4,找出最大总权重. 代码: #include <iostrea ...