当第一个请求失败时,重做先前的请求401 Unauthorized

时间:2014-08-19 17:27:10

标签: java android android-networking retrofit

我正在构建一个Android应用程序,它将从REST API中获取数据。

要将RetrofitOtto一起使用请求。

对于我的所有请求,我添加了一个RequestInterceptor,它将为我的所有请求添加一个标头(Authorization)。 在RequestInterceptor中,我正在调用当前access_token的方法,然后将标头填充到请求中。

RequestInterceptor requestInterceptor = new RequestInterceptor() {

    @Override
    public void intercept(RequestFacade request) {
        Token token = TokenPreferences.getToken();

        request.addHeader("Authorization", token.getTokenType() + " " + token.getAccessToken());
    }
};

RestAdapter restAdapter = new RestAdapter.Builder()
      .setEndpoint("https://example.com")
      .setRequestInterceptor(requestInterceptor)
      .build();

  ...

这在access_token过期之前一直正常,然后请求将失败,HTTP状态为401 Unauthorized。 发生这种情况时,我想提出一个新的请求,从我获得的refresh_token中获取一个新的access_token,然后再次执行第一个请求。

我不确定如何做到这一点。

3 个答案:

答案 0 :(得分:1)

尝试com.squareup.okhttp.Authenticator。据我所知,这比com.squareup.okhttp.Interceptor(你可以在其他地方找到的建议)更可取,因为它只会引发未经授权的请求。这是一个基本的例子:

public class ApiAuthenticator implements Authenticator {

    @Override
    public Request authenticate(Proxy proxy, Response response) throws IOException {
        for (Challenge challenge : response.challenges()) {
            if (challenge.getScheme().equals("Bearer")) {

                String authToken = // Refresh the token here

                if (authToken != null) {
                    return response.request().newBuilder()
                            .header("Authorization", "Bearer " + authToken)
                            .build();
                }
            }
        }
        return null;
    }

    @Override
    public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
        return null;
    }
}

您可以将其附加到您的客户端,如下所示:

okHttpClient.setAuthenticator(new ApiAuthenticator());

请注意,如果您使用Retrofit刷新令牌并且令牌无效,则可能会遇到403代码的意外,难以调试的行为,但解决方案只是使用try / catch块。

try {
    token = oauthService.refreshAccessToken(args);
} catch (RetrofitError error) {
    // Do something that leads to login
}

答案 1 :(得分:0)

Retrofit中未实现重试机制。它将在v2中。 (Retrying requests manually

您应该通过onFailure()回调的递归调用实现重试Deepack suggested

答案 2 :(得分:0)

我遇到了同样的问题,目前我还不知道如果因未经授权的错误导致请求失败,请重试我的请求。

虽然 @Yuriy Ashaev 提到重试机制应该是v2.0 Retrofit版本的一部分,但这应该仅用于5xx错误(请参阅Request Object draft description here)并尝试重试由于其他原因而失败的请求将引发异常。

截至目前,您仍然可以将自己的ErrorHandler添加到RestAdapter并捕获Unauthorized错误以获取刷新令牌。以下是实现此目的的方法:

class RestErrorHandler implements retrofit.ErrorHandler {

    @Override
    public Throwable handleError(RetrofitError cause) {
        Response r = cause.getResponse();
        if (r != null && r.getStatus() == 401) {

            Token token = mTokenProvider.fetchToken();
            if (token != null) {
                addHeader(HEADER_AUTHORIZATION, token.getToken_type() + " " + token.getAccess_token());
            }
            // Todo: Relaunch previous request
            return cause;
        }
        return cause;
    }
}

但是,除了在您的ErrorHandler中返回RetrofitError时将调用的所有 failure()请求回调中,我还没有看到从此点重试失败请求的任何方法。 ..

如果有人能指出我们如何从ErrorHandler重试失败的请求,我真的很感激,因为响应只指向f-请求网址。