如何刷新jwt并重新发送失败的http请求?

时间:2015-09-11 17:25:18

标签: javascript ajax promise jwt

我有一个jwt auth的后端,我想处理过期的令牌。

需要以下流程:

  1. 发出附有令牌的请求(并期待承诺)
  2. 如果一切正常,那么只需返回promise(并执行调用者的then / fail方法)
  3. 如果失败(401未经授权),则会请求刷新令牌并在本地更新令牌
  4. 如果步骤3成功,则返回原始请求的承诺
  5. 如果步骤3因401失败(令牌无法刷新)错误重定向到登录页面
  6. 问题: 在步骤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中的建议触发一个新周期来刷新令牌。

    注意:postget函数只是AuthenticatedRequest函数的包装器,方法设置为POSTGET

    AuthenticatedRequest函数返回一个promise,如果令牌未过期,则运行正常,但是,当令牌过期时,我在控制台中出现错误并获取新令牌并且函数是再次调用,我的控制台的屏幕截图 - http://i.stack.imgur.com/hJdId.png

    但更新令牌后,then的{​​{1}}方法不会被触发。我做错了什么?

    可能重复:

    2015年9月13日更新

    当我替换fetchModules并将reqwest.js与香草ajax一起使用时,

    @Bergi's回答有效gist

1 个答案:

答案 0 :(得分: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函数发送到另一个页面可能不是一个好的设计,可能只考虑重新抛出错误(在令牌失效后?)并将重定向和所有内容放在错误处理程序中来电者。