[一起学Node.js] Express MongoDB搭建多人博客-1

时间:2020-12-02 02:37:14

目录[-]

  • 学习环境
  • 快速开始
  • 安装Express
  • 新建一个工程
  • 工程结构
  • 路由控制
  • 工作原理
  • 路由规则
  • 添加路由规则
  • 模版引擎
  • 什么是模板引擎
  • 使用模板引擎
  • 页面布局
  • 搭建多人博客
  • 功能分析
  • 设计目标
  • 路由规划
  • 使用数据库
  • MongoDB简介
  • 安装MongoDB
  • 连接MongoDB
  • 会话支持
  • 注册和登陆
  • 页面设计
  • 页面通知
  • 注册响应
  • 登录与登出响应
  • 页面权限控制
  • 发表文章
  • 页面设计
  • 文章模型
  • 发表响应
  • 学习环境

    node.js: 0.10.7+

    快速开始

    安装Express

    ?
    1 npm
    install -g express

    我们需要用全局模式安装 express,因为只有这样我们才能在命令行中使用它。目前 express 最新版本为 express 3.2.4。

    新建一个工程

    今后的学习把 D:\blog 文件夹作为我们的工程目录。windows 下打开 cmd 切换到 D 盘,输入 express
    -e ejs blog
     (注意 express 3.* 中安装 ejs 不再是 -t 而是 -e,可以输入 express -h 查看),然后输入 cd blog&npm install 安装所需模块,如下图所示:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    安装完成后输入 node
    app
    ,此时命令行中会显示 Express server listening on port 3000,在浏览器里输入 localhost:3000,如下所示:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    我们用 express 初始化了一个工程,并指定使用 ejs 模板引擎,下一节我们讲解工程的内部结构。

    工程结构

    我们回头看看生成的工程目录里面有什么,打开 D:\blog,里面如图所示:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    app.js:启动文件。 
    package.json:存储着工程的信息及所需的依赖模块,当在 dependencies 中添加依赖时,运行npm install,会检查当前目录下的 package.json,并自动安装所有指定的依赖模块。 
    node_modules:存放 package.json 中安装的模块,当你在 package.json 添加依赖的模块并安装后,默认存放在这个文件夹下 
    public:存放 image、css、js 等文件 
    routes:存放路由文件 
    views:存放模版文件

    打开 app.js,让我们看看里面究竟有什么东西:

    ?
    12345678910111213141516171819202122232425262728293031323334 /** * Module dependencies. */ var
    express = require(
    'express')
      , routes = require('./routes')  , user = require('./routes/user')  , http = require('http')  , path = require('path'); var
    app = express();
     //
    all environments
    app.set('port', process.env.PORT || 3000);app.set('views', __dirname + '/views');app.set('view engine','ejs');app.use(express.favicon());app.use(express.logger('dev'));app.use(express.bodyParser());app.use(express.methodOverride());app.use(app.router);app.use(express.static(path.join(__dirname,'public'))); //
    development only
    if('development'== app.get('env')) {  app.use(express.errorHandler());} app.get('/', routes.index);app.get('/users', user.list); http.createServer(app).listen(app.get('port'), function(){  console.log('Express server listening on port ' + app.get('port'));});

    在 node.js 中模块分为核心模块和文件模块两种,核心模块是通过 require('xxxx') 导入的,文件模块是以 require('/xxxx') 或 require('./xxxx')、require('../xxxx') 形式导入的;核心模块是用c/c++编译的二进制模块,而文件模块是后缀为.js、.json、.node 的文件,在 node.js 中一个文件/文件夹也可以称之为一个模块。更多关于模块及模块加载顺序的信息请查阅官网:http://nodejs.org/api/all.html#all_modules 
    这里导入了 express、http、path 核心模块,routes 文件夹下的 index.js 和 user.js 文件模块。

    因为 express 框架是依赖 connect 框架(Node的一个中间件框架)创建而成的,可查阅 connect 文档:http://www.senchalabs.org/connect/和 express 官方文档:http://expressjs.com/api.html了解更多内容。 
    app.set(name, value):设置 name 的值为 value 
    app.set('port', process.env.PORT || 3000):设置端口为 process.env.PORT 或 3000 
    app.set('views', __dirname + '/views'):设置 views 文件夹为视图文件的目录,存放模板文件,__dirname 为全局变量,存储着当前正在执行脚本所在的目录名。 
    app.set('view engine', 'ejs'):设置视图模版引擎为 ejs

    app.use([path], function):使用中间件 function,可选参数path默认为”/” 
    app.use(express.favicon()):connect 内建的中间件,使用默认的 favicon 图标,如果想使用自己的图标,需改为 app.use(express.favicon(__dirname
    + '/public/images/favicon.ico'));
     这里我们把自定义的 favicon.ico 放到了 public/images 文件夹下。 
    app.use(express.logger('dev')):connect 内建的中间件,在开发环境下使用,在终端显示简单的不同颜色的日志,比如在启动 app.js 后访问 localhost:3000,终端会输出:

    ?
    123 Express
    server listening on port
    3000
    GET
    /
    20021ms - 206b
    GET
    /stylesheets/style.css
    3044ms

    数字200显示为绿色,304显示为蓝色。假如你去掉这一行代码,不管你怎么刷新网页,终端都只有一行 Express server listening on port 3000。 
    app.use(express.bodyParser()):connect 内建的中间件,用来解析请求体,支持 application/json, 
    application/x-www-form-urlencoded, 和 multipart/form-data。 
    app.use(express.methodOverride()):connect 内建的中间件,可以协助处理 POST 请求,伪装 PUT、DELETE 和其他 HTTP 方法。 
    app.use(app.router):设置应用的路由(可选),详细请参考:http://*.com/questions/12695591/node-js-express-js-how-does-app-router-work 
    app.use(express.static(path.join(__dirname, 'public'))):connect 内建的中间件,设置根目录下的 public 文件夹为静态文件服务器,存放 image、css、js 文件于此。 
    if ('development' == app.get('env')) {app.use(express.errorHandler());}:开发环境下的错误处理,输出错误信息。

    app.get('/', routes.index):路由控制器,如果用户访问” / “路径,则由 routes.index 来控制,routes/index.js 内容如下:

    ?
    123 exports.index
    = function(req, res){
      res.render('index', { title: 'Express'});};

    通过 exports.index 导出 index 函数接口,app.get('/',
    routes.index)
     相当于:

    ?
    123 app.get('/', function(req, res){  res.render('index', { title: 'Express'});};)

    res.render('index', { title: 'Express' }):调用 ejs 模板引擎解析 views/index.ejs(我们之前通过 app.set('views',
    __dirname + '/views')
     设置了模版文件默认存储在 views 下),并传入一个对象作为参数,这个对象只有一个属性 title: 'Express',即用字符串 Express 替换 views/index.ejs 中所有 title 变量,后面我们将会了解更多关于模板引的内容。

    ?
    123 http.createServer(app).listen(app.get('port'), function(){  console.log('Express server listening on port ' + app.get('port'));});

    这段代码的意思是创建服务器并监听3000端口,成功后在命令行中显示 Express server listening on port 3000,然后我们就可以通过在浏览器输入 localhost:3000 来访问了。

    这一小节我们学习了如何创建一个工程并启动它,了解了工程的大体结构,下一节我们将学习 Express 的基本使用及路由控制。

    路由控制

    工作原理

    上面提到过 app.js 中 app.get('/',
    routes.index)
     可以用以下代码取代:

    ?
    123 app.get('/', function(req, res){  res.render('index', { title: 'Express'});};)

    这段代码的意思是当访问主页时,调用 ejs 模板引擎,传入 title 变量的值为字符串 Express,来渲染 index.ejs 模版文件,生成静态页面并显示在浏览器里。

    我们来作一些修改,以上代码实现了路由的功能,我们当然可以不要 routes/index.js 文件,把实现路由功能的代码都放在 app.js 里,但随着时间的推移 app.js 会变得难以维护,这也违背了代码模块化的思想,所以我们把实现路由功能的代码都放在 routes/index.js 里。官方给出的写法是在 app.js 中实现了简单的路由分配,然后再去 index.js 中找到对应的路由函数,最终实现路由功能。我们不妨把路由控制器和实现路由功能的函数都放到 index.js 里,app.js 中只有一个总的路由接口。 
    打开 app.js,删除 ,
    user = require('./routes/user')
     (我们这里用不到 routes/user.js,同时删除这个文件)和

    ?
    12 app.get('/', routes.index);app.get('/users', user.list);

    在 app.js 最后添加:

    ?
    1 routes(app);

    修改 index.js 如下:

    ?
    12345 module.exports
    = function(app){
      app.get('/',function(req,res){    res.render('index', { title: 'Express'});  });};

    现在,再运行你的 app,你会发现主页毫无二致。这两种写法的区别就好比: 
    你的朋友结婚了,你收到请帖要赴宴。到了酒店门口被总管给拦住了。官方的写法是总管看了看请帖然后给你指了朋友团的地方,然后你过去坐下。咱的写法是总管看了看请帖简单确认了下你是被邀请的人,然后你进去自己找到朋友团的地方坐下。

    路由规则

    express 封装了多种 http 请求方式,但我们这里主要只使用 get 和 post 两种。 
    get 和 post 的第一个参数都为请求的路径,第二个参数为处理请求的回调函数,它有两个参数分别是 req 和 res,表示请求信息和响应信息 。路径请求及对应的获取路径有以下几种形式:

    req.query

    ?
    12345678910111213 //
    GET /search?q=tobi+ferret 
    req.query.q //
    => "tobi ferret" 
     //
    GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse 
    req.query.order //
    => "desc" 
     req.query.shoe.color //
    => "blue" 
     req.query.shoe.type //
    => "converse"

    req.body

    ?
    12345678910 //
    POST user[name]=tobi&user[email]=tobi@learnboost.com 
    req.body.user.name //
    => "tobi" 
     req.body.user.email //
    => "tobi@learnboost.com" 
     //
    POST { "name": "tobi" } 
    req.body.name //
    => "tobi"

    req.params

    ?
    123456789101112131415161718192021 //
    GET /user/tj 
    req.params.name //
    => "tj" 
     //
    GET /file/javascripts/jquery.js 
    req.params[0//
    => "javascripts/jquery.js" 
     **req.param(name)** //
    ?name=tobi 
    req.param('name'//
    => "tobi" 
     //
    POST name=tobi 
    req.param('name'//
    => "tobi" 
     //
    /user/tobi for /user/:name  
    req.param('name'//
    => "tobi"

    不难看出: 
    req.query 处理 get 请求 
    req.params 处理 /:xxx 形式的 get 请求 
    req.body 处理 post 请求 
    req.param(name) 可以处理 get 和 post 请求,但查找优先级由高到低为 req.params→req.body→req.query 
    路径规则还支持正则表达式,更多请查阅:http://expressjs.com/api.html

    添加路由规则

    当我们访问 localhost:3000 时,会显示:

    [一起学Node.js] Express MongoDB搭建多人博客-1

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

    [一起学Node.js] Express MongoDB搭建多人博客-1

    这是因为不存在 /nswbmw 的路由规则,而且它也不是一个 public 目录下的文件,所以 Express 返回了 404 Not Found 的错误。 
    下面我们来添加这条路由规则,使得当访问 localhost:3000/nswbmw 时,页面显示 hello,world! 
    注意:以下修改仅用于测试,看到效果后再把代码还原回来。 
    修改 index.js,在 app.get('/') 函数后添加一条路由规则:

    ?
    123 app.get('/nswbmw',function(req,res){  res.send('hello.world!');});

    访问 localhost:3000/nswbmw 页面显示如下:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    很简单吧?这一节我们学习了基本的路由规则及如何添加一条路由规则,下一节我们将学习模板引擎的知识。

    模版引擎

    什么是模板引擎

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

    模板引擎的功能是将页面模板和要显示的数据结合起来生成 HTML 页面。它既可以运 
    行在服务器端又可以运行在客户端,大多数时候它都在服务器端直接被解析为 HTML,解析 
    完成后再传输给客户端,因此客户端甚至无法判断页面是否是模板引擎生成的。有时候模板 
    引擎也可以运行在客户端,即浏览器中,典型的代表就是 XSLT,它以 XML 为输入,在客 
    户端生成 HTML 页面。但是由于浏览器兼容性问题,XSLT 并不是很流行。目前的主流还是 
    由服务器运行模板引擎。

    在 MVC 架构中,模板引擎包含在服务器端。控制器得到用户请求后,从模型获取数据, 
    调用模板引擎。模板引擎以数据和页面模板为输入,生成 HTML 页面,然后返回给控制器, 
    由控制器交回客户端。

    ——《Node.js开发指南》

    什么是 ejs ?

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

    使用模板引擎

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

    ?
    12 app.set('views', __dirname + '/views');app.set('view engine','ejs');

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

    ?
    1234567891011 <!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,然后把替换后的页面现实给用户。

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

    ?
    1234567891011 <!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>

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

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

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

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

    EJS 的官方示例:

    The Data

    ?
    12 {
    title:   
    'Cleaning Supplies',
      supplies: ['mop','broom','duster'] }

    The Template

    ?
    12345 <ul><%for(var i=0; i<supplies.length; i++) {%>   <li><%= supplies[i] %></li><%
    } %>
    </ul>

    The Result

    • mop
    • broom
    • duster

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

    页面布局

    Express 3.* 中我们不再使用 layout.ejs 进行页面布局,转而使用 include 来替代。include 的简单使用如下:

    a.ejs

    ?
    123 <%-
    include b %>
    hello,world!<%-
    include c %>

    b.ejs

    ?
    1 thisis b

    c.ejs

    ?
    1 thisis c

    最终 a.ejs 会显示:

    ?
    123 thisis bhello,world!thisis c

    这一节我们学习了模版引擎的相关知识,下一节我们正式开始学习如何从头开始搭建一个多人博客。

    搭建多人博客

    功能分析

    作为入门教程,我们要搭建的博客具有简单的允许多人注册、登录、发表文章、登出的功能。

    设计目标

    未登录:主页左侧导航显示 home、login、register,右侧显示已发表的文章、发表日期及作者。 
    登陆后:主页左侧导航显示 home、post、logout,右侧显示已发表的文章、发表日期及作者。 
    用户登录、注册、发表成功以及登出后都返回到主页。

    用户登陆前

    主页:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    登录页:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    注册页:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    用户登录后

    主页:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    发表页:

    [一起学Node.js] Express MongoDB搭建多人博客-1

    注意:没有登出页,当点击 LOGOUT 后,退出登陆并返回到主页。

    路由规划

    我们已经把设计的构想图贴出来了,接下来的任务就是写路由规划了。路由规划,或者说控制器规划是整个网站的骨架部分,因为它处于整个架构的枢纽位置,相当于各个接口之间的粘合剂,所以应该优先考虑。 
    根据构思的设计图,我们作以下路由规划:

    ?
    12345 /
    :首页
    /login
    :用户登录
    /reg
    :用户注册
    /post
    :发表文章
    /logout
    :登出

    login 和 reg 页只能是未登录的用户访问,而 post 和 logout 页只能是已登录的用户访问。首页则针对已登录和未登录的用户显示不同的内容。

    修改 index.js 如下:

    ?
    12345678910111213141516171819202122 module.exports
    = function(app){
      app.get('/',function(req,res){    res.render('index', { title: '主页'});  });  app.get('/reg',function(req,res){    res.render('reg', { title: '注册'});  });  app.post('/reg',function(req,res){  });  app.get('/login',function(req,res){    res.render('login', { title: '登录'});  });  app.post('/login',function(req,res){  });  app.get('/post',function(req,res){    res.render('post', { title: '发表'});  });  app.post('/post',function(req,res){  });  app.get('/logout',function(req,res){  });};

    如何针对已登录和未登录的用户显示不同的内容呢?或者说如何判断用户是否已经登陆了呢?进一步说如何记住用户的登录状态呢?我们通过引入会话机制,来记录用户登录状态,还要访问数据库来保存和读取用户信息。下一节我们将学习如何使用数据库。

    使用数据库

    MongoDB简介

    MongoDB 是一个对象数据库,它没有表、行等概念,也没有固定的模式和结构,所有的数据以文档的形式存储。所谓文档就是一个关联数组式的对象,它的内部由属性组成,一个属性对应的值可能是一个数、字符串、日期、数组,甚至是一个嵌套的文档。

    ——《Node.js开发指南》

    下面是一个 MongoDB 文档的示例:

    ?
    123456789101112 {  "_id": ObjectId( "4f7fe8432b4a1077a7c551e8"),    "name":"nswbmw"  "age":22,  "email": [ "xxx@126.com","xxx@gmail.com"],   "family": {      "mother": { ... },      "father": { ... },      "sister : { ... },      "address":"earth"   }}

    更多有关 MongoDB 的知识请参考 《mongodb权威指南》或查阅:http://www.mongodb.org/

    安装MongoDB

    安装 mongodb 很简单,去官网(http://www.mongodb.org/downloads)下载最新版的 mongodb,解压到D盘并把文件夹重命名为 mongodb,并在 mongodb 文件夹下新建 blog 文件夹作为我们的存储目录。打开 cmd,切换到 d:\mongodb\bin 目录下,在命令行中输入 mongod -dbpath “d:\mongodb\blog” 设置 blog 文件夹作为我们工程的存储目录,这样数据库就成功启动了。为了方便以后使用数据库,我们在桌面上新建 “启动mongodb.bat” ,并写入 d:\mongodb\bin\mongod.exe
    -dbpath d:\mongodb\blog
     ,这样我们以后只需运行桌面上的 “启动mongodb.bat” 就可启动数据库了。

    连接MongoDB

    数据库虽然安装并启动成功了,但我们需要连接数据库后才能使用数据库。怎么才能在 Node.js 中使用 MongoDb 呢?我们需要使用 node-mongodb-native 模块,打开 package.json,在 dependencies 中添加一行代码:

    ?
    12345678910111213 {  "name":"blog",  "version":"0.0.1",  "private":true,  "scripts": {    "start":"node app.js"  },  "dependencies": {    "express":"3.2.4",    "ejs":"*",    "mongodb":"*"  }}

    然后运行 npm install 更新依赖的模块,稍等片刻后模块就下载并安装完成。

    接下来在工程的目录中创建 settings.js 文件,这个文件用于保存数据库的连接信息。我们将数据库命名为 blog,数据库服务器在本地,因此 settings.js 文件的内容如下:

    ?
    12345 module.exports
    = {
      cookieSecret:'myblog',  db:'blog',  host:'localhost'};

    其中 db 是数据库的名称,host 是数据库的地址。cookieSecret 用于 Cookie 加密与数据库无关,我们留作后用。

    接下来在根目录下新建 models 文件夹,并在 models 文件夹下新建 db.js ,添加如下代码:

    ?
    12345 var
    settings = require(
    '../settings'),
        Db = require('mongodb').Db,    Connection = require('mongodb').Connection,    Server = require('mongodb').Server;module.exports
    =
    newDb(settings.db,newServer(settings.host, Connection.DEFAULT_PORT, {}));

    我们先不用弄清楚代码为什么这么写,我们现在只需知道以上代码通过 module.exports 输出了创建的数据库连接,在后面的小节中我们会用到这个模块。

    会话支持

    会话是一种持久的网络协议,用于完成服务器和客户端之间的一些交互行为。会话是一个比连接粒度更大的概念, 一次会话可能包含多次连接,每次连接都被认为是会话的一次操作。在网络应用开发中,有必要实现会话以帮助用户交互。例如网上购物的场景,用户浏览了多个页面,购买了一些物品,这些请求在多次连接中完成。许多应用层网络协议都是由会话支持的,如 FTP、Telnet 等,而 HTTP 协议是无状态的,本身不支持会话,因此在没有额外手段的帮助下,前面场景中服务器不知道用户购买了什么。

    为了在无状态的 HTTP 协议之上实现会话,Cookie 诞生了。Cookie 是一些存储在客户端的信息,每次连接的时候由浏览器向服务器递交,服务器也向浏览器发起存储 Cookie 的请求,依靠这样的手段服务器可以识别客户端。我们通常意义上的 HTTP 会话功能就是这样实现的。具体来说,浏览器首次向服务器发起请求时,服务器生成一个唯一标识符并发送给客户端浏览器,浏览器将这个唯一标识符存储在 Cookie 中,以后每次再发起请求,客户端

    浏览器都会向服务器传送这个唯一标识符,服务器通过这个唯一标识符来识别用户。 对于开发者来说,我们无须关心浏览器端的存储,需要关注的仅仅是如何通过这个唯一标识符来识别用户。很多服务端脚本语言都有会话功能,如 PHP,把每个唯一标识符存储到文件中。Express 也提供了会话中间件,默认情况下是把用户信息存储在内存中,但我们既然已经有了 MongoDB,不妨把会话信息存储在数据库中,便于持久维护。

    ——《Node.js开发指南》

    为了使用这一功能,我们首先要获取一个叫做 connect-mongo 的模块,在 package.json 中添加一行代码:

    ?
    1234567891011121314 {  "name":"blog",  "version":"0.0.1",  "private":true,  "scripts": {    "start":"node app.js"  },  "dependencies": {    "express":"3.2.4",    "ejs":"*",    "mongodb":"*",    "connect-mongo":"*"  }}

    运行 npm install 安装模块。然后打开 app.js,在 ,
    path = require('path')
     后添加以下代码:

    ?
    12 ,
    MongoStore = require(
    'connect-mongo')(express)
    ,
    settings = require(
    './settings');

    在 app.use(express.methodOverride()); 后添加:

    ?
    123456789 app.use(express.cookieParser());app.use(express.session({  secret: settings.cookieSecret,  key: settings.db,  cookie: {maxAge: 1000*60*60*24*30},//30 days  store:newMongoStore({    db: settings.db  })}));

    其中 express.cookieParser() 是 Cookie 解析的中间件。express.session() 则提供会话支持,secret 用来防止篡改 cookie,key 的值为 cookie 的名字,通过设置 cookie 的 maxAge 值设定cookie的生存期,这里我们设置 cookie 的生存期为30天,设置它的 store 参数为 MongoStore 实例,把会话信息存储到数据库中,以避免丢失。在后面的小节中,我们可以通过 req.session 获取当前用户的会话对象,以维护用户相关的信息。