微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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.methodget
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.1
   res.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.1
    res.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=2
    console.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/2
    console.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中间件功能

  1. 执行任何代码

  2. 修改请求和响应对象。

  3. 终结请求-响应循环。

  4. 调用堆栈中的下一个中间件。

5.3 中间件的分类

  1. 应用级中间件(过滤非法的请求,例如防盗链)

  2. 第三方中间件(通过npm下载的中间件,例如body-parser)

  3. 内置中间件(express内部封装好的中间件)

  4. 路由器中间件 (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的使用

  1. 下载安装

npm i ejs --save

  1. 配置模板引擎

app.set(“view engine” , “ejs”);

  1. 配置模板的存放目录

app.set(“views”,"./views")

  1. 在views目录下创建模板文件

xxx.ejs

  1. 使用模板,通过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属性,使用步骤:

  1. 下载安装
npm i cookie-parser --save
  1. 引入
var cookieParser = require("cookie-parser");
  1. 设置为中间件
app.use(cookieParser());
  1. 创建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});
  1. 修改Cookie

​ //Cookie一旦发送给浏览器,就不能再修改

​ //但是我们可以使用同名的cookie来替换已有cookie

res.cookie("username","zhubajie");
  1. 删除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的使用

  1. 下载安装

npm i connect-mongo express-session --save

  1. 引入模块

var session = require(“express-session”);

  1. 设置为中间件
app.use(session({
     name: 'id22',  //设置cookie的name,认值是:connect.sid
     secret: 'atguigu', //参与加密的字符串(又称签名)
     saveUninitialized: false, //是否设置初始值value
     resave: true ,//是否在每次请求时重新保存session
     cookie: {
          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的区别

  1. 存在的位置:

cookie 存在于客户端,临时文件夹中

session 存在于服务器的内存中,一个session域对象为一个用户浏览器服务

  1. 安全性:

cookie是以明文的方式存放在客户端的,安全性低,可以通过一个加密算法进行加密后存放

session存放于服务器的内存中,所以安全性好

  1. 网络传输量:

cookie会传递消息给服务器

session本身存放于服务器,但是通过cookie传递id,会有少量的传送流量

  1. 生命周期(以20分钟为例):

cookie的生命周期是累计的,从创建时,就开始计时,20分钟后,cookie生命周期结束

session的生命周期是间隔的,从创建时,开始计时如在20分钟,没有访问session,那么session生命周期被销毁;但是,如果在20分钟内(如在第19分钟时)访问过session,那么,将重新计算session的生命周期;关机会造成session生命周期的结束,但是对cookie没有影响

  1. 大小:

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"
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