简介
Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架, 提供一系列强大特性帮助你创建各种Web应用。Express 不对 node.js 已有的特性进行二次抽象,我们只是在它之上扩展了Web应用所需的功能。丰富的HTTP工具以及来自Connect框架的中间件随取随用,创建强健、友好的API变得快速又简单
官网
安装
首先假定你已经安装了 Node.js,接下来为你的应用创建一个目录,然后进入此目录并将其作为当前工作目录。
通过 npm init
命令为你的应用创建一个 package.json
文件。 欲了解 package.json
是如何起作用的,请参考 Specifics of npm’s package.json handling.
$ npm init
此命令将要求你输入几个参数,例如此应用的名称和版本。 你可以直接按“回车”键接受大部分默认设置即可,下面这个除外:
entry point: (index.js)
键入 app.js
或者你所希望的名称,这是当前应用的入口文件。如果你希望采用默认的 index.js
文件名,只需按“回车”键即可。
接下来在 myapp
目录下安装 Express 并将其保存到依赖列表中。如下:
$ npm install express --save
如果只是临时安装 Express,不想将它添加到依赖列表中,可执行如下命令:
$ npm install express --no-save
npm 5.0+ 版本在默认情况下会将安装的模块添加到 package.json
文件中的 dependencies
列表中。对于较老的 npm 版本,你就必须指定 --save
参数。然后,照旧执行 npm install
命令即可自动安装依赖列表中所列出的所有模块。
hello world
创建app.js 并写入
const express = require('express');
const app = express();
const port = 3000;
app.get('/', function(req, res) {
res.send('Hello World!')
});
app.listen(port, function(){
console.log(`请求访问127.0.0.1:${port}!`)
});
运行结果
到此简单的hello world 已经完成
使用
内置路由和外置路由
内置路由和外置路由简单理解就是把路由写在app.js(入口文件)文件中,还是写在其他文件中,写在app.js文件里就是内置路由其他文件就是外置路由。如上面的hello world案例就是内置路由,不过一般都是使用外置路由。
例
route.js
//引入express 框架模块
var express = require('express');
//获取路由对象
var router = express.Router();
//设置路由
router.get('/',(req,res)=>{
res.send('123');
})
router.get('/user',(req,res)=>{
res.send('user');
})
router.post('/edit',(req,res)=>{
res.send('post_edit');
})
// 导出 路由router
module.exports = router;
app.js
var express = require('express');
var app = express();
// 引入外置路由模块
var rout = require('./route');
// 使用引入外置的路由
app.use(rout);
app.listen('8000',()=>{
console.log('127.0.0.1:8000')
})
运行结果
使用art-template模板引擎
在express框架中使用art-template模板引擎还需要安装express-art-template
安装
npm install --save art-template
npm install --save express-art-template
官方示例:
var express = require('express');
var app = express();
app.engine('art', require('express-art-template'));
app.set('view options', {
debug: process.env.NODE_ENV !== 'production'
});
app.get('/', function (req, res) {
res.render('index.art', {
user: {
name: 'aui',
tags: ['art', 'template', 'nodejs']
}
});
});
Demo
app.js
var express = require('express');
var app = express();
//注册引擎
app.engine('html', require('express-art-template'));
// 引入外置路由模块
var rout = require('./route');
// 使用引入外置的路由
app.use(rout);
app.listen('8000',()=>{
console.log('127.0.0.1:8000')
})
route.js
//引入express 框架模块
var express = require('express');
//获取路由对象
var router = express.Router();
//设置路由
router.get('/',(req,res)=>{
//默认会去当前目录下的views目录下获取静态页面
res.render('index.html', {title:'express-art-template-title'});
})
// 导出 路由router
module.exports = router;
./views/index.html
<h1>{{title}}</h1>
运行结果
遇到的问题
模板路径的问题
在项目中新建views目录,将所有静态页面放入views目录
响应html页面
之前使用http模块的时候,是用fs读取html文件内容并且设置响应头才可以响应html页面,比较麻烦。那么现在express框架有什么比较简单的办法呢?
API
res.sendFile(路径[,选项] [,fn])
res.sendFile()
Express v4.8.0及更高版本受支持。
在给定的位置传输文件path
。Content-Type
根据文件名的扩展名设置响应HTTP标头字段。除非root
在选项对象中设置了选项,path
否则必须是文件的绝对路径。
该API提供对正在运行的文件系统上的数据的访问。确保(a)如果path
参数包含用户输入,则将参数构造为绝对路径的方法是安全的;或者(b)将root
选项设置为包含访问权限的目录的绝对路径。
当root
被提供的选项,所述path
参数被允许是相对路径,包括含有..
。Express将验证提供的相对路径path
是否可以在给定的root
选项内解析。
下表提供了有关该options
参数的详细信息。
属性 | 描述 | 默认 | 可用性 |
---|---|---|---|
maxAge |
Cache-Control 以毫秒为单位设置标头的max-age属性,或以ms格式设置字符串 |
0 | |
root |
相对文件名的根目录。 | ||
lastModified |
将Last-Modified 标头设置为操作系统上文件的最后修改日期。设置false 为禁用它。 |
已启用 | 4.9.0+ |
headers |
包含要与文件一起使用的HTTP标头的对象。 | ||
dotfiles |
用于提供点文件的选项。可能的值为“允许”,“拒绝”,“忽略”。 | “忽视” | |
acceptRanges |
启用或禁用接受远程请求。 | true |
4.14+ |
cacheControl |
启用或禁用设置Cache-Control 响应头。 |
true |
4.14+ |
immutable |
immutable 在Cache-Control 响应头中启用或禁用指令。如果启用,maxAge 还应指定该选项以启用缓存。该immutable 指令将阻止受支持的客户端在maxAge 选项的有效期内提出条件请求,以检查文件是否已更改。 |
false |
4.16+ |
fn(err)
传输完成或发生错误时,该方法将调用回调函数。如果指定了回调函数并且发生错误,则回调函数必须通过结束请求-响应周期或将控制权传递给下一条路由来显式处理响应过程。
注意:上面写了除非设置了root选项,否则文件路径必须是绝对路径
这时候就要使用__dirname
这个,来获取当前目录的绝对路径了
文档:http://nodejs.cn/api/modules/dirname.html
响应html页面的Demo
route.js
//引入express 框架模块
var express = require('express');
//获取路由对象
var router = express.Router();
//设置路由
router.get('/',(req,res)=>{
//只能绝对路径
res.sendFile(__dirname+'/views/index.html');
})
// 导出 路由router
module.exports = router;
利用 Express 托管静态文件
官方文档:http://www.expressjs.com.cn/starter/static-files.html
为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的 express.static
内置中间件函数。
此函数特征如下:
express.static(root, [options])
The root
argument specifies the root directory from which to serve static assets. For more information on the options
argument, see express.static.
例如,通过如下代码就可以将 public
目录下的图片、CSS 文件、JavaScript 文件对外开放访问了:
app.use(express.static('public'))
现在,你就可以访问 public
目录中的所有文件了:
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
Express 在静态目录查找文件,因此,存放静态文件的目录名不会出现在 URL 中。
如果要使用多个静态资源目录,请多次调用 express.static
函数:
app.use(express.static('public'))
app.use(express.static('files'))
访问静态资源文件时,express.static
函数会根据目录的添加顺序查找所需的文件。
Demo
1.新建静态资源存放路径,如public
2.入口文件中设置静态资源目录
app.use(express.static('public'))
就可以了
例:
app.js
var express = require('express');
var app = express();
//设置静态资源目录
app.use(express.static('public'))
app.listen('8000',()=>{
console.log('127.0.0.1:8000')
})
./public/img/test.jpg
访问http://127.0.0.1:8000/img/test.jpg
如果是在其他静态页面中使用则直接写
<img src="/img/test.jpg">
直接写相对于public 的目录下的路径即可
使用formidable进行文件上传
npm地址:https://www.npmjs.com/package/formidable
安装
npm install formidable
选项
options.encoding
{string} -默认值'utf-8'
;设置传入表单字段的编码,options.uploadDir
{string} -默认值os.tmpdir()
;用于放置文件上载的目录。稍后可以使用进行移动fs.rename()
options.keepExtensions
{boolean} -默认值false
;是否包含原始文件的扩展名options.maxFileSize
{number} -默认值200 * 1024 * 1024
(200mb);限制上传文件的大小。options.maxFields
{number} -默认值1000
;限制Querystring解析器将解码的字段数,将0设置为无限制options.maxFieldsSize
{number} -默认值20 * 1024 * 1024
(20mb);限制所有字段(文件除外)可一起分配的内存量(以字节为单位)。options.hash
{boolean} -默认值false
;包括为传入文件计算的校验和,将其设置为某种哈希算法, 有关可用算法,请参见 crypto.createHashoptions.multiples
{boolean} -默认值false
;当您调用该.parse
方法时,files
(回调的)参数将包含用于输入的文件数组,这些输入使用HTML5multiple
属性提交多个文件。同样,该fields
参数将包含名称以“ []”结尾的字段的值数组。
普通表单控件和文件表单控件数据结构示例
普通表单控件
{ name: 'zhangsan' }
文件表单控件
{
file: File {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
//文件大小
size: 57313,
//文件路径
path: 'public\upload_aa5dfaec37e92b4efe60ae1cec4d6f2d.jpg',
//文件名
name: 'u=313355857,739398057&fm=26&gp=0.jpg',
//文件类型
type: 'image/jpeg',
hash: null,
//最后修改时间
lastModifiedDate: 2020-10-06T09:17:13.572Z,
_writeStream: WriteStream {
_writableState: [WritableState],
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
path: 'public\upload_aa5dfaec37e92b4efe60ae1cec4d6f2d.jpg',
fd: 3,
flags: 'w',
mode: 438,
start: undefined,
autoClose: true,
pos: undefined,
bytesWritten: 57313,
closed: false,
[Symbol(kFs)]: [Object],
[Symbol(kCapture)]: false,
[Symbol(kIsPerformingIO)]: false
},
[Symbol(kCapture)]: false
}
}
Demo
var express = require('express');
var fs = require('fs');
var formidable = require('formidable');
var app = express();
app.post('/upload',(req,res)=>{
//创建上传表单
var form = new formidable.IncomingForm();
//设置
//formidable的默认保存路径是:“C:UsersAdministratorAppDataLocalTemp”
//修改formidable 临时存放存储路径为当前目录下的public
form.uploadDir = './public';
// 保留文件扩展名
form.keepExtensions = true;
/**
* err 表示错误信息
* fields 表示普通表单控件
* files 表示文件表单控件
*/
form.parse(req, function (err, fields, files) {
console.log(fields);
console.log(files);
var times = new Date().getTime();
// 组装上传路径
var file_path = './public/'+times+files.file.name;
// 将缓存文件移动至制定目录
fs.rename(files.file.path,file_path,(err)=>{
console.log(file_path);
});
res.end();
});
})
app.listen('8000',()=>{
console.log('127.0.0.1:8000')
})
运行结果
使用cookie与session
express官方资源中,为我们提供了一个中间件,cookie-session
安装
npm install cookie-session
Demo
var express = require('express');
var cookieSession = require('cookie-session')
var app = express();
// 注册中间件
app.use(cookieSession({
name: 'session', // 客户端cookie的名称
keys: ['ss'] // 用于加密的关键字
}))
app.get('/', (req, res) => {
// 获取并判断session
if(req.session.sess_data){
res.send('已经登陆')
}else{
// 如果没有session,跳转到登陆页面
res.send('<script>alert("没登陆");window.location.href="/up"</script>');
}
})
app.get('/up', (req, res) => {
// 展示登陆页面,获取用户数据并写入session
req.session.sess_data = {name:12,age:89};
res.send('已写入session');
});
app.listen('8000',()=>{
console.log('127.0.0.1:8000')
})
这个Demo第一次访问如果没session 会在弹框之后自动写入session
再次访问
Express的中间件
什么是中间件
在一个整体的流程中的某个环节,因为某些原因加入了额外的处理环节;
中间件的使用
应用中间件
语法:
app.use()
app.use(function(){})
无论发送任何请求都会执行的中间件
app.use('/path', function(){})
只要在请求path路由时才会执行的中间件(无论GET/POST)
app.method()
app.get()
在get请求时会执行的中间件
app.post()
在post请求时会执行的中间件
app.use() 的用法
var express = require('express');
var app = express();
// 在中间件之前,不受中间件影响
app.get('/',function(req,res){
console.log(123);
})
// 应用中间件
//表示匹配任何路由
// 请求 '/user' 时,会先调用中间件
app.use(function (req, res, next) {
console.log(req);
next();
});
// 调用之前先调用中间件
app.get('/user',function(req,res){
console.log('user');
})
app.listen('8000', () => {
console.log('127.0.0.1:8000')
})
app.method() 的用法
var express = require('express');
var app = express();
// 在中间件之前,不受中间件影响
app.get('/',function(req,res){
console.log(123);
})
// 应用中间件,也叫路由中间件
// 只有在 post 请求user 时才起作用
app.post('/user',function (req, res, next) {
console.log(req);
//表示匹配完成这个中间件就继续往下执行。
next();
});
// 调用之前先调用中间件
// 接受所有请求方式请求user
app.all('/user',function(req,res){
console.log('user');
})
app.listen('8000', () => {
console.log('127.0.0.1:8000')
})
路由中间件
路由器层中间件的工作方式与应用层中间件基本相同,差异之处在于它绑定到 express.Router()
的实例。
使用 router.use()
和 router.METHOD()
函数装入路由器层中间件;
例:
var app = express();
var router = express.Router();
//没有挂载路径的中间件。这段代码对每个发送到路由器的请求都执行
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
//中间件子堆栈向/user/:id路径显示任何类型的HTTP请求的请求信息
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// 处理/user/:id路径的GET请求的中间件子堆栈
router.get('/user/:id', function (req, res, next) {
// 如果用户ID为0,则跳到下一个路由器
if (req.params.id == 0) next('route');
// 否则,将控制权传递给该堆栈中的下一个中间件函数
else next(); //
}, function (req, res, next) {
// 呈现常规页面
res.render('regular');
});
// 用于/user/:id路径的处理程序,它将呈现一个特殊的页面
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
// 使用路由
app.use('/', router);
内置中间件
除 express.static
外,先前 Express 随附的所有中间件函数现在以单独模块的形式提供:中间件函数的列表
Express 中唯一内置的中间件函数是 express.static
。此函数基于 serve-static,负责提供 Express 应用程序的静态资源。
对于每个应用程序,可以有多个静态目录:
app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
第三方中间件
使用第三方中间件向 Express 应用程序添加功能。
安装具有所需功能的 Node.js 模块,然后在应用层或路由器层的应用程序中将其加装入。
var cookieSession = require('cookie-session');
// 注册中间件
app.use(cookieSession({
name: 'session', // 客户端cookie的名称
keys: ['xilingzuishuai'] // 用于加密的关键字
}))