三、Express

参考
Express框架
Express
基于 Node.js 平台,快速、开放、极简的 web 开发框架。

$ npm install express --save

一、特色

1、Web 应用

Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。

2、API

丰富的 HTTP 快捷方法和任意排列组合的 Connect 中间件,让你创建健壮、友好的 API 变得既快速又简单。

3、性能

Express 不对 Node.js 已有的特性进行二次抽象,我们只是在它之上扩展了 Web 应用所需的基本功能。

二、安装

首先假定你已经安装了 Node.js,接下来为你的应用创建一个目录,然后进入此目录并将其作为当前工作目录。

$ mkdir myapp
$ cd myapp

通过 npm init 命令为你的应用创建一个 package.json 文件。 欲了解 package.json 是如何起作用的,请参考 Specifics of npm’s package.json handling。

$ npm init

此命令将要求你输入几个参数,例如此应用的名称和版本。 你可以直接按“回车”键接受默认设置即可,下面这个除外:

entry point: (index.js)

键入 app.js 或者你所希望的名称,这是当前应用的入口文件。如果你希望采用默认的 index.js 文件名,只需按“回车”键即可。

接下来安装 Express 并将其保存到依赖列表中:

$ npm install express --save

如果只是临时安装 Express,不想将它添加到依赖列表中,只需略去 --save 参数即可:

$ npm install express

安装 Node 模块时,如果指定了 --save 参数,那么此模块将被添加到 package.json 文件中 dependencies 依赖列表中。 然后通过 npm install 命令即可自动安装依赖列表中所列出的所有模块。

三、Hello world 实例

接下来,我们一起创建一个基本的 Express 应用。

注意:这里所创建是一个最最简单的 Express 应用,并且仅仅只有一个文件 — 和通过 Express 应用生成器 所创建的应用完全不一样,Express 应用生成器所创建的应用框架包含多 JavaScript 文件、Jade 模板和针对不同用途的子目录。

进入 myapp 目录,创建一个名为 app.js 的文件,然后将下列代码复制进去:

var express = require('express');
var app = express();

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

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

上面的代码启动一个服务并监听从 3000 端口进入的所有连接请求。他将对所有 (/) URL 或 路由 返回 “Hello World!” 字符串。对于其他所有路径全部返回 404 Not Found。

req (请求) 和 res (响应) 与 Node 提供的对象完全一致,因此,你可以调用 req.pipe()、req.on(‘data’, callback) 以及任何 Node 提供的方法。

通过如下命令启动此应用:

$ node app.js

然后在浏览器中打开 http://localhost:3000/ 并查看输出结果。
在这里插入图片描述

四、路由

路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。

路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下: app.METHOD(path, [callback…], callback), app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。

下面是一个基本的路由示例:

var express = require('express');
var app = express();

// respond with "hello world" when a GET request is made to the homepage
app.get('/', function(req, res) {
  res.send('hello world');
});

1、路由方法

路由方法源于 HTTP 请求方法,和 express 实例相关联。

下面这个例子展示了为应用跟路径定义的 GET 和 POST 请求:

// GET method route
// 对网站首页的访问返回 "Hello World!" 字样
app.get('/', function (req, res) {
  res.send('Hello World!')
})

// 网站首页接受 POST 请求
app.post('/', function (req, res) {
  res.send('Got a POST request')
})

// /user 节点接受 PUT 请求
app.put('/user', function (req, res) {
  res.send('Got a PUT request at /user')
})

// /user 节点接受 DELETE 请求
app.delete('/user', function (req, res) {
  res.send('Got a DELETE request at /user')
})

Express 定义了如下和 HTTP 请求对应的路由方法: get, post, put, head, delete, options, trace, copy, lock, mkcol, move, purge, propfind, proppatch, unlock, report, mkactivity, checkout, merge, m-search, notify, subscribe, unsubscribe, patch, search, 和 connect。

