浏览器存储技术 Cookie

服务器将少量数据交于浏览器存储管理

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

一个网页一般最多 20个的 cookie,每个 cookie 一般 4KB

第一次访问 url,服务器会创建一个 Cookie 给浏览器

浏览器会保存 Cookie,以后每次请求,都会携带所有 Cookie,一并发送给服务器

  • 登录 Cookie

1. 浏览器发送请求给服务器,请求登录

  • app.get('/cookie1', (request, response)=>{
    response.cookie('userid', '123456', {masAge: 100*3600*24});
    response.send('cookie1 的 get 请求 的响应');
    });

2. 服务器返回响应给浏览器,会创建并发送 Cookie(包含了当前用户的唯一标识)

3. 浏览器接受响应,会将 Cookie 保存下来

4. 浏览器下一次发送请求时,都会自动携带上 Cookie

  • npm install cookie-parser
  • const cookieParser = require('cookie-parser');
    app.use(cookieParser()); // 应用中间件,解析 Cookie 的数据,挂载到 request.cookie 上
    app.get('/cookie2', (request, response)=>{
    response.send(request.cookies);
    });

5. 服务器接受到请求,解析 Cookie,从而判断是哪个用户发送的请求(解决 http 协议无状态问题)

6.  主动清除 Cookie

  • app.get('/cookie3', (request, response)=>{
    response.clearCookie('userid');
    response.send('key 为 userid 的 cookie 已经清除');
    });
  • 前端操作 Cookie
  • 清除 Cookie
  • document.cookie = 'hello=123; expires=' + new Date(Data.now()-1000);
  • 判断用户到底登录没?哪个用户登录的?

不能将用户的隐私直接暴露

数据加密 或者 数据库文档 id 装进 Cookie

res.cookie('userid', user.id, {maxAge: 1000*24*3600*7});

  • const cookieParser = require('cookie-parser');
    
    indexRouter.use(cookieParser());    // 应用中间件,解析 Cookie 的数据,挂载到 request.cookie 上
    
    indexRouter.get('/user_center',async (request, response)=>{
    const {userId} = request.cookies;
    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');
    };
    });
  • 登录注册实例

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",
    "mongoose": "^5.4.0",
    "sha1": "^1.1.1"
    }
    }

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/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/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/css/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: 0;
    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: 0;
    right: 0; color: red;
    font-size: 14px;
    text-align: center;
    line-height: 20px;
    background-color: #cecece;
    }

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/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/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)=>{
    const {userId} = request.cookies;
    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){
    response.cookie('userId', findName.id, {maxAge: 1000*24*3600*7});
    response.redirect('/user_center'); // 跳转到用户 个人空间 页面
    }else{
    serverInfo.tips='用户名或密码错误';
    response.render('login.ejs', {serverInfo}); // 渲染错误信息
    };
    }catch(err) {
    cosole.log(err);
    }
    });
    }).catch(err=>console.log(err)); module.exports = formRouter;

