{"id":21719731,"url":"https://github.com/troyzhxu/httputils","last_synced_at":"2025-10-24T23:03:25.175Z","repository":{"id":37130863,"uuid":"248886221","full_name":"troyzhxu/httputils","owner":"troyzhxu","description":"Http工具包：OkHttp轻量封装 、功能全面、设计力求优雅与纯粹，Java领域前后端处Http问题的新选择。","archived":false,"fork":false,"pushed_at":"2022-07-05T08:17:06.000Z","size":540,"stargazers_count":22,"open_issues_count":1,"forks_count":11,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T20:52:04.713Z","etag":null,"topics":["android","download","gradle","http","http-okhttp","httputils","httputils-okhttp","java","json","range","upload"],"latest_commit_sha":null,"homepage":"http://okhttps.ejlchina.com/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/troyzhxu.png","metadata":{"files":{"readme":"README-2.0.0.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-21T01:37:37.000Z","updated_at":"2024-12-04T09:54:59.000Z","dependencies_parsed_at":"2022-09-05T00:41:27.841Z","dependency_job_id":null,"html_url":"https://github.com/troyzhxu/httputils","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/troyzhxu/httputils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fhttputils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fhttputils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fhttputils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fhttputils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/troyzhxu","download_url":"https://codeload.github.com/troyzhxu/httputils/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fhttputils/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266419444,"owners_count":23925767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","download","gradle","http","http-okhttp","httputils","httputils-okhttp","java","json","range","upload"],"created_at":"2024-11-26T01:41:54.482Z","updated_at":"2025-10-24T23:03:25.169Z","avatar_url":"https://github.com/troyzhxu.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HttpUtils\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.ejlchina/httputils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.ejlchina/httputils/)\n[![License](https://img.shields.io/hexpm/l/plug.svg)](https://gitee.com/ejlchina-zhxu/httputils/blob/master/LICENSE)\n[![Troy.Zhou](https://img.shields.io/badge/%E4%BD%9C%E8%80%85-ejlchina-orange.svg)](https://github.com/ejlchina)\n\n## 介绍\nHttp工具包，封装 OkHttp，自动解析，链式用法、异步同步、前后端通用\n\n * 支持异步、同步请求\n * 支持Restfull风格\n * JSON自动封装与解析\n * TCP连接池\n * 请求拦截器\n * Http2\n * 回调线程配置\n * 异步预处理器\n * GET|POST|PUT|DELETE\n * 文件上传下载\n\n## 当前文档版本 2.0.0 [查阅 1.x.x 点我跳转](https://gitee.com/ejlchina-zhxu/httputils/blob/1.x/README.md)\n\n## 安装教程\n\n### Maven\n\n```\n\u003cdependency\u003e\n     \u003cgroupId\u003ecom.ejlchina\u003c/groupId\u003e\n     \u003cartifactId\u003ehttputils\u003c/artifactId\u003e\n     \u003cversion\u003e2.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n### Gradle\n\n`compile 'com.ejlchina:httputils:2.0.0'`\n\n## 使用说明\n\n+ [1 简单示例](#1-简单示例)\n  - [1.1 构建-http](#11-构建-http)\n  - [1.2 同步请求](#12-同步请求)\n  - [1.3 异步请求](#13-异步请求)\n+ [2 请求方法](#2-请求方法)\n  - [2.1 GET](#21-GET)\n  - [2.2 POST](#22-POST)\n  - [2.3 PUT](#23-PUT)\n  - [2.4 DELETE](#24-DELETE)\n+ [3 解析执行结果](#3-解析执行结果)\n  - [3.1 回调函数](#31-回调函数)\n  - [3.2 HttpResult](#32-HttpResult)\n  - [3.3 HttpCall](#33-HttpCall)\n+ [4 构建HTTP任务](#4-构建HTTP任务)\n  - [4.1 添加请求头](#41-添加请求头)\n  - [4.2 添加路径参数](#42-添加路径参数)\n  - [4.3 添加查询参数](#43-添加查询参数)\n  - [4.4 添加表单参数](#44-添加表单参数)\n  - [4.5 添加Json参数](#45-添加Json参数)\n  - [4.6 添加文件参数](#46-添加文件参数)\n  - [4.7 添加标签](#47-添加标签)\n+ [5 配置 HTTP](#5-配置-http)\n  - [5.1 设置 BaseUrl](#51-设置-baseurl)\n  - [5.2 回调执行器](#52-回调执行器)\n  - [5.3 配置 OkHttpClient](#53-配置-okhttpclient)\n  - [5.4 并行预处理器](#54-并行预处理器)\n  - [5.5 串行预处理器](#55-串行预处理器)\n\n### 1 简单示例\n\n#### 1.1 构建 HTTP\n\n```java\n\tHTTP http = HTTP.builder().build();\t\t\n```\n　　`HTTP`对象有以下三个方法：\n\n* `async(String urlPath)` 开始一个异步HTTP任务\n* `sync(String urlPath)` 开始一个同步HTTP任务\n* `cancel(String tag)` 根据标签批量取消HTTP任务\n\n　　为了简化文档，下文中出现的`http`均是已构建好的`HTTP`对象。\n\n#### 1.2 同步请求\n\n　　使用方法`sync(String url)`开始一个同步请求：\n\n```java\n// 最终路径 http://api.demo.com/users?name=Jack\nUser user = http.sync(\"http://api.demo.com/users\")\n\t\t.addUrlParam(\"name\", \"Jack\")\t\t\t\t// 添加查询参数\n\t\t.get()\t\t\t\t\t\t\t\t\t\t// 发送GET请求\n\t\t.getBody()\t\t\t\t\t\t\t\t\t// 获取响应报文体\n\t\t.toBean(User.class);\t\t\t\t\t\t// 得到目标数据\n```\n　　方法`sync`返回一个同步`HttpTask`，可链式使用。\n\n#### 1.3 异步请求\n\n　　使用方法`async(String url)`开始一个异步请求：\n\n```java\n// 最终路径为 http://api.demo.com/users/1\nhttp.async(\"http://api.demo.com/users/{id}\")\n\t\t.addPathParam(\"id\", 1)\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\t// 得到目标数据\n\t\t\tUser user = result.getBody().toBean(User.class);\n\t\t})\n\t\t.get();\t  \t// GET请求\n```\n　　方法`async`返回一个异步`HttpTask`，可链式使用。\n\n### 2 请求方法\n\n　　同步与异步的`HttpTask`都拥有`get`、`post`、`put`与`delete`方法。不同的是：同步`HttpTask`的这些方法返回一个`HttpResult`，而异步`HttpTask`的这些方法返回一个`HttpCall`。\n\n#### 2.1 GET\n\n```java\nHttpResult result = http.sync(\"http://api.demo.com/users\").get();\t\t// 同步 GET\n\nHttpCall call = http.async(\"http://api.demo.com/users\")\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\n\t\t}).get();\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 异步 GET\n```\n#### 2.2 POST\n\n```java\nHttpResult result = http.sync(\"http://api.demo.com/users\")\n\t\t.addBodyParam(\"name\", \"Jack\")\n\t\t.addBodyParam(\"age\", 20)\n\t\t.post();\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 同步 POST\n\nHttpCall call = http.async(\"http://api.demo.com/users\")\n\t\t.addBodyParam(\"name\", \"Jack\")\n\t\t.addBodyParam(\"age\", 20)\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\n\t\t}).post();\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 异步 POST\n```\n#### 2.3 PUT\n\n```java\nHttpResult result = http.sync(\"http://api.demo.com/users/1\")\n\t\t.addJsonParam(\"name\", \"Jack\")\n\t\t.put();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 同步 PUT\n\nHttpCall call = http.async(\"http://api.demo.com/users/1\")\n\t\t.addJsonParam(\"name\", \"Jack\")\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\n\t\t})\n\t\t.put();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 异步 PUT\n```\n#### 2.4 DELETE\n\n```java\nHttpResult result = http.sync(\"http://api.demo.com/users/1\").delete();\t// 同步 DELETE\n\nHttpCall call = http.async(\"http://api.demo.com/users/1\")\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\n\t\t})\n\t\t.delete();\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 异步 DELETE\n```\n### 3 解析执行结果\n\n#### 3.1 回调函数\n\n　　只有异步请求才可以设置回调函数：\n\n```java\nhttp.async(\"http://api.demo.com/users/1\")\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\t// 响应回调\n\t\t})\n\t\t.setOnException((Exception e) -\u003e {\n\t\t\t// 异常回调\n\t\t})\n\t\t.setOnComplete((State state) -\u003e {\n\t\t\t// 完成回调，无论成功失败都会执行\n\t\t})\n\t\t.get();\n```\n　　所有的同步请求方法均返回一个 HttpResult 对象，所有的异步请求方法均返回一个 HttpCall 对象。\n\n#### 3.2 HttpResult\n\n　　`HttpResult`对象是HTTP请求执行完后的结果，它是同步请求方法（ `get`、`post`、`put`、`delete`）的返回值，也是异步请求响应回调（`OnResponse`）的参数，它有如下方法：\n\n* `getState()` \t\t得到请求执行状态枚举，它有以下取值：\n\t* `State.CANCELED` 请求被取消\n\t* `State.RESPONSED` 已收到响应\n\t* `State.TIMEOUT` 请求超时\n\t* `State.NETWORK_ERROR` 网络错误\n\t* `State.EXCEPTION` 其它请求异常\n* `getStatus()` \t得到HTTP状态码\n* `isSuccessful()` \t是否响应成功，状态码在 [200..300) 之间\n* `getHeaders()` \t得到HTTP响应头\n* `getBody()` \t\t得到响应报文体`Body`对象，它有如下方法：\n    * `toBytes()` \t\t\t\t\t\t返回字节数组\n    * `toByteStream()` \t\t\t\t\t返回字节输入流\n    * `toCharStream()` \t\t\t\t\t返回字符输入流\n    * `toString()` \t\t\t\t\t\t返回字符串\n    * `toJsonObject()` \t\t\t\t\t返回Json对象\n    * `toJsonArray()` \t\t\t\t\t返回Json数组\n    * `toBean(Class\u003cT\u003e type)` \t\t\t返回根据type自动json解析后的JavaBean\n    * `toBean(TypeReference\u003cT\u003e type)`\t返回根据type自动json解析后的JavaBean\n    * `toFile(String filePath)` \t\t下载到指定路径并返回保存后的文件（下载文件时非常有用）\n    * `toFile(File file)` \t\t\t\t下载到指定文件并返回保存后的文件（下载文件时非常有用）\n    * `getContentType()`\t\t\t\t返回报文体的媒体类型\n    * `getContentLength()`\t\t\t\t返回报文体的字节长度\n    * 对同一个`Body`对象，以上`toXXX()`类方法只能使用一个且仅能使用一次\n* `getError()` \t\t执行中发生的异常，自动捕获执行请求是发生的 网络超时、网络错误 和 其它请求异常\n\n　　例如，下载文件到指定目录：\n\t\n```java\nString path = \"D:/reports/2020-03-01.xlsx\";\t// 文件保存目录\n\n// 同步下载\nhttp.sync(\"http://api.demo.com/reports/2020-03-01.xlsx\")\n\t\t.get().getBody().toFile(path);\n\n// 异步下载\nhttp.async(\"http://api.demo.com/reports/2020-03-01.xlsx\")\n\t\t.setOnResponse((HttpResult result) -\u003e {\n\t\t\tresult.getBody().toFile(path);\n\t\t})\n\t\t.get();\n```\n\n#### 3.3 HttpCall\n\n　　`HttpCall`对象是异步请求方法（ `get`、`post`、`put`、`delete`）的返回值，与`java`的`Future`接口很像，它有如下方法：\n\n* `cancel()` 取消本次请求，返回取消结果\n* `isCanceled()` 返回请求是否被取消\n* `isDone()` 返回是否执行完成，包含取消和失败\n* `getResult()` 返回执行结果`HttpResult`对象，若请求未执行完，则挂起当前线程直到执行完成再返回\n\n　　取消一个异步请求示例：\n\n```java\nHttpCall call = http.async(\"http://api.demo.com/users/1\").get();\n\nSystem.out.println(call.isCanceled());\t // false\n\nboolean success = call.cancel();   // 取消请求\n\nSystem.out.println(success);\t \t\t // true\nSystem.out.println(call.isCanceled());\t // true\n```\n\n### 4 构建HTTP任务\n\n　　`HTTP`对象的`sync`与`async`方法返回一个`HttpTask`对象，该对象提供了一系列可链式使用的`addXXX`、`setXXX` 与`tag`方法用于构建任务本身。\n\n#### 4.1 添加请求头\n\n　　单个添加（同步异步添加方法一样）：\n\n```java\nhttp.sync(\"http://api.demo.com/orders\")\n\t\t.addHeader(\"Access-Token\", \"xxxxxx\")\n\t\t.addHeader(\"Content-Type\", \"application/json\")\n\t\t.get();\n```\n　　多个添加（同步异步添加方法一样）：\n\n```java\nMap\u003cString, String\u003e headers = new HashMap\u003c\u003e()\nheaders.put(\"Access-Token\", \"xxxxxx\");\nheaders.put(\"Accept\", \"application/json\");\n\nhttp.sync(\"http://api.demo.com/orders\")\n\t\t.addHeader(headers)\n\t\t.get();\n```\n\n#### 4.2 添加路径参数\n\n　　路径参数用于替换URL字符串中的占位符。\n\n　　单个添加（同步异步添加方法一样）：\n\n```java\nhttp.sync(\"http://api.demo.com/shops/{shopName}/products/{productId}\")\n\t\t.addPathParam(\"shopName\", \"taobao\")\n\t\t.addPathParam(\"productId\", 20)\n\t\t.get();\n```\n　　多个添加（同步异步添加方法一样）：\n\n```java\nMap\u003cString, String\u003e params = new HashMap\u003c\u003e()\nparams.put(\"shopName\", \"taobao\");\nparams.put(\"productId\", 20);\n\nhttp.sync(\"http://api.demo.com/shops/{shopName}/products/{productId}\")\n\t\t.addPathParam(params)\n\t\t.get();\n```\n\n#### 4.3 添加查询参数\n\n　　查询参数（URL参数）用于拼接在 url 字符串的 ? 之后。\n\n　　单个添加（同步异步添加方法一样）：\n\n```java\nhttp.sync(\"http://api.demo.com/products\")\n\t\t.addUrlParam(\"name\", \"手机\")\n\t\t.addUrlParam(\"type\", \"5G\")\n\t\t.get();\n```\n　　多个添加（同步异步添加方法一样）：\n\n```java\nMap\u003cString, String\u003e params = new HashMap\u003c\u003e()\nparams.put(\"name\", \"手机\");\nparams.put(\"type\", \"5G\");\n\nhttp.sync(\"http://api.demo.com/products\")\n\t\t.addUrlParam(params)\n\t\t.get();\n```\n\n#### 4.4 添加表单参数\n\n　　表单参数（Body参数）以 key=value\u0026 的形式携带与请求报文体内。\n\n　　单个添加（同步异步添加方法一样）：\n\n```java\nhttp.sync(\"http://api.demo.com/signin\")\n\t\t.addBodyParam(\"username\", \"Jackson\")\n\t\t.addBodyParam(\"password\", \"xxxxxx\")\n\t\t.post();\n```\n　　多个添加（同步异步添加方法一样）：\n\n```java\nMap\u003cString, String\u003e params = new HashMap\u003c\u003e()\nparams.put(\"username\", \"Jackson\");\nparams.put(\"password\", \"xxxxxx\");\n\nhttp.sync(\"http://api.demo.com/signin\")\n\t\t.addBodyParam(params)\n\t\t.post();\n```\n\n#### 4.5 添加Json参数\n\n　　JSON 参数最终以 json 字符串的形式携带与请求报文体内。\n\n　　单个添加（同步异步添加方法一样）：\n\n```java\nhttp.sync(\"http://api.demo.com/signin\")\n\t\t.addJsonParam(\"username\", \"Jackson\")\n\t\t.addJsonParam(\"password\", \"xxxxxx\")\n\t\t.post();\n```\n　　多个添加（同步异步添加方法一样）：\n\n```java\nMap\u003cString, String\u003e params = new HashMap\u003c\u003e()\nparams.put(\"username\", \"Jackson\");\nparams.put(\"password\", \"xxxxxx\");\n\nhttp.sync(\"http://api.demo.com/signin\")\n\t\t.addJsonParam(params)\n\t\t.post();\n```\n　　直接设置JSON字符串：\n\n```java\nhttp.sync(\"http://api.demo.com/signin\")\n\t\t.setRequestJson(\"\\\"username\\\":\\\"Jackson\\\",\\\"password\\\":\\\"xxxxxx\\\"\")\n\t\t.post();\n```\n　　JavaBean 自动转 JSON：\n\n```java\nLogin login = new Login();\nlogin.setUsername(\"Jackson\");\nlogin.setPassword(\"xxxxxx\");\n\nhttp.sync(\"http://api.demo.com/signin\")\n\t\t.setRequestJson(login)\n\t\t.post();\n```\n\n#### 4.6 添加文件参数\n\n　　上传本地文件：\n\n```java\nFile file1 = new File(\"D:/1.jpg\");\nFile file2 = new File(\"D:/2.jpg\");\n\nhttp.sync(\"http://api.demo.com/upload\")\n\t\t.addFileParam(\"image1\", file1)\n\t\t.addFileParam(\"image2\", file2)\n\t\t.post();\n```\n　　使用文件输入流上传：\n\n```java\n// 获得文件的输入流\nInputStream input = ...\n\nhttp.sync(\"http://api.demo.com/upload\")\n\t\t.addFileParam(\"image\", \"jpg\", input)\n\t\t.post();\n```\n　　使用文件字节数组上传：\n\n```java\n// 获得文件的字节数组\nbyte[] content = ...\n\nhttp.sync(\"http://api.demo.com/upload\")\n\t\t.addFileParam(\"image\", \"jpg\", content)\n\t\t.post();\n```\n　　文件参数和表单参数可以一起添加：\n\n```java\nFile file = new File(\"D:/首页广告.jpg\");\n\nhttp.sync(\"http://api.demo.com/messages\")\n\t\t.addBodyParam(\"name\", \"广告图\")\n\t\t.addFileParam(\"image\", file)\n\t\t.post();\n```\n\n#### 4.7 添加标签\n\n　　有时候我们对HTTP任务加以分类，这时候可以使用标签功能：\n\n```java\nhttp.async(\"http://api.demo.com/users\")\n\t\t.tag(\"MyTag\")\n\t\t.get();\n```\n　　当使用标签后，就可以按标签批量的对HTTP任务进行取消：\n\n```java\nhttp.cancel(\"MyTag\");\n```\n　　也可以在统一配置的预处理器中，以标签对任务进行分类处理，参见[并行预处理器](#54-并行预处理器)与[串行预处理器](#55-串行预处理器)。\n\n### 5 配置 HTTP\n\n#### 5.1 设置 BaseUrl\n\n```java\nHTTP http = HTTP.builder()\n\t\t.baseUrl(\"http://api.demo.com\")\t\t// 设置 BaseUrl\n\t\t.build();\n```\n　　该配置全局生效，在配置了`BaseUrl`之后，具体的请求便可以省略`BaseUrl`部分，使得代码更加简洁，例如：\n\n```java\nhttp.sync(\"/users\").get()\t\t\t\t\t// http://api.demo.com/users\n\nhttp.sync(\"/auth/signin\")\t\t\t\t\t// http://api.demo.com/auth/signin\n\t\t.addBodyParam(\"username\", \"Jackson\")\n\t\t.addBodyParam(\"password\", \"xxxxxx\")\n\t\t.post()\t\t\t\t\t\t\t\t// POST请求\n```\n　　在配置了`BaseUrl`之后，如有特殊请求任务，仍然可以使用全路径的方式，一点都不妨碍：\n\n```java\nhttp.sync(\"https://www.baidu.com\").get()\n```\n\n#### 5.2 回调执行器\n\n　　如何想改变执行回调函数的线程时，可以配置回调函数执行器。例如在Android里，让所有的回调函数都在UI线程里执行，则可以在构建`HTTP`时配置回调执行器：\n\n```java\nHTTP http = HTTP.builder()\n\t\t.callbackExecutor((Runnable run) -\u003e {\n\t\t\trunOnUiThread(run);\t\t\t\t// 在UI线程执行\n\t\t})\n\t\t.build();\n```\n\n#### 5.3 配置 OkHttpClient\n\n　　与其他封装`OkHttp`的框架不同，`HttpUtils`并不会遮蔽`OkHttp`本身就很好用的功能，如下：\n\n```java\nHTTP http = HTTP.builder()\n\t.config((Builder builder) -\u003e {\n\t\t// 配置连接池 最小10个连接（不配置默认为 5）\n\t\tbuilder.connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES));\n\t\t// 配置连接超时时间\n\t\tbuilder.connectTimeout(20, TimeUnit.SECONDS);\n\t\t// 配置拦截器\n\t\tbuilder.addInterceptor((Chain chain) -\u003e {\n\t\t\tRequest request = chain.request();\n\t\t\t// 必须同步返回，拦截器内无法执行异步操作\n\t\t\treturn chain.proceed(request);\n\t\t});\n\t\t// 其它配置: SSL、缓存、代理、事件监听...\n\t})\n\t.build();\n```\n\n#### 5.4 并行预处理器\n\n　　预处理器（`Preprocessor`）可以让我们在请求发出之前对请求本身做一些改变，但与 OkHttp 提供的拦截器（`Interceptor`）不同的是：预处理器可以让我们异步处理这些问题。\n\n　　例如，当我们想为请求任务自动添加`Token`头信息，而`Token`只能通过异步方法`requestToken`获取时，这时使用`Interceptor`就很难处理了，但我们可以使用预处理器轻松解决：\n\n```java\nHTTP http = HTTP.builder()\n\t\t.addPreprocessor((Process process) -\u003e {\n\t\t\tHttpTask\u003c?\u003e task = process.getTask();\t\t// 获得当前的请求任务\n\t\t\tString tag = task.getTag();\t\t\t\t\t// 取得添加在任务上的标签\n\t\t\tif (!\"Auth\".equals(tag)) {\t\t\t\t\t// 根据标签判断该任务是否需要Token\n\t\t\t\treturn;\n\t\t\t}\n\t\t\trequestToken((String token) -\u003e {\t\t\t// 异步获取 Token\n\t\t\t\ttask.addHeader(\"Token\", token);\t\t\t// 为任务添加 Token头信息\n\t\t\t\tprocess.proceed();\t\t\t\t\t\t// 继续当前的任务\n\t\t\t});\t\n\t\t})\n\t\t.build();\n```\n　　和`Interceptor`一样，`Preprocessor`也可以添加多个。\n\n#### 5.5 串行预处理器\n\n　　普通预处理器都是可并行处理的，然而有时我们希望某个预处理器同时只处理一个任务。比如 当`Token`过期时我们需要去刷新获取新`Token`，而刷新`Token`这个操作只能有一个任务去执行，因为如果`n`个任务同时执行的话，那么必有`n-1`个任务刚得刷新得到的`Token`可能会立马失效，而这是我们所不希望的。\n\n　　为了解决这个问题，`HttpUtils`提供了串行预处理器，它可以让HTTP任务排好队，一个一个地进入预处理器：\n\n```java\nHTTP http = HTTP.builder()\n\t\t.addSerialPreprocessor((Process process) -\u003e {\n\t\t\tHttpTask\u003c?\u003e task = process.getTask();\t\t// 获得当前的请求任务\n\t\t\tString tag = task.getTag();\t\t\t\t\t// 取得添加在任务上的标签\n\t\t\tif (!\"Auth\".equals(tag)) {\t\t\t\t\t// 根据标签判断该任务是否需要Token\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// 检查过期，若需要则刷新Token\n\t\t\trequestTokenAndRefreshIfExpired((String token) -\u003e {\n\t\t\t\ttask.addHeader(\"Token\", token);\t\t\t// 为任务添加 Token头信息\n\t\t\t\tprocess.proceed();\t\t\t\t\t\t// 调用此方法前，不会有其它任务进入该处理器\n\t\t\t});\t\n\t\t})\n\t\t.build();\n```\n　　串行预处理器实现了让HTTP任务排队串行处理的功能，但值得一提的是：它并没有因此而阻塞任何线程！\n\n\n## 参与贡献\n\n1.  Fork 本仓库\n2.  新建 Feat_xxx 分支\n3.  提交代码\n4.  新建 Pull Request\n\n\n## 码云特技\n\n1.  使用 Readme\\_XXX.md 来支持不同的语言，例如 Readme\\_en.md, Readme\\_zh.md\n2.  码云官方博客 [blog.gitee.com](https://blog.gitee.com)\n3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目\n4.  [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目，是码云综合评定出的优秀开源项目\n5.  码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)\n6.  码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroyzhxu%2Fhttputils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftroyzhxu%2Fhttputils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroyzhxu%2Fhttputils/lists"}