有些路由方法名不是合规的 JavaScript 变量名,此时使用括号记法,比如: app[‘m-search’](’/’, function …

app.all() 是一个特殊的路由方法,没有任何 HTTP 方法与其对应,它的作用是对于一个路径上的所有请求加载中间件。

在下面的例子中,来自 “/secret” 的请求,不管使用 GET、POST、PUT、DELETE 或其他任何 http 模块支持的 HTTP 请求,句柄都会得到执行。

app.all('/secret', function (req, res, next) {
  console.log('Accessing the secret section ...')
  next(); // pass control to the next handler
})

2、路由路径

路由路径和请求方法一起定义了请求的端点,它可以是字符串、字符串模式或者正则表达式。

Express 使用 path-to-regexp 匹配路由路径,请参考文档查阅所有定义路由路径的方法。 Express Route Tester 是测试基本 Express 路径的好工具,但不支持模式匹配。

查询字符串不是路由路径的一部分。

使用字符串的路由路径示例:

// 匹配根路径的请求
app.get('/', function (req, res) {
  res.send('root');
});

// 匹配 /about 路径的请求
app.get('/about', function (req, res) {
  res.send('about');
});

// 匹配 /random.text 路径的请求
app.get('/random.text', function (req, res) {
  res.send('random.text');
});

使用字符串模式的路由路径示例:

// 匹配 acd 和 abcd
app.get('/ab?cd', function(req, res) {
  res.send('ab?cd');
});

// 匹配 abcd、abbcd、abbbcd等
app.get('/ab+cd', function(req, res) {
  res.send('ab+cd');
});

// 匹配 abcd、abxcd、abRABDOMcd、ab123cd等
app.get('/ab*cd', function(req, res) {
  res.send('ab*cd');
});

// 匹配 /abe 和 /abcde
app.get('/ab(cd)?e', function(req, res) {
 res.send('ab(cd)?e');
});

字符 ?、+、* 和 () 是正则表达式的子集,- 和 . 在基于字符串的路径中按照字面值解释。

使用正则表达式的路由路径示例:

// 匹配任何路径中含有 a 的路径:
app.get(/a/, function(req, res) {
  res.send('/a/');
});

// 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等
app.get(/.*fly$/, function(req, res) {
  res.send('/.*fly$/');
});

3、路由句柄

可以为请求处理提供多个回调函数,其行为类似 中间件。唯一的区别是这些回调函数有可能调用 next(‘route’) 方法而略过其他路由回调函数。可以利用该机制为路由定义前提条件,如果在现有路径上继续执行没有意义,则可将控制权交给剩下的路径。

路由句柄有多种形式,可以是一个函数、一个函数数组,或者是两者混合,如下所示.

使用一个回调函数处理路由:

app.get('/example/a', function (req, res) {
  res.send('Hello from A!');
});

使用多个回调函数处理路由(记得指定 next 对象):

app.get('/example/b', function (req, res, next) {
  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from B!');
});

使用回调函数数组处理路由:

var cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

var cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

var cb2 = function (req, res) {
  res.send('Hello from C!')
}

app.get('/example/c', [cb0, cb1, cb2])
混合使用函数和函数数组处理路由:

var cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

var cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

app.get('/example/d', [cb0, cb1], function (req, res, next) {
  console.log('response will be sent by the next function ...')
  next()
}, function (req, res) {
  res.send('Hello from D!')
})

4、响应方法

下表中响应对象(res)的方法向客户端返回响应,终结请求响应的循环。如果在路由句柄中一个方法也不调用,来自客户端的请求会一直挂起。

方法	描述
res.download()	提示下载文件。
res.end()	终结响应处理流程。
res.json()	发送一个 JSON 格式的响应。
res.jsonp()	发送一个支持 JSONPJSON 格式的响应。
res.redirect()	重定向请求。
res.render()	渲染视图模板。
res.send()	发送各种类型的响应。
res.sendFile	以八位字节流的形式发送文件。
res.sendStatus()	设置响应状态代码,并将其以字符串形式作为响应体的一部分发送。

5、app.route()

可使用 app.route() 创建路由路径的链式路由句柄。由于路径在一个地方指定,这样做有助于创建模块化的路由,而且减少了代码冗余和拼写错误。

下面这个示例程序使用 app.route() 定义了链式路由句柄。

app.route('/book')
  .get(function(req, res) {
    res.send('Get a random book');
  })
  .post(function(req, res) {
    res.send('Add a book');
  })
  .put(function(req, res) {
    res.send('Update the book');
  });

6、express.Router 路由模块化

可使用 express.Router 类创建模块化、可挂载的路由句柄。Router 实例是一个完整的中间件和路由系统,因此常称其为一个 “mini-app”。

下面的实例程序创建了一个路由模块,并加载了一个中间件,定义了一些路由,并且将它们挂载至应用的路径上。

示例一

在 app 目录下创建名为 birds.js 的文件,内容如下:

var express = require('express');
var router = express.Router();

// 该路由使用的中间件
router.use(function timeLog(req, res, next) {
  console.log('Time: ', Date.now());
  next();
});
// 定义网站主页的路由
router.get('/', function(req, res) {
  res.send('Birds home page');
});
// 定义 about 页面的路由
router.get('/about', function(req, res) {
  res.send('About birds');
});

module.exports = router;

然后在应用中加载路由模块:

var birds = require('./birds')
...
app.use('/birds', birds)

应用即可处理发自 /birds 和 /birds/about 的请求,并且调用为该路由指定的 timeLog 中间件。

示例二

新建一个 user.js 配置如下代码

var express = require('express')
var router = express.Router()
router.get('/', function (req, res) {
res.send('用户列表')
})
router.get('/add, function (req, res) {
res.send('增加用户')
})
router.get('/edit, function (req, res) {
res.send('修改用户')
})
module.exports = router

