Using the interceptor, I try to update the access token. But the code doesn't work... How can I update the access token using the http client interceptor?
try (CloseableHttpClient httpClient = HttpClients.custom().
addExecInterceptorAfter(ChainElement.PROTOCOL.name(), "a1", (request, scope, chain) -> {
ClassicHttpResponse response = chain.proceed(request, scope);
if (response.getCode() == HttpStatus.SC_UNAUTHORIZED) {
userAuthBean.updateAccessTokenFromAPI();
request.addHeader("Authorization", "Bearer " + userAuthBean.getAccessToken());
chain.proceed(request, scope);
}
return response;
})
.build())
{
HttpGet request = new HttpGet(uri);
request.addHeader("Authorization", "Bearer " + userAuthBean.getAccessToken());
try (CloseableHttpResponse response = httpClient.execute(request)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
System.out.println(result);
}
} catch (IOException | ParseException ioException) {
ioException.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
This code for retrying the request in case if 403 is obtained, ideally should not be in interceptor. Interceptors are to be generally written straightforward which manipulates the current* request/response and cause the call chain to process. They make your code hideous, and make debugging a lot more plain since the logic is hidden from plain-sight in most of the cases.
Generally, these interceptors can be best used to log the requests(To ELK/Kafka or wherever) and add missing attributes/headers if any for *every request going through the http client (Even this is a code-smell IMO).
Instead, what you need is chaining of Function
as shown below,
public static void main(String[] args) throws IOException {
getWithAuthTokenRetry.apply(new Request.Builder().url("http://google.com").build());
}
public static Function<Request, Response> get =
(req) -> {
OkHttpClient okHttpClient = new OkHttpClient();
Response res = null;
try {
res = okHttpClient.newCall(req).execute(); // Simulate calls!!
} catch (IOException e) {
e.printStackTrace();
}
return res;
};
public static Function<Request, Response> getWithAuthTokenRetry =
request -> {
Function<Response, Response> authenticateAndRetryFunction =
res -> {
if (res != null && res.code() == 200) { //403 Here
String authToken = "Generated AuthToken"; // Simulating new AuthToken
Request updatedRequest = request.newBuilder().header("Auth", authToken).build();
System.out.println(updatedRequest.headers());
res = get.apply(updatedRequest);
}
return res;
};
return get.andThen(authenticateAndRetryFunction).apply(request);
};
This is a very broad implementation, which does not deal with Exceptions properly, but I guess those can be figured out as per requirement.
Also, ClosableHttpClient need not be created for every request, create a instance of HttpComponentsClientHttpRequestFactory with ClosableHttpClient.