提问人:firstuser 提问时间:11/8/2023 更新时间:11/8/2023 访问量:81
将 axios 与 useeffect 一起使用时,在 JavaScript 代码中获取争用条件
Getting race condition in JavaScript code when using axios with useeffect
问:
我在 react 中使用 csrf 令牌和 jwt 身份验证,我的 jwt 令牌存储在 httponly cookie 中,所以我的前端无法访问此 cookie,所以我在我的 spring 后端中制作了一个端点,用于检查用户是否经过身份验证并返回 true 或 false。也是将 csrf-token 作为 cookie(non-httponly cookie)获取的端点,因此获取的 csrf-cookie iam 的名称是,它的相应值是 csrf 令牌值。因此,根据 Spring Security,我应该将此 CSRF 令牌作为标头发送,其中包含 CSRF 令牌的名称和值,并且对于每个状态(指后端)更改请求(如 etc)删除 CSRF 令牌,并且不会更改请求,因此对于每个状态(指后端)更改请求,我们应该通过调用端点来生成一个新令牌,因此,而不是每次创建时都重复所有这些步骤我的 javascript 中的 HttpUtility 类 获取 csrf 令牌并检查我的请求是否经过身份验证 HttpUtil 类的代码是:api/user/is-authenticated
api/user/csrf-token
XSRF-TOKEN
X-XSRF-TOKEN
POST,PUT,DELETE
GET
api/user/csrf-token
import axios from 'axios';
import Cookies from 'js-cookie';
class HttpRequestUtility {
static axiosInstance = axios.create({
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
});
static csrfAxiosInstance = axios.create({
withCredentials: true
})
static authenticatedAxiosInstance = axios.create({
withCredentials : true,
headers: {
'Content-Type': 'application/json'
}
})
static axiosInstanceConfigured = false;
static authenticatedAxiosInstanceConfigured = false;
static configAxiosInstance() {
// Add a request interceptor
this.axiosInstance.interceptors.request.use(async config => {
// Call your function to get the CSRF token
const csrfToken = await this.getCsrfToken();
// Set the CSRF token in the headers
config.headers['X-XSRF-TOKEN'] = csrfToken;
return config;
}, error => {
return Promise.reject(error);
});
}
static configAuthenticatedAxiosInstance() {
// Add a request interceptor
this.authenticatedAxiosInstance.interceptors.request.use(async config => {
const isAuthenticatedUrl = "http://localhost:8080/api/user/is-authenticated"
if(await this.getAxiosInstance().get(isAuthenticatedUrl)){
// Call your function to get the CSRF token
const csrfToken = await this.getCsrfToken();
// Set the CSRF token in the headers
config.headers['X-XSRF-TOKEN'] = csrfToken;
return config;
}
else{
throw new Error("User is not Authenticated")
}
}, error => {
return Promise.reject(error);
});
}
static async getCsrfToken() {
let csrfCookie = Cookies.get('XSRF-TOKEN');
if (!csrfCookie) {
try {
await this.csrfAxiosInstance.get('http://localhost:8080/api/user/csrf-token');
csrfCookie = Cookies.get('XSRF-TOKEN');
} catch (error) {
console.error("Failed to get CSRF token ", error);
}
}
return csrfCookie
}
static getAxiosInstance() {
if (!this.axiosInstanceConfigured) {
this.configAxiosInstance();
this.axiosInstanceConfigured = !this.axiosInstanceConfigured
}
return this.axiosInstance;
}
static getAuthenticatedAxiosInstance(){
if(!this.authenticatedAxiosInstanceConfigured){
this.configAuthenticatedAxiosInstance();
this.authenticatedAxiosInstanceConfigured = !this.authenticatedAxiosInstanceConfigured
}
return this.authenticatedAxiosInstance;
}
}
export default HttpRequestUtility
我在 react 中有一个 useEffect 钩子,如下面的代码所示,它有一个 get 请求,它不会更改状态(指后端),因此它不会删除 csrf 令牌。而且我的useEffect钩子中也有一个请求,它改变了状态(指的是后端),所以它删除了前端中的csrf-token,我的代码是这样的:PUT
useEffect(() => {
const fetchData = async () => {
try {
const getUserUrl = "http://localhost:8080/api/user/get";
const response = await HttpRequestUtility.getAuthenticatedAxiosInstance().get(getUserUrl);
response.data.noteIds.map((element)=>{
console.log("Note id's are : "+element)
})
console.log("users are ", response.data);
const data = {
username: "test Data"
}
await HttpRequestUtility.getAuthenticatedAxiosInstance().put("http://localhost:8080/api/user/edit",data)
} catch (error) {
console.log(error);
const logoutUrl = "http://localhost:8080/api/user/logout"
await HttpRequestUtility.getAxiosInstance().post(logoutUrl)
navigate("/login");
}
}
fetchData();
}, [])
注意:上面的useEffect代码用于演示我的问题,我不会像那样使用它来展示我的问题,我正在举例说明用例
所以当这段代码从我的 HttpUtility 类中执行时:
static async getCsrfToken() {
let csrfCookie = Cookies.get('XSRF-TOKEN');
if (!csrfCookie) {
try {
await this.csrfAxiosInstance.get('http://localhost:8080/api/user/csrf-token');
csrfCookie = Cookies.get('XSRF-TOKEN');
} catch (error) {
console.error("Failed to get CSRF token ", error);
}
}
return csrfCookie
}
由于 useEffect 钩子在 react 开发模式下执行两次,它正在向端点发送两个 put 请求,我的问题不在于 useeffect 如何发送两个 put 请求,我的问题是当我在执行多个状态更改请求时,例如从前端一个接一个地使用 HttpUtility 类作为 javascript 是单线程和事件驱动的语言,它正在上述方法中进行上下文切换它从 useEffect 到达第一个 put 请求,因为它是网络调用请求,它正在执行第二个 put 请求,当第二个 put 请求执行到此代码时,它会转到第一个 put 请求并删除“XSRF-TOKEN”cookie,因为它是一个状态(指后端)更改请求,所以当第二个 put 请求恢复并转到这一行时,我未定义为csrf 令牌已删除,请求在没有 csrf 令牌的情况下执行,我收到错误。所以任何人都可以帮助我更好地实现 httpUtility 类,这样它就不会进入这种竞争条件。api/user/edit
PUT,POST,DELETE
getCsrfToken
await this.csrfAxiosInstance.get('http://localhost:8080/api/user/csrf-token');
await this.csrfAxiosInstance.get('http://localhost:8080/api/user/csrf-token');
csrfCookie = Cookies.get('XSRF-TOKEN')
我还为我的方法实现了一个锁定变量,如下所示:getCsrfToken
static lock = Promise.resolve();
static async getCsrfToken() {
let csrfCookie = Cookies.get('XSRF-TOKEN');
if (!csrfCookie) {
// Wait for the lock to be released before proceeding
await lock;
lock = (async () => {
try {
await this.csrfAxiosInstance.get('http://localhost:8080/api/user/csrf-token');
csrfCookie = Cookies.get('XSRF-TOKEN');
} catch (error) {
console.error("Failed to get CSRF token ", error);
}
return csrfCookie;
})();
// Wait for the lock to be released before returning
csrfCookie = await lock;
}
return csrfCookie;
}
在此版本的函数中,我们在锁中使用异步函数。这允许我们将 await 与 get 请求一起使用。设置锁后,我们等待锁,然后再返回 csrfCookie。这可确保在发布请求和 cookie 检索完成之前,函数不会返回。
但这也不起作用,任何人都可以帮助我,我从昨天开始就陷入了这个问题
答: 暂无答案
评论