1. 概述

Fuel HTTP Library 是一个专为 Kotlin/Android 开发者设计的轻量级网络请求库,作者称其为“最容易使用的 HTTP 网络库”。它同样支持 Java,功能全面,API 简洁,适合用于构建现代 Android 应用或 Kotlin 后端项目。

Fuel 的主要特性包括:

✅ 支持常见的 HTTP 方法(GET、POST、DELETE 等)
✅ 支持异步和同步请求
✅ 支持文件上传/下载(multipart/form-data)
✅ 支持全局配置管理
✅ 内置对象序列化模块(支持 Gson、Jackson、Moshi、Forge)
✅ 支持 Kotlin 协程(Coroutines)和 RxJava 2.x
✅ 提供 Router 设计模式支持,便于统一管理 API 接口


2. 依赖配置

Fuel 是一个模块化设计的库,我们可以根据需求选择引入不同的模块。以下是我们常用的几个模块:

  • fuel:核心模块
  • fuel-gson:Gson 支持
  • fuel-rxjava:RxJava 支持
  • fuel-coroutines:协程支持
  • gson:Gson 依赖

Maven 配置如下:

<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel</artifactId>
    <version>${fuel.version}</version>
</dependency>
<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel-gson</artifactId>
    <version>${fuel.version}</version>
</dependency>
<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel-rxjava</artifactId>
    <version>${fuel.version}</version>
</dependency>
<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel-coroutines</artifactId>
    <version>${fuel.version}</version>
</dependency>
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>${gson.version}</version>
</dependency>

最新版本请参考 Maven Central


3. 发起请求

Fuel 提供了简洁的 API,可以通过 String 扩展方式发起请求,也可以使用 Fuel 类显式调用。

3.1 GET 请求

异步 GET 请求示例:

"http://httpbin.org/get".httpGet().response { request, response, result ->
    // 处理响应
}

同步 GET 请求:

val (request, response, result) = "http://httpbin.org/get".httpGet().response()

带参数的 GET 请求:

val (request, response, result) = 
  "https://jsonplaceholder.typicode.com/posts"
  .httpGet(listOf("userId" to "1")).response()
// 最终 URL: https://jsonplaceholder.typicode.com/posts?userId=1

3.2 POST 请求

使用 httpPost()Fuel.post() 发起 POST 请求:

"http://httpbin.org/post".httpPost().response { request, response, result ->
    // 处理响应
}
val (request, response, result) = Fuel.post("http://httpbin.org/post").response()

发送 JSON 数据:

val bodyJson = """
  { "title" : "foo",
    "body" : "bar",
    "id" : "1"
  }
"""
val (request, response, result) = Fuel.post("https://jsonplaceholder.typicode.com/posts")
  .body(bodyJson)
  .response()

3.3 其他 HTTP 方法

Fuel 支持所有常见 HTTP 方法:

Fuel.put("http://httpbin.org/put")
Fuel.delete("http://httpbin.org/delete")
Fuel.head("http://httpbin.org/get")
Fuel.patch("http://httpbin.org/patch")

⚠️ 注意:由于 java.net.HttpUrlConnection 不支持 PATCH,Fuel 会将其转换为 POST 并添加 X-HTTP-Method-Override: PATCH 请求头,需确保服务端支持该头。


4. 全局配置

Fuel 提供 FuelManager.instance 用于设置全局配置。

4.1 基础路径(basePath)

FuelManager.instance.basePath = "http://httpbin.org"
val (request, response, result) = "/get".httpGet().response()
// 实际请求地址:http://httpbin.org/get

4.2 默认请求头(baseHeaders)

FuelManager.instance.baseHeaders = mapOf("OS" to "Debian")

局部设置请求头:

val (request, response, result) = "/get"
  .httpGet()
  .header(mapOf("OS" to "Debian"))
  .response()

4.3 默认参数(baseParams)

FuelManager.instance.baseParams = listOf("foo" to "bar")

4.4 其他配置选项

通过 FuelManager 可以设置以下内容:

  • keystore:证书存储,默认为 null
  • socketFactory:自定义或基于 keystore 生成
  • hostnameVerifier:默认使用 HttpsURLConnection 提供的验证器
  • timeout / timeoutRead:连接和读取超时时间
  • requestInterceptors / responseInterceptors:请求/响应拦截器

4.5 请求/响应拦截器

可以添加内置拦截器,如 LogRequestAsCurlInterceptor,也可以自定义:

FuelManager.instance.addRequestInterceptor(LogRequestAsCurlInterceptor)

自定义 Token 拦截器:

FuelManager.instance.addRequestInterceptor(tokenInterceptor())
fun tokenInterceptor() = {
    next: (Request) -> Request ->
    { req: Request ->
        req.header(mapOf("Authorization" to "Bearer AbCdEf123456"))
        next(req)
    }
}

5. 响应处理

Fuel 使用 Result<out T, FuelError> 封装请求结果,支持多种响应类型:

fun response(handler: (Request, Response, Result<ByteArray, FuelError>) -> Unit)
fun responseString(handler: (Request, Response, Result<String, FuelError>) -> Unit)
fun responseJson(handler: (Request, Response, Result<Json, FuelError>) -> Unit)
fun <T> responseObject(deserializer: ResponseDeserializable<T>, handler: (Request, Response, Result<T, FuelError>) -> Unit)

示例:

val (request, response, result) = Fuel.post("http://httpbin.org/post").responseString()
val (payload, error) = result // payload 是 String 类型

⚠️ 注意:使用 responseJson() 需要引入 fuel-android 模块:

<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel-android</artifactId>
    <version>${fuel.version}</version>
