临时会话对象 session

也是用来 解决 http 无状态协议的问题(无法区分多次请求是否发送自同一客户端

npm install express-session

npm install connect-mongo

  • 基本使用
  • const session = require('express-session');
    const MongoStore = require('connect-mongo')(session);
  • app.use(express.session({
    secret: 'keyboard cat', // 加密字符串,参与 sessionid 加密
    saveUninitialized: false, // 在存储某东东之前,不会创建 session 对象
    resave: false, // 如果没有修改 session 对象,就不会重新保存
    store: new MongoStore({
    url: 'mongodb://localhost: 27017/test-app', // 连接数据库的地址
    touchAfter: 24 * 3600 // 24 小时更新一次
    })
    })); ...
    // 设置 session 会在数据库中创建 session 对象
    // 保存 userId=findRet.id 到数据库
    request.session.userId = findRet.id;
    ...
    // 解析 cookie 中的 session 去数据库中找对应 sessionId 的数据
    // 返回一个 cookie
    const {userId} = request.session;
    ...
  • session 优势

读写二合一

存储数据近乎无限大,取决于 服务器 的存储容量

传输流量小(数据传输过程中 cookie 更小更少)

  • 私有变量 _name
  • 一定要在最开始 激活 session    
    app.use(session({... ...});

登录/注册 实例

package.json

  • {
    "name": "node_express",
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "dependencies": {
    "connect-mongo": "^2.0.3",
    "cookie-parser": "^1.4.3",
    "ejs": "^2.6.1",
    "express": "^4.16.4",
    "express-session": "^1.15.6",
    "mongoose": "^5.4.0",
    "sha1": "^1.1.1"
    }
    }

public/login.html

  • <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8"/>
    <title>用户登录</title> <link rel="stylesheet" type="text/css" href="css/index.css"/>
    </head> <body>
    <div id="outer_box" class="login">
    <h2>用户登录</h2>
    <form action="http://localhost:3000/login" method="post">
    <div class="clothes">
    <label for="input_name">用&nbsp;户&nbsp;名</label>
    <input id="input_name" type="text" name="user_name" placeholder="请输入用户名" />
    </div> <div class="clothes">
    <label for="input_pwd">密&nbsp;&nbsp;&nbsp;码</label>
    <input id="input_pwd" type="password" name="user_pwd" placeholder="请输入密码" />
    </div> <div class="clothes">
    <a class="btn" href="http://localhost:3000/register">
    <button type="button">注册</button>
    </a>
    <button class="login btn" type="submit">登录</button>
    </div>
    </form>
    </div>
    </body>
    </html>

public/register.html

  • <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8"/>
    <title>用户注册</title> <link rel="stylesheet" type="text/css" href="css/index.css"/>
    </head> <body>
    <div id="outer_box" class="register">
    <h2>用户注册</h2>
    <form action="http://localhost:3000/register" method="post">
    <div class="clothes">
    <label for="input_name">用&nbsp;户&nbsp;名</label>
    <input id="input_name" type="text" name="user_name" placeholder="请输入用户名" />
    </div> <div class="clothes">
    <label for="input_pwd">密&nbsp;&nbsp;&nbsp;码</label>
    <input id="input_pwd" type="password" name="user_pwd" placeholder="请输入密码" />
    </div> <div class="clothes">
    <label for="input_repeat_pwd">确认密码</label>
    <input id="input_repeat_pwd" type="password" name="user_repeat_pwd" placeholder="请再次输入密码" />
    </div> <div class="clothes">
    <label for="input_email">注册邮箱</label>
    <input id="input_email" type="text" name="user_email" placeholder="请输入邮箱地址" />
    </div> <div class="clothes">
    <button class="register btn" type="submit">注册</button>
    <a class="btn" href="http://localhost:3000/login">
    <button type="button">登录</button>
    </a>
    </div>
    </form>
    </div>
    </body>
    </html>

public/user_center.html

  • <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8"/>
    <title>用户中心</title> <link rel="stylesheet" type="text/css" href="css/index.css"/>
    </head> <body>
    <div id="outer_box" class="login">
    <h2>个人空间</h2>
    </div>
    </body>
    </html>

public/index.css

  • body {
    width: 100%;
    height: 100%; color: #000;
    background: #b9c2a4;
    background-size: cover; /* 指定背景图片大小 */
    } /*************************************************/
    #outer_box {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #1a45c3;
    } #outer_box.login {
    color: #9e098b;
    } #outer_box.register {
    color: #1a45c3;
    } #outer_box>h2{
    padding-bottom: 40px;
    margin-left: -50px;
    } .clothes {
    position: relative;
    width: 260px;
    display: flex;
    justify-content: space-between;
    margin: 20px 0;
    font-size: 18px;
    line-height: 32px;
    } .tips {
    position: absolute;
    top:;
    right: -100%;
    margin-left: -50%;
    margin-top: 2px;
    width: 252px;
    height: 32px;
    text-align: center;
    color: #f00;
    } .clothes>label{
    width: 80px;
    text-align: center;
    } .clothes>input{
    width: 170px;
    height: 32px;
    } button {
    width: 100%;
    height: 100%; font-size: 16px;
    background-color: #c4ceda;
    cursor: pointer;
    } .clothes .btn{
    width: 64px;
    height: 32px;
    margin: 0 20px;
    } .clothes button.register{
    background-color: #1a45c3;
    color: #fff;
    } .clothes button.login{
    background-color: #9e098b;
    color: #fff;
    } #outer_box>h2 {
    position: relative;
    } #server_info {
    display: block;
    width: 139px;
    height: 20px;
    border-radius: 10px; position: absolute;
    top:;
    right:; color: red;
    font-size: 14px;
    text-align: center;
    line-height: 20px;
    background-color: #cecece;
    }