index.js

  • const express =  require('express');
    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. 配置模板引擎 /*********************** 中间件 **********************/
    // 暴露路由 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_浏览器存储技术 Cookie(服务器将少量数据交于浏览器存储管理)的更多相关文章

  1. 计算机浏览器存储技术cookie、sessionStorage、localStorage

    HTTP无状态协议是指协议对于事务处理没有记忆能力.会话跟踪协议的状态是指下一次传输可以"记住"这次传输信息的能力,无状态是指同一个会话(注意什么叫同一个会话)的连续两个请求互相不 ...

  2. http 协议_DNS_域名解析 DNS 服务器_内容分发网络 CDN_缓存机制_HTML5 浏览器存储技术_cookie_sessionStorage_localStorage

    TCP/IP 协议族 是按层次去划分的 应用层    决定了向用户提供应用服务时通信的活动. FTP 协议(文件传输协议)DNS(域名协议)HTTP(超文本传输协议) 传输层    提供处于网络连接中 ...

  3. 浏览器存储:cookie

    Cookie是什么:cookie是指存储在用户本地终端上的数据,同时它是与具体的web页面或者站点相关的.Cookie数据会自动在web浏览器和web服务器之间传输,也就是说HTTP请求发送时,会把保 ...

  4. 浅谈浏览器存储(cookie、localStorage、sessionStorage)

    今天我们从前端的角度了解一下浏览器存储,我们常见且常用的存储方式主要由两种:cookie.webStorage(localStorage和sessionStorage).下面我们来一一认识它们. Co ...

  5. Ajax交互,浏览器接收不到服务器的Json数据(跨域问题)

    该问题的情景如下: 问题描述 Ajax的请求代码放在一台机器上,而服务器的java 路由程序放在另一个机子上,所以Ajax的url填写的是带"http://"  的地址,而不是相对 ...

  6. 深入了解浏览器存储:对比Cookie、LocalStorage、sessionStorage与IndexedDB

    摘要: 对比Cookie.LocalStorage.sessionStorage与IndexedDB 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 随着移动网络的发展与演化,我 ...

  7. LocalStorage存储和cookie存储

    localStorage是H5的新特性,主要用来本地存储,一般浏览器支持的大小是5M,不同浏览器会有所不同,解决了cookie存储空间不足的问题. 2.使用:     ⑴.存 if(!window.l ...

  8. 会话技术cookie与session

    目录 会话技术cookie 会话技术 cookie 服务器怎样把Cookie写 给客户端 服务器如何获取客户端携带的cookie session session简介 Session如何办到在一个ser ...

  9. 会话跟踪技术 - Cookie 和 Session 快速上手 + 登陆注册案例

    目录 1. 会话跟踪技术概述 2. Cookie 2.1 Cookie的概念和工作流程 2.2 Cookie的基本使用 2.3 Cookie的原理分析 2.4 Cookie的使用细节 2.4.1 Co ...

随机推荐

  1. 前端面试题整理—JavaScript篇(二)

    1.使用js实现一个可持续的动画 2.实现一个可以自由拖动的悬浮框 3.实现一个倒计时效果 4.使用js仿写一个原生下拉列表框 5.创建10个<a>标签,点击的时候弹出对应的序号 6.实现 ...

  2. [物理学与PDEs]第4章第2节 反应流体力学方程组 2.4 反应流体力学方程组的数学结构

    1.  粘性热传导反应流体力学方程组是拟线性对称双曲 - 抛物耦合组. 2.  理想反应流体力学方程组是一阶拟线性对称双曲组 (取 ${\bf u},p,S,Z$ 为未知函数). 3.  右端项具有间 ...

  3. IIS--互联网信息服务

    IIS--互联网信息服务 1.IIS是微软出品的一个服务器插件 2.IIS的功能:1)发布web网站 2)发布ftp站点 WEB服务器:1.监听TCP80端口 --- http://www.baidu ...

  4. js中escape对应的C#解码函数 UrlDecode

    js中escape对应的C#解码函数 System.Web.HttpUtility.UrlDecode(s),使用过程中有以下几点需要注意   js中escape对应的C#解码函数 System.We ...

  5. UE4 AR开发笔记

    1.基础使用 ArToolKit:生成图片特征,可以用彩图.(图片先灰化)    genTexData效准相机.由于有的相机照相有弧度.  calib_camera 2.使用UE4ARPlugins做 ...

  6. 用sklearn 实现linear regression

    基本的regression算法有四种方法可以实现,分别是下面四种 LinearRegressionRidge (L2 regularization)Lasso (L1 regularization)E ...

  7. Hello jna

    记录下这几天用jna3.5.0调c++写的dll的经历 os:win7 用jna调dll首先需要一个dll文件并有可调的方法,然后根据方法的名称,参数,返回值编写一个interface c++需要包含 ...

  8. django drf 基础学习2

    DRF基本程序调用一 models初步编写  1 编写model.py    from django.db import models 导入    class dbinfo(models.Model) ...

  9. java -jar参数携带问题

    方式一 -DpropName=propValue的形式携带,要放在-jar参数前面,亲测,放在它后面好像取不到值 java -fileName=JOURNAL_TREENODE_DATA-201904 ...

  10. Lua“控制”C

    [前言] Lua语言本身是一个功能非常有限,而比较单调的语言,而且标准库也非常的平庸,它的NB之处就在于,它能和C.C++等高级语言完美“私通”.我们可以使用C.C++语言去给Lua写一个完美的库,让 ...