I used to be unruly in the code, and now I work day and night in blog posts, just to share the results with you today. If you find this article useful, remember to follow me and I will bring you more.
introduce
HttpUtils is a recently open-sourced framework for lightweight encapsulation of OkHttp. Its original asynchronous preprocessor , unique tags , flexible upload and download progress monitoring and process control functions can easily solve many headaches. Also strive for purity and elegance.
- Chain call, one point to the end
- BaseURL, URL placeholder, JSON automatic packaging and parsing
- Synchronous interceptors, asynchronous preprocessors, callback executors
- File upload and download (process control, progress monitoring)
- TCP connection pool, Http2
Project address Gitee: https://gitee.com/ejlchina-zhxu/httputils GitHub: https://github.com/ejlchina/httputils
Installation tutorial
Maven
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>httputils</artifactId>
<version>2.2.0</version>
</dependency>
Gradle
compile 'com.ejlchina:httputils:2.2.0'
Instructions for use
1 Simple example
1.1 Building HTTP
HTTP http = HTTP.builder().build();
The above code builds a simplest HTTP
instance, which has the following three methods:
async(String url)
start an asynchronous requestsync(String url)
start a sync requestcancel(String tag)
Batch cancel requests based on tags
For ease of use, we prefer to specify one at build time BaseUrl
(see [5.1 Setting BaseUrl] below):
HTTP http = HTTP.builder()
.baseUrl("http://api.demo.com")
.build();
In order to simplify the documentation, the following examples are http
set at build time .BaseUrl
HTTP
1.2 Synchronization request
sync(String url)
Start a synchronous request with the method :
List<User> users = http.sync("/users") // http://api.demo.com/users
.get() // GET请求
.getBody() // 获取响应报文体
.toList(User.class); // 得到目标数据
The method sync
returns a sync HttpTask
, which can be chained.
1.3 Asynchronous requests
async(String url)
Start an asynchronous request with the method :
http.async("/users/1") // http://api.demo.com/users/1
.setOnResponse((HttpResult result) -> {
// 得到目标数据
User user = result.getBody().toBean(User.class);
})
.get(); // GET请求
The method async
returns an async HttpTask
, which can be chained.
2 Request method (GET|POST|PUT|DELETE)
Both synchronous and asynchronous HttpTask
have get
, post
, put
and delete
methods. The difference is: the synchronous HttpTask
ones return one HttpResult
, and the asynchronous HttpTask
ones return one HttpCall
.
HttpResult res1 = http.sync("/users").get(); // 同步 GET
HttpResult res2 = http.sync("/users")post(); // 同步 POST
HttpResult res3 = http.sync("/users/1").put(); // 同步 PUT
HttpResult res4 = http.sync("/users/1").delete();// 同步 DELETE
HttpCall call1 = http.async("/users").get(); // 异步 GET
HttpCall call2 = http.async("/users").post(); // 异步 POST
HttpCall call3 = http.async("/users/1").put(); // 异步 PUT
HttpCall call4 = http.async("/users/1").delete();// 异步 DELETE
3 Parse the request result
3.1 Callback function
The callback function can only be set for asynchronous requests:
http.async("/users/{id}") // http://api.demo.com/users/1
.addPathParam("id", 1)
.setOnResponse((HttpResult result) -> {
// 响应回调
})
.setOnException((Exception e) -> {
// 异常回调
})
.setOnComplete((State state) -> {
// 完成回调,无论成功失败都会执行
})
.get();
3.2 HttpResult
HttpResult
It is the result after the HTTP request is executed. It is the return value of the synchronous request method ( get
, post
, put
, delete
) and the parameter of the asynchronous request response callback ( OnResponse
). It defines the following methods:
getState()
Get the request execution status enumeration, which has the following values:State.CANCELED
request cancelledState.RESPONSED
Response receivedState.TIMEOUT
Request timed outState.NETWORK_ERROR
Network ErrorState.EXCEPTION
Other request exceptions
getStatus()
get HTTP status codeisSuccessful()
Whether the response is successful, the status code is between [200..300)getHeaders()
get HTTP response headersgetBody()
Get the response message bodyBody
instance, which defines the following methods (for the sameBody
instance, the followingtoXXX()
class methods can only be used one and can only be called once):toBytes()
return byte arraytoByteStream()
return byte input streamtoCharStream()
return character input streamtoString()
return stringtoJsonObject()
return Json objecttoJsonArray()
return Json arraytoBean(Class<T> type)
Returns the JavaBean automatically parsed according to type jsontoList(Class<T> type)
Returns a list of JavaBeans automatically parsed according to type jsontoFile(String filePath)
Download to the specified pathtoFile(File file)
Download to the specified filetoFolder(String dirPath)
Download to the specified directorytoFolder(File dir)
Download to the specified directorygetContentType()
Returns the media type of the message bodygetContentLength()
Returns the length in bytes of the message bodyclose()
The message body is closed, and it is used when the message body is not consumed, for example, only the header of the message is read.
getError()
Exceptions that occur during execution, automatically capture execution requests are network timeouts, network errors and other request exceptions that occurclose()
Close the message and use it when the message body is not consumed, such as only reading the length
For example, the request result is automatically transferred to Bean and List:
// 自动转Bean
Order order = http.sync("/orders/1")
.get().getBody().toBean(Order.class);
// 自动转List
List<Order> orders = http.sync("/orders")
.get().getBody().toList(Order.class);
Example, download a file to the specified directory:
String path = "D:/reports/2020-03-01.xlsx"; // 文件保存目录
// 同步下载
http.sync("/reports/2020-03-01.xlsx")
.get().getBody().toFile(path).start();
// 异步下载
http.async("/reports/2020-03-01.xlsx")
.setOnResponse((HttpResult result) -> {
result.getBody().toFile(path).start();
})
.get();
For a more detailed introduction to uploading and downloading, please see the following article: OkHttp elegantly encapsulates the uploading and downloading decryption of HttpUtils .
3.3 HttpCall
HttpCall
The object is the return value of the asynchronous request method ( get
, post
, put
, ), much like the interface of , it has the following methods:delete
java
Future
cancel()
Cancel this request and return the cancellation resultisCanceled()
Returns whether the request was canceledisDone()
Returns whether the execution is complete, including cancellation and failuregetResult()
Returns the execution resultHttpResult
object. If the request is not completed, suspend the current thread until the execution is completed and then return
Example of cancelling an asynchronous request:
HttpCall call = http.async("/users/1").get();
System.out.println(call.isCanceled()); // false
boolean success = call.cancel(); // 取消请求
System.out.println(success); // true
System.out.println(call.isCanceled()); // true
4 Build HTTP tasks
HTTP
The sync
AND async
method of an object returns an HttpTask
object that provides a chainable addXXX
AND setXXX
sequence of methods for building the task itself.
-
addHeader(String name, String value)
add request header -
addHeader(Map<String, String> headers)
add request header -
addPathParam(String name, Object value)
Add path parameters: replace the {name} placeholder in the URL -
addPathParam(Map<String, ?> params)
Add path parameters: replace the {name} placeholder in the URL -
addUrlParam(String name, Object value)
Add URL parameters: spliced after the ? in the URL (query parameters) -
addUrlParam(Map<String, ?> params)
Add URL parameters: spliced after the ? in the URL (query parameters) -
addBodyParam(String name, Object value)
Add Body parameter: put it in the message body in the form of form key=value& (form parameter) -
addBodyParam(Map<String, ?> params)
Add Body parameter: put it in the message body in the form of form key=value& (form parameter) -
addJsonParam(String name, Object value)
Add Json parameter: the request body is Json (supports multi-layer structure) -
addJsonParam(Map<String, ?> params)
Add Json parameter: the request body is Json (supports multi-layer structure) -
setRequestJson(Object json)
Set the Json string of the request body or the JavaBean to be converted to Json -
setRequestJson(Object bean, String dateFormat)
Set the Json string of the request body or the JavaBean to be converted to Json -
addFileParam(String name, String filePath)
upload files -
addFileParam(String name, File file)
upload files -
addFileParam(String name, String type, InputStream inputStream)
upload files -
addFileParam(String name, String type, String fileName, InputStream input)
upload files -
addFileParam(String name, String type, byte[] content)
upload files -
addFileParam(String name, String type, String fileName, byte[] content)
upload files -
setTag(String tag)
Add tags to HTTP tasks -
setRange(long rangeStart)
Set the Range header information for resuming the upload from a breakpoint -
setRange(long rangeStart, long rangeEnd)
Set Range header information for chunked download
5 Using labels
Sometimes we want to classify HTTP tasks, in which case we can use the label function:
http.async("/users") //(1)
.setTag("A").get();
http.async("/users") //(2)
.setTag("A.B").get();
http.async("/users") //(3)
.setTag("B").get();
http.async("/users") //(4)
.setTag("B.C").get();
http.async("/users") //(5)
.setTag("C").get();
After using tags, you can cancel HTTP tasks in batches by tags:
int count = http.cancel("B"); //(2)(3)(4)被取消(取消标签包含"B"的任务)
System.out.println(count); // 输出 3
Likewise, only asynchronous HTTP tasks can be canceled. In addition to being used to cancel tasks, tags can also play a role in the preprocessor, see below [6.4 Parallel Preprocessor] and [6.5 Serial Preprocessor].
6 Configure HTTP
6.1 Setting BaseUrl
HTTP http = HTTP.builder()
.baseUrl("http://api.demo.com") // 设置 BaseUrl
.build();
After configuration BaseUrl
, specific requests can be omitted BaseUrl
to make the code more concise, for example:
http.sync("/users").get() // http://api.demo.com/users
http.sync("/auth/signin") // http://api.demo.com/auth/signin
.addBodyParam("username", "Jackson")
.addBodyParam("password", "xxxxxx")
.post() // POST请求
After configuration BaseUrl
, if there is a special request, the full path method can still be used, which does not hinder at all:
http.sync("https://www.baidu.com").get()
6.2 Calling back the executor
When you want to change the thread that executes the callback function, you can configure the callback executor. For example, in Android, if all callback functions are executed on the UI thread, you can HTTP
configure the following at build time:
HTTP http = HTTP.builder()
.callbackExecutor((Runnable run) -> {
runOnUiThread(run); // 在UI线程执行
})
.build();
The callbacks affected by this configuration are: OnResponse
, OnException
and OnComplete
.
6.3 Configuring OkHttpClient
Unlike other frameworks that encapsulate OkHttp, HttpUtils does not obscure the functions that OkHttp itself is very useful, as follows:
HTTP http = HTTP.builder()
.config((Builder builder) -> {
// 配置连接池 最小10个连接(不配置默认为 5)
builder.connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES));
// 配置连接超时时间
builder.connectTimeout(20, TimeUnit.SECONDS);
// 配置拦截器
builder.addInterceptor((Chain chain) -> {
Request request = chain.request();
// 必须同步返回,拦截器内无法执行异步操作
return chain.proceed(request);
});
// 其它配置: SSL、缓存、代理、事件监听...
})
.build();
6.4 Parallel Preprocessors
The preprocessor ( Preprocessor
) allows us to do some processing on the request itself according to the business before the request is sent, but unlike OkHttp's interceptor ( Interceptor
): the preprocessor allows us to handle these issues asynchronously .
For example, when we want to automatically add Token
header information for the request task, which Token
can only be obtained through asynchronous methods requestToken
, it is difficult to use at this time Interceptor
, but it can be easily solved by using the preprocessor:
HTTP http = HTTP.builder()
.addPreprocessor((PreChain chain) -> {
HttpTask<?> task = chain.getTask();// 获得当前的HTTP任务
if (!task.isTagged("Auth")) { // 根据标签判断该任务是否需要Token
return;
}
requestToken((String token) -> { // 异步获取 Token
task.addHeader("Token", token);// 为任务添加头信息
chain.proceed(); // 继续当前的任务
});
})
.build();
And Interceptor
like, Preprocessor
you can also add more than one.
6.5 Serial Preprocessor
Ordinary preprocessors can be processed in parallel, but sometimes we want a preprocessor to process only one task at a time. For example, when it Token
expires, we need to refresh to get a new one Token
, and the refresh Token
operation can only be performed by one task, because if n
two tasks are executed at the same time, then there must be n-1
a task that has just been refreshed and Token
may be invalid immediately, and this is our undesired.
To solve this problem, HttpUtils provides a serial preprocessor, which allows HTTP tasks to be queued to enter the preprocessor one by one:
HTTP http = HTTP.builder()
.addSerialPreprocessor((PreChain chain) -> {
HttpTask<?> task = chain.getTask();
if (!task.isTagged("Auth")) {
return;
}
// 检查过期,若需要则刷新Token
requestTokenAndRefreshIfExpired((String token) -> {
task.addHeader("Token", token);
chain.proceed(); // 调用此方法前,不会有其它任务进入该处理器
});
})
.build();
The serial preprocessor implements the ability to queue HTTP tasks for serial processing, but it's worth mentioning that it doesn't block any threads because of it!
7 Using the HttpUtils class
The class HttpUtils
is the most important core class in the 1.x version. Because the HTTP
interface is abstracted in the 2.x version, its importance is not as important as it used to be. However, using it reasonably can still bring a lot of convenience, especially in environments without IOC containers, such as Android development and the development of some tool projects.
The class HttpUtils
defines four static methods:
async(String url)
Start an asynchronous request (the content is implemented through aHTTP
singleton)sync(String url)
Start a synchronous request (the content is implemented through aHTTP
singleton)cancel(String tag)
Cancel request by tag (content is implemented through aHTTP
singleton)of(HTTP http)
ConfigureHttpUtils
the held instance (a lazy instanceHTTP
without any configuration is used by default before calling this method )HTTP
That is, classes http
can be used wherever instances can be used HttpUtils
, for example:
// 在配置HTTP实例之前,只能使用全路径方式
List<Role> roles = HttpUtils.sync("http://api.demo.com/roles")
.get().getBody().toList(Role.class);
// 配置HTTP实例,全局生效
HttpUtils.of(HTTP.builder()
.baseUrl("http://api.demo.com")
.build());
// 内部使用新的HTTP实例
List<User> users = HttpUtils.sync("/users")
.get().getBody().toList(User.class);
Next article: OkHttp elegantly encapsulates HttpUtils upload and download decryption
I used to be unruly in the code, and now I work day and night in blog posts, just to share the results with you today. If you find this article useful, remember to follow me and I will bring you more.