Express-静态资源-路由-ajax-session
node -Express课程
1 Express简介
1.1 Express的介绍
Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你快速创建各种 Web 和移动设备应用。
简单来说Express就是运行在node中的用来搭建服务器的模块。 ejs
1.2 Express的使用
1.2.1 下载
下载模块:https://www.npmjs.com/
npm:node package manage
npm i express --save 安装express并添加到依赖项
1.2.2 静态资源
use:中间件是一个函数,该函数的职责是完成请求与响应之间的一些逻辑
static:是一个函数,通过该函数可以指定一个文件夹目录,可以直接访问该文件夹内的静态资源,特点有:
① 是一个文件夹目录
② 指定的资源目录可以写多个
③ 静态资源如果名字相同,那么当查找到第一个以后不会继续向下查找
④ 当你的资源名字为index.html时,访问时index.html可以省略
//引入express模块
var express = require('express')
//express得到的是一个函数对象
//创建应用对象
var app = express()
//配置静态资源
app.use(express.static(_diname+"weibo"));//中间件 文件夹
//开启服务器,监听3000端口
app.listen(80,“127.0.0.1”,function() {})
1.2.3 安装方法
1 先初始化npm,会创建一个package.json: npm init -y
2 下载安装express ,两种方法: 得到node-modules
① npm install express
② npm i express
3 创建一个server.js 引入第二点的服务器
**注意:**node-modules不用发(文件太大) 如果开发没有node-modules,在终端中npm i(安装的是记录) 或者npm install
2 路由(Route)
2.1 Route的介绍
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成的。
2.2 Route的定义
我们可以将路由定义为三个部分:
第一部分:HTTP请求的方法(get或post)
第二部分:URI路径 --地址
第三部分: 回调函数,有三个参数,req,res,next next是一个函数,该回调函数完成后,通过运行next函数可以继续向下查找符合条件的路由
2.3 Route的实现
Express中提供了一系列函数,可以让我们很方便的实现路由:
app.<method>(path,callback)
语法解析:
method指的是HTTP请求方法,比如:
app.get()
app.post()
path指要通过回调函数来处理的URL地址
callback参数是应该处理该请求并把响应发回客户端的请求处理程序
2.4 Route的基本使用
当请求地址是/one时,会执行回调函数,返回‘这里是路由返回的信息,/hello收到了get请求’
当请求方式相同,请求的uri也相同,那么当找到第一个满足条件的路由后,不会继续向下进行匹配。
// 路由:可以通过请求方式,uri 组成的。
app.get("/one",function(req,res){res.end("over1")
})
app.get("/one",function(req,res){res.end("over2")
})
当路由相同时,可以通过next()继续向下查找满足条件的路由
// next 是一个函数。
app.get("/one",function (req,res,next) {console.log(11111111);// res.end("one1");next();// 该回调执行完成后,通过运行next函数可以继续向下查找符合条件的路由。
})
app.get("/one",function (req,res) {console.log(22222222222);res.end("one2");
})
2.5 Request对象
2.5.1 Request对象是什么
Request对象是路由回调函数中的第一个参数,代表了用户发送给服务器的请求信息
通过Request对象可以读取用户发送的请求包括URL地址中的查询字符串中的参数,和post请求的请求体中的参数。
2.5.2 Request对象属性和方法
属性/方法 | 描述 |
---|---|
request.query | 获取get请求查询字符串的参数,拿到的是一个对象 |
request.params | 获取get请求参数路由的参数,拿到的是一个对象 |
request.body | 获取post请求体,拿到的是个对象(要借助中间件)bodyparser |
request.get(xxxx) | 获取请求头中指定key对应的value |
request.get(“host”) | 127.0.0.1 |
req.method | get |
req.httpVersion | 版本号 1.1 |
req.headers | 请求头信息 |
// http://127.0.0.1/my/1/2?userName=zhangsan&age=100
app.get("/my/:a/:b",function (req,res) {// console.log(req.url);// /my/1/2?userName=zhangsan&age=100// console.log(req.httpVersion);// 1.1// console.log(req.query);// {userName:"zhangsan",age:100}// console.log(req.params);// {a:"1",b:"2"}// console.log(req.method);// GET// console.log(req.body);//undefined * 需要与 body-parser结合使用。// console.log(req.headers);// 请求头// console.log(req.get("host"));// 127.0.0.1res.writeHead(200,{"content-type":"text/html;charset=utf-8;"})res.end("我的")
})
2.6 Response对象
2.6.1Response对象是什么
Response对象是路由回调函数中的第二个参数,代表了服务器发送给用户的响应信息。
通过Response对象可以设置响应报文中的各个内容,包括响应头和响应体。
2.6.2 Response对象的属性和方法
属性/方法 | 描述 |
---|---|
response.send() | 给浏览器做出一个响应 百度, 可以自动加格式,写对象 |
response.end() | (不会自动追加响应头),结束响应,设置响应体的内容 |
response.download() | 告诉浏览器下载一个文件 |
response.sendFile() | 可以设置响应的文件 |
response.redirect() | 输入a页面,打开b页面,认为a页面重定向到b页面 301:永久重定向 http://taobao.com -----> https 302:临时重定向 个人中心 |
response.set(header,value) | 自定义响应头内容 set setHeader hearder |
res.status(code) | 设置响应状态码 |
res.json | 专门处理json数据,比send执行效率高些 |
// http://127.0.0.1/my/1/2?userName=zhangsan&age=100
app.get("/my/:a/:b",function (req,res) {// console.log(req.url);// /my/1/2?userName=zhangsan&age=100// console.log(req.httpVersion);// 1.1// console.log(req.query);// {userName:"zhangsan",age:100}// console.log(req.params);// {a:"1",b:"2"}// console.log(req.method);// GET// console.log(req.body);//undefined * 需要与 body-parser结合使用。// console.log(req.headers);// 请求头// console.log(req.get("host"));// 127.0.0.1res.writeHead(200,{"content-type":"text/html;charset=utf-8;"})res.end("我的")
})
3 ajax:get和post
3.1 ajax:get接收参数
通过ajax 设置路由器接收参数 页面不需要刷新,更改局部内容
get接收参数,query形式传参
btn.onclick = function() {const xhr = new XMLHttpRequest();xhr.open("get","http://127.0.0.1/sum?a="+document.myForm.a.value+"&b="+ document.myForm.b.value+"")xhr.send();xhr.onload = function() {document.myForm.sum.value = xhr.responseText;}}
app.get("/sum",function(req,res) {// http://127.0.0.1/sum?a=1&b=2console.log(req.query);//{} const {a,b} = req.query;const sum = a/1+b/1; //转为数字res.end(sum+"")//转为字符串或者res.end(sum.toString())
})
:a /:b 在地址栏中出现,说明a和b不是固定的 是一个变量,可以存放不同的值,可以传参
用req.params来接收参数
btn.onclick = function () {const xhr = new XMLHttpRequest();// http://127.0.0.1/sum/100/200 xhr.open("get","http://127.0.0.1/sum/"+document.myForm.a.value+"/"+document.myForm.b.value);xhr.send();xhr.onload = function () {// console.log(xhr.responseText);document.myForm.sum.value = xhr.responseText;}}
app.get("/sum/:a/:b",function(req,res) {// http://127.0.0.1/sum/1/2console.log(req.params);//{ a: '1', b: '2' }const {a,b} = req.params;const sum = a/1+b/1; //转为数字res.end(sum.toString())
})
指定后缀(扩展名) 也是用req.params接收,和上面的方式有冲突,只能用其一
// http://127.0.0.1/sum/1/2.html
app.get("/sum/:a/:b.html",function (req,res) {console.log(req.params);// {a:1,b:2}res.end("over");
})
// http://127.0.0.1/sum/1-2.html
app.get("/sum/:a-:b.html",function (req,res) {console.log(req.params);// { a: '1', b: '2' }res.end("/sum/:a-:b.html");
})
3.2 ajax:post接收参数
地址栏里按回车都是get请求 send接收的是一个字符串
当数据格式为:x-www-form-urlencoded
依赖模块bodyParse ,不是内置模块,是第三方模块(node-modules中有)使用中间件,内容在请求体中
bodyParse作用:接收post放置在请求体的内容,并将其放置到req.body当中
有警告,设置extended:false true 代表的是深度解析,解析成数组
btn.onclick = function () {const xhr = new XMLHttpRequest();xhr.open("post","http://127.0.0.1/sum");xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")// send接收的是一个字符串 xhr.send("a="+document.myForm.a.value+"&b="+document.myForm.b.value+"&c[0]=3&c[1]=4");
}
const express = require("express");
// 1、依赖上body-parser模块
const bodyParser = require("body-parser");
const app = express();
// 2、将接收的数据格式设置为urlencoded
// bodyParser作用:接收post放置在请求体的内容。并将其放置到req.body当中。
app.use(bodyParser.urlencoded({// false: a=1&b=2&c[0]=3&c[1]=4 ===> {a:1,b:2,c[0]:3,c[1]:4}// true: a=1&b=2&c[0]=3&c[1]=4 ===> { a: '1', b: '2', c: [ '3', '4' ] }extended:true,// 是否深度解析,一般设置为false
}));
app.use(express.static(__dirname+"/ajax"))
// 要求以post方式访问/sum
app.post("/sum",function (req,res) {console.log(req.body);const {a,b} = req.body;const sum = a/1+b/1;res.end(sum.toString());
})
app.listen(80,function () {console.log("success");
})
当数据格式为:application/json
btn.onclick = function () {const xhr = new XMLHttpRequest();xhr.open("post","http://127.0.0.1/sum");xhr.setRequestHeader("content-type","application/json")// send接收的是一个字符串xhr.send(JSON.stringify({a:document.myForm.a.value,b:document.myForm.b.value}));xhr.onload = function () {document.myForm.sum.value = xhr.responseText;}
}
const express = require("express");
// 1、依赖上body-parser模块
const bodyParser = require("body-parser");
const app = express();
// 2、将接收的数据格式设置为json
// bodyParser作用:接收post放置在请求体的内容。并将其放置到req.body当中。
app.use(bodyParser.json());
app.use(express.static(__dirname+"/ajax"))
// 要求以post方式访问/sum
app.post("/sum",function (req,res) {console.log(req.body);const {a,b} = req.body;const sum = a/1+b/1;res.end(sum.toString());
})
app.listen(80,function () {console.log("success");
})
4 Route的运行流程(all)
当Express服务器接收到一个HTTP请求时,它会查找已经为适当的HTTP方法和路径定义的路由
如果找到一个,Request和Response对象会被创建,并被传递给路由的回调函数
我们便可以通过Request对象读取请求,通过Response对象返回响应
Express中还提供了all()方法,可以处理两种请求。
uri可以写成 ***** 不限制地址
// 限制必须为post请求,但是请求地址不限制
app.post("*",function (req,res) {res.send("post->*")
})
// 限制必须为get请求,但是请求地址不限制
app.get("*",function (req,res) {res.send("get->*")
})
all:不限制请求方式 地址必须为定义的/my
*与all都写,请求方式与地址都不限制
// 不限制请求方式,地址必须为/my
app.all("/my",function (req,res) {res.send("all->我的")
})
// 请求方式与地址不限制。
app.all("*",function (req,res) {res.send("all->我的")
})
以上的代码等于use的使用
app.use(function (req,res,next) {// res.send("use")next();
})
// 相当于
app.all("*",function (req,res,next) {// res.send("all->我的")next();
})
all 案例
应用:404案例 放在最后面 当输入不是文件的名字时,显示404或者定向到指定的页面
app.all("*",function (req,res) {// res.send("404");// res.sendFile(__dirname+"/site/404.html");res.redirect("/");// 重定向到首页
})
应用:解决跨域 放在最前面 或者哪些页面需要就在哪一行添加比如添加广告页
app.all("*",function (req,res,next) {res.set("Access-Control-Allow-Origin","*");next();
})
app.use(function (req,res,next) {res.set("Access-Control-Allow-Origin","*");next();
})
app.get("/addAdv",function (req,res) {// res.set("Access-Control-Allow-Origin","*");res.send("添加广告")
})
将中间件封装成函数,在程序中引入
const utils = require("./utils");
const fs = require("fs");
module.exports = {over(req,res,next){res.set("Access-Control-Allow-Origin","*");next();}
const middleware = require("./module/middleware");
app.use(middleware.over)
传递参数,要有返回值,否则是undefined,闭包
const utils = require("./utils");
const fs = require("fs");
module.exports = {over(req,res,next){res.set("Access-Control-Allow-Origin","*");next();}fn(origin){return function (req,res,next) {res.set("Access-Control-Allow-Origin",origin);next();}},
app.use(middleware.fn("http://localhost:10241"))
应用:权限设置:重定向redirect
app.use(function (req,res,next) {if(req.query.vip) next()else res.redirect("/");})
用以上的方法,404始终执行不到,所以封装next,再引入
const utils = require("./utils");
const fs = require("fs");
module.exports = {vipLogin(req,res,next){if(req.query.vip) next();else res.redirect("/")}
app.get("/addGoods",vipLogin,function (req,res) {res.send("添加商品")
})
app.get("/upGoods",vipLogin,function (req,res) {res.send("修改商品")
})
应用:用户的记录功能(访问地址,时间,IP),用next 引入封装的时间
IP:在端口号后面设置格式为初始值,得到的就是IP4版本
const express = require("express");
const utils = require("./module/utils");
const middleware = require("./module/middleware");
const fs = require("fs");
const app = express();
app.use(middleware.createLog(__dirname+"/my.log"))
app.use(function (req,res,next) {let str = "";str+="访问地址:"+req.url+"\n";str+="访问IP:"+req.connection.remoteAddress+"\n";str+="访问时间:"+utils.getNowTime()+"\n";str+="*************************************************\n";fs.writeFile(__dirname+"/data.log",str,{flag:"a"},function (err) {next();})// console.log(req.connection.remoteAddress);//})
app.get("/",middleware.createLog(__dirname+"/my.log"),function (req,res) {res.send("首页")
})
app.get("/reg",function (req,res) {res.send("注册")
})
....
简化,封装,引用
return function (req,res,next) {let str = "";str+="访问地址:"+req.url+"\n";str+="访问IP:"+req.connection.remoteAddress+"\n";str+="访问时间:"+utils.getNowTime()+"\n";str+="*************************************************\n";fs.writeFile(url,str,{flag:"a"},function (err) {next();})
route 模块化
内置;express.router
const express = require("express");
const app = express();
const userRouter = express.Router();
const advRouter = express.Router();
const goodsRouter = express.Router();
// 路由模块化:将拥有相同特点的路由放置到一个JS当中。
userRouter.get("/",function (req,res) {res.send("首页")
})
userRouter.get("/reg",function (req,res) {res.send("注册")
})
userRouter.get("/login",function (req,res) {res.send("登陆")
})
userRouter.get("/my",function (req,res) {res.send("个人中心")
})advRouter.get("/addAdv",function (req,res) {res.send("添加广告")
})goodsRouter.get("/addGoods",function (req,res) {res.send("添加商品")
})
goodsRouter.get("/upGoods",function (req,res) {res.send("修改商品")
})
goodsRouter.get("/delGoods",function (req,res) {res.send("删除商品")
})app.use(userRouter);
app.use(goodsRouter);
app.use(advRouter);
app.all("*",function (req,res) {// res.send("404");// res.sendFile(__dirname+"/site/404.html");res.redirect("/");// 重定向
})
app.listen(80,function () {console.log("success");
})
优化版:各种封装,再引入
const express = require("express");
const userRouter = require("./module/router/user");
const advRouter = require("./module/router/adv");
const goodsRouter = require("./module/router/goods");
const app = express();
app.use(userRouter);
app.use(goodsRouter);
app.use(advRouter);
app.all("*",function (req,res) {// res.send("404");// res.sendFile(__dirname+"/site/404.html");res.redirect("/");// 重定向
})
app.listen(80,function () {console.log("success");
})
adv.js
const router = require("express").Router();router.get("/addAdv",function (req,res) {res.send("添加广告")
})router.get("/upAdv",function (req,res) {res.send("修改广告")
})module.exports = router;
good.js
const router = require("express").Router();
router.get("/addGoods",function (req,res) {res.send("添加商品")
})
router.get("/upGoods",function (req,res) {res.send("修改商品")
})
router.get("/delGoods",function (req,res) {res.send("删除商品")
})module.exports = router;
user.js
const router = require("express").Router();
router.get("/",function (req,res) {res.send("首页")
})
router.get("/reg",function (req,res) {res.send("注册")
})
router.get("/login",function (req,res) {res.send("登陆")
})
router.get("/my",function (req,res) {res.send("个人中心")
})
module.exports = router;
5 中间件
5.1中间件简介
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。
中间件(Middleware) 是一个函数,它可以访问请求对象(request), 响应对象(response), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。
5.2中间件功能
执行任何代码。
修改请求和响应对象。
终结请求-响应循环。
调用堆栈中的下一个中间件。
5.3 中间件的分类
应用级中间件(过滤非法的请求,例如防盗链)
第三方中间件(通过npm下载的中间件,例如body-parser)
内置中间件(express内部封装好的中间件)
路由器中间件 (Router)
5.4中间件实例
//引入express
var express = require('express')
//创建应用对象
var app = express()
//配置静态资源
app.use(express.static('public'))
//中间件,没有挂载路径,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {console.log('这是中间件的响应~~~')//如果不调用next方法,下面路由将不起作用next()
})
//配置路由
app.get('/index', function (req, res) {console.log('路由index收到get请求')res.send('这里是路由返回的信息,/hello收到了get请求')
})app.post('/index', function (req, res) {console.log('路由index收到post请求')res.send('这里是路由返回的信息,/hello收到了post请求')
})//启动服务器
app.listen(3000, function () {console.log('服务器启动成功,监听3000端口')
})
6 Router路由器
6.1 Router是什么
Router 是一个完整的中间件和路由系统,也可以看做是一个小型的app对象。
6.2 为什么使用Router
Router—路由器 Route–路由
为了更好的分类管理route
6.3 Router的使用
//引入express模块
var express = require('express');
//引入body-parser模块
var bodyParser = require('body-parser');
//引入Users模型对象
var Users = require('../models/Users');
//创建router对象
var router = express.Router();
//解析请求体,将参数挂在到req.body
router.use(bodyParser.urlencoded({extended: false}));
router.post('/login', function (req, res) {var username = req.body.username;var password = req.body.password;Users.findOne({username: username}, function (err, data) {if (!err && data && data.password === password) {res.send('恭喜您登录成功~~~');} else {res.send('用户名或密码错误~~~');}})
})
router.post('/regist', function (req, res) {//获取用户提交的参数var username = req.body.username;var password = req.body.password;var rePassword = req.body.rePassword;var email = req.body.email;/*1. 正则验证(-)2. 密码和确认密码是否一致3. 去数据库中查找有无此用户名4. 插入数据*///判断密码和确认密码是否一致if (password !== rePassword) {res.send('两次密码输入不一致,请重新输入~~');return}//去数据库中查找有无此用户名Users.findOne({username: username}, function (err, data) {if (!err) {/*data如果查到了 返回文档对象如果没找到 返回null*/if (data) {// 查到了指定用户名res.send(data.username + '用户名已被注册~~请重新输入');} else {// 没有找到指定有户名,将用户信息插入到数据库中Users.create({username: username,password: password,email: email}, function (err) {if (!err) {res.send('恭喜您,注册成功了~~');} else {res.send('error');}})}} else {res.send('error');}})
})
//暴露路由器对象
module.exports = router
7 EJS模板(了解)
7.1 EJS是什么
EJS是一个高效的 JavaScript 模板引擎。
模板引擎是为了使用户界面与业务数据(内容)分离而产生的。
简单来说,使用EJS模板引擎就能动态渲染数据。(服务器端渲染)
7.2 EJS的使用
- 下载安装
npm i ejs --save
- 配置模板引擎
app.set(“view engine” , “ejs”);
- 配置模板的存放目录
app.set(“views”,"./views")
- 在views目录下创建模板文件
xxx.ejs
- 使用模板,通过response来渲染模板
response.render(‘模板名称’, 数据对象)
7.3 EJS语法
ejs.render():第一个参数是一个字符串,第二个参数是数据,数据的格式为对象
字符串当中可以直接使用对象的属性
以下是一个ejs文件:
const ejs = require("ejs");const arr = ["一","二"];
const pageSum = 12;
const str = `<div><%=num%> //12<%for(let i=0;i<num;i++) {%><h3><%= i%></h3> //<h3>0-11</h3><%}%></div>`console.log(ejs.render(str,{arr, num:pageSum}))
通过服务使用ejs
const express = require("express");
const ejs = require("ejs");
const bookList = require("./data");
const app = express();
app.get("/getBookList",function (req,res) {const htmlStr = ejs.render( `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>1服务端渲染下的index.html</title></head><body><%=bookList.length%></body><script></script></html>`,{bookList})res.send(htmlStr);})
app.listen(80,function () {console.log("success");
})
将界面与数据进行分离
home.js
<table><tr><td>id</td><td>作者</td><td>作品</td></tr><%for(let i=0;i<bookList.length;i++){%><tr><td><%=bookList[i].id%></td><td><%=bookList[i].author%></td><td><%=bookList[i].bookName%></td></tr><%}%></table>
const express = require("express");
const ejs = require("ejs");
const bookList = require("./data");
const app = express();
app.get("/getBookList",function (req,res) {// home.ejs--->views->home.ejs 默认会去views文件夹当中查找文件。// res.render("home.ejs",{// a:1,// b:2,// bookList// })// 将默认文件夹views更改为当前目录下的html文件夹app.set("views",__dirname+"/html");app.set("view engine","html");// .ejs ----> .html 更改扩展名app.engine("html",ejs.renderFile);// 将html通过ejs的解析数据方法来使用res.render("my.html",{a:1,b:2,bookList})
})
app.listen(80,function () {console.log("success");
})
8 会话控制session
8.1会话控制是什么
HTTP协议是一个无状态的协议,它无法区分多次请求是否发送自同一客户端。
而我们在实际的使用中,却又大量的这种需求,我们需要通过会话的控制来解决该问题。
8.2 cookie
8.2.1 cookie是什么
cookie本质是一个存储在浏览器的文本,随着http请求自动传递给服务器。
也可以说cookie是一个头(请求头/响应头):
服务器以响应头的形式将Cookie发送给浏览器
浏览器收到以后会自动将Cookie保存
浏览器再次访问服务器时,会以请求头的形式将Cookie发回
服务器就可以通过检查浏览器发回的Cookie来识别出不同的浏览器
① cookie来自于服务器,cookie是在服务端生成的
通过浏览器打开某个网址,在响应头当中增加Set-cookie
② 会将cookie保存在本地
③ 当你再次发送请求时,会将保存的cookie以请求头的形式发送给服务端
④ 服务端可以接收cookie,可以对cookie进行验证,从而可以识别用户是谁
app.get("/setCookie",function(req,res) {// 设置一个cookie,第一个参数为设置,第二个参数为值res.set("Set-cookie","userName=laodai")res.send("设置cookie成功")
})
**注意:**创建多个cookie,不能单独创建,要以数组的形式来设置
app.get("/setCookie",function(req,res) {res.set("Set-cookie",["userName=laodai","age=25"])res.send("设置cookie成功")
})
获取值
app.get("/getCookie",function(req,res) {console.log(req.header.cookie)res.send("获取cookie成功")
})
8.2.2 cookie的不足
各个浏览器对cookie的数量和大小都有不同的限制,这样就导致我们不能在Cookie中保存过多的信息。一般数量不超过50个,单个大小不超过4kb。
cookie是由服务器发送给浏览器,再由浏览器将cookie发回,如果cookie较大会导致发送速度非常慢,降低用户的体验。
8.2.3 cookie的使用
通过配置cookie-parser中间件,可以将cookie解析为一个对象,并且添加为req的cookies属性,使用步骤:
- 下载安装
npm i cookie-parser --save
- 引入
var cookieParser = require("cookie-parser");
- 设置为中间件
app.use(cookieParser());
- 创建Cookie
res.cookie("username","laodai")res.cookie("age","12",{maxAge:20*1000,//单位毫秒})
//设置一个有效期为1天的cookie
res.cookie("username","sunwukong" , {maxAge:1000*60*60*24});
//设置一个永久有效的cookie
res.cookie("username","sunwukong" , {maxAge:1000*60*60*24*365*10});
- 修改Cookie
//Cookie一旦发送给浏览器,就不能再修改了
//但是我们可以使用同名的cookie来替换已有cookie
res.cookie("username","zhubajie");
- 删除Cookie
//可以通过通过使用一个立即失效的cookie来替换cookie的形式来删除cookie
res.cookie("username","",{maxAge:0});
//用来删除一个cookie
res.clearCookie(“username”)//用来删除一个指定cookie
获取值:
app.get("/getCookie",function(req,res) {console.log(req.cookies)//接收res.send("获取cookie成功")
})
8.2.4 cookie的属性
属性:
① max-age:指定过期时间 单位为秒 默认为session
② expires:指的是utc时间,当前时间超过指定时间为过期
如果max-age与expires同时指定的话,听max-age的
如何指定UTC时间:
function getUtcTime(s=10) {const da = new Date()da.setTime(Date.now+s*1000)//指定时间return da.toUTCString()//转换为UTC时间
}age=12;max-age=3600;expires=${getUtcTime()};path=/abc
③ ***path:***指定使用cookie的目录,如果值为/abc,说明值允许在/abc目录下使用cookie
④***domain:***域名,如果设置为.xxx.com,那么不限制二级域名,如果设置为api.xxx.com,那么只能够在api.xxx.com中访问
⑤ max-age:0 将过期时间设置为0
8.3 session
8.3.1 session是什么
Session 是一个对象,存储特定用户会话所需的属性及配置信息。
8.3.2 session运作流程
我们可以在服务器中为每一次会话创建一个对象,然后每个对象都设置一个唯一的id,并将该id以cookie的形式发送给浏览器,然后将会话中产生的数据统一保存到这个对象中,这样我们就可以将用户的数据全都保存到服务器中,而不需要保存到客户端,客户端只需要保存一个id即可。
8.3.3 session的使用
- 下载安装
npm i connect-mongo express-session --save
- 引入模块
var session = require(“express-session”);
- 设置为中间件
app.use(session({name: 'id22', //设置cookie的name,默认值是:connect.sidsecret: 'atguigu', //参与加密的字符串(又称签名)saveUninitialized: false, //是否设置初始值valueresave: true ,//是否在每次请求时重新保存sessioncookie: {httpOnly: true, // 开启后前端无法通过 JS 操作maxAge: 1000*30 // 这一条 是控制 sessionID 的过期时间的!!!path:"/abc"domain:".wx.com"},
}));
4)设置值
app.get("/setSession",function (req,res) {req.session.userName = "laodai";req.session.age = 25;res.send("设置成功")
})
5)获取值
app.get("/getSession",function (req,res) {console.log(req.session.userName,req.session.sge)//获取值res.send("获取成功")
})
6)删除值
app.get("/delSession",function (req,res) {// 第一种方法req.session.cookie.maxAge=0;// 第二种方法req.session.destroy(function(err) {res.send("删除成功")})
6.3.4 cookie和session的区别
- 存在的位置:
cookie 存在于客户端,临时文件夹中
session 存在于服务器的内存中,一个session域对象为一个用户浏览器服务
- 安全性:
cookie是以明文的方式存放在客户端的,安全性低,可以通过一个加密算法进行加密后存放
session存放于服务器的内存中,所以安全性好
- 网络传输量:
cookie会传递消息给服务器
session本身存放于服务器,但是通过cookie传递id,会有少量的传送流量
- 生命周期(以20分钟为例):
cookie的生命周期是累计的,从创建时,就开始计时,20分钟后,cookie生命周期结束
session的生命周期是间隔的,从创建时,开始计时如在20分钟,没有访问session,那么session生命周期被销毁;但是,如果在20分钟内(如在第19分钟时)访问过session,那么,将重新计算session的生命周期;关机会造成session生命周期的结束,但是对cookie没有影响
- 大小:
cookie 保存的数据不能超过4K,很多浏览器都限制一个站点最多保存50个cookie
session 保存数据理论上没有任何限制(内存有多大就能有多大)
9 jwt:json web token
前后端通讯,进行加密
第三方模块:npm install jwt-simple 先进行安装,再引用
encode加密 decode解密
解密流程:
1 用户登录成功时,服务端生成token(令牌),返回给前端
2 前端保存token
3 当前端请求有权限限制的接口时,将token传递给服务端
4 服务端接收token,并解析
验证token(authorization授权)是否正确:
① 是否可以正常解析
② 时间是否过期
server.js
const jwt = require("jwt-simple");
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(express.static(__dirname));
app.use(bodyParser.json())
// userName,passWord
const KEY = "%^&*()_";
app.get("/main",function (req,res) {// console.log(jwt.decode(req.headers.authorization,KEY));console.log(req.headers.cookie.split("=")[1]);const {userName,overTime} = jwt.decode(req.headers.cookie.split("=")[1],KEY);console.log(userName,overTime)res.json({ok:1,msg:"成功"})// const {userName,overTime} = jwt.decode(req.headers.authorization,KEY);// if(Date.now()>overTime){// res.send({// ok:-1,// msg:"已过期"// })// }else{// res.send({// ok:1,// msg:"成功"// })// }})
app.post("/login",function (req,res) {const {userName,passWord} = req.body;if(userName === "admin" && passWord === "123456"){const token = jwt.encode({userName:"admin",overTime:Date.now()+10*1000},KEY);res.set("Set-cookie","connect.id="+token);res.json({ok:1,// token})}else{res.json({ok:-1,msg:"登陆失败"})}
})
app.listen(80,function () {console.log("success");
})
login.html
const btn = document.querySelector("button");btn.onclick = function () {const xhr = new XMLHttpRequest();xhr.open("post","http://127.0.0.1/login");xhr.setRequestHeader("content-type","application/json");xhr.send(JSON.stringify({userName:"admin",passWord:"123456"}));xhr.onload = function () {const {ok,token,msg} = JSON.parse(xhr.responseText);if(ok === 1){localStorage.userName = "admin";// localStorage.token = token;// 页面之间的跳转window.location.href = "/main.html"}else{alert(msg);}}}
main.html
if(localStorage.token){const xhr = new XMLHttpRequest();xhr.open("get","http://127.0.0.1/main");// xhr.setRequestHeader("authorization",localStorage.token);xhr.send();xhr.onload = function () {const {ok,msg} = JSON.parse(xhr.responseText);if(ok === -1){location.href="/login.html";}// console.log(xhr.responseText);}}else{location.href="/login.html"}
Express-静态资源-路由-ajax-session相关推荐
- 前端学习(1378):express静态资源处理
const express = require('express'); const path=require('path'); const app = express();app.use(expres ...
- 实战react技术栈+express前后端博客项目(3)-- 后端路由、代理以及静态资源托管等配置说明...
项目地址:github.com/Nealyang/Re- 本想等项目做完再连载一波系列博客,随着开发的进行,也是的确遇到了不少坑,请教了不少人.遂想,何不一边记录踩坑,一边分享收获呢.分享当然是好的, ...
- Spring Boot 静态资源映射与上传文件路由配置
默认静态资源映射目录 默认映射路径 在平常的 web 开发中,避免不了需要访问静态资源,如常规的样式,JS,图片,上传文件等;Spring Boot 默认配置对静态资源映射提供了如下路径的映射 /st ...
- node.js学习笔记3 express基本使用、托管静态资源、express中间件
内容 1. 什么是express 1.1 http模块和express的关系 2. express能做什么 3. express的基本使用 3.1 安装 3.2 创建最基本的web服务器 3.3 监听 ...
- 关于使用NodeJS+Express搭建服务器访问静态资源的一些填坑经验
前言 NodeJs是一个能让前端开发工程师变成全栈工程师的神器.最近在搞一个私活,需要上传图片到服务器存储.按照以前的想法,是用Java写代码搭服务器.奈何,大学毕业后就一直在搞前端和安卓开发.Jav ...
- Koa 学习 01 Koa 介绍和基本使用(路由、静态资源托管、中间件)
Koa 介绍 Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造,致力于成为 web 应用和 API 开发领域中的一个更小.更富有表现力.更健壮的基石. 官网:https://k ...
- 渲染静态页面、get请求、post请求、express框架、路由、中间件
1. 渲染静态页面 const http = require('http'); const fs = require('fs'); const url = require('url'); const ...
- Express请求处理-静态资源的处理
场景 Node的Web应用框架Express的简介与搭建HelloWorld: Node的Web应用框架Express的简介与搭建HelloWorld_霸道流氓气质的博客-CSDN博客 注: 博客: ...
- Express与传统Web应用(服务端渲染、art-template模板引擎、配置静态资源托管)
一.服务端渲染相关的概念 什么是渲染? 例如对于我们前端开发者来说最常见的一种场景就是:请求后端接口数据,然后将数据通过模板绑定语法绑定到页面中,最终呈现给用户. 数据: 模板: 渲染(数据+模板)结 ...
- nodejs 创建一个静态资源服务器 +路由
0.补充 1.Node.js 创建的第一个应用 1.引入 http 模块 var http = require("http"); 2.创建服务器 接下来我们使用 http.crea ...
最新文章
- 微信8.0.6正式发布,新增了7大变化,个个实用~
- android屏幕适配详解
- [MyBatisPlus]模拟多数据源环境及测试
- mongoose $sum
- FireEye:GreedyWonk行动针对经济和外交政策网站
- 动态图制作软件设计(二)
- gdb调试出现“no debugging symbols found”
- 黑马程序员-学习日志-文件的合并
- Excel查询颜色RGB值
- python中的snip用法_--snip--总是报错,找了好久不知道问题出在哪,望大佬求解(python-pygame)...
- 记dubbo consumer服务因订阅其他有异常的服务导致超时的问题
- 爬虫(二) 豆瓣音乐评论爬虫 文末附完整代码
- 菜鸟知识-五大智能手机操作系统
- 博通wifi驱动详解
- 编码器基础知识大扫盲
- 余弦相似度:通过计算两个向量的夹角余弦值来评估他们的相似度
- java如何将mp4写入光盘_iOS - 读取/写入mp4视频的XMP元数据
- cityscapes数据处理
- web前端项目上线流程是怎样的
- 从N986和A199看华为中兴
热门文章
- mysql text 函数的使用方法_MySQL空间数据操作:GeomFromText()和astext()函数报错解决...
- Jenkins ssh 发布jar 时区不对
- Beyond Compare 4
- JDK时区与电脑系统时区不一致,导致时间new date不对
- linux 真实内存,Linux计算真实可用内存
- MySQL笔记(四)多表连接查询
- 小汤学编程之JavaScript学习day01——认识JS、JS基础语法
- 小汤学编程之JAVA基础day15——枚举、注解和Properties
- 剑指前端(前端入门笔记系列)——数组(基本语法)
- python 对redis key的基本操作