挂载这个模块文件

var user= require('./routes/user)
app.use('/user, user)

五、利用 Express 托管静态文件

通过 Express 内置的 express.static 可以方便地托管静态文件,例如图片、CSS、JavaScript 文件等。

将静态资源文件所在的目录作为参数传递给 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

所有文件的路径都是相对于存放目录的,因此,存放静态文件的目录名不会出现在 URL 中。

如果你的静态资源存放在多个目录下面,你可以多次调用 express.static 中间件:

app.use(express.static('public'))
app.use(express.static('files'))

访问静态资源文件时,express.static 中间件会根据目录添加的顺序查找所需的文件。

如果你希望所有通过 express.static 访问的文件都存放在一个“虚拟(virtual)”目录(即目录根本不存在)下面,可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:

app.use('/static', express.static('public'))

现在,你就可以通过带有 “/static” 前缀的地址来访问 public 目录下面的文件了。

http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css
http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html

六、使用中间件

Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。

中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。

中间件的功能包括:

执行任何代码。
修改请求和响应对象。
终结请求-响应循环。
调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。

Express 应用可使用如下几种中间件:

应用级中间件
路由级中间件
错误处理中间件
内置中间件
第三方中间件

使用可选则挂载路径,可在应用级别或路由级别装载中间件。另外,你还可以同时装在一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。

1、应用级中间件

应用级中间件绑定到 app 对象 使用 app.use() 和 app.METHOD(), 其中, METHOD 是需要处理的 HTTP 请求的方法,例如 GET, PUT, POST 等等,全部小写。例如:

var app = express()

// 没有挂载路径的中间件,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它
app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method)
  next()
})

// 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
  res.send('USER')
})

下面这个例子展示了在一个挂载点装载一组中间件。

// 一个中间件栈,对任何指向 /user/:id 的 HTTP 请求打印出相关信息
app.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 请求定义了两个路由。第二个路由虽然不会带来任何问题,但却永远不会被调用,因为第一个路由已经终止了请求-响应循环。

// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
  console.log('ID:', req.params.id)
  next()
}, function (req, res, next) {
  res.send('User Info')
})

// 处理 /user/:id, 打印出用户 id
app.get('/user/:id', function (req, res, next) {
  res.end(req.params.id)
})
如果需要在中间件栈中跳过剩余中间件,调用 next('route') 方法将控制权交给下一个路由。 注意: next('route') 只对使用 app.VERB() 或 router.VERB() 加载的中间件有效。

// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
  // 如果 user id 为 0, 跳到下一个路由
  if (req.params.id == 0) next('route')
  // 否则将控制权交给栈中下一个中间件
  else next() //
}, function (req, res, next) {
  // 渲染常规页面
  res.render('regular')
});

// 处理 /user/:id, 渲染一个特殊页面
app.get('/user/:id', function (req, res, next) {
  res.render('special')
})

2、路由级中间件

路由级中间件和应用级中间件一样,只是它绑定的对象为 express.Router()。

var router = express.Router()
路由级使用 router.use() 或 router.VERB() 加载。

