- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用reactjs、mbox 和axios,但遇到了问题。我有一个 api,它给出了访问 token 和刷新 token 。访问 token 每 20 分钟就会失效,当发生这种情况时,服务器会发回 401,我的代码将自动发送刷新 token 以获取新的访问 token 。
一旦授予新的访问 token ,将再次发送相同的被拒绝的请求。现在我的代码工作得很好,直到我抛出多个拒绝,这些拒绝几乎可以同时触发。
因此,第一个请求发出,返回 401 并获取新的刷新 token ,所有其他请求将尝试执行相同的操作,但其他请求现在将失败,因为将使用刷新 token 并且将针对第一个请求发出新的请求。
这将启动我的代码,将用户重定向到登录页面。
所以本质上我一次只能有 1 个请求。
export const axiosInstance = axios.create({
baseURL: getBaseUrl(),
timeout: 5000,
contentType: "application/json",
Authorization: getAuthToken()
});
export function updateAuthInstant() {
axiosInstance.defaults.headers.common["Authorization"] = getAuthToken();
}
function getAuthToken() {
if (localStorage.getItem("authentication")) {
const auth = JSON.parse(localStorage.getItem("authentication"));
return `Bearer ${auth.accessToken}`;
}
}
axiosInstance.interceptors.response.use(
function(response) {
return response;
},
function(error) {
const originalRequest = error.config;
if (error.code != "ECONNABORTED" && error.response.status === 401) {
if (!originalRequest._retry) {
originalRequest._retry = true;
return axiosInstance
.post("/tokens/auth", {
refreshToken: getRefreshToken(),
grantType: "refresh_token",
clientId : "myclient"
})
.then(response => {
uiStores.authenticaionUiStore.setAuthentication(JSON.stringify(response.data))
updateAuthInstant();
return axiosInstance(originalRequest);
});
} else {
uiStores.authenticaionUiStore.logout();
browserHistory.push({ pathname: '/login',});
}
}
return Promise.reject(error);
}
);
编辑
我遇到的问题是,当用户复制直接网址时,我需要检查以重置身份验证的代码不起作用
app.js
<React.Fragment>
<Switch>
<Route path="/members" component={MemberAreaComponent} />
</Switch>
</React.Fragment >
在memberAreaComponent中
<Route path="/members/home" component={MembersHomeComponent} />
当我输入http://www.mywebsite/members/home
MembersHomeComponent - componentDidMount runs first
MemberAreaComponent - componentDidMount runs second
AppCoontainer = componentDidMount runs last.
最佳答案
嗨,我在react/redux应用程序中实现了相同的场景。但它会帮助你实现目标。您不需要在每个 API 调用中检查 401。只需在您的第一个验证 API 请求中实现它即可。您可以使用 setTimeOut 在身份验证 token 到期之前发送刷新 token api 请求。因此,locatStorage 将得到更新,并且所有 axios 请求都不会获得过期的 token 。这是我的解决方案:
在我的Constants.js
中,我在localStorage中维护用户 token ,如下所示:
export const USER_TOKEN = {
set: ({ token, refreshToken }) => {
localStorage.setItem('access_token', token);
localStorage.setItem('refresh_token', refreshToken);
},
remove: () => {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
},
get: () => ({
agent: 'agent',
token: localStorage.getItem('access_token'),
refreshToken: localStorage.getItem('refresh_token'),
}),
get notEmpty() {
return this.get().token !== null;
},
};
export const DEFAULT_HEADER = {
get: () => ({
'Content-type': 'application/json;charset=UTF-8',
agent: `${USER_TOKEN.get().agent}`,
access_token: `${USER_TOKEN.get().token}`,
}),
};
页面加载时,用户验证 API 请求如下:
dispatch(actions.validateUser(userPayload)) // First time authentication with user credentials and it return access token, refresh token and expiry time
.then(userData => {
const { expires_in, access_token, refresh_token } = userData
USER_TOKEN.set({ // setting tokens in localStorage to accessible to all API calls
token: access_token,
refreshToken: refresh_token,
});
const timeout = expires_in * 1000 - 60 * 1000; // you can configure as you want but here it is 1 min before token will get expired
this.expiryTimer = setTimeout(() => { // this would reset localStorage before token expiry timr
this.onRefreshToken();
}, timeout);
}).catch(error => {
console.log("ERROR", error)
});
onRefreshToken = () => {
const { dispatch } = this.props;
const refresh_token = USER_TOKEN.get().refreshToken;
dispatch(actions.refreshToken({ refresh_token })).then(userData => {
const { access_token, refresh_token } = userData
USER_TOKEN.set({
token: access_token,
refreshToken: refresh_token,
});
});
};
如有任何问题,请随时提出,另一种方法是实现 axios abort Controller 来取消待处理的 promise 。我也很乐意提供帮助!
已编辑 - 您可以在所有 API 请求中维护 axios token 源,以便随时中止它们。 在所有 api 中维护 axios token 源。一旦您解决了第一个 promise ,您就可以取消所有其他待处理的 API 请求。您可以在第一个 promise 得到解决后调用 onAbort 方法。看这个:
//in your component
class MyComponent extends Component{
isTokenSource = axios.CancelToken.source(); // a signal you can point to any API
componentDidMount{
// for example if you're sending multiple api call here
this.props.dispatch(actions.myRequest(payload, this.isTokenSource.token))
.then(() => {
// all good
})
.catch(error => {
if (axios.isCancel(error)) {
console.warn('Error', error);
}
});
}
onAbortStuff = () => { // cancel request interceptor
console.log("Aborting Request");
this.isTokenSource.cancel('API was cancelled'); // This will abort all the pending promises if you send the same token in multiple requests,
}
render(){
//
}
在您的 axios 请求中,您可以像这样发送 token :
export const myRequest= (id, cancelToken) => {
const URL = `foo`;
return axios(URL, {
method: 'GET',
headers: DEFAULT_HEADER.get(),
cancelToken: cancelToken
})
.then(response => {
// handle success
return response.data;
})
.catch(error => {
throw error;
});
};
您可以引用这篇文章,它对于理解取消订阅非常有帮助。 https://medium.freecodecamp.org/how-to-work-with-react-the-right-way-to-avoid-some-common-pitfalls-fc9eb5e34d9e
您可以通过以下方式构建路线:索引.js
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
App.js:
class App extends Component {
state = {
isAuthenticated: false,
};
componentDidMount() {
//authentication API and later you can setState isAuthenticate
}
render() {
const { isAuthenticated } = this.state;
return isAuthenticated ? <Routes /> : <Loading />;
}
如果您仍然发现任何问题,我非常乐意为您提供帮助。
关于reactjs - 当多个请求发出时如何处理刷新 token ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51915340/
我们知道,当使用 hibernate 对数据库进行批量更新时(即使在 HQL 中),所做的更改不会复制到存储在当前 session 中的实体。 所以我可以调用 session.refresh 来加载对
我正在做一个项目,所有的东西都保存在事件中,所以服务器需要一些时间来响应新数据。我正在使用 Fluent 等待使用 ajax 的页面,但是这个不使用任何 ajax。所以我想刷新页面检查是否有新项目,如
我有一个从 Vector 创建的 JTable。 如何刷新 JTable 以显示添加到 Vector 的新数据? 最佳答案 当 TableModel 发生更改时,您的 JTable 应该会自动更新。我
有没有办法使用下面的代码来刷新已经存在的 div id,而不是刷新时间? window.onload = startInterval; function startInterval() {
我更新了在 Shiny Server 上运行的 Shiny 应用程序使用的 DataSet.RData。但是, Shiny 的应用程序仍在旧数据上运行。我已通过浏览器历史记录清除并重新启动浏览器几次,
我的应用程序中有一个无限滚动的网格面板(ExtJs 4.2.1),类似于 this example .用户可以单击刷新按钮,然后必须使用数据库中的数据更新网格的行。我在刷新按钮处理程序中调用 stor
我不知道这三种方法中哪一种最适合我。他们都为我工作。有谁知道刷新、更新和重画之间的区别吗? 最佳答案 根据在线文档: Refresh - 重新绘制屏幕上的控件。 Call Refresh method
有什么办法吗 ICollectionView.Refresh() 或者 CollectionViewSource.GetDefaultView(args.NewValue).Refresh(); 在
这个问题已经有答案了: Updating address bar with new URL without hash or reloading the page [duplicate] (4 个回答)
我有一个 javascript 设置超时以在 10 秒后关闭 div,并且我想在 div 关闭时添加页面刷新。我正在使用的代码如下。 var container_close_sec = "1
我有一组具有以下名称的页面.... update1.php update2.php update3.php update4.php update5.php update6.php update7.ph
如果是则触发js函数。我可以使一个复选框保持选中状态,并在页面刷新时检查值并选中“checked”,并提交以下内容... checked="checked" /> 你都不记得触发js函数。 这是我的
我正在尝试刷新 php 脚本以在数据库更新时显示更新的内容。我首先构建了我的 php,然后刷新代码,然后合并它们。但是,脚本不会更新。有谁知道为什么吗? $(document).ready
当我要删除的节点扩展集合类型时,Grails中有一个错误阻止我使用removeFrom *。直接从关联中删除节点不会更新二级缓存。 A hasMany B 有什么方法可以使关联缓存手动无效或强制重新加
我正在使用 hibernate 和 mysql 来抽象一个数据库,以便在 java 驱动的网站中使用。我使用 hibernate 很好地解决了所有查询,但似乎无法弄清楚如何使用它进行更新、插入和删除,
如何通过调用 oncreateview 方法重新创建 fragment ?我有一个 fragment ,用于通过表单插入新数据,单击按钮后,我想通过删除在 EditText 中输入的数据来重新创建 f
当我从一个到另一个时,我试图刷新我的观点。我知道我应该将刷新代码放在 viewWillAppear 中,但我不知道该放什么代码。 你们能帮帮我吗? 谢谢! 最佳答案 在您看来,请调用 setNeeds
我正在开发 iPhone 应用程序并希望使用: CFStreamCreatePairWithSocketToHost(NULL, url, port, &serverReadStream, &serv
看到我已经创建了一个用于登录用户的脚本。而且我还添加了设置选项卡,以便用户可以编辑他们的设置!但是当我尝试它时,mysql 表中的数据发生了变化,但配置文件中显示的用户名和用户电子邮件保持不变!当我注
好的。这就是它的样子。 当我启动应用程序时,我从服务器收到的第一件事是数据: {name: "test", type: "checkbox" checked: true, } 这使得其中一个复选框
我是一名优秀的程序员,十分优秀!