前言
最近准备在用NodeJs写一个关于鉴权登录的功能,相关库采用的是express、express-session、cros。但是,在cookie保存问题上遇到了问题,即服务端生成的cookie无法保存到浏览器上。查询了好久,终于解决了这一问题,特来记录这一波折的经历.
1、express-session简介
express-session是Express的中间件,它将会话数据存储在服务器上;它仅仅将会话标识(sessionID)保存在cookie中,而非会话数据(用户名、密码等关键信息)。
2、express-session常用参数
| 参数 | 作用 |
|---|---|
| secret | 密钥,一个String类型的字符串,作为服务端的session签名 |
| name | cookie的名称,默认为connect.sid |
| resave | 每次访问之后,过期时间是否重新设置(建议为true) |
| saveUninitialized | 初始便生成cookie,但这个cookie无效 |
| cookie | cookie信息,默认值为{path:"/",httpOnly:true,secure:false,maxAge:null} |
| rolling | 在每次请求时强行设置cookie,这将重置cookie过期时间 |
3、express-session的使用
3.1、 首先安装express-session
npm i express-session
3.2、引入
const session = require("express-session")
3.3、配置
// 注册session中间件
app.use(session({
name: "session-test",
// 服务器生成的session签名
secret: "shallow",
// 每次访问之后,过期时间重新设置过期时间
resave: true,
// 最初访问网站就下发一个cookie,但是没有效果
saveUninitialized:true,
cookie:{
// 过期时间 10min
maxAge:1000 * 60 * 10,
},
}))
3.4、生成cookie
初次尝试的代码如下
服务端代码:
// 创建应用对象
const express = require('express');
const session = require("express-session")
const bodyParser = require('body-parser');
const cors = require("cors")
// 创建应用对象
const app = express();
// 处理application/json内容格式的请求体
app.use(bodyParser.json());
// 处理application/x-www-form-urlencoded内容格式的请求体
app.use(bodyParser.urlencoded({extended: false}));
// 跨域配置
app.use(cors({
// 允许任何源
origin:"*"
}))
// 注册session中间件
app.use(session({
name: "session-test",
// 服务器生成的session签名
secret: "shallow",
// 每次访问之后,过期时间重新设置过期时间
resave: true,
// 最初访问网站就下发一个cookie,但是没有效果
saveUninitialized:true,
cookie:{
// 过期时间 10min
maxAge:1000 * 60 * 10,
// domain:"127.0.0.1"
// 为true时,表示只有https协议才能访问cookie
},
}))
// 模拟数据库中存着的用户信息
var username = "test",
password = "123";
app.get("/data", (req,res) =>{
if(req.session.isLogin){
res.send("已经登录,可访问数据")
}else{
res.send("请先登录")
}
})
// 创建路由规则
app.post("/login", (req,res) =>{
if(req.body.username == username && req.body.password == password){
req.session.isLogin = true
res.send("login success")
}
})
// 监听端口启动服务
app.listen(8002,() => {
console.log("服务已启动,8002端口监听中...");
})
login.html代码如下:这里的
ajax.js就是在上一篇文章中封装的XMLHttpRequest,详细代码链接:Express无法通过req.body获取请求传递的数据,本文的重点是Cookie不能保存在Application中,因此对封装的XMLHttpRequest就没有做多余的展示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./ajax.js"></script>
</head>
<body>
<button id="login">登录</button>
<button id="getinfo">获取数据</button>
<script>
let dom = document.getElementById("login")
let dom2 = document.getElementById("getinfo")
// 登录请求
dom.addEventListener("click",function(){
let options = {
method:"post",
url:"http://127.0.0.1:8002/login",
data:{"username":"test","password":"123"},
contentType:"application/json",
withCredentials: false
}
let res = AJAX(options)
console.log("res", res);
})
//请求数据
dom2.addEventListener("click",function(){
let options = {
method:"get",
url:"http://127.0.0.1:8002/data",
data:{"id": 1},
withCredentials: true
}
let res = AJAX(options)
console.log("res", res);
})
</script>
</body>
</html>
点击登录按钮后,我们可以看到,登录请求成功,服务端成功返回数据res login success,并且cookie中有我们在espress-session中配置的name值session-test,如下图所示:
服务端也成功生成session,并设置isLogin值为True(req.session.isLogin = true)。
但是!!!,Application中的cookie空空如也。
4、解决方法
在网上搜寻了各种资料之后,得出,要想浏览器保存cookie,有一个前提
就是跨域的设置。要设置Access-Control-Allow-Origin,credentials。
需要注意的一点是,此时Access-Control-Allow-Origin不能像之前那样,设置为*了,必须要指定具体的域名。否则,就算是后台可以返回数据了,但是origin不同域,浏览器依旧不会去保存cookie。
同时也要将credentials设置为true,告知前端可以携带cookie请求头。同时前端要在请求时,也要将withCredentials设置为true。
// 跨域配置
app.use(cors({
origin:"http://127.0.0.1:5500",
credentials: true,
}))
前端发请求的设置,注意,这里的
withCredentials并不是在里setRequestHeader里设置。(xhr.setRequestHeader("withCredentials"), true)而是通过
xhr.withCredentials = true来设置。
login.html代码如下:(修改部分)
dom.addEventListener("click",function(){
let options = {
method:"post",
url:"http://127.0.0.1:8002/login",
data:{"username":"test","password":"123"},
contentType:"application/json",
// 添加了withCredentials
withCredentials: true
}
let res = AJAX(options)
console.log("res", res);
})
经过以上设置,我们点击登录按钮之后,成功将cookie设置到浏览器中。
5、总结
如果想将Cookie保存在Application中,需要明确以下四个点:
- 服务端的跨域配置项
Access-Control-Allow-Origin不能设置为*,需要设置为对应的域名。 - 服务端
Access-Control-Allow-Credentials设置为true,允许前端携带cookie信息。 - 请求时,将
withCredentials设置为true。