Я пишу внутреннее приложение в Spring Boot, которое вызывает другой API от третьего лица.
У меня проблема с этим конкретным вызовом, который извлекает объект токена, содержащий токен-носитель , которые затем я использую в их других конечных точках. Полученный токен иногда работает, в большинстве случаев это не так, при вызове других конечных точек, что приводит к несанкционированному ответу.
@RestController
public class CotizacionController {
Logger logger = LoggerFactory.getLogger(CotizacionController.class);
@Value("${service.credentials.tokenServer}")
private String tokenServer;
@Value("${service.credentials.grantType}")
private String grantType;
@Value("${service.credentials.username}")
private String username;
@Value("${service.credentials.password}")
private String password;
HttpClient client = HttpClient.newHttpClient();
@RequestMapping("/create")
public Object Create() throws IOException, InterruptedException {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("grant_type", grantType);
parameters.put("username", username);
parameters.put("password", password);
String form = parameters.keySet().stream()
.map(key -> key + "="
+ URLEncoder.encode(parameters.get(key),
StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenServer))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(BodyPublishers.ofString(form)).build();
HttpResponse<?> response = client.send(request, BodyHandlers.ofString());
TokenResponse result = new ObjectMapper().readValue(response
.body().toString(), TokenResponse.class);
return result;
}
}
А вот пример объекта токена:
{
"access_token": "z-bu-Pde6M2dlPiaRzd5XpTrT7ohpFQZe157HHVLfdKJWsdmKCloK7AYGEw7SLCe28tjYAxo8MZOE_3W00HEa-bqgUvcrAKfxIubAq0UGXv7jLPWbRwWzhAUCDon3kdstUrJ_OKRN2y26W6qyDBGDqlP5NRSF4unH_pD_ShmpDlSxZdYUqD0da5Y2_uO6YRs5GuWA7XhI9sPa98SxuXN_dwiDJVif418xK646fUgWR8",
"token_type": "bearer",
"expires_in": "3599"
}
Получение токенов с помощью почтальона отлично работает , поэтому это не может быть проблемой из стороннего API. У меня также есть эта такая же служба, реализованная в. NET Core 3, и она также отлично работает там.
Что меня больше всего смущает, так это то, что фактический вызов HttpClient работает, я действительно получить правильный Json, который очень хорошо сопоставлен с моим объектом TokenResponse. Просто значение токена недействительно ... иногда.
Я также пробовал использовать библиотеки RestTemplate и WebClient Spring, но результаты те же. Вызов работает, но полученный токен недействителен.
Сначала я думал, что у меня состояние гонки, так как изначально у меня был другой HttpClient с другой конечной точкой, использующей ответ от вызова токена. Поэтому я упростил его до вызова токена и ручного копирования значения токена в запросы почтальона. Не сработало.
Тогда я подумал, что, возможно, мой заголовок авторизации HttpClient был искажен, но это опровергнуто, поскольку простое копирование токена в защищенную конечную точку с помощью запроса почтальона показывает, что токен не работает.
И другие вещи, которые я пробовал:
- Вставка строки формы, которую я генерирую в контроллере, в запрос Postman, чтобы убедиться, что она действительна.
- Убедитесь, что кодировщик URLEncoder не испортить какие-либо значения формы.
- Скопируйте значение токена из объекта токена для использования в другой конечной точке с помощью Postman.
- Пропустить сопоставление объектов и вернуть простую строку и вручную скопировать значение токена из ответа в Postman, чтобы затем я мог использовать его в другой конечной точке.
Я довольно потерян на этом этапе, единственное, что приходит в голову, это то, что, возможно, метод HttpClient.send () может анализировать тело таким образом, чтобы это могло повлиять на его содержимое? Сомневаюсь, но не понимаю, что еще могло произойти.