Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
String response = myResource.request(MediaType.TEXT_PLAIN)
.header("myHeader", "The header value")
.get(String.class);
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
В этом разделе описываются некоторые дополнительные функции клиентского API JAX-RS.
Здесь рассматриваются следующие темы:
Дополнительные параметры конфигурации могут быть добавлены в запрос клиента после его создания, но до его вызова.
Здесь рассматриваются следующие темы:
Вы можете установить заголовки HTTP для запроса, вызвав метод Invocation.Builder.header
.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
String response = myResource.request(MediaType.TEXT_PLAIN)
.header("myHeader", "The header value")
.get(String.class);
Если нужно установить несколько заголовков в запросе, вызовите метод Invocation.Builder.headers
и передайте объект javax.ws.rs.core.MultivaluedMap
с парами имён-значений заголовков HTTP. Вызов метода headers
заменяет все существующие заголовки на заголовки, предоставленные в объекте MultivaluedMap
.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
MultivaluedMap<String, Object> myHeaders =
new MultivaluedMap<>("myHeader", "The header value");
myHeaders.add(...);
String response = myResource.request(MediaType.TEXT_PLAIN)
.headers(myHeaders)
.get(String.class);
Интерфейс MultivaluedMap
позволяет вам указать несколько значений для данного ключа.
MultivaluedMap<String, Object> myHeaders =
new MultivaluedMap<String, Object>();
List<String> values = new ArrayList<>();
values.add(...)
myHeaders.add("myHeader", values
Вы можете добавить cookies HTTP в запрос, вызвав метод Invocation.Builder.cookie
, который принимает пару имя-значение в качестве параметров.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
String response = myResource.request(MediaType.TEXT_PLAIN)
.cookie("myCookie", "The cookie value")
.get(String.class);
Класс javax.ws.rs.core.Cookie
инкапсулирует атрибуты cookies HTTP, такие как в имя, значение, путь, домен и версию cookies в соответствии со спецификацией RFC. В следующем примере объект Cookie
настроен парой имя-значение, путём и доменом.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Cookie myCookie = new Cookie("myCookie", "The cookie value",
"/webapi/read", "example.com");
String response = myResource.request(MediaType.TEXT_PLAIN)
.cookie(myCookie)
.get(String.class);
Пользовательские фильтры можно зарегистрировать с помощью клиентского запроса или ответа, полученного от целевого ресурса. Чтобы зарегистрировать классы фильтров при создании объекта Client
, вызовите метод Client.register
.
Client client = ClientBuilder.newClient().register(MyLoggingFilter.class);
В предыдущем примере для всех вызовов, которые используют этот объект Client
, зарегистрирован фильтр MyLoggingFilter
.
Вы также можете зарегистрировать классы фильтров на цели, вызвав WebTarget.register
.
Client client = ClientBuilder.newClient().register(MyLoggingFilter.class);
WebTarget target = client.target("http://example.com/webapi/secure")
.register(MyAuthenticationFilter.class);
В предыдущем примере фильтры MyLoggingFilter
и MyAuthenticationFilter
присоединяются к вызову.
Классы фильтра запросов и ответов реализуют интерфейсы javax.ws.rs.client.ClientRequestFilter
и javax.ws.rs.client.ClientResponseFilter
соответственно. Оба этих интерфейса определяют метод filter
. Все фильтры должны быть помечены javax.ws.rs.ext.Provider
.
Следующий класс представляет собой фильтр журнала для клиентских запросов и ответов.
@Provider
public class MyLoggingFilter implements ClientRequestFilter,
ClientResponseFilter {
static final Logger logger = Logger.getLogger(...);
// реализация метода ClientRequestFilter.filter
@Override
public void filter(ClientRequestContext requestContext)
throws IOException {
logger.log(...);
...
}
// реализация метода ClientResponseFilter.filter
@Override
public void filter(ClientRequestContext requestContext,
ClientResponseContext responseContext) throws IOException {
logger.log(...);
...
}
}
Если требуется остановить выполнение вызова, при активном фильтре вызовите метод abortWith
объекта контекста и с объектом javax.ws.rs.core.Response
в качестве параметра.
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
...
Response response = new Response();
response.status(500);
requestContext.abortWith(response);
}
В сетевых приложениях проблемы сети могут повлиять на воспринимаемую производительность приложения, особенно при длительных или сложных сетевых вызовах. Асинхронная обработка помогает предотвратить блокировку и позволяет лучше использовать ресурсы приложения.
В клиентском API JAX-RS метод Invocation.Builder.async
используется при создании запроса клиента, чтобы указать, что вызов сервиса должен выполняться асинхронно. Асинхронный вызов немедленно возвращает управление вызывающей стороне вместе с объектом типа java.util.concurrent.Future<T>
(часть API параллелизма Java SE) и с типом, установленным на возвращаемый тип вызова сервиса. Объекты Future<T>
имеют методы для проверки завершения асинхронного вызова, получения окончательного результата, отмены вызова и проверки отмены вызова.
В следующем примере показано, как вызвать асинхронный запрос к ресурсу.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Future<String> response = myResource.request(MediaType.TEXT_PLAIN)
.async()
.get(String.class);
Интерфейс InvocationCallback
определяет два метода: complete
и failed
, которые вызываются, когда асинхронный вызов завершается соответственно либо успешно, либо неудачей. Объект InvocationCallback
может быть зарегистрирован при формировании запроса.
В следующем примере показано, как зарегистрировать объект Callback-вызова при асинхронном вызове.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Future<Customer> fCustomer = myResource.request(MediaType.TEXT_PLAIN)
.async()
.get(new InvocationCallback<Customer>() {
@Override
public void completed(Customer customer) {
// Выполнение действия с объектом заказчика
}
@Override
public void failed(Throwable throwable) {
// Обработка ошибки
}
});
Использование кастомных Callback-вызовов в асинхронных вызовах легко в простых случаях и в случаях множества независимых вызовов. В случае вложенных вызовов использование кастомных Callback-вызовов становится очень трудным для реализации, отладки и обслуживания.
JAX-RS определяет новый тип инициатора запроса — RxInvoker
— и реализация этого типа по умолчанию CompletionStageRxInvoker
. Новый метод rx
используется как в следующем примере:
CompletionStage<String> csf = client.target("forecast/{destination}") resolveTemplate("destination", "mars").request().rx().get(String.class);
csf.thenAccept(System.out::println);
В этом примере создаётся асинхронная обработка интерфейса CompletionStage<String>
, которая ожидает его завершения и отображения результата. Возвращённый CompletionStage
может затем использоваться только для получения результата, как показано в приведённом выше примере, или может быть объединён с другими этапами завершения для упрощения и улучшения обработки асинхронных задач.
Технология серверных событий (Server-sent Events — SSE) используется для асинхронной отправки уведомлений клиенту по стандартным протоколам HTTP или HTTPS. Клиенты могут подписаться на уведомления о событиях, которые отправляются на сервер. Сервер генерирует события и отправляет уведомления об этих событиях клиентам, которые подписаны на получение уведомлений. Соединение с односторонним каналом связи устанавливается клиентом. Как только соединение установлено, сервер отправляет уведомления клиенту всякий раз, когда доступны новые данные.
Канал связи, установленный клиентом, действует до тех пор, пока клиент не закроет соединение. Он же используется сервером для отправки уведомлений о событиях.
SSE API определён в пакете javax.ws.rs.sse
и включает интерфейсы SseEventSink
, SseEvent
, Sse
и SseEventSource
. Чтобы принимать подключения и отправлять уведомления одному или нескольким клиентам, вставьте SseEventSink
в метод ресурса, который создаёт ответы типа MIME text/event-stream
.
В следующем примере показано, как принимать подключения SSE и отправлять уведомления клиентам:
@GET
@Path("eventStream")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void eventStream(@Context SseEventSink eventSink,
@Context Sse sse) {
executor.execute(() -> {
try (SseEventSink sink = eventSink) {
eventSink.send(sse.newEvent("event1"));
eventSink.send(sse.newEvent("event2"));
eventSink.send(sse.newEvent("event3"));
}
});
}
SseEventSink
инъецируется в метод ресурса, а основное клиентское соединение остается открытым и используется для отправки уведомлений. Соединение сохраняется до тех пор, пока клиент не отключится от сервера. Метод send
возвращает объект CompletionStage<T>
, который указывает, что действие асинхронной отправки сообщения клиенту включено.
Уведомления, передающиеся клиентам, могут содержать такие подробности, как event
, data
, id
, retry
и comment
.
Широковещательная рассылка — это действие по отправке уведомления одновременно нескольким клиентам. JAX-RS SSE API предоставляет SseBroadcaster
для регистрации всех объектов SseEventSink
и отправки уведомлений всем зарегистрированным клиентам. Жизненный цикл и область видимости SseBroadcaster
полностью контролируются приложениями, а не средой выполнения JAX-RS. В следующем примере показано использование широковещательной рассылки:
@Path("/")
@Singleton
public class SseResource {
@Context
private Sse sse;
private volatile SseBroadcaster sseBroadcaster;
@PostConstruct
public init() {
this.sseBroadcaster = sse.newBroadcaster();
}
@GET
@Path("register")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void register(@Context SseEventSink eventSink) {
eventSink.send(sse.newEvent("welcome!"));
sseBroadcaster.register(eventSink);
}
@POST
@Path("broadcast")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void broadcast(@FormParam("event") String event) {
sseBroadcaster.broadcast(sse.newEvent(event));
}
}
Аннотация @Singleton
определена для класса ресурса и делает невозможным создание нескольких объектов класса. Метод register
используется для добавления нового SseEventSink
. Метод broadcast
используется для отправки уведомления SSE всем зарегистрированным клиентам.
JAX-RS SSE предоставляет клиенту интерфейс SseEventSource
для подписки на уведомления. Клиент может получать асинхронные уведомления о входящих событиях, вызывая один из методов subscribe
в javax.ws.rs.sse.SseEventSource
.
В следующем примере показано, как использовать API SseEventSource
для открытия соединения SSE и чтения сообщений за период:
WebTarget target = client.target("http://...");
try (SseEventSource source = SseEventSource.target(target).build()) {
source.register(System.out::println);
source.open();
Thread.sleep(500); // Получение сообщений только за 500 мс
source.close();
} catch (InterruptedException e) {
// обработка ошибки
}
Назад | Вперёд | Содержание |