如何刷新 jwt 并重新发送失败的 http 请求?
Posted
技术标签:
【中文标题】如何刷新 jwt 并重新发送失败的 http 请求?【英文标题】:How to refresh jwt and resend failed http request? 【发布时间】:2015-12-08 08:08:29 【问题描述】:我有一个带有 jwt auth 的后端,我想处理过期的令牌。
需要以下流程:
-
发出带有令牌的请求(并期望得到承诺)
如果一切正常,则返回 promise(并执行调用者的 then/fail 方法)
如果失败(401 未授权),则请求刷新令牌并在本地更新令牌
如果第 3 步成功,则返回原始请求的承诺
如果第 3 步失败并出现 401(无法刷新令牌)错误重定向到登录页面
问题: 在第 4 步中,(再次)调用了原始函数,但未触发调用者的 then/fail 方法。
以下是我将 jwt 令牌附加到 url 并发送 http 请求的方法:
var AuthenticatedRequest = function(url, data, method)
return (function tryRequest()
console.log('calling tryRequest');
return reqwest(
url: ApiUtil.tokenUrlTo(url),
method: method,
crossOrigin: true,
type: 'json',
data: data
)
.fail(function(err)
if (err.status === 401)
return post('/auth/refresh-token')
.then(function(response)
console.log('assume token set');
//code to update token locally
)
.then(tryRequest)
.fail(function(err)
// Can't refresh token. Send to login page
)
;
)
;
)();
;
这里是调用者:
fetchModules: function()
get('/admin/modules')
.then(function(response)
Actions.modulesFetchSuccess(response.collection);
)
.fail(function(err)
Actions.modulesFetchError(ApiUtil.errorArrayForResponse(err));
)
;
,
现在,如果我因为令牌过期而收到 401,我会触发一个新周期来刷新令牌,如本问题 Restart a promise after fail 中所建议的那样。
注意:post
和 get
函数只是 AuthenticatedRequest
函数的包装器,其方法设置为 POST
或 GET
。
AuthenticatedRequest
函数返回一个承诺,如果令牌未过期,则运行正常,但是,当令牌过期时,我在控制台中收到错误并获取新令牌并再次调用该函数, 我的控制台截图 - http://i.stack.imgur.com/hJdId.png
但是fetchModules
的then
方法在令牌更新后不会被触发。我做错了什么?
可能的重复:
AngularJS - Handling refresh token? How to resend request when not authorized Restart a promise after fail2015 年 9 月 13 日更新
@Bergi's 当我替换 reqwest.js
并使用 q.js
与 vanilla ajax 时,@Bergi's 答案有效,如 gist 所示
【问题讨论】:
你用的是什么promise库,reqwest
是什么? fail
方法通常不链接(例如在 jQuery 中)
@Bergi:我正在使用reqwest.js
啊,好吧,那个库似乎不支持真正的承诺。它确实提供了一个类似于 Promise 的界面,但它并没有像人们预期的那样工作。您应该使用适当的承诺库(选择任何一个)和cast the reqwest
to one like here。
如果您选择了一个库,如果您仍有问题,我很乐意协助您应用它。请edit您的问题添加新信息。
不,如果需要,我可以更改库。
【参考方案1】:
问题是.fail
总是能发现你的错误,而不仅仅是第一次。您对tryRequest
的递归调用将包括重试本身,并且永远不会返回失败的承诺。
如果您只想重试一次,则需要将其放在外部:
function AuthenticatedRequest(url, data, method)
function tryRequest()
console.log('calling tryRequest');
return reqwest(
url: ApiUtil.tokenUrlTo(url),
method: method,
crossOrigin: true,
type: 'json',
data: data
);
return tryRequest().fail(function(err)
if (err.status !== 401) throw err;
return post('/auth/refresh-token')
.then(function(response)
console.log('assume token set');
// code to update token locally
)
.then(tryRequest)
.fail(function(err)
// Can't refresh token. Send to login page
);
);
请注意,从AuthenticatedRequest
函数将用户发送到另一个页面可能不是一个好的设计,也许可以考虑重新抛出错误(在使令牌无效之后?)并将重定向和所有内容放在调用者的错误处理程序中.
【讨论】:
我试过了,还是同样的错误,caller's
then /fail 没有被调用。
我替换了 reqwest 并将您的方法与 q.js 和本机 XHR 一起使用。像魅力一样工作。
@ShivekKhurana:完美:-)
如果您需要更多选项,您还应该能够使用function xhr(options) return Q(reqwest(options));
,而不是原生 XHR 功能。
我会记住这一点并在需要时扩展它。谢谢你,你帮了很多忙:)以上是关于如何刷新 jwt 并重新发送失败的 http 请求?的主要内容,如果未能解决你的问题,请参考以下文章