上述在应用级创建的中间件系统,可通过如下代码改写为路由级:

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) {
  // 如果 user 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)

3、错误处理中间件

错误处理中间件有 4 个参数,定义错误处理中间件时必须使用这 4 个参数。即使不需要 next 对象,也必须在签名中声明它,否则中间件会被识别为一个常规中间件,不能处理错误。

错误处理中间件和其他中间件定义类似,只是要使用 4 个参数,而不是 3 个,其签名如下: (err, req, res, next)。

app.use(function(err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

4、内置中间件

从 4.x 版本开始,, Express 已经不再依赖 Connect 了。除了 express.static, Express 以前内置的中间件现在已经全部单独作为模块安装使用了。请参考 中间件列表。

express.static(root, [options])

express.static 是 Express 唯一内置的中间件。它基于 serve-static,负责在 Express 应用中提托管静态资源。

参数 root 指提供静态资源的根目录。

可选的 options 参数拥有如下属性。

属性	描述	类型	缺省值
dotfiles	是否对外输出文件名以点(.)开头的文件。可选值为 “allow”、“deny” 和 “ignore”	String	“ignore”
etag	是否启用 etag 生成	Boolean	true
extensions	设置文件扩展名备份选项	Array	[]
index	发送目录索引文件,设置为 false 禁用目录索引。	Mixed	“index.html”
lastModified	设置 Last-Modified 头为文件在操作系统上的最后修改日期。可能值为 truefalse。	Boolean	true
maxAge	以毫秒或者其字符串格式设置 Cache-Control 头的 max-age 属性。	Number	0
redirect	当路径为目录时,重定向至 “/”。	Boolean	true
setHeaders	设置 HTTP 头以提供文件的函数。	Function

下面的例子使用了 express.static 中间件,其中的 options 对象经过了精心的设计。

var options = {
  dotfiles: 'ignore',
  etag: false,
  extensions: ['htm', 'html'],
  index: false,
  maxAge: '1d',
  redirect: false,
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now())
  }
}

app.use(express.static('public', options))
每个应用可有多个静态目录。

app.use(express.static('public'))
app.use(express.static('uploads'))
app.use(express.static('files'))

5、第三方中间件

通过使用第三方中间件从而为 Express 应用增加更多功能。

安装所需功能的 node 模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。

下面的例子安装并加载了一个解析 cookie 的中间件: cookie-parser
$ npm install cookie-parser

var express = require('express')
var app = express()
var cookieParser = require('cookie-parser')

// 加载用于解析 cookie 的中间件
app.use(cookieParser())

七、在 Express 中使用模板引擎

需要在应用中进行如下设置才能让 Express 渲染模板文件:

views, 放模板文件的目录,比如: app.set(‘views’, ‘./views’)
view engine, 模板引擎,比如: app.set(‘view engine’, ‘ejs’)
art-template
art-template for express 4.x.

1、Install

npm install --save art-template
npm install --save express-art-template

2、Example

var express = require('express')
var app = express()

// view engine setup
app.engine('art', require('express-art-template'))
app.set('view', {
    debug: process.env.NODE_ENV !== 'production'
})
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'art')

// routes
app.get('/', function (req, res) {
    res.render('index.art', {
        user: {
            name: 'aui',
            tags: ['art', 'template', 'nodejs']
        }
    })
})

八、获取 Get Post 请求的参数

  • GET 请求的参数在 URL 中,在原生 Node 中,需要使用 url 模块来识别参数字符串。在
    Express 中,不需要使用 url 模块了。可以直接使用 req.query 对象。
  • POST 请求在 express 中不能直接获得,可以使用 body-parser 模块。使用后,将可以用
    req.body 得到参数。但是如果表单中含有文件上传,那么还是需要使用 multiparty 模块。
    1.安装
npm install body-parser

2.使用 req.body 获取 post 过来的参数

var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.use(function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
res.end(JSON.stringify(req.body, null, 2))
})

九、Express Cookie 的基本使用

1、Cookie 简介

  • cookie 是存储于访问者的计算机中的变量。可以让我们用同一个浏览器访问同一个域
    名的时候共享数据。
  • HTTP 是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页
    面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问,都是没有任何
    关系的。
  • Cookie 是一个简单到爆的想法:当访问一个页面的时候,服务器在下行 HTTP 报文中,
    命令浏览器存储一个字符串; 浏览器再访问同一个域的时候,将把这个字符串携带到上行
    HTTP 请求中。第一次访问一个服务器,不可能携带 cookie。 必须是服务器得到这次请求,
    在下行响应报头中,携带 cookie 信息,此后每一次浏览器往这个服务器发出的请求,都会
    携带这个 cookie。

