我有以下代码,其中我请求从 keycloak 获取承载令牌,并发出另一个请求以保存在浏览器编辑器上编写的内容(通过单击名为“保存”的按钮)。
这里的问题是:令牌仅持续 5 分钟,因此我想在调用 makeApiRequest 之前调用函数 getToken (生成新的有效令牌),以便请求正常运行。现在,当我运行应用程序后等待 5 分钟并单击“保存”时,我会收到未经授权的状态代码,例如未正确生成令牌第二次,但如果我再次单击“保存”按钮,它就会起作用(编辑器的内容是按预期保存)。下图是一个例子:
这是我的js文件:
import React, { useEffect, useState } from 'react';
import { MyEditor } from '@myEditor/example-editor';
function MeEditor() {
const tokenURL = 'http://keycloak:1902/auth/realms/myEditor/openid-connect/token';
const apiURL = 'http://localhost:1777/MyEditor/api/note';
const clientId = 'my_cli_client';
const clientSecret = 'my_cli_client_secret';
const [tokenInfo, setTokenInfo] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [editorText, setEditorText] = useState('');
useEffect(() => {
getToken();
}, []);
const getToken = async () => {
const params = new URLSearchParams();
params.append('grant_type', 'client_credentials');
params.append('client_id', clientId);
params.append('client_secret', clientSecret);
const response = await fetch(tokenURL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data = await response.json();
const expirationTime = new Date().getTime() + data.expires_in * 1000;
setTokenInfo({
accessToken: data.access_token,
expiresAt: expirationTime,
});
setIsLoading(false);
};
const makeApiRequest = async () => {
const postData = {
data: {
correlationId: 123,
subjectId: '01',
text: editorText,
},
};
const response = await fetch(apiURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + tokenInfo.accessToken,
},
body: JSON.stringify(postData),
});
if (response.ok) {
const apiResponse = await response.json();
console.log(apiResponse);
} else {
console.error('API request failed:', response.status, response.statusText);
}
};
const handleSaveButtonClick = async () => {
setIsSaving(true);
const currentTime = new Date().getTime();
if (!tokenInfo || currentTime > tokenInfo.expiresAt) {
await getToken();
}
if (tokenInfo) {
await makeApiRequest();
}
setIsSaving(false);
};
const handleEditorChange = (newText) => {
setEditorText(newText);
};
return (
<div className="editor-container">
{isLoading ? (
<p>Loading...</p>
) : tokenInfo ? (
<React.Fragment>
<MyEditor
tokenProvider={{ getToken: () => tokenInfo.accessToken }}
defaultValue={editorText}
onChange={handleEditorChange}
/>
<button onClick={handleSaveButtonClick} disabled={isSaving}>
{isSaving ? 'Saving...' : 'Save'}
</button>
</React.Fragment>
) : (
<p>No token available.</p>
)}
</div>
);
}
export default MyEditor;
知道我可能会错过什么吗?我尝试重构下面的验证,以在 makeApiRequest 之前生成一个新的有效令牌(如果旧的令牌不再有效),但到目前为止还没有运气
if (!tokenInfo || currentTime > tokenInfo.expiresAt) {
await getToken();
}
我认为问题是由于 useEffect 造成的,您在 useEffect 中所做的更新不会立即可见,因为您使用了异步状态。问题应该出在
setTokenInfo({
accessToken: data.access_token,
expiresAt: expirationTime,
});
你应该做类似的事情
setTokenInfo((lastToken) => { set new token information })