Recently, the project needed to use Java to call the HTTP API heavily, so I thought about encapsulating a common HTTP client lib for the team. The library needs to support the following features:

Connection pool management, including connection creation and timeout, idle connection number control, connection number per host configuration, and so on. Basically, we want a connection eating management feature that comes with the GO HTTP standard library. Domain name resolution control. Therefore, you need to perform a controllable load balancing on the calling side at the domain name resolution layer, and perform failure rate statistics and health check on each server IP address. Form/JSON calls are well supported. Support synchronous and asynchronous invocation. There are numerous HTTP Client lib component libraries in the Java ecosystem, but they can be broadly divided into three categories:

JDK standard library HttpURLConnection; Apache HttpComponents HttpClient, and a wrapper based on that library, such as Unirest. HttpComponents HttpClient is not based on Apache HttpComponents HttpClient, a large number of rewrite application layer code HTTP client component library, typical representative is okhttp.httpurlConnection

The biggest advantage of using HttpURLConnection to initiate HTTP requests is that it does not need to introduce additional dependencies, but it is cumbersome to use and lacks the support of connection pool management and domain name mechanical control. Take the example of making an HTTP POST request:

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.URL;

public class HttpUrlConnectionDemo {

public static void main(String[] args) throws Exception {

String urlString = “httpbin.org/post”;

String bodyString = “password=e10adc3949ba59abbe56e057f20f883e&username=test3”;

URL url = new URL(urlString);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod(“POST”);

conn.setDoOutput(true);

OutputStream os = conn.getOutputStream();

os.write(bodyString.getBytes(“utf-8”));

os.flush();

os.close();

if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {

InputStream is = conn.getInputStream();

BufferedReader reader = new BufferedReader(new InputStreamReader(is));

StringBuilder sb = new StringBuilder();

String line;

while ((line = reader.readLine()) ! = null) {

sb.append(line);

}

System.out.println(“rsp:” + sb.toString());

} else {

System.out.println(“rsp code:” + conn.getResponseCode());

}

}

}

HttpURLConnection is an HTTP request that encapsulates the transport layer of the network stack. HTTP over QUIC is an HTTP request that encapsulates the transport layer of the network stack. The operation primitive is to write request request and read response on the open connection. Also, HttpURLConnection does not support HTTP/2. Obviously, the authorities are aware of these issues, so in Java 9, the authorities introduced a high level HTTP/2 support HttpClient in the standard library. The library’s interface encapsulation is pretty much in place, making a simple POST request:

HttpRequest request = HttpRequest.newBuilder()

.uri(new URI(“postman-echo.com/post”))

.headers(“Content-Type”, “text/plain; charset=UTF-8”)

.POST(HttpRequest.BodyProcessor.fromString(“Sample request body”))

.build();

The biggest feature of encapsulation is that chain calls are very smooth and support for connection management and other features. However, the library is only available in Java 9 and later, Java 9 and Java 10 are not LTS maintenance releases, and the next Java 11 LTS will be released in 2018.09.25, which will take some time to come online. So, while I like the built-in library (without introducing third-party dependencies, after all), it’s not currently available in a production environment.

Apache HttpComponents HttpClient

Apache Commons HttpClient has been discontinued. If you are still using Apache Commons HttpClient, Switch to Apache HttpComponents HttpClient.

Apache HttpComponents HttpClient supports the following features:

import java.io.ByteArrayOutputStream;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.apache.commons.io.IOUtils;

import org.apache.http.HttpResponse;

import org.apache.http.NameValuePair;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.fluent.Request;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.client.methods.RequestBuilder;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.impl.client.HttpClients;

public class HttpComponentsDemo {

final static CloseableHttpClient client = HttpClients.createDefault();

// General call

private String sendPostForm(String url, Map<String, String> params) throws Exception {

HttpPost request = new HttpPost(url);

// set header

request.setHeader(“X-Http-Demo”, HttpComponentsDemo.class.getSimpleName());

// set params

if (params ! = null) {

List nameValuePairList = new ArrayList();

for (Map.Entry<String, String> entry : params.entrySet()) {

nameValuePairList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));

}

UrlEncodedFormEntity bodyEntity = new UrlEncodedFormEntity(nameValuePairList, “UTF-8”);

//System.out.println(“body:” + IOUtils.toString(bodyEntity.getContent()));

request.setEntity(new UrlEncodedFormEntity(nameValuePairList));

}

// send request

CloseableHttpResponse response = client.execute(request);

// read rsp code

System.out.println(“rsp code:” + response.getStatusLine().getStatusCode());

// return content

String ret = readResponseContent(response.getEntity().getContent());

response.close();

return ret;

}

// Fluent chain call

private String sendGet(String url) throws Exception {

return Request.Get(url)

.connectTimeout(1000)

.socketTimeout(1000)

.execute().returnContent().asString();

}

private String readResponseContent(InputStream inputStream) throws Exception {

if (inputStream == null) {

return “”;

}

ByteArrayOutputStream out = new ByteArrayOutputStream();

byte[] buf = new byte[512];

int len;

while (inputStream.available() > 0) {

len = inputStream.read(buf);

out.write(buf, 0, len);

}

return out.toString();

}

