如何在使用 Spring 的 POST 请求中将对象保留在会话范围内?
How do I persist objects in the session scope on POST requests with Spring?
我正在用 Spring 整理一些简单的页面,并想将一些数据添加到会话持续存在的对象中。它似乎对 GET 请求有效,但对使用 POST 方法的请求无效。
我有一个 UserData 组件如下:
package com.mycompany.controllers.components;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("session")
public class UserData {
private boolean loggedIn;
public UserData() {
loggedIn = false;
}
public boolean isLoggedIn() {
return loggedIn;
}
public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}
}
我有一个控制器如下:
package com.mycompany.controllers;
...
@RestController
@Scope("session")
public class DefaultController {
@Autowired
UserData userData;
...
@GetMapping("/")
public ResponseEntity index() {
printUserData(userData);
ResponseEntity entity;
if((entity = authenticate(userData)) != null) {
return entity;
}
...
}
@GetMapping("/setloggedIn")
public ResponseEntity setLoggedIn() {
printUserData(userData);
userData.setLoggedIn(true);
}
@PostMapping("/logIn" )
public ResponseEntity logIn(@RequestBody LogInDTO dto) {
printUserData(userData);
...
userData.setLoggedIn(true);
}
protected static void printUserData(UserData user) {
if(user== null) {
LOG.info("UserData is null");
return;
}
LOG.info("UserData logged in: {}", user.isLoggedIn());
}
}
当我导航到“/”时,UserData.isLoggedIn()
的输出如预期的那样是错误的。
当我向“/logIn”发出 post 请求时,输出再次如预期的那样是错误的。在一些参数验证之后,方法 UserData.setLoggedIn(true)
被调用但导航到“/”输出仍然是错误的。
当我导航到“/setLoggedIn”时,loggedIn 最初为 false,但这也将 loggedIn 设置为 true,现在对“/”或“/setLoggedIn”的所有请求都会导致输出为 true。
对“/logIn”的进一步 POST 请求给出 false
的输出
我是不是遗漏了什么或者这是正常现象?
更新 1
当我检查 GET 请求的会话 ID 时,我可以看到它等于存储在我的 cookie 中的 JSESSIONID。我看到每个 POST 请求都有不同的会话 ID。
所以问题是,如何将 JSESSIONID 与 POST 请求一起发送。我目前正在按如下方式执行请求:
fetch('/logIn', {
method: 'POST',
body: JSON.stringify({
username: txtUsername.value,
password: txtPassword.value
}),
headers : {
'Content-Type' : 'application/json'
}
})
.then(result => {
result.text().then(function(text) {
if(result.status == 200) {
location.reload();
} else {
alert("Error:\n" + text);
}
});
})
.catch(e => {
console.log(e);
alert("Error:\n" + e);
});
更新 2
我发现 JSESSIONID cookie 是 HttpOnly,无法被 JavaScript 读取,这可能是它没有随 POST 请求一起发送的原因吗?导致 servlet 每次都创建一个新会话。
fetch 命令需要“"credentials: 'include'" 设置为真。这允许 http-only cookie 与 post 请求一起发送,因此服务器能够解析当前会话。工作获取代码如下所示:
fetch('/logIn', {
method: 'POST',
body: JSON.stringify({
username: txtUsername.value,
password: txtPassword.value
}),
credentials: 'include', // <<< FIX
headers : {
'Content-Type' : 'application/json'
}
})
.then(result => {
result.text().then(function(text) {
if(result.status == 200) {
location.reload();
} else {
alert("Error:\n" + text);
}
});
})
.catch(e => {
console.log(e);
alert("Error:\n" + e);
});
我正在用 Spring 整理一些简单的页面,并想将一些数据添加到会话持续存在的对象中。它似乎对 GET 请求有效,但对使用 POST 方法的请求无效。
我有一个 UserData 组件如下:
package com.mycompany.controllers.components;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("session")
public class UserData {
private boolean loggedIn;
public UserData() {
loggedIn = false;
}
public boolean isLoggedIn() {
return loggedIn;
}
public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}
}
我有一个控制器如下:
package com.mycompany.controllers;
...
@RestController
@Scope("session")
public class DefaultController {
@Autowired
UserData userData;
...
@GetMapping("/")
public ResponseEntity index() {
printUserData(userData);
ResponseEntity entity;
if((entity = authenticate(userData)) != null) {
return entity;
}
...
}
@GetMapping("/setloggedIn")
public ResponseEntity setLoggedIn() {
printUserData(userData);
userData.setLoggedIn(true);
}
@PostMapping("/logIn" )
public ResponseEntity logIn(@RequestBody LogInDTO dto) {
printUserData(userData);
...
userData.setLoggedIn(true);
}
protected static void printUserData(UserData user) {
if(user== null) {
LOG.info("UserData is null");
return;
}
LOG.info("UserData logged in: {}", user.isLoggedIn());
}
}
当我导航到“/”时,
UserData.isLoggedIn()
的输出如预期的那样是错误的。当我向“/logIn”发出 post 请求时,输出再次如预期的那样是错误的。在一些参数验证之后,方法
UserData.setLoggedIn(true)
被调用但导航到“/”输出仍然是错误的。当我导航到“/setLoggedIn”时,loggedIn 最初为 false,但这也将 loggedIn 设置为 true,现在对“/”或“/setLoggedIn”的所有请求都会导致输出为 true。
对“/logIn”的进一步 POST 请求给出 false
的输出
我是不是遗漏了什么或者这是正常现象?
更新 1
当我检查 GET 请求的会话 ID 时,我可以看到它等于存储在我的 cookie 中的 JSESSIONID。我看到每个 POST 请求都有不同的会话 ID。
所以问题是,如何将 JSESSIONID 与 POST 请求一起发送。我目前正在按如下方式执行请求:
fetch('/logIn', {
method: 'POST',
body: JSON.stringify({
username: txtUsername.value,
password: txtPassword.value
}),
headers : {
'Content-Type' : 'application/json'
}
})
.then(result => {
result.text().then(function(text) {
if(result.status == 200) {
location.reload();
} else {
alert("Error:\n" + text);
}
});
})
.catch(e => {
console.log(e);
alert("Error:\n" + e);
});
更新 2
我发现 JSESSIONID cookie 是 HttpOnly,无法被 JavaScript 读取,这可能是它没有随 POST 请求一起发送的原因吗?导致 servlet 每次都创建一个新会话。
fetch 命令需要“"credentials: 'include'" 设置为真。这允许 http-only cookie 与 post 请求一起发送,因此服务器能够解析当前会话。工作获取代码如下所示:
fetch('/logIn', {
method: 'POST',
body: JSON.stringify({
username: txtUsername.value,
password: txtPassword.value
}),
credentials: 'include', // <<< FIX
headers : {
'Content-Type' : 'application/json'
}
})
.then(result => {
result.text().then(function(text) {
if(result.status == 200) {
location.reload();
} else {
alert("Error:\n" + text);
}
});
})
.catch(e => {
console.log(e);
alert("Error:\n" + e);
});