2. HTTP请求
如果你不了解如何创建接口清单,请先参看服务端请求部分。
APIMap.kt
| Kotlin | |
|---|---|
假设我们已经在APIMap中定义了接口清单,客户端发送请求将十分容易。
我们只需要引用该接口调用request方法,传递与定义输入类型相同的参数即可发送请求,并收到与定义输出类型相同的服务器响应。
Test.kt
上述例子将会输出Rachel, hello world!
Rachel框架为了方便发送客户端请求,设计了三种请求风格,它们可以互相替换,但是在不同的场景下某些方式可能写起来更轻松。
虽然框架在设计时我们完全可以使用返回值的方式请求并接受响应,例如:
| Kotlin | |
|---|---|
但我们并没有采取这样的设计,主要原因有以下几点:
-
在
kotlin语言层面上你无法同时获取多个返回值,使用Pair或手动构造data class呈现的繁琐度与我们初衷相违背。 -
使用
lambda来处理响应的好处在于将所谓的“返回值”转变为了lambda的参数,这样便能自由定义多个数量的返回值了,并且我们可以用_去标记不关心的值。 -
如果直接返回值,那么我们将无法处理错误的情况。而现在
request函数的返回值是Throwable, 在请求成功情况下我们无需关心,直接丢弃返回值。 而请求失败的情况下,我们也可以通过漂亮的DSL来实现错误处理。例如:
风格一:回调式
回调式写法最为容易,通常用于消耗响应结果的情况,不需要将结果留存执行后续任务。
这种风格request的返回值是错误处理,当然如果你只需要在lambda中执行相关操作,而不关心处理错误,则无需处理。
Tip
我知道你们关心回调地狱的事,事实上request的lambda回调式写法只是在语法层面上提供更好的编程效率,请求在作用域下仍然是同步的。
位于lambda体外部的语句仍然是在lambda执行完后才开始执行,因为request的block参数也是suspend函数,所以根本不存在嵌套回调。
包含错误处理的示例如下:
| Kotlin | |
|---|---|
请求会先执行lambda体内的操作,如果发生了错误则立即返回错误,此时由printStackTrace打印错误堆栈。
无论成功失败与否,最后一条输出语句始终会等待前面请求包括lambda体中所有操作完成。
请求始终发生在IO的协程作用域,所以你无需手动切换协程上下文。
请求一定会捕获所有异常,所以你无需担心程序崩溃。
Tip
需要注意的是,你的请求参数并不在请求的错误处理范围内,如果在构造参数时发生异常则不会被请求处理。
风格二:返回式
| Kotlin | |
|---|---|
返回式通常用于需要获取结果等待后续处理的情景,但实际上这种情景大多数可以完全被回调式覆盖,除非你在某些需要返回值的函数中发生请求。
返回式的结果是一个Data类包装,你可以区分其是Data.Sucess或Data.Failure来分别获取实际的值与错误。
要注意的是,不推荐使用返回式的原因正是因为函数很难同时返回多个值(在你不手动定义data类的前提下,这样会显得繁琐)。
所以Data.Sucess的结果仍然是一个APIResult的包装,它可以接受一个或多个不同类型的参数构造,在服务端返回也是如此。
你可以通过其成员依次访问每一个值。
风格三:返回 Null 式
| Kotlin | |
|---|---|
有时候可能必须要使用风格二,但是我们对响应结果的错误处理并不关心,那么可以更加方便的直接使用requestNull来发送请求。
它把Data<O1>类包装改为APIResult<O1>?作为结果返回,配合kotlin可空表达式我们便可以更方便的书写。
Tip
特别的,对于返回值只有一个参数的情况,APIResult<O1>?直接退化成O1?类型。对于没有返回值的情况,我们也可以直接省略。