views/login.ejs

  • <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8"/>
    <title>用户登录</title> <link rel="stylesheet" type="text/css" href="css/index.css"/>
    </head> <body>
    <div id="outer_box" class="login">
    <h2>
    用户登录
    <div id="server_info">
    <%= serverInfo.tips %>
    </div>
    </h2>
    <form action="http://localhost:3000/login" method="post">
    <div class="clothes">
    <label for="input_name">用&nbsp;户&nbsp;名</label>
    <input id="input_name" type="text" name="user_name" value="<%= serverInfo.uName %>" placeholder="请输入用户名" />
    </div> <div class="clothes">
    <label for="input_pwd">密&nbsp;&nbsp;&nbsp;码</label>
    <input id="input_pwd" type="password" name="user_pwd" placeholder="请输入密码" />
    </div> <div class="clothes">
    <a class="btn" href="http://localhost:3000/register">
    <button type="button">注册</button>
    </a>
    <button class="login btn" type="submit">登录</button>
    </div>
    </form>
    </div>
    </body>
    </html>

views/register.ejs

  • <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8"/>
    <title>用户注册</title> <link rel="stylesheet" type="text/css" href="css/index.css"/>
    </head> <body>
    <div id="outer_box" class="register">
    <h2>用户注册</h2>
    <form action="http://localhost:3000/register" method="post">
    <div class="clothes">
    <label for="input_name">用&nbsp;户&nbsp;名</label>
    <input id="input_name" type="text" name="user_name" value="<%= serverInfo.uName %>" placeholder="请输入用户名" />
    <div class="tips"><%= serverInfo.nameErr %></div>
    </div> <div class="clothes">
    <label for="input_pwd">密&nbsp;&nbsp;&nbsp;码</label>
    <input id="input_pwd" type="password" name="user_pwd" placeholder="请输入密码" />
    <div class="tips"><%= serverInfo.passwordErr %></div>
    </div> <div class="clothes">
    <label for="input_repeat_pwd">确认密码</label>
    <input id="input_repeat_pwd" type="password" name="user_repeat_pwd" placeholder="请再次输入密码" />
    <div class="tips"><%= serverInfo.repeatErr %></div>
    </div> <div class="clothes">
    <label for="input_email">注册邮箱</label>
    <input id="input_email" type="text" name="user_email" value="<%= serverInfo.uEmail %>" placeholder="请输入邮箱地址" />
    <div class="tips"><%= serverInfo.emailErr %></div>
    </div> <div class="clothes">
    <button class="register btn" type="submit">注册</button>
    <a class="btn" href="http://localhost:3000/login">
    <button type="button">登录</button>
    </a>
    </div>
    </form>
    </div>
    </body>
    </html>

