Http client library java

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

License

javaquery/httpclient

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

Welcome to the JavaQuery http client

The http client is created on top of Apache http client (org.apache.httpcomponents:httpclient:4.5) with the goal of providing extensive functionality on any http request.

The http client has the following features to make your http request experience rich.

Create common or request specific HttpRequestHandler (implement com.javaquery.http.handler.HttpRequestHandler) and you can add following interceptor in the request.

  • beforeRequest(HttpExecutionContext httpExecutionContext, HttpRequest httpRequest);
  • afterResponse(HttpExecutionContext httpExecutionContext, HttpRequest httpRequest, HttpResponse httpResponse);
  • onError(HttpExecutionContext httpExecutionContext, HttpRequest httpRequest, Exception exception);

Same as request handler, create common or request specific HttpResponseHandler(com.javaquery.http.handler.HttpResponseHandler) and you can add following action on your response.

  • You can make other request in after response of request handler and update final response to process.
  • Get response as JSONObject or JSONArray directly.

Define your custom RetryPolicy for response specific status code or based on server response. Implement RetryPolicy.RetryCondition and RetryPolicy.BackoffStrategy .

I have created working http request examples in test cases. Explore all test cases to understand how this http client works.

Читайте также:  Send message html php

Источник

Старые песни о главном. Java и исходящие запросы

(Иллюстрация)

Одна из задач, с которой сталкиваются 99,9% разработчиков, — это обращение к сторонним endpoint’ам. Это могут быть как внешние API, так и «свои» микросервисы. Сейчас все и вся бьют на микросервисы, да. Получить или отправить данные просто, но иногда изобретают велосипеды. Можете назвать 5 способов реализации запросов на Java (c использованием библиотек и без)? Нет — добро пожаловать под кат. Да? Заходите и сравните 😉

0. Intro

Задача, которую мы будем решать, предельно проста: нам необходимо отправить запрос GET/POST и получить ответ, который приходит в формате JSON. Чтобы не писать очередной оригинальный микросервис, я воспользуюсь примером, который предоставляет набор endpoint’ов с некоторыми данными. Все примеры кода максимально упрощены, никаких хитросделанных кейсов с auth-токенами и заголовками тут не будет. Только POST и GET, GET и POST, и так 5 раз или около того.
Итак, поехали.

1. Built-in Java solution

Было бы странно, если бы поставленную задачу нельзя было решить без использования сторонних библиотек. Конечно, можно! Но грустно. Пакет java.net, а именно HttpURLConnection, URL и URLEnconder.

Для отправки запроса, что GET, что POST, необходимо создать объект URL и открыть на его основе соединение:

final URL url = new URL("http://jsonplaceholder.typicode.com/posts?_limit=10"); final HttpURLConnection con = (HttpURLConnection) url.openConnection();

Далее необходимо сдобрить соединение всеми параметрами:

con.setRequestMethod("GET"); con.setRequestProperty("Content-Type", "application/json"); con.setConnectTimeout(CONNECTION_TIMEOUT); con.setReadTimeout(CONNECTION_TIMEOUT);

И получить InputStream, откуда уже прочитать все полученные данные.

 try (final BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()))) < String inputLine; final StringBuilder content = new StringBuilder(); while ((inputLine = in.readLine()) != null) < content.append(inputLine); >return content.toString(); > catch (final Exception ex)

И, собственно, вот такой ответ мы получим (он будет одинаков для всех последующих примеров, ибо мы работаем с одними и теми же endpoint’ами):

В случае с POST-запросом все немного сложнее. Мы же хотим не только получить ответ, но и передать данные. Для этого нам нужно их туда положить. Документация нам говорит что это может сработать следующим образом:

final Map parameters = new HashMap<>(); parameters.put("title", "foo"); parameters.put("body", "bar"); parameters.put("userId", "1"); con.setDoOutput(true); final DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.writeBytes(getParamsString(parameters)); out.flush(); out.close(); 

Где getParamsString это простой метод, перегоняющий Map в String, содержащие пары «ключ-значение»:

