Express session 在每次请求时重置 session
Express session resets session on every request
我有一个 VueJS 项目,它使用 axios 调用另一个域上的服务器。在此服务器上,我需要在会话中保存一些值,这样就不需要在每次请求时都查找它们。
服务器是 NodeJS,在 Heroku 上运行,我使用 Redis 进行内存存储。我可以成功地将数据保存到会话中,但是在每次新请求时,系统都会创建一个具有新 ID 的新会话,因此我无法访问在上一个请求期间保存的值。
编辑
根据一些建议更新代码后,我可以在会话 cookie 的网络控制台中看到以下错误:
Preflight Invalid Allow Credentials
编辑 2
通过向 corsOptions 添加“credentials: true”,我能够解决 Preflight Invalid Allow Credentials。这解决了我在网络会话中看到的错误,但我仍然为每个请求获取一个新的会话 ID。
服务器上的代码:
const express = require('express');
const app = express();
const cors = require('cors');
var corsWhitelist = ['http://127.0.0.1:8080','http://127.0.0.1:8081']
var corsOptions = {
origin: function (origin, callback) {
if (corsWhitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS - '+origin))
}
},
credentials: true
}
let REDIS_URL = process.env.REDIS_URL;
var Redis = require('ioredis');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const RedisStore = require('connect-redis')(session);
const sessionClient = new Redis(REDIS_URL)
sessionClient.on('error', function (err) {
console.log('could not establish a connection with redis. ' + err);
});
sessionClient.on('connect', function (err) {
console.log('connected to redis successfully');
});
app.set('trust proxy', 1)
app.use(cookieParser());
app.use(session({
store: new RedisStore({ client: sessionClient }),
secret: 'someSecret',
resave: false,
saveUninitialized: true,
cookie: {
secure: false,
httpOnly: false,
maxAge: 1000 * 60 * 10
}
}))
app.use(cors(corsOptions));
app.options('*', cors(corsOptions))
// Add headers
app.use(function (req, res, next) {
if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
const getUser = async function(req, res, next) {
if (!req.session.user) {
req.session.user = "test@example.com"
req.session.save()
}
next()
}
app.get('/session', getUser, (req, res) => {
// get the session id
console.log('session id:', req.session.id)
// the session will be automatically stored in Redis with the key prefix 'sess:'
const sessionKey = `sess:${req.session.id}`;
// let's see what is in there
client.get(sessionKey, (err, data) => {
console.log('session data in redis:', data)
})
res.status(200).send('OK');
})
VueJS 上的方法:
getSession: async function () {
axios({
url: 'https://server.example.com/session',
withCredentials: true,
}).then(res => {
console.log(res)
})
},
要使其正常工作需要进行一些更改:
预检设置被设置了两次,所以在下面的代码中,我需要删除第二行:
app.use(cors(corsOptions));
app.options('*', cors(corsOptions)) //delete this
我试图在“//添加headers”下设置的headers没有进入预检请求,因此我需要将“credentials: true”添加到corsOptions 并删除“// Add headers”下的代码:
var corsOptions = {
origin: function (origin, callback) {
if (corsWhitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS - '+origin))
}
},
credentials: true
}
最后但同样重要的是,session 定义中的 cookie 设置不适用于 cross-domain 请求。具体来说,“sameSite:'none'”和“secure:true”是必需的。结果如下所示:
app.use(session({
store: new RedisStore({ client: client }),
secret: 'someSecret',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
httpOnly: false,
sameSite: 'none',
maxAge: 1000 * 60 * 10
}
}))
我有一个 VueJS 项目,它使用 axios 调用另一个域上的服务器。在此服务器上,我需要在会话中保存一些值,这样就不需要在每次请求时都查找它们。
服务器是 NodeJS,在 Heroku 上运行,我使用 Redis 进行内存存储。我可以成功地将数据保存到会话中,但是在每次新请求时,系统都会创建一个具有新 ID 的新会话,因此我无法访问在上一个请求期间保存的值。
编辑 根据一些建议更新代码后,我可以在会话 cookie 的网络控制台中看到以下错误:
Preflight Invalid Allow Credentials
编辑 2 通过向 corsOptions 添加“credentials: true”,我能够解决 Preflight Invalid Allow Credentials。这解决了我在网络会话中看到的错误,但我仍然为每个请求获取一个新的会话 ID。
服务器上的代码:
const express = require('express');
const app = express();
const cors = require('cors');
var corsWhitelist = ['http://127.0.0.1:8080','http://127.0.0.1:8081']
var corsOptions = {
origin: function (origin, callback) {
if (corsWhitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS - '+origin))
}
},
credentials: true
}
let REDIS_URL = process.env.REDIS_URL;
var Redis = require('ioredis');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const RedisStore = require('connect-redis')(session);
const sessionClient = new Redis(REDIS_URL)
sessionClient.on('error', function (err) {
console.log('could not establish a connection with redis. ' + err);
});
sessionClient.on('connect', function (err) {
console.log('connected to redis successfully');
});
app.set('trust proxy', 1)
app.use(cookieParser());
app.use(session({
store: new RedisStore({ client: sessionClient }),
secret: 'someSecret',
resave: false,
saveUninitialized: true,
cookie: {
secure: false,
httpOnly: false,
maxAge: 1000 * 60 * 10
}
}))
app.use(cors(corsOptions));
app.options('*', cors(corsOptions))
// Add headers
app.use(function (req, res, next) {
if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
const getUser = async function(req, res, next) {
if (!req.session.user) {
req.session.user = "test@example.com"
req.session.save()
}
next()
}
app.get('/session', getUser, (req, res) => {
// get the session id
console.log('session id:', req.session.id)
// the session will be automatically stored in Redis with the key prefix 'sess:'
const sessionKey = `sess:${req.session.id}`;
// let's see what is in there
client.get(sessionKey, (err, data) => {
console.log('session data in redis:', data)
})
res.status(200).send('OK');
})
VueJS 上的方法:
getSession: async function () {
axios({
url: 'https://server.example.com/session',
withCredentials: true,
}).then(res => {
console.log(res)
})
},
要使其正常工作需要进行一些更改:
预检设置被设置了两次,所以在下面的代码中,我需要删除第二行:
app.use(cors(corsOptions));
app.options('*', cors(corsOptions)) //delete this
我试图在“//添加headers”下设置的headers没有进入预检请求,因此我需要将“credentials: true”添加到corsOptions 并删除“// Add headers”下的代码:
var corsOptions = {
origin: function (origin, callback) {
if (corsWhitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS - '+origin))
}
},
credentials: true
}
最后但同样重要的是,session 定义中的 cookie 设置不适用于 cross-domain 请求。具体来说,“sameSite:'none'”和“secure:true”是必需的。结果如下所示:
app.use(session({
store: new RedisStore({ client: client }),
secret: 'someSecret',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
httpOnly: false,
sameSite: 'none',
maxAge: 1000 * 60 * 10
}
}))