Node.js_express_浏览器存储技术 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">用 户 名</label>
<input id="input_name" type="text" name="user_name" placeholder="请输入用户名" />
</div> <div class="clothes">
<label for="input_pwd">密 码</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">用 户 名</label>
<input id="input_name" type="text" name="user_name" placeholder="请输入用户名" />
</div> <div class="clothes">
<label for="input_pwd">密 码</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">用 户 名</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">密 码</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">用 户 名</label>
<input id="input_name" type="text" name="user_name" value="<%= serverInfo.uName %>" placeholder="请输入用户名" />
</div> <div class="clothes">
<label for="input_pwd">密 码</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(服务器将少量数据交于浏览器存储管理)的更多相关文章
- 计算机浏览器存储技术cookie、sessionStorage、localStorage
HTTP无状态协议是指协议对于事务处理没有记忆能力.会话跟踪协议的状态是指下一次传输可以"记住"这次传输信息的能力,无状态是指同一个会话(注意什么叫同一个会话)的连续两个请求互相不 ...
- http 协议_DNS_域名解析 DNS 服务器_内容分发网络 CDN_缓存机制_HTML5 浏览器存储技术_cookie_sessionStorage_localStorage
TCP/IP 协议族 是按层次去划分的 应用层 决定了向用户提供应用服务时通信的活动. FTP 协议(文件传输协议)DNS(域名协议)HTTP(超文本传输协议) 传输层 提供处于网络连接中 ...
- 浏览器存储:cookie
Cookie是什么:cookie是指存储在用户本地终端上的数据,同时它是与具体的web页面或者站点相关的.Cookie数据会自动在web浏览器和web服务器之间传输,也就是说HTTP请求发送时,会把保 ...
- 浅谈浏览器存储(cookie、localStorage、sessionStorage)
今天我们从前端的角度了解一下浏览器存储,我们常见且常用的存储方式主要由两种:cookie.webStorage(localStorage和sessionStorage).下面我们来一一认识它们. Co ...
- Ajax交互,浏览器接收不到服务器的Json数据(跨域问题)
该问题的情景如下: 问题描述 Ajax的请求代码放在一台机器上,而服务器的java 路由程序放在另一个机子上,所以Ajax的url填写的是带"http://" 的地址,而不是相对 ...
- 深入了解浏览器存储:对比Cookie、LocalStorage、sessionStorage与IndexedDB
摘要: 对比Cookie.LocalStorage.sessionStorage与IndexedDB 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 随着移动网络的发展与演化,我 ...
- LocalStorage存储和cookie存储
localStorage是H5的新特性,主要用来本地存储,一般浏览器支持的大小是5M,不同浏览器会有所不同,解决了cookie存储空间不足的问题. 2.使用: ⑴.存 if(!window.l ...
- 会话技术cookie与session
目录 会话技术cookie 会话技术 cookie 服务器怎样把Cookie写 给客户端 服务器如何获取客户端携带的cookie session session简介 Session如何办到在一个ser ...
- 会话跟踪技术 - Cookie 和 Session 快速上手 + 登陆注册案例
目录 1. 会话跟踪技术概述 2. Cookie 2.1 Cookie的概念和工作流程 2.2 Cookie的基本使用 2.3 Cookie的原理分析 2.4 Cookie的使用细节 2.4.1 Co ...
随机推荐
- 深入学习CSS外边距margin(重叠效果,margin传递效果,margin:auto实现块级元素水平垂直居中效果)
前言 margin是盒模型几个属性中一个非常特殊的属性.简单举几个例子:只有margin不显示当前元素背景,只有margin可以设置为负值,margin和宽高支持auto,以及margin具有非常奇怪 ...
- Shiro 系列: 简单命令行程序示例
在本示例中, 使用 INI 文件来定义用户和角色. 首先学习一下 INI 文件的规范. =======================Shiro INI 的基本规范================== ...
- C#windows服务调试技巧
1.创建项目 2.为了方便调试,设置为控制台程序 3.修改Service1代码 4.修改Main代码 这样当使用-console方式启动时,就是以普通的控制台方式启动,方便调试程序. 5.其它安装之类 ...
- mpvue体验微信小程序开发
微信小程序 https://developers.weixin.qq.com/miniprogram/introduction/index.html?t=18082114 微信小程序是一种全新的连接用 ...
- Vue2.0的三种常用传值方式、父传子、子传父、非父子组件传值
参考链接:https://blog.csdn.net/lander_xiong/article/details/79018737
- kerbose常用操作
1.查看有那些用户认证 kadmin.local -q "list_principals" 2.用keytab文件进行认证 kinit -kt /root/keytab/hive. ...
- brew install
1. 访问 https://brew.sh/ 命令行下运行: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.co ...
- Laravel 生成migration ,boolean字段字段转为tinyInteger
Schema::create('consults', function (Blueprint $table) { $table->increments('id'); $table->str ...
- 解决 CentOS7 安装完成后ifconfig命令不能用
今天用VMWare安装了CentOS7,选择了最小安装包模式,安装完毕之后想查看一下本机的ip地址,发现报错 # ifconfig -bash: ifconfig: command not found ...
- linux的时间问题
在linux系统中时间分为修改时间(modify time 简写:mtime ),访问时间(access time 简写: atime),状态修改时间(change time 简写:ctime)三种: ...