public static String getParamsString(final Map params) < final StringBuilder result = new StringBuilder(); params.forEach((name, value) -> < try < result.append(URLEncoder.encode(name, "UTF-8")); result.append('='); result.append(URLEncoder.encode(value, "UTF-8")); result.append('&'); >catch (final UnsupportedEncodingException e) < e.printStackTrace(); >>); final String resultString = result.toString(); return !resultString.isEmpty() ? resultString.substring(0, resultString.length() - 1) : resultString; >

При успешном создании мы получим объект обратно:

Ссылочка на source, который можно запустить.

2. Apache HttpClient

Если уйти в сторону от встроенных решений, то первое, на что мы наткнемся — HttpClient от Apache. Для доступа нам понадобится сам JAR-файл. Или, так как я использую Maven, то соответствующая зависимость:

  org.apache.httpcomponents httpclient 4.5.6 

И то, как выглядят запросы с использованием HttpClient’a, уже намного лучше (source):

 final CloseableHttpClient httpclient = HttpClients.createDefault(); final HttpUriRequest httpGet = new HttpGet("http://jsonplaceholder.typicode.com/posts?_limit=10"); try ( CloseableHttpResponse response1 = httpclient.execute(httpGet) ) < final HttpEntity entity1 = response1.getEntity(); System.out.println(EntityUtils.toString(entity1)); >final HttpPost httpPost = new HttpPost("http://jsonplaceholder.typicode.com/posts"); final List params = new ArrayList<>(); params.add(new BasicNameValuePair("title", "foo")); params.add(new BasicNameValuePair("body", "bar")); params.add(new BasicNameValuePair("userId", "1")); httpPost.setEntity(new UrlEncodedFormEntity(params)); try ( CloseableHttpResponse response2 = httpclient.execute(httpPost) ) < final HttpEntity entity2 = response2.getEntity(); System.out.println(EntityUtils.toString(entity2)); >httpclient.close();

Мы получили те же данные, но написали при этом вдвое меньше кода. Интересно, куда еще могут завести поиски в таком, казалось бы, базовом вопросе? Но у Apache есть еще один модуль, решающий нашу задачу.

Читайте также:  Вычисление четных чисел php

3. Apache Fluent API

  org.apache.httpcomponents fluent-hc 4.5.6 

И уже с использованием Fluent Api наши вызовы становятся намного читабельнее (source):

 final Content getResult = Request.Get("http://jsonplaceholder.typicode.com/posts?_limit=10") .execute().returnContent(); System.out.println(getResult.asString()); final Collection params = new ArrayList<>(); params.add(new BasicNameValuePair("title", "foo")); params.add(new BasicNameValuePair("body", "bar")); params.add(new BasicNameValuePair("userId", "1")); final Content postResultForm = Request.Post("http://jsonplaceholder.typicode.com/posts") .bodyForm(params, Charset.defaultCharset()) .execute().returnContent(); System.out.println(postResultForm.asString());

И как бонус — пример. Если мы хотим передавать данные в боди не как форму, а как всеми любимый JSON:

 final Content postResult = Request.Post("http://jsonplaceholder.typicode.com/posts") .bodyString("", ContentType.APPLICATION_JSON) .execute().returnContent(); System.out.println(postResult.asString());

По сути вызовы схлопнулись в одну строчку кода. Как по мне, это намного более дружелюбно по отношению к разработчикам, чем самый первый способ.

4. Spring RestTemplate

Что же дальше? Дальше опыт меня завел в мир Spring. И, что не удивительно, у спринга тоже имеются инструменты для решения нашей простенькой задачи (странно, правда? Задача, даже не так — потребность! — базового уровня, а решений зачем-то больше одного). И первое же решение (базовое), которое вы найдете в экосистеме Spring, это RestTemplate. И для этого нам нужно тянуть уже немалую часть всего зоопарка. Так что если вам нужно отправить запрос в НЕспринговом приложении, то ради этого лучше не тянуть всю кухню. А если спринг уже есть, то почему бы и да? Как притянуть все, что необходимо для этого, можно посмотреть здесь. Ну а собственно GET-запрос с использованием RestTemplate выглядит следующим образом:

 final RestTemplate restTemplate = new RestTemplate(); final String stringPosts = restTemplate.getForObject("http://jsonplaceholder.typicode.com/posts?_limit=10", String.class); System.out.println(stringPosts);

