英文:
Local redirect sends a ghost GET request for some reason
问题
Here is the translated code part:
我正在尝试创建一个具有以下行为的网站:
- 如果未经身份验证的用户尝试访问/home页面,他将被重定向到/login页面。
- 一旦他通过/login页面登录,他将收到一个会话Cookie并被重定向到/home页面。
- 如果用户返回到/login页面但具有有效的会话Cookie,他将自动重定向到/home页面。
我正在使用Node.js和Express。
以下是我目前使用的代码:
服务器端:
```js
app.get('/login', (req, res) => {
res.sendFile(__dirname + "/html/login.html")
});
app.post('/login', (req, res) => {
//尝试验证用户
//如果用户ID或密码无效
res.status(401).end();
//否则创建Cookie并注册会话
res.cookie("session_token", sessionToken, { sameSite: 'Strict', expires: expiresAt })
res.cookie("session_id", id, { sameSite: 'Strict', expires: expiresAt })
res.status(200).send()
});
app.get('/home', (req, res) => {
//如果无法验证用户
if (!function_to_authenticate_the_user(req)) return res.redirect(308, '/login')
//否则
res.status(200).sendFile(__dirname + "/html/home.html")
});
app.get('/isSessionValid', loginRL, (req, res) => {
if (function_to_authenticate_the_user(req)) return res.status(200).send();
else return res.status(401).send()
});
用户端(函数由按钮的onclick属性触发):
function login(id, mdp) {
fetch('/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
'id': id,
'password': password
})
}).then(res => {
if (res.status === 401) {
//显示错误消息
} else if (res.status === 200) {
location.replace('/home')
}
})
}
window.addEventListener('load', () => {
if (!document.cookie) return
const cookies = Object.fromEntries(document.cookie.split('; ').map(c => c.split('=')));
if (!cookies.session_token || !cookies.session_id) return
fetch('/isSessionValid', {
method: 'GET',
}).then(res => {
if (res.status === 200) location.replace('/home')
})
});
问题:
由于某种我不理解的原因,一旦用户发送POST请求到/login并收到带有Cookie的200响应,它会发送GET请求到/home页面(这是应该的),但还会发送另一个GET请求到/login页面(我不明白为什么)。
它同时发送这两个请求。并且由于(第二个)/login请求被优先处理,浏览器会自动将GET /home解释为308状态(服务器从未收到任何关于/home的请求)。
由于用户现在具有有效的会话Cookie,浏览器尝试再次重定向到/home,但还会自动发送另一个GET请求到/login,一直循环。
我尝试了服务器端和用户端的调试。出于某种原因,服务器似乎从未收到任何来自/home的GET请求。
我尝试删除窗口加载事件监听器,但仍然会发送另一个GET请求到/login,并且无法成功重定向到/home(只是停止了请求的无限循环)。
当我手动将URL设置为从当前/login页面到/home时,会发生相同的行为(一个幽灵请求到/login,不加载/home)。
我尝试更改服务器代码如下:
app.get('/home', (req, res) => {
console.log('received a request')
if (!function_to_authenticate_the_user(req)) {
console.log('trying to redirect')
return res.redirect(301, '/login')
}
res.status(200).sendFile(__dirname + "/html/home.html")
});
但浏览器仍然在控制台中显示以下请求:
GET http://localhost:8000/home [HTTP/1.1 308 Permanent Redirect 0ms]
GET http://localhost:8000/login [HTTP/1.1 200 OK 0ms]
服务器不会记录任何内容。
我尝试删除用户端代码中的location.replace('/home'),但没有解决问题。
我漏掉了什么?
<details>
<summary>英文:</summary>
I'm trying to create a site with the following behavior :
- If the user attempts to get to the /home page without being authenticated, he gets redirected to the /login page.
- Once he logs in through the /login page, he receive a session cookie and gets redirected to the /home page
- If the user gets back to the /login page but has a valid session cookie, he gets automatically redirected to the /home page
I'm using node.js with express.
Here is the current code I use :
Server-side :
```js
app.get('/login', (req, res) => {
res.sendFile(__dirname + "/html/login.html")
});
app.post('/login', (req, res) => {
//try to authenticate the user
//if invalid user_id or password
res.status(401).end();
//else creating a cookie and registering the session
res.cookie("session_token", sessionToken, { sameSite: 'Strict', expires: expiresAt })
res.cookie("session_id", id, { sameSite: 'Strict', expires: expiresAt })
res.status(200).send()
});
app.get('/home', (req, res) => {
//if the user can't be authenticated
if (!function_to_authenticate_the_user(req)) return res.redirect(308,'/login')
//else
res.status(200).sendFile(__dirname + "/html/home.html")
});
app.get('/isSessionValid', loginRL, (req, res) => {
if (function_to_authenticate_the_user(req)) return res.status(200).send();
else return res.status(401).send()
});
User-side (function is triggered by an onclick property on a button) :
function login(id, mdp) {
fetch('/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
'id': id,
'password': password
})
}).then(res => {
if (res.status === 401) {
// display error message
} else if (res.status === 200) {
location.replace('/home')
}
})
}
window.addEventListener('load', () => {
if (!document.cookie) return
const cookies = Object.fromEntries(document.cookie.split('; ').map(c => c.split('=')));
if (!cookies.session_token || !cookies.session_id) return
fetch('/isSessionValid', {
method: 'GET',
}).then(res => {
if (res.status === 200) location.replace('/home')
})
});
The issue :
For some reason I don't understand, once the user sends a POST request to /login and get a 200 response with a cookie, it sends a GET request to the /home page (which is what it should do) BUT ALSO another GET request to the /login page (and I don't understand why)
It sends both requests at the same time. And for some reason the (second) /login request gets prioritized and the browser automatically interprets the GET /home as a 308 status (the server NEVER receive any request to /home)
And since the user now has a valid session cookie, the browser tries again to redirect to /home but also automatically sends another GET request to /login and over and over again.
I tried to debug both server-side and user-side.
For some reason, the server seems to never get any GET request from /home
I tried to remove the window load event listener but it stills sends another get request to /login and never redirects successfully to /home (it just stops the never ending loop of requests)
When I manually sets the url to /home from a current /login page, the same behavior happens (a ghost request to /login and doesn't load /home)
I tried to change the server code to :
app.get('/home', (req, res) => {
console.log('received a request')
if (!function_to_authenticate_the_user(req)) {
console.log('trying to redirect')
return res.redirect(301,'/login')
}
res.status(200).sendFile(__dirname + "/html/home.html")
});
but the browsers keeps displaying the following requests in the console :
GET http://localhost:8000/home [HTTP/1.1 308 Permanent Redirect 0ms]
GET http://localhost:8000/login [HTTP/1.1 200 OK 0ms]
and the server never logs anything.
I tried to remove the location.replace('/home') in the user-side code but it didn't solve the issue.
What am I missing ?
答案1
得分: 0
浏览器正在缓存您的 308 重定向。为测试目的,您可以清除浏览器缓存并禁用缓存(在 Chrome 中:检查 -> 网络标签 -> 选择禁用缓存)。
由于 Express 默认使用 HTTP 302 重定向代码,您可以将 res.redirect(308,'/login')
更改为 res.redirect('/login')
。
英文:
The browser is caching your 308 redirect.
For testing purposes you can clear your cache and disable caching in your browser (in Chrome: inspect -> network tab -> check disable cache)
Since Express is using HTTP code 302 for redirects by default, you could change res.redirect(308,'/login')
to res.redirect('/login')
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论