如何处理服务器为连续请求发送两个不同的cookie



当我在同一页面上发出两个同步的连续获取请求时,服务器会为该客户端发出两个不同的会话。这是因为第二个请求在第一个响应将Set Cookie标头发送回客户端之前发送到服务器

控制台显示两个请求都没有发送cookie。因此,两个响应都创建了一个新会话。

-----------'/first' request------------
'req.headers.cookie: undefined
'req.sessionID: uZCc-2EtuOIdqD5xfcBCBLQjZbRmy29k
'/first' Set-Cookie header: connect.sid=s%3AuZCc-2EtuOIdqD...
-----------'/second' request------------
'req.headers.cookie: undefined
'req.sessionID: Gzr5CPYvE5deGA-Ul7EwOzHbaWFtpXR3
'/second' Set-Cookie header: connect.sid=s%3AGzr5CPYvE5deGA... 

您可以进一步看到,这个问题是由第二个请求在取消注释// await addNSecondsDelay(5);(请记住清除要复制的cookie(以创建5秒延迟时过早触发引起的。这将只创建一个会话。

我不希望每次新客户访问一个有多个请求的页面时都会创建一个额外的未使用会话。我可以想出几种方法来解决这个问题,比如异步调用fetch,但这似乎不适合更复杂的情况——也许html页面是动态创建的,并且不能将每个动态生成的组件的fetch调用链接在一起。这似乎也会减缓页面加载过多的速度。

是否有适当的方法确保不创建两个会话?

后端服务器

// other-server.js
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const app = express();
const sess = {
saveUninitialized: false,
resave: false,
secret: 'very secret 12345',
cookie: {
sameSite: true,
secure: false,
},
};
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(session(sess));
app.use((req, res, next) => {
console.log(`n-----------'${req.path}' request------------`);
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Accept, Content-Type');
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5001');
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader(
'Access-Control-Allow-Methods',
'GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH'
);
res.on('close', function () {
console.log(
`'${req.path}' Set-Cookie header: ${res.getHeaders()['set-cookie'][0].slice(0, 30)}...`
);
});
req.session.a = 'hi';
console.log(`'req.headers.cookie: ${req.headers.cookie}`);
console.log(`'req.sessionID: ${req.sessionID}`);
next();
});
app.post('/first', (req, res) => {
res.json({ message: "1st fetch's response" });
});
app.post('/second', (req, res) => {
res.json({ message: "2nd fetch's response" });
});
app.listen(4001, () => {
console.log('start');
});

前端服务器

// server.js
const express = require('express');
const app = express();
app.use(express.static('./public'));
app.listen(5001);

index.html

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<script>
const addNSecondsDelay = (n) => {
console.log('5 second delay ...');
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, n * 1000);
});
};
const asyncFunctionCall = async () => {
fetch('http://localhost:4001/first', {
method: 'POST',
credentials: 'include',
})
.then((response) => {
return response.json();
})
.then((json) => {
console.log('Received:  ' + JSON.stringify(json));
});
// await addNSecondsDelay(5);
fetch('http://localhost:4001/second', {
method: 'POST',
credentials: 'include',
})
.then((response) => {
return response.json();
})
.then((json) => {
console.log('Received:  ' + JSON.stringify(json));
});
};
asyncFunctionCall();
</script>
</body>
</html>

理想的解决方案是在加载网页的同一服务器上运行API?如果是这样的话,那么将网页加载到浏览器中的行为就已经在网页中的任何Javascript运行之前在浏览器中设置了会话cookie。

以下是您的选项:

  1. 在做任何其他事情之前发送1个请求,这样您就只得到一个cookie
  2. 让它有两个饼干并不重要

您收到的最后一个Set-Cookie标头"获胜",并且没有很好的方法来知道这两个请求确实来自同一个客户端(这就是cookie的作用(,所以您不能直接轻松解决此问题。

我能想到的唯一其他选择是让客户端自己生成一些唯一的id,并将其与两个请求一起发送,但我怀疑这在安全性方面也是一个漏洞。

最新更新