2、Cookie 特点

  • cookie 保存在浏览器本地
  • 正常设置的 cookie 是不加密的,用户可以自由看到;
  • 用户可以删除 cookie,或者禁用它
  • cookie 可以被篡改
  • cookie 可以用于攻击
  • cookie 存储量很小。未来实际上要被 localStorage 替代,但是后者 IE9 兼容。

3、Cookie 的使用

Express 中要使用 Cookie 的话,我们需要使用 cookie-parser 模块来实现

  • (1)安装 cnpm instlal cookie-parser --save
  • (2)引入 var cookieParser = require('cookie-parser');
  • (3)设置中间件 app.use(cookieParser());
  • (4)设置 cookie
res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});
  • (5) 获取 cookie
req.cookies.name
Cookie 属性说明描述
domain域名 name=value:键值对,可以设置要保存的 Key/Value,注意这里的 name不能和其他属性项的名字一样
Expires过 期 时 间 ( 秒 ) , 在 设 置 的 某 个 时 间 点 后 该 Cookie 就 会 失 效 , 如expires=Wednesday, 09-Nov-99 23:12:40 GMT
maxAge最大失效时间(毫秒),设置在多少后失效
secure当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效
Path表示 cookie 影响到的路路径,如 path=/。如果路径不能匹配时,浏览器则不发送这个 Cookie
httpOnly是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了“httpOnly”属性,则通过程序(JS 脚本、applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生
singed表示是否签名 cookie, 设为 true 会对这个 cookie 签名,这样就需要用res.signedCookies 而不是 res.cookies 访问它。被篡改的签名 cookie 会被服务器拒绝,并且 cookie 值会重置为它的原始值

设置 cookie 的几种方法

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true });
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });

获取 cookie

req.cookies.name

删除 cookie,设置过期时间为当前时间,或者设置失效秒数为0

res.cookie('rememberme', '', { expires: new Date(0)});
res.cookie('username','zhangsan',{domain:'.ccc.com',maxAge:0,httpOnly:true});

4、加密 Cookie

  • 配置中间件的时候需要传参
  • 设置 cookie 的时候配置 signed 属性
  • signedCookies 调用设置的 cookie
var cookieParser = require('cookie-parser');
app.use(cookieParser('123456'));
res.cookie('userinfo','hahaha',{domain:'.ccc.com',maxAge:900000,httpOnly:true,signed:true});
console.log(req.signedCookies);

十、Express Session 的基本使用

1、 Session 简单介绍

  • session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而
    session 保存在服务器上。
  • Cookie 数据存放在客户的浏览器上,Session 数据放在服务器上。Session 相比 Cookie 要
    更安全一些。由于 Session 保存到服务器上,所以当访问量增多的时候,会比较占用服务器
    的性能。单个 cookie 保存的数据大小不能超过 4K,很多浏览器都限制一个站点最多保存 20
    个 cookie。Session 没有这方面的限制。Session 是基于 Cookie 进行工作的。

2、Session 的工作流程

当浏览器访问服务器并发送第一次请求时,服务器端会创建一个 session 对象,生成一
个类似于 key,value 的键值对, 然后将 key(cookie)返回到浏览器(客户)端,浏览器下次
再访问时,携带 key(cookie),找到对应的 session(value)。

3、 express-session 的使用

https://www.npmjs.com/package/express-session

(1)安装 express-session

cnpm install express-session --save

(2)引入 express-session

var session = require("express-session");

(3)设置官方文档提供的中间件

app.use(session({
secret: 'keyboard cat', resave: true, saveUninitialized: true
}))

(4) 使用
设置值 req.session.username = "张三";
获取值 req.session.username

4、 express-session 的常用参数

app.use(session({
secret: '12345', name: 'name', cookie: {maxAge: 60000}, resave: false, saveUninitialized: true
}));
参数作用
secret一个 String 类型的字符串,作为服务器端生成 session 的签名。
name返回客户端的 key 的名称,默认为 connect.sid,也可以自己设置。
resave强制保存 session 即使它并没有变化,。默认为 false。 don’t save session if unmodified
saveUninitialized强制将未初始化的 session 存储。当新建了一个 session 且未设定属性或值时,它就处于未初始化状态。在设定一个 cookie 前,这对于登陆验证,减轻服务端存储压力,权限控制是有帮助的。(默认:true)。建议手动添加。
cookie设置返回到前端 key 的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false,maxAge: null }。
rolling在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)

5、 express-session 的常用方法

req.session.destroy(function(err) { /*销毁 session*/})
req.session.username='张三'; //设置 session
req.session.username //获取 session
req.session.cookie.maxAge=0; //重新设置 cookie 的过期时间

