evi*_*uin 74 java asynchronous httprequest
我对Java很新,所以对某些人来说这似乎是显而易见的.我在ActionScript上做了很多工作,这是基于事件的,我很喜欢.我最近尝试编写了一小部分执行POST请求的Java代码,但我遇到了一个问题,即它是一个同步请求,因此代码执行会等待请求完成,超时或出现错误.
如何创建异步请求,代码继续执行,并在HTTP请求完成时调用回调?我瞥了一眼线程,但我认为这太过分了.
Bal*_*usC 48
Java确实比ActionScript更低级别.这就像比较苹果和橘子.虽然ActionScript在"引擎盖下"透明地处理它,但在Java中,您需要自己管理异步处理(线程).
幸运的是,在Java中,有一种java.util.concurrentAPI可以很好地完成这项工作.
你的问题基本上可以解决如下:
// 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();
Run Code Online (Sandbox Code Playgroud)
其中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());
}
}
Run Code Online (Sandbox Code Playgroud)
和
public class Response {
private InputStream body;
public Response(InputStream body) {
this.body = body;
}
public InputStream getBody() {
return body;
}
}
Run Code Online (Sandbox Code Playgroud)
java.util.concurrent教程.Psy*_*syx 28
如果您处于JEE7环境中,那么您必须有一个不错的JAXRS实现,这将允许您使用其客户端API轻松地发出异步HTTP请求.
这看起来像这样:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
当然,这只是使用期货.如果你可以使用更多的库,你可以看看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");
}
Run Code Online (Sandbox Code Playgroud)
最后但并非最不重要的是,如果你想重用你的异步调用,你可能想看看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);
}
}
Run Code Online (Sandbox Code Playgroud)
调用此命令将如下所示:
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");
}
Run Code Online (Sandbox Code Playgroud)
PS:我知道线程已经过时了,但是在没有提到Rx/Hystrix方式的情况下,没有人提到这个问题.
Emm*_*ery 17
请注意,java11 现在提供了一个新的 HTTP api HttpClient,它支持完全异步操作,使用 java 的CompletableFuture。
它还支持同步版本,具有同步调用send和异步调用sendAsync。
异步请求示例(取自 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);
Run Code Online (Sandbox Code Playgroud)
eri*_*oco 13
基于此SO线程上的Apache HTTP组件链接,我遇到了HTTP组件的Fluent外观API. 这里的一个例子展示了如何设置异步HTTP请求的队列(并获得完成/失败/取消的通知).就我而言,我不需要一个队列,一次只需要一个异步请求.
这是我结束的地方(也使用HTTP Components中的URIBuilder,例如这里).
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 () {}
});
Run Code Online (Sandbox Code Playgroud)
您可能想看一下这个问题:Java中的异步IO?
看起来你最好的选择,如果你不想自己争论线程是一个框架.上一篇文章提到了Grizzly,https://grizzly.dev.java.net/和Netty,http: //www.jboss.org/netty/ .
来自netty文档:
Netty项目旨在提供异步事件驱动的网络应用程序框架和工具,以便快速开发可维护的高性能和高可伸缩性协议服务器和客户端.