Гуд. НО! Работать со строкой уже не хочется, тем более есть возможность получать не строки, а готовые объекты, которые мы ожидаем получить! Создаем объект Post:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Builder; import lombok.Getter; import lombok.Setter; @Builder @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) public class Post < private int id; private String title; private String body; private int userId; public String toString() < return String.format("\n id: %s \n title: %s \n body: %s \n userId: %s \n", id, title, body, userId); >>

Здесь:
Builder, Getter, Setter — сахар от Lombok, чтобы не писать все руками. Да, вот она, лень-матушка.
JsonIgnoreProperties — чтобы в случае получения неизвестных полей не вылетать в ошибку, а использовать те поля, которые нам известны.
Ну и toString, чтобы выводить наши объекты в консоль, и это можно было прочитать. Ну и собственно наши GET- и POST- запросы перевоплощаются в (source):

 // Map it to list of objects final Post[] posts = restTemplate.getForObject("http://jsonplaceholder.typicode.com/posts?_limit=10", Post[].class); for (final Post post : posts) < System.out.println(post); >final Post postToInsert = Post.builder() .body("bar") .title("foo") .userId(1) .build(); final Post insertedPost = restTemplate.postForObject("http://jsonplaceholder.typicode.com/posts", postToInsert, Post.class); System.out.println(insertedPost);

И у нас уже в руках объекты, а не строка, которую надо разбирать самостоятельно.

Читайте также:  Html checkbox set value

Кул. Теперь мы можем написать некоторую обертку вокруг RestTemplate, чтобы запрос строился корректно. Выглядит не так уж плохо, но, как по мне, это можно еще улучшить. Чем меньше кода пишется, тем меньше вероятность ошибки. Все же знают, что основная проблема зачастую PEBCAK (Problem Exists between Chair and Keyboard)…

5. Spring Feign

И тут на сцену выходит Feign, который входит в состав Spring Cloud. Сначала добавим к уже добавленному ранее спринговому окружению Feign-зависимость:

  org.springframework.cloud spring-cloud-starter-feign 1.4.5.RELEASE  

По сути все, что надо, это объявить интерфейс и сдобрить его хорошей жменькой аннотаций. Особенно данный подход будет симпатичен тем, кто пишет контроллеры с использованием спринга.

Вот что нам надо сделать для отправки запросов посредством Feign (source).

@FeignClient(name = "jsonplaceholder", url = "http://jsonplaceholder.typicode.com", path = "/posts") public interface ApiClient < @RequestMapping(method = GET, value = "/", consumes = APPLICATION_JSON_VALUE) ListgetPosts(@RequestParam("_limit") final int postLimit); @RequestMapping(method = POST, value = "/", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) Post savePost(@RequestBody Post post); >

Красота, не правда ли? И да, те модели данных, которые мы писали для RestTemplate, отлично переиспользуются здесь.

6. Conclusion

Существует еще не один способ реализации помимо представленных пяти. Данная подборка это лишь отражение опыта автора в том порядке, в котором я знакомился с ними и начинал использовать в проектах. Сейчас активно пользую Feign, радуюсь жизни и жду, когда появится еще что-то более удобное, чтобы можно было крикнуть в монитор «, выбираю тебя!» — и все было готово к использованию и интеграции. Ну а пока Feign.

P.S. Как один из «ленивых» способов можно рассматривать генерируемый Swagger клиент. Но, как говорится, есть нюанс. Далеко не все разработчики используют Swagger для документирования своих API, и еще меньше делают это настолько качественно, чтобы можно было спокойно сгенерировать и использовать клиент, а не получить вместо него энтомологическую коллекцию, от которой будет больше вреда, чем пользы.

Источник

Оцените статью