Soy bastante nuevo en Java, por lo que esto puede parecer obvio para algunos. He trabajado mucho con ActionScript, que se basa en gran medida en eventos y eso me encanta. Recientemente intenté escribir un poco de código Java que realiza una solicitud POST, pero me he enfrentado al problema de que es una solicitud síncrona, por lo que la ejecución del código espera a que la solicitud se complete, se agote el tiempo de espera o presente un error.
¿Cómo puedo crear una solicitud asincrónica, donde el código continúa la ejecución y se invoca una devolución de llamada cuando se completa la solicitud HTTP? He echado un vistazo a los hilos, pero creo que es excesivo.
java
asynchronous
httprequest
maligno
fuente
fuente
Respuestas:
Tenga en cuenta que java11 ahora ofrece una nueva API HTTP HttpClient , que admite una operación totalmente asíncrona, utilizando CompletableFuture de Java .
También es compatible con una versión sincrónica, con llamadas como send , que es sincrónica, y sendAsync , que es asincrónica.
Ejemplo de una solicitud asincrónica (tomada de apidoc):
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://example.com/")) .timeout(Duration.ofMinutes(2)) .header("Content-Type", "application/json") .POST(BodyPublishers.ofFile(Paths.get("file.json"))) .build(); client.sendAsync(request, BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println);
fuente
Si se encuentra en un entorno JEE7, debe tener una implementación decente de JAXRS rondando, lo que le permitiría realizar fácilmente solicitudes HTTP asíncronas utilizando su API de cliente.
Esto se vería así:
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)); } }
Por supuesto, esto es solo usar futuros. Si está de acuerdo con el uso de más bibliotecas, puede echar un vistazo a RxJava, el código se vería así:
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"); }
Y por último, pero no menos importante, si desea reutilizar su llamada asíncrona, es posible que desee echar un vistazo a Hystrix, que, además de un montón de otras cosas geniales, le permitiría escribir algo como esto:
Por ejemplo:
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); } }
Llamar a este comando se vería así:
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"); }
PD: Sé que el hilo es antiguo, pero me sentí mal que nadie mencionara el método Rx / Hystrix en las respuestas con votos positivos.
fuente
Es posible que también desee mirar Async Http Client .
fuente
Basado en un enlace a los componentes HTTP de Apache en este hilo SO , encontré la API de fachada Fluent para componentes HTTP. Un ejemplo muestra cómo configurar una cola de solicitudes HTTP asincrónicas (y recibir una notificación de su finalización / falla / cancelación). En mi caso, no necesitaba una cola, solo una solicitud asíncrona a la vez.
Aquí es donde terminé (también usando URIBuilder de HTTP Components, ejemplo aquí ).
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 () {} });
fuente
Es posible que desee echar un vistazo a esta pregunta: ¿ E / S asíncrona en Java?
Parece su mejor opción, si no quiere discutir los hilos usted mismo, es un marco. La publicación anterior menciona a Grizzly, https://grizzly.dev.java.net/ y Netty, http://www.jboss.org/netty/ .
De los netty docs:
El proyecto Netty es un esfuerzo por proporcionar un marco de aplicación de red asincrónico impulsado por eventos y herramientas para el desarrollo rápido de servidores y clientes de protocolo de alto rendimiento y alta escalabilidad que se pueden mantener.
fuente
Apache HttpComponents también tiene un cliente http asíncrono ahora también:
/** <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; } } }
fuente
Debe quedar claro que el protocolo HTTP es síncrono y esto no tiene nada que ver con el lenguaje de programación. El cliente envía una solicitud y obtiene una respuesta sincrónica.
Si desea un comportamiento asincrónico a través de HTTP, esto debe construirse a través de HTTP (no sé nada sobre ActionScript, pero supongo que esto es lo que hace ActionScript también). Hay muchas bibliotecas que podrían brindarle dicha funcionalidad (por ejemplo, Jersey SSE ). Tenga en cuenta que de alguna manera definen las dependencias entre el cliente y el servidor, ya que tienen que estar de acuerdo con el método de comunicación no estándar exacto por encima de HTTP.
Si no puede controlar tanto al cliente como al servidor o si no desea tener dependencias entre ellos, el enfoque más común para implementar la comunicación asíncrona (por ejemplo, basada en eventos) a través de HTTP es utilizar el enfoque de webhooks (puede verificar esto para implementación de ejemplo en java).
¡Espero haber ayudado!
fuente
Aquí hay una solución que usa apache HttpClient y realiza la llamada en un hilo separado. Esta solución es útil si solo realiza una llamada asíncrona. Si está haciendo varias llamadas, sugiero usar apache HttpAsyncClient y colocar las llamadas en un grupo de subprocesos.
import java.lang.Thread; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClients; public class ApacheHttpClientExample { public static void main(final String[] args) throws Exception { try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { final HttpGet httpget = new HttpGet("http://httpbin.org/get"); new Thread(() -> { final String responseBody = httpclient.execute(httpget); }).start(); } } }
fuente