views/user_center.ejs

  • <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8"/>
    <title>用户中心</title> <link rel="stylesheet" type="text/css" href="css/index.css"/>
    </head> <body>
    <div id="outer_box" class="login">
    <h2><%= serverInfo.uName%> - 个人空间</h2>
    </div>
    </body>
    </html>

db/connectDB.js

  • const mongoose = require('mongoose');
    
    module.exports = new Promise((resolve, reject)=>{
    mongoose.connect('mongodb://localhost:27017/user_database', {useNewUrlParser:true})
    mongoose.connection.once('open', err=>{
    if(err){
    console.log(err);
    reject(err);
    }else{
    resolve('数据库已连接');
    };
    });
    });

models/userModel.js

  • const mongoose = require('mongoose');
    
    const Schema = mongoose.Schema;
    const fieldSchema = new Schema({
    "userName": {
    "type": String,
    "unique": true,
    "required": true
    },
    "userPassword": {
    "type": String,
    "required": true
    },
    "userEmail": {
    "type": String,
    "unique": true,
    "required": true
    },
    "createTime": {
    "type": Date,
    "default": Date.now()
    }
    }); module.exports = mongoose.model("user_info", fieldSchema);

routers/get/index_router.js

  • const express = require('express');
    
    const promiseConnect = require('../../db/connectDB.js');
    const userInfoModel = require('../../models/userModel.js'); const {resolve} = require('path');
    const cookieParser = require('cookie-parser'); const indexRouter = new express.Router();
    indexRouter.use(cookieParser()); /************************ get ***********************/
    indexRouter.get('/', (request, response)=>{
    response.sendFile(resolve(__dirname, '../../public/login.html'));
    }); indexRouter.get('/login', (request, response)=>{
    response.sendFile(resolve(__dirname, '../../public/login.html'));
    }); indexRouter.get('/register', (request, response)=>{
    response.sendFile(resolve(__dirname, '../../public/register.html'));
    }); promiseConnect.then(result=>{
    console.log("index_router.js - "+result); indexRouter.get('/user_center',async (request, response)=>{
    // s4: 解析 cookie 中的 session 去数据库中找对应 sessionId 的数据
    const {userId} = request.session; // 返回一个 Cookie 对象 if(userId){ // 用户已经登录
    const findRet = await userInfoModel.findOne({"_id":userId});
    if(findRet){
    let serverInfo = {uName:findRet.userName};
    response.render('user_center.ejs', {serverInfo});
    }else{ // 恶意 Cookie
    response.clearCookie("userId");
    response.redirect('/login');
    };
    }else{ // 用户未登录
    response.redirect('/login');
    };
    });
    }).catch(err=>console.log(err)); module.exports = indexRouter;

