Как вы создаете асинхронный HTTP-запрос в JAVA?

Я довольно новичок в Java, поэтому некоторым это может показаться очевидным. Я много работал с ActionScript, который основан на событиях, и мне это нравится. Недавно я попытался написать небольшой кусочек кода Java, который выполняет запрос POST, но я столкнулся с проблемой, заключающейся в том, что это синхронный запрос, поэтому выполнение кода ожидает завершения запроса, истечения времени ожидания или представления ошибки.

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

71 голос | спросил evilpenguin 29 J0000006Europe/Moscow 2010, 20:55:50

7 ответов


0

Java действительно более низкого уровня, чем ActionScript. Это как сравнивать яблоки с апельсинами. В то время как ActionScript обрабатывает все это прозрачно «под капотом», в Java вам нужно самостоятельно управлять асинхронной обработкой (многопоточностью).

К счастью, в Java есть java.util.concurrent API, который может сделать это хорошим способом.

Ваша проблема может быть решена следующим образом:

// Have one (or more) threads ready to do the async tasks. Do this during startup of your app.
ExecutorService executor = Executors.newFixedThreadPool(1); 

// Fire a request.
Future<Response> response = executor.submit(new Request(new URL("http://google.com")));

// Do your other tasks here (will be processed immediately, current thread won't block).
// ...

// Get the response (here the current thread will block until response is returned).
InputStream body = response.get().getBody();
// ...

// Shutdown the threads during shutdown of your app.
executor.shutdown();

где Request и Response как следует:

public class Request implements Callable<Response> {
    private URL url;

    public Request(URL url) {
        this.url = url;
    }

    @Override
    public Response call() throws Exception {
        return new Response(url.openStream());
    }
}

и

public class Response {
    private InputStream body;

    public Response(InputStream body) {
        this.body = body;
    }

    public InputStream getBody() {
        return body;
    }
}

Смотрите также:

ответил BalusC 29 J0000006Europe/Moscow 2010, 21:27:34
0

Если вы находитесь в среде JEE7, у вас должна быть приличная реализация JAXRS, которая позволит вам легко выполнять асинхронный HTTP-запрос, используя его клиентский API.

Это будет выглядеть так:

public class Main {

    public static Future<Response> getAsyncHttp(final String url) {
        return ClientBuilder.newClient().target(url).request().async().get();
    }

    public static void main(String ...args) throws InterruptedException, ExecutionException {
        Future<Response> response = getAsyncHttp("http://www.nofrag.com");
        while (!response.isDone()) {
            System.out.println("Still waiting...");
            Thread.sleep(10);
        }
        System.out.println(response.get().readEntity(String.class));
    }
}

Конечно, это просто использование фьючерсов. Если у вас все в порядке с использованием еще нескольких библиотек, вы можете взглянуть на RxJava, тогда код будет выглядеть так:

public static void main(String... args) {
    final String url = "http://www.nofrag.com";
    rx.Observable.from(ClientBuilder.newClient().target(url).request().async().get(String.class), Schedulers
            .newThread())
            .subscribe(
                    next -> System.out.println(next),
                    error -> System.err.println(error),
                    () -> System.out.println("Stream ended.")
            );
    System.out.println("Async proof");
}

И последнее, но не менее важное: если вы хотите повторно использовать свой асинхронный вызов, вам может понадобиться взглянуть на Hystrix, которая - в дополнение к невероятному количеству других вещей - позволит вам написать что-то вроде этого:

Например:

public class AsyncGetCommand extends HystrixCommand<String> {

    private final String url;

    public AsyncGetCommand(final String url) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HTTP"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionIsolationThreadTimeoutInMilliseconds(5000)));
        this.url = url;
    }

    @Override
    protected String run() throws Exception {
        return ClientBuilder.newClient().target(url).request().get(String.class);
    }

 }

Вызов этой команды будет выглядеть следующим образом:

public static void main(String ...args) {
    new AsyncGetCommand("http://www.nofrag.com").observe().subscribe(
            next -> System.out.println(next),
            error -> System.err.println(error),
            () -> System.out.println("Stream ended.")
    );
    System.out.println("Async proof");
}

PS: я знаю, что ветка старая, но было неправильно, что никто не упоминает путь Rx /Hystrix в ответах с повышенным голосованием.

ответил Psyx 30 +03002014-10-30T03:07:21+03:00312014bEurope/MoscowThu, 30 Oct 2014 03:07:21 +0300 2014, 03:07:21
0

Вы также можете посмотреть Async Http Client .