public static void main(String[] args) throws Exception {

HttpComponentsDemo httpUrlConnectionDemo = new HttpComponentsDemo();

String url = “httpbin.org/post”;

Map<String, String> params = new HashMap<String, String>();

Params. Put (“foo”, “bar中文”);

String rsp = httpUrlConnectionDemo.sendPostForm(url, params);

System.out.println(“http post rsp:” + rsp);

url = “httpbin.org/get”;

System.out.println(“http get rsp:” + httpUrlConnectionDemo.sendGet(url));

}

}

Detailed configuration and customization support for Client is also in place:

// Create a connection manager with custom configuration.

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(

socketFactoryRegistry, connFactory, dnsResolver);

// Create socket configuration

SocketConfig socketConfig = SocketConfig.custom()

.setTcpNoDelay(true)

.build();

// Configure the connection manager to use socket configuration either

// by default or for a specific host.

connManager.setDefaultSocketConfig(socketConfig);

connManager.setSocketConfig(new HttpHost(“somehost”, 80), socketConfig);

// Validate connections after 1 sec of inactivity

connManager.setValidateAfterInactivity(1000);

// Create message constraints

MessageConstraints messageConstraints = MessageConstraints.custom()

.setMaxHeaderCount(200)

.setMaxLineLength(2000)

.build();

// Create connection configuration

ConnectionConfig connectionConfig = ConnectionConfig.custom()

.setMalformedInputAction(CodingErrorAction.IGNORE)

.setUnmappableInputAction(CodingErrorAction.IGNORE)

.setCharset(Consts.UTF_8)

.setMessageConstraints(messageConstraints)

.build();

// Configure the connection manager to use connection configuration either

// by default or for a specific host.

connManager.setDefaultConnectionConfig(connectionConfig);

connManager.setConnectionConfig(new HttpHost(“somehost”, 80), ConnectionConfig.DEFAULT);

// Configure total max or per route limits for persistent connections

// that can be kept in the pool or leased by the connection manager.

connManager.setMaxTotal(100);

connManager.setDefaultMaxPerRoute(10);

connManager.setMaxPerRoute(new HttpRoute(new HttpHost(“somehost”, 80)), 20);

Basically, Apache HttpComponents HttpClient is the best HTTP Client library choice when the Java native standard library doesn’t work. However, the library does not currently support HTTP/2, and the HTTP/2 version is still in beta (2018.09.23), so it is not suitable for use in Android apps.

OkHttp

Because the current version of Apache HttpComponents HttpClient does not support HTTP/2, HTTP/2 is attractive for mobile clients in terms of handshake latency, response latency, and resource overhead. So this gives plenty of room for a high-level HTTP/ 2-enabled HTTP client lib. One of the most typical is OkHttp.

import okhttp3.*;

import org.apache.http.util.CharsetUtils;

import java.util.HashMap;

import java.util.Map;

public class OkHttpDemo {

OkHttpClient client = new OkHttpClient();

private String sendPostForm(String url, final Map<String, String> params) throws Exception {

FormBody.Builder builder = new FormBody.Builder(CharsetUtils.get(“UTF-8”));

if (params ! = null) {

for (Map.Entry<String, String> entry: params.entrySet()) {

builder.add(entry.getKey(), entry.getValue());

}

}

RequestBody requestBody = builder.build();

Request request = new Request.Builder().url(url).post(requestBody).build();

return client.newCall(request).execute().body().string();

}

private String sendGet(String url) throws Exception {

Request request = new Request.Builder().url(url).build();

return client.newCall(request).execute().body().string();

}

public static void main(String[] args) throws Exception {

OkHttpDemo okHttpDemo = new OkHttpDemo();

String url = “httpbin.org/post”;

Map<String, String> params = new HashMap<String, String>();

Params. Put (“foo”, “bar中文”);

String rsp = okHttpDemo.sendPostForm(url, params);

System.out.println(“http post rsp:” + rsp);

url = “httpbin.org/get”;

System.out.println(“http get rsp:” + okHttpDemo.sendGet(url));

}

}

OkHttp is one of the most widely used HTTP Clilent libs in Android APP development because of its friendly interface design, support for HTTP/2, and automatic detection and recovery mechanisms in both weak and netless environments.

On the other hand, OkHttp provides an interface similar to the HttpClint interface in Java 9 (strictly speaking, Java 9 borrowed interface design from OkHttp and other open source libraries). Therefore, switching from OkHttp to the standard library in Java 11 is relatively easy for developers who prefer to reduce dependencies in favor of the native standard library. As a result, HTTP libraries represented by OkHttp may be cannibalized in future usage scenarios.

summary

The HttpURLConnection encapsulation level is too low and supports too few features to be used in projects. Unless you really don’t want to introduce third party HTTP dependencies (e.g., reduce package size, target environment doesn’t provide third party library support, etc.). HttpClient, introduced in Java 9, has good packaging layers and support features. However, due to the Java version, the application scenario is very limited, and it is recommended to wait and see for a while before considering online use. If you don’t need HTTP/2 features, Apache HttpComponents HttpClient is your best choice, such as HTTP calls between servers. Otherwise, use OkHttp, like Android development. Welcome Java engineers who have worked for one to five years to join Java architecture development: 854393687 group provides free Java architecture learning materials (which have high availability, high concurrency, high performance and distributed, Jvm performance tuning, Spring source code, MyBatis, Netty, Redis, Kafka, Mysql, Zookeeper, Tomcat, Docker, Dubbo, multiple knowledge architecture data, such as the Nginx) reasonable use their every minute and second time to learn to improve yourself, don’t use “no time” to hide his ideas on the lazy! While young, hard to fight, to the future of their own account!