2019年/10月/24日
和httpclient玩耍
本文是对各种httpclient的玩耍总结,不同的client表现出来的是不同的使用风格,我们在使用时需要注意对client对象生命周期和线程安全性的关注 文中包含部分使用代码和对于库源码的部分提取。推荐一个测试http的站点:https://httpbin.org/headers
JDK自带
//最原始的调用
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
conn.setRequestMethod("GET");
InputStream is = conn.getInputStream();
StringBuilder sb = toStr(is);
System.out.println(sb.toString());
//Java9
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://labs.consol.de/"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandler.asString());
注意,HttpURLConnection是默认KeepAlive的,对一个目标地址默认5个复用连接 具体细节看官网
Jodd
没有连接池,直接在socket上解析
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<version>5.0.13</version>
</dependency>
String text = HttpRequest.get(urlStr).timeout(3000).connectionTimeout(3000).send().bodyText();
System.out.println(text);
HttpRequest httpRequest = HttpRequest
.post("http://srv:8080/api/dlapp/add-file-entry")
.form(
"repositoryId", "10178",
"folderId", "11219",
"sourceFileName", "a.zip",
"mimeType", "application/zip",
"title", "test",
"description", "Upload test",
"changeLog", "testing...",
"file", new File("d:\\a.jpg.zip")
);
HttpResponse httpResponse = httpRequest.send();
但是如果你需要使用连接复用,使用下面这种方式
HttpRequest request = HttpRequest.get("http://jodd.org");
HttpResponse response = request.connectionKeepAlive(true).send();
// next request
request = HttpRequest.get("http://jodd.org/jodd.css");
response = request.keepAlive(response, true).send();
...
// last request
request = HttpRequest.get("http://jodd.org/jodd.png");
response = request.keepAlive(response, false).send();
// optionally
//response.close();
Apache
安全性,可单例
@Contract(threading = ThreadingBehavior.SAFE)
public abstract class CloseableHttpClient implements HttpClient, Closeable
RequestConfig config = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).setConnectionRequestTimeout(3000).build();
CloseableHttpClient client = HttpClients.custom().build();
HttpGet httpGet = new HttpGet(urlStr);
httpGet.setConfig(config);
HttpEntity entity = client.execute(httpGet).getEntity();
System.out.println(EntityUtils.toString(entity));
Apache fluent
默认的连接池
final static PoolingHttpClientConnectionManager CONNMGR;
final static HttpClient CLIENT;
System.out.println(Request.Get(urlStr).connectTimeout(3000).socketTimeout(3000).execute().returnContent().asString());
Unirest
这个库是对apache的封装
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.1.02</version>
</dependency>
System.out.println(Unirest.get(urlStr).connectTimeout(3000).socketTimeout(3000).asString().getBody());
CompletableFuture<HttpResponse<JsonNode>> future = Unirest.post("http://httpbin.org/post")
.header("accept", "application/json")
.field("param1", "value1")
.field("param2", "value2")
.asJsonAsync(response -> {
int code = response.getStatus();
JsonNode body = response.getBody();
});
OkHttp
核心对象OkHttpClient线程安全
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build();
Request request = new Request.Builder()
.url(urlStr)
.get()
.build();
String res = "";
try (Response response = client.newCall(request).execute()) {
res = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
AsynchttpClient
Dsl类创建出来的DefaultAsyncHttpClient是线程安全的
<dependency>
<groupId>org.asynchttpclient</groupId>
<artifactId>async-http-client</artifactId>
<version>2.2.0</version>
</dependency>
Future<Response> responseFuture = Dsl.asyncHttpClient()
.prepareGet(urlStr)
.execute();
String res = responseFuture.get().getResponseBody();
CompletableFuture<Response> whenResponse = asyncHttpClient
.prepareGet("http://www.example.com/")
.execute()
.toCompletableFuture()
.exceptionally(t -> { /* Something wrong happened... */ } )
.thenApply(response -> { /* Do something with the Response */ return resp; });
whenResponse.join();
ApacheHttpAsyncClient
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.4</version>
</dependency>
CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
client.start();
HttpGet httpGet = new HttpGet(urlStr);
client.execute(httpGet, new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse httpResponse) {
HttpEntity entity = httpResponse.getEntity();
try {
System.out.println(EntityUtils.toString(entity));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Exception e) {
}
@Override
public void cancelled() {
}
});
Spring Http
RestTemplate是线程安全的
//同步
RestTemplate restTemplate = new RestTemplate();
String forObject = restTemplate.getForObject(urlStr, String.class);
System.out.println(forObject);
//Template with Apache Http
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
//异步
Mono<String> mono = WebClient.create().method(HttpMethod.GET).uri(urlStr).retrieve().bodyToMono(String.class);
System.out.println(mono.block());
Google http
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<version>1.23.0</version>
</dependency>
HttpRequestFactory requestFactory
= new NetHttpTransport().createRequestFactory();
HttpRequest request = requestFactory.buildGetRequest(
new GenericUrl("https://httpbin.org/headers"));
String rawResponse = request.execute().parseAsString();
System.out.println(rawResponse);