What is okhttp?
It is a client network access library based on HTTP+HTTP/2 Java development, with rich functions and efficient performance. Open source by Square, there is currently 3w+ Star on Github, which shows people’s love for it.
The demo presentation
Let’s start with a simple example: Build a Maven project and import dependencies:
< the dependency > < groupId > com. Squareup. Okhttp3 < / groupId > < artifactId > okhttp < / artifactId > < version > 3.7.0 < / version > </dependency>Copy the code
Execute a GET request as follows:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
try (Response response = client.newCall(request).execute()) {
String resStr = response.body().string();
System.out.println(resStr);
} catch (IOException e) {
e.printStackTrace();
}
Copy the code
Here’s another example of a POST request:
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
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();
}
Copy the code
As you can see from the code examples above, the OKHTTP API is quite simple to use. Create a client of OkHttpClient, create a Request, and execute the Request through the client.
Components in Okhttp
-
client
The HTTP client’s job is simply to accept your request and execute it, returning the corresponding response.
-
request
Each request contains the URL,header, and request method (get, POST…). , request body. Okhttp provides the ability to rewrite requests, follow requests (redirects), and retry.
-
response
The response contains the response code, response header, and response body, and OKHTTP provides automatic rewriting of the response.
-
calls
The process from request to response is abstracted as a call, which performs the task in both Synchronous and asynchronous ways: Synchronous: blocks the current thread until a result is returned
Asynchronous: queue the request and get the response via a callback, Asynchronous request is returned in a separate work thread.
Examples of asynchronous request code:
client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if(! response.isSuccessful()) throw new IOException("Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0, size = responseHeaders.size(); i < size; i++) { System.out.println(responseHeaders.name(i) + ":"+ responseHeaders.value(i)); } System.out.println(responseBody.string()); }}}); }Copy the code
More code sample reference github:github.com/square/okht…
Interceptors
An interceptor is a powerful feature of OKHTTP that allows you to do something in a request or response. Interceptors can be divided into two main categories, APPLICATION and NETWORK, depending on where they are called. The two types of interceptors are classified according to whether they come before or after the core interceptor (which is the core of the library and what I think is a great design, as mentioned in a later section), as shown below
Interceptor usage example, the following creates a log interceptor to print logs before a request is sent and after a response is received
class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
returnresponse; }}Copy the code
Chain.request () and chain.proceed(request) above are key. Chain.request () gets the request from the chain, and chain.proceed() performs the specific request and passes it to the next chain. Add the created interceptor to the client
OkHttpClient client = new OkHttpClient().newBuilder()
.addInterceptor(new LoggingInterceptor())
.build();
Copy the code
The above code adds an interceptor of type Application by default. If you want to add an interceptor of type Netword, see the following code:
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor())
.build();
Copy the code
Interceptor application
-
Rewrite the request
Related headers and request bodies can be added, removed, or replaced. The following code shows an example of a compressed request body:
final class GzipRequestInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request originalRequest = chain.request();if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { return chain.proceed(originalRequest); } Request compressedRequest = originalRequest.newBuilder() .header("Content-Encoding"."gzip") .method(originalRequest.method(), gzip(originalRequest.body())) .build(); return chain.proceed(compressedRequest); } private RequestBody gzip(final RequestBody body) { return new RequestBody() { @Override public MediaType contentType() { return body.contentType(); } @Override public long contentLength() { return- 1; // Wedo not know the compressed length inadvance! } @Override public void writeTo(BufferedSink sink) throws IOException { BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); body.writeTo(gzipSink); gzipSink.close(); }}; }Copy the code
-
Rewrite the response
It is also possible to modify the received response header and body, but this is generally dangerous and not recommended.
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .header("Cache-Control", "max-age=60") .build(); }};Copy the code
Events
Okhttp provides many event points that developers can easily extend and listen to. For example, you can use these event points to monitor the frequency and performance of invocation requests. The event point is shown in the figure below:
Pit alert: EventListener is only available in versions 3.11 and older
class PrintingEventListener extends EventListener {
private long callStartNanos;
private void printEvent(String name) {
long nowNanos = System.nanoTime();
if (name.equals("callStart")) {
callStartNanos = nowNanos;
}
long elapsedNanos = nowNanos - callStartNanos;
System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name);
}
@Override public void callStart(Call call) {
printEvent("callStart");
}
@Override public void callEnd(Call call) {
printEvent("callEnd");
}
@Override public void dnsStart(Call call, String domainName) {
printEvent("dnsStart");
}
@Override public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
printEvent("dnsEnd"); }... }Copy the code
Add a listener to the client
OkHttpClient client = new OkHttpClient().newBuilder()
.eventListener(new PrintingEventListener())
.build();
Copy the code
Since EvenetListener is bound to each call, if you want to differentiate one call from another, you can create an EventListener in the factory mode, creating a unique ID for each listener so that you can distinguish between calls in the log by that ID. As follows:
class PrintingEventListener extends EventListener {
public static final Factory FACTORY = new Factory() {
final AtomicLong nextCallId = new AtomicLong(1L);
@Override public EventListener create(Call call) {
long callId = nextCallId.getAndIncrement();
System.out.printf("%04d %s%n", callId, call.request().url());
returnnew PrintingEventListener(callId, System.nanoTime()); }}; final long callId; final long callStartNanos; public PrintingEventListener(long callId, long callStartNanos) { this.callId = callId; this.callStartNanos = callStartNanos; } private voidprintEvent(String name) {
long elapsedNanos = System.nanoTime() - callStartNanos;
System.out.printf("%04d %.3f %s%n", callId, elapsedNanos / 1000000000d, name);
}
@Override public void callStart(Call call) {
printEvent("callStart");
}
@Override public void callEnd(Call call) {
printEvent("callEnd"); }... }Copy the code
Finally, set up the eventFactory in the client
OkHttpClient client = new OkHttpClient().newBuilder()
.eventListenerFactory(PrintingEventListener.FACTORY)
.build();
Copy the code