</dependency>

6. JSON 序列化与反序列化

Fuel 支持多种 JSON 解析库,如 Gson、Jackson、Moshi、Forge。我们以 Gson 为例说明。

定义数据类和反序列化器:

data class Post(var userId: Int, var id: Int, var title: String, var body: String) {

    class Deserializer : ResponseDeserializable<Array<Post>> {
        override fun deserialize(content: String): Array<Post> =
            Gson().fromJson(content, Array<Post>::class.java)
    }
}

使用自定义反序列化器:

"https://jsonplaceholder.typicode.com/posts"
  .httpGet().responseObject(Post.Deserializer()) { _, _, result ->
    val postsArray = result.component1()
}

使用泛型方式(内部使用 Gson):

"https://jsonplaceholder.typicode.com/posts/1"
  .httpGet().responseObject<Post> { _, _, result ->
    val post = result.component1()
}

序列化对象发送:

val post = Post(1, 1, "Lorem", "Lorem Ipse dolor sit amet")
val (request, response, result) = Fuel.post("https://jsonplaceholder.typicode.com/posts")
    .header("Content-Type" to "application/json")
    .body(Gson().toJson(post).toString())

⚠️ 注意:务必设置 Content-Type,否则服务器可能无法正确解析 JSON。


7. 文件下载与上传

7.1 下载文件

使用 download() 方法下载文件并保存:

Fuel.download("http://httpbin.org/bytes/32768")
  .fileDestination { response, request -> 
    File.createTempFile("temp", ".tmp")
  }

带进度监听的下载:

Fuel.download("http://httpbin.org/bytes/327680")
  .progress { readBytes, totalBytes ->
    val progress = readBytes.toFloat() / totalBytes.toFloat()
    // 处理进度
  }

7.2 上传文件

使用 upload() 方法上传文件:

Fuel.upload("/upload").source { request, url ->
  File.createTempFile("temp", ".tmp")
}

指定 HTTP 方法(如 PUT):

Fuel.upload("/upload", Method.PUT).source { request, url ->
  File.createTempFile("temp", ".tmp")
}

多文件上传:

Fuel.upload("/post").sources { request, url ->
  listOf(
    File.createTempFile("temp1", ".tmp"),
    File.createTempFile("temp2", ".tmp")
  )
}

上传 InputStream 数据:

Fuel.upload("/post").blob { request, url ->
  Blob("filename.png", someObject.length, { someObject.getInputStream() })
}

8. RxJava 与协程支持

Fuel 支持 RxJava 与 Kotlin 协程,便于异步处理请求。

8.1 RxJava 示例

Fuel 提供了 RxJava 扩展方法,如:

fun Request.rxResponse(): Single<Pair<Response, Result<ByteArray, FuelError>>>
fun Request.rxResponseString(charset: Charset): Single<Pair<Response, Result<String, FuelError>>>
fun <T : Any> Request.rxResponseObject(deserializable: Deserializable<T>): Single<Pair<Response, Result<T, FuelError>>>

示例:

"https://jsonplaceholder.typicode.com/posts?id=1"
  .httpGet().rxObject(Post.Deserializer()).subscribe { res, throwable ->
    val post = res.component1()
  }

8.2 Kotlin 协程示例

Fuel 提供协程扩展函数,如:

runBlocking {
    Fuel.get("http://httpbin.org/get").awaitStringResponse()
}

处理对象:

runBlocking {
    Fuel.get("https://jsonplaceholder.typicode.com/posts?id=1")
      .awaitObjectResult(Post.Deserializer())
}

9. API 路由设计

Fuel 支持通过 FuelRouting 接口实现统一的 API 路由管理,便于集中管理接口路径、参数、请求方法等。

示例定义:

sealed class PostRoutingAPI : FuelRouting {

    override val basePath = "https://jsonplaceholder.typicode.com"

    class Post(val id: String, override val body: String?) : PostRoutingAPI()
    class Comment(val postId: String, override val body: String?) : PostRoutingAPI()

    override val method: Method
        get() {
            return when (this) {
                is Post -> Method.GET
                is Comment -> Method.GET
            }
        }

    override val path: String
        get() {
            return when (this) {
                is Post -> "/posts"
                is Comment -> "/comments"
            }
        }

    override val params: List<Pair<String, Any?>>?
        get() {
            return when (this) {
                is Post -> listOf("id" to this.id)
                is Comment -> listOf("postId" to this.postId)
            }
        }

    override val headers: Map<String, HeaderValues>?
        get() = null

    override val bytes: ByteArray?
        get() = null
}

使用路由接口:

Fuel.request(PostRoutingAPI.Post("1", null))
  .responseObject(Post.Deserializer()) { request, response, result ->
    // 处理响应
  }
Fuel.request(PostRoutingAPI.Comment("1", null))
  .responseString { request, response, result ->
    // 处理响应
  }

10. 总结

Fuel 是一个功能丰富、使用简洁的 Kotlin HTTP 客户端库,适合用于 Android 和 Kotlin 后端开发。它不仅支持同步/异步请求、文件上传下载、JSON 序列化,还整合了 RxJava 和 Coroutines,便于异步处理。通过 FuelRouting 接口,还可以实现统一的 API 路由管理,提升代码结构清晰度。

推荐理由:

  • API 简洁,上手快
  • 支持多种序列化方式
  • 支持主流异步框架
  • 易于扩展和配置

如果你正在寻找一个轻量级、功能完整的 Kotlin HTTP 客户端,Fuel 是一个非常值得尝试的选择。


原始标题:Fuel HTTP Library with Kotlin