问题
We use Google Contacts API with OAuth2:
credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setClientSecrets(OAuth2ClientId(), OAuth2ClientSecret())
.addRefreshListener(new CredentialRefreshListener() {...});
myService = new ContactsService("My-App");
myService.setOAuth2Credentials(credential);
and quite regularly we receive '401 Unauthorized' response that the GData library can't handle.
AuthenticationException throws NPE when WWW-Authenticate
header is missing.
Caused by: java.lang.NullPointerException: No authentication header information
at com.google.gdata.util.AuthenticationException.initFromAuthHeader(AuthenticationException.java:96) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.util.AuthenticationException.<init>(AuthenticationException.java:67) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:608) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:564) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:560) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:538) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:536) ~[gdata-core-1.0-1.47.1.jar:na]
at com.google.gdata.client.Service.getFeed(Service.java:1135) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.Service.getFeed(Service.java:1077) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:676) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.Service.query(Service.java:1237) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
at com.google.gdata.client.Service.query(Service.java:1178) ~[gdata-core-1.0-1.47.1.jar:1.47.1]
We managed to add a wrapper that would try token refreshing on this NPE. It helps but then there are still many cases when refreshing fails:
credential.refreshToken() == false
When we run refreshToken()
in the debugger we see that executeRefreshToken()
is executed without an exception but tokenResponse==null
is returned. As a result refreshToken()
returns false
and no reason is passed to the listeners
try {
TokenResponse tokenResponse = executeRefreshToken();
if (tokenResponse != null) {
setFromTokenResponse(tokenResponse);
for (CredentialRefreshListener refreshListener : refreshListeners) {
refreshListener.onTokenResponse(this, tokenResponse);
}
return true;
}
} catch (TokenResponseException e) {
boolean statusCode4xx = 400 <= e.getStatusCode() && e.getStatusCode() < 500;
// check if it is a normal error response
if (e.getDetails() != null && statusCode4xx) {
// We were unable to get a new access token (e.g. it may have been revoked), we must now
// indicate that our current token is invalid.
setAccessToken(null);
setExpiresInSeconds(null);
}
for (CredentialRefreshListener refreshListener : refreshListeners) {
refreshListener.onTokenErrorResponse(this, e.getDetails());
}
if (statusCode4xx) {
throw e;
}
}
return false;
Our tokens are always for multiple scopes: https://www.googleapis.com/auth/userinfo.email https://www.google.com/m8/feeds https://www.googleapis.com/auth/calendar https://mail.google.com/ https://www.googleapis.com/auth/tasks
回答1:
There is currently a bug in the Contacts API where certain HTTP User-Agent
strings, cause the 401 response to return as an HTML page instead of an XML response, and missing the WWW-Authenticate
header that the AuthenticationException
class is relying on. GContacts-Java
is one of these special user agent strings. A workaround is to change the user agent of your client after you create it:
ContactsService service = new ContactsService(applicationName);
service.getRequestFactory().setHeader("User-Agent", applicationName);
This should eliminate the NPE, and allow the client library to automatically detect expired tokens and refresh them automatically.
来源:https://stackoverflow.com/questions/26286369/google-contacts-api-failing-to-refresh-access-token