当前位置: 首页 > 知识库问答 >
问题:

如何发送并行 GET 请求并等待结果响应?

慕凌龙
2023-03-14

我在spring mvc 3.2.2中使用apache http客户端同步发送5个get请求,如图所示。

如何异步(并行)发送所有这些内容并等待请求返回,以便从所有 GET 请求返回已解析的有效负载字符串?

public String myMVCControllerGETdataMethod()
{
   // Send 1st request 
   HttpClient httpclient = new DefaultHttpClient();
   HttpGet httpget = new HttpGet("http://api/data?type=1");   
   ResponseHandler<String> responseHandler = new BasicResponseHandler();
   String responseBody = httpclient.execute(httpget, responseHandler);

   // Send 2st request 
   HttpClient httpclient2 = new DefaultHttpClient();
   HttpGet httpget2 = new HttpGet("http://api/data?type=2");   
   ResponseHandler2<String> responseHandler2 = new BasicResponseHandler();
   String responseBody2 = httpclient.execute(httpget, responseHandler2);

   // o o o more gets here

   // Perform some work here...and wait for all requests to return
   // Parse info out of multiple requests and return
   String results = doWorkwithMultipleDataReturned();

   model.addAttribute(results, results);
   return "index";

}

共有3个答案

吴和硕
2023-03-14

将请求代码移动到单独的方法:

private String executeGet(String url){
   HttpClient httpclient = new DefaultHttpClient();
   HttpGet httpget = new HttpGet(url);   
   ResponseHandler<String> responseHandler = new BasicResponseHandler();
   return httpclient.execute(httpget, responseHandler);
}

并将它们提交给ExecutorService

ExecutorService executorService = Executors.newCachedThreadPool();

Future<String> firstCallFuture = executorService.submit(() -> executeGet(url1));
Future<String> secondCallFuture = executorService.submit(() -> executeGet(url2));

String firstResponse = firstCallFuture.get();
String secondResponse = secondCallFuture.get();

executorService.shutdown();

或者

Future<String> firstCallFuture = CompletableFuture.supplyAsync(() -> executeGet(url1));
Future<String> secondCallFuture = CompletableFuture.supplyAsync(() -> executeGet(url2));

String firstResponse = firstCallFuture.get();
String secondResponse = secondCallFuture.get();

还是像《如何使用Spring WebClient同时进行多个调用》中描述的那样使用RestTemplate?

齐浩淼
2023-03-14

您应该使用AsyncHttpClient。你可以提出任意数量的请求,当它得到响应时,它会给你回电。您可以配置它可以创建多少个连接。所有线程都由库处理,所以这比自己管理线程要容易得多。

看看下面的例子:https://github.com/AsyncHttpClient/async-http-client

邬安邦
2023-03-14

一般来说,您需要将您的工作单元封装在Runnablejava.util.concurrent.Callable中,并通过java.util.concurrent.Executor(或org.springframework.core.task.TaskExecutor)执行它们。这允许每个工作单元单独执行,通常以异步方式(取决于执行器的实现)。

因此,对于您的具体问题,您可以这样做:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController {
    //inject this
    private Executor executor;

    @RequestMapping("/your/path/here")
    public String myMVCControllerGETdataMethod(Model model) {
        //define all async requests and give them to injected Executor
        List<GetRequestTask> tasks = new ArrayList<GetRequestTask>();
        tasks.add(new GetRequestTask("http://api/data?type=1", this.executor));
        tasks.add(new GetRequestTask("http://api/data?type=2", this.executor));
        //...
        //do other work here
        //...
        //now wait for all async tasks to complete
        while(!tasks.isEmpty()) {
            for(Iterator<GetRequestTask> it = tasks.iterator(); it.hasNext();) {
                GetRequestTask task = it.next();
                if(task.isDone()) {
                    String request = task.getRequest();
                    String response = task.getResponse();
                    //PUT YOUR CODE HERE
                    //possibly aggregate request and response in Map<String,String>
                    //or do something else with request and response
                    it.remove();
                }
            }
            //avoid tight loop in "main" thread
            if(!tasks.isEmpty()) Thread.sleep(100);
        }
        //now you have all responses for all async requests

        //the following from your original code
        //note: you should probably pass the responses from above
        //to this next method (to keep your controller stateless)
        String results = doWorkwithMultipleDataReturned();
        model.addAttribute(results, results);
        return "index";
    }

    //abstraction to wrap Callable and Future
    class GetRequestTask {
        private GetRequestWork work;
        private FutureTask<String> task;
        public GetRequestTask(String url, Executor executor) {
            this.work = new GetRequestWork(url);
            this.task = new FutureTask<String>(work);
            executor.execute(this.task);
        }
        public String getRequest() {
            return this.work.getUrl();
        }
        public boolean isDone() {
            return this.task.isDone();
        }
        public String getResponse() {
            try {
                return this.task.get();
            } catch(Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    //Callable representing actual HTTP GET request
    class GetRequestWork implements Callable<String> {
        private final String url;
        public GetRequestWork(String url) {
            this.url = url;
        }
        public String getUrl() {
            return this.url;
        }
        public String call() throws Exception {
            return new DefaultHttpClient().execute(new HttpGet(getUrl()), new BasicResponseHandler());
        }
    }
}

请注意,此代码尚未经过测试。

对于您的Exector实现,请查看Spring的TaskExecitor和任务:执行器命名空间。您可能希望此用例有一个可重用的线程池(而不是每次都创建一个新线程)。

 类似资料:
  • 客户端通过HTTP请求(通过浏览器post)调用Servlet,然后Servlet应向外部网站发送请求(get),并从网站接收响应(post)。servlet继续响应并向客户端发送响应(post)。 我的问题是如何在Servlet中发送和接收请求/响应并将某些内容发送回客户端?

  • 问题内容: 假设有一个函数,应该执行一个HTTP请求并将其用于该请求。 如果在循环中调用if ,我希望下一个请求是在上一个完成之后执行的(串行执行,一个接一个)。为了不使回调和Promises混乱,我想使用async / await模式(与Babel.js一起编译以与Node 6+一起运行)。 但是,我不清楚如何等待响应对象进行进一步处理,以及如何作为以下结果返回它: 如果我使用 mocha 为H

  • 这是我第一次使用剧作家,我不知道如何等待请求和验证响应。我已经使用cypress很长时间了,管理网络请求非常容易。例如,我需要在单击按钮后验证响应,这就是我使用cypress的方法: 这就是我试图对剧作家做同样的事情的方式,但是它验证了早在点击保存按钮之前就发送的请求。我不知道如何正确管理这个请求,这是我的测试套件的一个停止: 任何帮助或建议都将不胜感激

  • 返回的流量 返回一个 如果您不能回答我的问题,请至少告诉我如何并行地执行多个API调用,并在WebClient中等待结果

  • 问题内容: 我需要编写一个命令行客户端,以便在服务器上播放井字游戏。服务器接受http请求并将json发送回我的客户端。我正在寻找一种快速的方法,以使用Boost库发送http请求并以字符串形式接收json。 问题答案: 符合说明的最简单的事情: 这将收到完整的响应。您可以使用虚拟服务器对其进行测试:( 也可以 在Coliru上运行): 这将表明已收到请求,并且响应将由上面的客户代码写出。 请注意

  • 请求方式: "|3|1|url|\r" 参数: url 设置Get请求的url链接 返回值: "|3|code|data|\r" 参数: code http请求返回的成功或者错误码, 成功:code = 200 获取数据失败:code = -1 http请求字段错误:code = 1 data http请求返回的数据 Arduino样例: softSerial.print("|3|1|http:/