routers/post/form_router.js

  • const express =  require('express');
    
    const sha1 =  require('sha1');
    
    const promiseConnect = require('../../db/connectDB.js');
    const userInfoModel = require('../../models/userModel.js'); const formRouter = new express.Router(); /************************ post ***********************/
    let logged = false ;
    promiseConnect.then(result=>{
    console.log("form_router.js - "+result); formRouter.post('/register', async (request, response)=>{
    const {
    user_name:uName,
    user_pwd:uPwd,
    user_repeat_pwd:urePwd,
    user_email:uEmail,
    } = request.body; /**** 解构赋值 ****/ userInfo = {
    "userName": uName,
    "userPassword": uPwd,
    "userEmail": uEmail
    }; let serverInfo = {uName, uEmail}; if(urePwd !== uPwd){
    serverInfo.repeatErr = '密码两次输入不一致';
    };
    if(!(/^[a-zA-Z][a-zA-Z0-9_]{5,20}$/.test(uName))){
    serverInfo.nameErr = '用户名不合法';
    };
    if(!(/^[a-zA-Z0-9_]{6,20}$/.test(uPwd))){
    serverInfo.passwordErr = '密码不合法';
    };
    if(!(/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(uEmail))){
    serverInfo.emailErr = '邮箱不合法';
    }; const fond = await userInfoModel.findOne({"userName": uName});
    if(fond){
    serverInfo.nameErr = '用户名已被注册';
    }; const badEmail = await userInfoModel.findOne({"userEmail": uEmail});
    if(badEmail){
    serverInfo.emailErr = '邮箱已被注册';
    }; if(serverInfo.repeatErr || serverInfo.nameErr || serverInfo.passwordErr || serverInfo.emailErr){
    response.render('register.ejs', {serverInfo}); // 渲染错误信息
    return;
    }else{
    userInfo.userPassword = sha1(userInfo.userPassword);
    await userInfoModel.create(userInfo);
    response.redirect('/login'); // 跳转到登录
    };
    }); formRouter.post('/login',async (request, response)=>{
    logged = false;
    let uName = request.body['user_name'];
    let uPwd = request.body['user_pwd'];
    userInfo = {
    "userName": uName,
    "userPassword": uPwd
    }; if(!(/^[a-zA-Z][a-zA-Z0-9_]{5,20}$/.test(uName))){
    logged = false;
    }else if(!(/^[a-zA-Z0-9_]{6,20}$/.test(uPwd))){
    logged = false;
    };
    try{
    const findName = await userInfoModel.findOne({"userName": uName});
    if(findName && (findName.userPassword===sha1(uPwd)) ){
    logged = true;
    }; let serverInfo = {uName};
    if(logged){
    // s3: 设置 session 会在数据库中创建 session 对象
    // 保存 userId=findRet.id 到数据库
    request.session.userId = findName.id; response.redirect('/user_center'); // 跳转到用户 个人空间 页面
    }else{
    serverInfo.tips='用户名或密码错误';
    response.render('login.ejs', {serverInfo}); // 渲染错误信息
    };
    }catch(err) {
    console.log(err);
    }
    });
    }).catch(err=>console.log(err)); module.exports = formRouter;

index.js

  • const express =  require('express');
    // s1: 导入 session 模块
    const session = require('express-session');
    const mongoSession = require('connect-mongo')(session); const app = express(); const indexRouter = require('./routers/get/index_router.js');
    const formRouter = require('./routers/post/form_router.js'); app.set('views', 'views'); // 1. 配置模板路径
    app.set('view engine', 'ejs'); // 2. 配置模板引擎 /*********************** 中间件 **********************/
    // s2: 通过中间件,激活 session
    app.use(session({
    secret: 'myMongoSession',
    saveUninitialized: false,
    resave: false,
    store: new mongoSession({
    url: 'mongodb://localhost:27017/user_database',
    touchAfter: 1000*3600*24
    })
    })); // 暴露路由 login.html register.html
    app.use(express.static('public')); // 默认调用 next(); // 将 用户输入的数据 挂载到 请求体 request.body 上
    app.use(express.urlencoded({extended: true})); // 默认调用 next(); app.use(indexRouter);
    app.use(formRouter); /**************** 端口号 3000, 启动服务器 ***************/
    app.listen(3000, err=>console.log(err?err:'\n\n服务器已启动: http://localhost:3000\n\t\tHunting Happy!'));