ответил kschneid 29 J0000006Europe/Moscow 2010, 21:15:45
0

На основе ссылки на HTTP-компоненты Apache на этот поток SO я наткнулся на API интерфейса Fluent для HTTP-компонентов. Пример там показывает, как настроить очередь асинхронных HTTP-запросов (и получать уведомления об их завершении /сбое /отмене). В моем случае мне не нужна была очередь, только один асинхронный запрос за раз.

Вот где я остановился (также используя URIBuilder из компонентов HTTP, пример здесь ).

import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.http.client.fluent.Async;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;

//...

URIBuilder builder = new URIBuilder();
builder.setScheme("http").setHost("myhost.com").setPath("/folder")
    .setParameter("query0", "val0")
    .setParameter("query1", "val1")
    ...;
URI requestURL = null;
try {
    requestURL = builder.build();
} catch (URISyntaxException use) {}

ExecutorService threadpool = Executors.newFixedThreadPool(2);
Async async = Async.newInstance().use(threadpool);
final Request request = Request.Get(requestURL);

Future<Content> future = async.execute(request, new FutureCallback<Content>() {
    public void failed (final Exception e) {
        System.out.println(e.getMessage() +": "+ request);
    }
    public void completed (final Content content) {
        System.out.println("Request completed: "+ request);
        System.out.println("Response:\n"+ content.asString());
    }

    public void cancelled () {}
});
ответил ericsoco 7 32012vEurope/Moscow11bEurope/MoscowWed, 07 Nov 2012 07:00:20 +0400 2012, 07:00:20
0

Возможно, вы захотите взглянуть на этот вопрос: Асинхронный ввод-вывод в Java?

Похоже, ваш лучший выбор, если вы не хотите сами разбирать темы, это фреймворк. Предыдущий пост упоминает Grizzly, https://grizzly.dev.java.net/ и Netty, http://www.jboss.org/netty/.

Из документов Netty:

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

ответил Paul Rubel 29 J0000006Europe/Moscow 2010, 21:09:05
0

Apache HttpComponents также теперь имеет асинхронный http-клиент:

/**
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpasyncclient</artifactId>
      <version>4.0-beta4</version>
    </dependency>
**/

import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;

import org.apache.http.HttpResponse;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.apache.http.protocol.HttpContext;

public class HttpTest {

  public static void main(final String[] args) throws Exception {

    final CloseableHttpAsyncClient httpclient = HttpAsyncClients
        .createDefault();
    httpclient.start();
    try {
      final Future<Boolean> future = httpclient.execute(
          HttpAsyncMethods.createGet("http://www.google.com/"),
          new MyResponseConsumer(), null);
      final Boolean result = future.get();
      if (result != null && result.booleanValue()) {
        System.out.println("Request successfully executed");
      } else {
        System.out.println("Request failed");
      }
      System.out.println("Shutting down");
    } finally {
      httpclient.close();
    }
    System.out.println("Done");
  }

  static class MyResponseConsumer extends AsyncCharConsumer<Boolean> {

    @Override
    protected void onResponseReceived(final HttpResponse response) {
    }

    @Override
    protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl)
        throws IOException {
      while (buf.hasRemaining()) {
        System.out.print(buf.get());
      }
    }

    @Override
    protected void releaseResources() {
    }

    @Override
    protected Boolean buildResult(final HttpContext context) {
      return Boolean.TRUE;
    }
  }
}
ответил Dan Brough 17 J000000Wednesday13 2013, 18:20:51
0

Необходимо четко указать, что протокол HTTP является синхронным, и это не имеет ничего общего с языком программирования. Клиент отправляет запрос и получает синхронный ответ.

Если вы хотите асинхронного поведения по HTTP, это должно быть построено по HTTP (я ничего не знаю о ActionScript, но я полагаю, что это то же самое, что и ActionScript). Существует множество библиотек, которые могут предоставить вам такую ​​функциональность (например, Джерси SSE ). Обратите внимание, что они каким-то образом определяют зависимости между клиентом и сервером, так как они должны согласовать точный нестандартный метод связи выше HTTP.

Если вы не можете управлять как клиентом, так и сервером или если вы не хотите, чтобы между ними были зависимости, наиболее распространенный подход к реализации асинхронной (например, на основе событий) связи через HTTP использует подход веб-крючков (вы можете проверить this для примера реализации в java).

Надеюсь, я помог!

ответил Pantelis Natsiavas 1 J000000Wednesday15 2015, 11:01:46

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132