6、 负载均衡配置 Session,把 Session 保存到数据库里面

1.需要安装 express-session 和 connect-mongo 模块
2.引入模块

var session = require("express-session");
const MongoStore = require('connect-mongo')(session);

3.配置中间件

app.use(session({
secret: 'keyboard cat', resave: false, saveUninitialized: true, rolling:true, cookie:{
maxAge:100000
},
store: new MongoStore({
url: 'mongodb://127.0.0.1:27017/student', touchAfter: 24 * 3600 // time period in seconds
})
}))

十一、Express 应用生成器

通过应用生成器工具 express 可以快速创建一个应用的骨架。

通过如下命令安装:

$ npm install express-generator -g

-h 选项可以列出所有可用的命令行选项:

$ express -h

  Usage: express [options] [dir]

  Options:

    -h, --help          output usage information
    -V, --version       output the version number
    -e, --ejs           add ejs engine support (defaults to jade)
        --hbs           add handlebars engine support
    -H, --hogan         add hogan.js engine support
    -c, --css <engine>  add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git           add .gitignore
    -f, --force         force on non-empty directory

例如,下面的示例就是在当前工作目录下创建一个命名为 myapp 的应用。

$ express myapp

   create : myapp
   create : myapp/package.json
   create : myapp/app.js
   create : myapp/public
   create : myapp/public/javascripts
   create : myapp/public/images
   create : myapp/routes
   create : myapp/routes/index.js
   create : myapp/routes/users.js
   create : myapp/public/stylesheets
   create : myapp/public/stylesheets/style.css
   create : myapp/views
   create : myapp/views/index.jade
   create : myapp/views/layout.jade
   create : myapp/views/error.jade
   create : myapp/bin
   create : myapp/bin/www

然后安装所有依赖包:

$ cd myapp 
$ npm install

启动这个应用(MacOS 或 Linux 平台):

$ DEBUG=myapp npm start

Windows 平台使用如下命令:

> set DEBUG=myapp & npm start

然后在浏览器中打开 http://localhost:3000/ 网址就可以看到这个应用了。i

通过 Express 应用生成器创建的应用一般都有如下目录结构:

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.jade
    ├── index.jade
    └── layout.jade

7 directories, 9 files

十二、Express 结合 multer 上传图片

1、 Multer 模块介绍

  • Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用
    于上传文件。它是写在 busboy 之上非常高效。
  • 注意: Multer 不会处理任何非 multipart/form-data 类型的表单数据。
    https://www.npmjs.com/package/multer

2、 Express 上传文件模块 multer 的使用

(1)安装 multer
npm install --save multer
(2)引入配置 multer 模块 :
var multer = require('multer')
//配置
var storage = multer.diskStorage({
//文件保存路径 注意路径必须存在
destination: function (req, file, cb) {
cb(null, 'public/upload/')
},
//修改文件名称
filename: function (req, file, cb) {
var fileFormat = (file.originalname).split(".");
cb(null,Date.now() + "." + fileFormat[fileFormat.length - 1]);
}
})
var upload = multer({ storage: storage })
(3)使用 multer
router.post('/doAdd', upload.single("pic"), function (req, res) {
res.send({
file: req.file,//返回文件名
body: req.body
})
});

3、 Express 按照日期生成上传文件目录

var express = require('express');
var multer = require('multer')
var sd = require('silly-datetime');
var path = require('path');
var mkdirp = require('mkdirp');
var router = express.Router();
//配置
var storage = multer.diskStorage({
//文件保存路径 注意路径必须存在
destination: async (req, file, cb)=> {
// 1、获取当前日期 以及当前的时间戳
let day = sd.format(new Date(), 'YYYYMMDD');
//2、创建图片保存的路径
let dir = path.join('public/upload/',day)
//3、异步创建目录
await mkdirp(dir);
cb(null, dir)
},//修改文件名称
filename: function (req, file, cb) {
var fileFormat = (file.originalname).split(".");
cb(null,Date.now() + "." + fileFormat[fileFormat.length - 1]);
}
})
var upload = multer({ storage: storage })
router.post('/doAdd', upload.single("pic"), function (req, res) {
res.send({
file: req.file,//返回文件名
body: req.body
})
});

module.exports = router;

4、 多文件上传

var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/doAdd', cpUpload, function (req, res, next) {
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值