Node.js_express_临时会话对象 session的更多相关文章

  1. session会话对象

    一.session会话对象介绍: 会话对象让你能够跨请求保持某些参数,它也会在同一个session实例发出的所有请求之间保持cookie. 二.步骤 1.对session对象进行一次实例化 2.进行登 ...

  2. 会话跟踪session cookie

    会话跟踪 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在 ...

  3. php中会话保持 session 与cooker

    会话保持 1.session Session:在计算机中,尤其是在网络应用中,称为"会话控制".Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 ...

  4. JSP内置对象Session

    创建和获取客户的会话 setAttribute()与getAttribute() session.setAttribute(String name , Object obj) 如session.set ...

  5. 标准会话对象——StandardSession

    Tomcat使用了一个StandardSession对象用来表示标准的会话结构,用来封装需要存储的状态信息.标准会话对象StandardSession实现了Session.Serializable.H ...

  6. jsp内置对象-session对象

    一.session概述 隐含对象session是javax.servlet.http.HttpSession接口实现类的对象,用于保存用户的状态信息. 在web开发中,服务器为每个用户浏览器创建一个会 ...

  7. Java中的会话Cookie&&Session

    会话技术 会话: 一次会话中包含多次请求和响应. 一次会话:浏览器第一次给服务器资源发送请,会话建立,直到有一方断开为止 功能:在一次会话的范围内的多次请求之间共享数据 方式: 客户端会话技术:coo ...

  8. 会话跟踪session

    会话跟踪 HTTP是“无状态”协议:客户程序每次读取Web页面,都打开到web服务器的单独的连接,而且,服务器也不自动维护客户的上下文信息.类似客户决定结账时,如何确定之前创建的购物车中哪个属于此客户 ...

  9. 会话追踪(session tracking)

    HTTP是一种无连接的协议,如果一个客户端只是单纯地请求一个文件(HTML或GIF),服务器端可以响应给客户端,并不需要知道一连串的请求是否来自于相同的客户端,而且也不需要担心客户端是否处在连接状态. ...

随机推荐

  1. python Django cookie和session

    在一个会话的多个请求中共享数据,这就是会话跟踪技术.例如在一个会话中的请求如下:  请求银行主页: 请求登录(请求参数是用户名和密码): 请求转账(请求参数与转账相关的数据): 请求信誉卡还款(请求参 ...

  2. JProfiler性能分析工具

    1.简介 JProfiler是一个商业授权的Java剖析工具,用于分析Java EE和Java SE应用程序. 2.JVMTI JDK本身定义了目标明确并功能完善的JNI(Java Native In ...

  3. django - 总结

    0.html-socket import socket def handle_request(client): request_data = client.recv(1024) print(" ...

  4. 爬取qq音乐巅峰榜---内地音乐的榜单

    import requestsimport jsonimport sys for i in range(0,10): url = "https://szc.y.qq.com/v8/fcg-b ...

  5. vue安装scss,并且全局引入

    在写vue的css样式时,觉得需要css预处理器让自己的css更加简洁.适应性更强.可读性更佳,更易于代码的维护,于是在vue-cli脚手架采用scss.写过的人都知道,每写一个.vue文件都要在st ...

  6. C# - 表达式与语句

    表达式与语句(Expression&Statement) 操作数(Operands) 1.数字.2.字符.3.变量.4.类型.5.对象.6.方法 操作符(Operator) 参考:C# - 操 ...

  7. POJ 2318 TOYS (叉积+二分)

    题目: Description Calculate the number of toys that land in each bin of a partitioned toy box. Mom and ...

  8. Illegal invocation with document.querySelector [duplicate]

    document.querySelectorAll赋给其它变量时, 为什么要.bind(document)? https://stackoverflow.com/questions/12637061/ ...

  9. Revit手工创建族(转)

    http://www.cnblogs.com/greatverve/p/revit-family.html 手工创建族 1.画两个参考平面. 图3001 2.点击族类型,添加参数. 图3002,300 ...

  10. C语言可重入函数和不可重入函数

    可重入函数和不可重入函数的概念 在函数中如果我们使用静态变量了,导致产生中断调用别的函数的 过程中可能还会调用这个函数,于是原来的 静态变量被在这里改变了,然后返回主体函数,用着的那个静态变量就被改变 ...