JAVA中如何创建异步HTTP请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3142915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you create an asynchronous HTTP request in JAVA?
提问by evilpenguin
I'm fairly new to Java, so this may seem obvious to some. I've worked a lot with ActionScript, which is very much event based and I love that. I recently tried to write a small bit of Java code that does a POST request, but I've been faced with the problem that it's a synchronous request, so the code execution waits for the request to complete, time out or present an error.
我对 Java 还很陌生,所以这对某些人来说似乎很明显。我在 ActionScript 方面做了很多工作,它非常基于事件,我很喜欢它。我最近尝试编写一小段执行 POST 请求的 Java 代码,但我遇到了它是同步请求的问题,因此代码执行等待请求完成、超时或出现错误。
How can I create an asynchronous request, where the code continues the execution and a callback is invoked when the HTTP request is complete? I've glanced at threads, but I'm thinking it's overkill.
如何创建异步请求,其中代码继续执行并在 HTTP 请求完成时调用回调?我瞥了一眼线程,但我认为这太过分了。
采纳答案by Emmanuel Touzery
Note that java11 now offers a new HTTP api HttpClient, which supports fully asynchronous operation, using java's CompletableFuture.
请注意,java11 现在提供了一个新的 HTTP api HttpClient,它支持完全异步操作,使用 java 的CompletableFuture。
It also supports a synchronous version, with calls like send, which is synchronous, and sendAsync, which is asynchronous.
它还支持同步版本,具有同步调用send和异步调用sendAsync。
Example of an async request (taken from the apidoc):
异步请求示例(取自 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);
回答by Paul Rubel
You may want to take a look at this question: Asynchronous IO in Java?
您可能想看看这个问题:Java 中的异步 IO?
It looks like your best bet, if you don't want to wrangle the threads yourself is a framework. The previous post mentions Grizzly, https://grizzly.dev.java.net/, and Netty, http://www.jboss.org/netty/.
看起来你最好的选择,如果你不想自己纠缠线程是一个框架。上一篇文章提到了 Grizzly,https://grizzly.dev.java.net/ 和 Netty,http://www.jboss.org/netty/ 。
From the netty docs:
来自 netty 文档:
The Netty project is an effort to provide an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance & high scalability protocol servers & clients.
Netty 项目致力于提供异步事件驱动的网络应用程序框架和工具,以快速开发可维护的高性能和高可扩展性协议服务器和客户端。
回答by kschneid
You may also want to look at Async Http Client.
您可能还想查看Async Http Client。
回答by ericsoco
Based on a link to Apache HTTP Componentson this SO thread, I came across the Fluent facade API for HTTP Components. An example thereshows how to set up a queue of asynchronous HTTP requests (and get notified of their completion/failure/cancellation). In my case, I didn't need a queue, just one async request at a time.
基于此 SO 线程上Apache HTTP 组件的链接,我遇到了 HTTP 组件的 Fluent 外观 API。 那里的示例显示了如何设置异步 HTTP 请求队列(并获得完成/失败/取消的通知)。就我而言,我不需要队列,一次只需要一个异步请求。
Here's where I ended up (also using URIBuilder from HTTP Components, example here).
这是我结束的地方(也使用来自 HTTP 组件的 URIBuilder,示例here)。
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 () {}
});
回答by Dan Brough
Apache HttpComponentsalso have an async http client now too:
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;
}
}
}
回答by Psyx
If you are in a JEE7 environment, you must have a decent implementation of JAXRS hanging around, which would allow you to easily make asynchronous HTTP request using its client API.
如果您在 JEE7 环境中,您必须有一个体面的 JAXRS 实现,这将允许您使用其客户端 API 轻松发出异步 HTTP 请求。
This would looks like this:
这看起来像这样:
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));
}
}
Of course, this is just using futures. If you are OK with using some more libraries, you could take a look at RxJava, the code would then look like:
当然,这只是使用期货。如果你可以使用更多的库,你可以看看 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");
}
And last but not least, if you want to reuse your async call, you might want to take a look at Hystrix, which - in addition to a bazillion super cool other stuff - would allow you to write something like this:
最后但并非最不重要的是,如果你想重用你的异步调用,你可能想看看 Hystrix,它 - 除了无数超级酷的其他东西 - 允许你写这样的东西:
For example:
例如:
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);
}
}
Calling this command would look like:
调用这个命令看起来像:
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: I know the thread is old, but it felt wrong that no ones mentions the Rx/Hystrix way in the up-voted answers.
PS:我知道这个线程很旧,但是在投票的答案中没有人提到 Rx/Hystrix 方式,这感觉是错误的。
回答by Pantelis Natsiavas
It has to be made clear the HTTP protocol is synchronous and this has nothing to do with the programming language. Client sends a request and gets a synchronous response.
必须明确 HTTP 协议是同步的,这与编程语言无关。客户端发送请求并获得同步响应。
If you want to an asynchronous behavior over HTTP, this has to be built overHTTP (I don't know anything about ActionScript but I suppose that this is what the ActionScript does too). There are many libraries that could give you such functionality (e.g. Jersey SSE). Note that they do somehow define dependencies between the client and the server as they do have to agree on the exact non standard communication method above HTTP.
如果您想通过 HTTP 进行异步行为,则必须通过HTTP构建(我对 ActionScript 一无所知,但我想这也是 ActionScript 所做的)。有许多库可以为您提供此类功能(例如Jersey SSE)。请注意,他们确实以某种方式定义了客户端和服务器之间的依赖关系,因为他们必须就 HTTP 之上的确切非标准通信方法达成一致。
If you cannot control both the client and the server or if you don't want to have dependencies between them, the most common approach of implementing asynchronous (e.g. event based) communication over HTTP is using the webhooks approach(you can check thisfor an example implementation in java).
如果你无法控制客户端和服务器,或者,如果你不想让他们之间的依赖关系,通过HTTP实现异步(例如基于事件的)通信使用的最常用的方法网络挂接接近(你可以检查这一个java中的示例实现)。
Hope I helped!
希望我有所帮助!