From 9d58f71eaba451902eaebb3e54e1fd5d4a42a504 Mon Sep 17 00:00:00 2001
From: drake
Date: Wed, 2 Aug 2023 15:34:08 +0800
Subject: [PATCH] =?UTF-8?q?docs:=20=E7=AE=80=E5=8C=96=E4=BD=BF=E7=94=A8?=
=?UTF-8?q?=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
docs/config.md | 4 +-
docs/converter.md | 280 ++++------------------------------
docs/coroutine-request.md | 16 +-
docs/customizer-converter.md | 287 +++++++++++++++++++++++++++++++++++
docs/default-response.md | 50 ------
docs/index.md | 100 ++++--------
docs/issues.md | 27 +++-
docs/request.md | 119 ++++++---------
docs/scope.md | 48 +++---
docs/sync-request.md | 34 ++---
mkdocs.yml | 23 ++-
12 files changed, 477 insertions(+), 513 deletions(-)
create mode 100644 docs/customizer-converter.md
delete mode 100644 docs/default-response.md
diff --git a/README.md b/README.md
index a809a12a0..8b350d175 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
-
+
diff --git a/docs/config.md b/docs/config.md
index 05a16a6fc..ea8eb19ad 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -45,10 +45,10 @@
| 函数 | 描述 |
|-|-|
-| setDebug | 是否输出网络日志, 和`LogRecordInterceptor`互不影响 |
+| setDebug | 是否输出网络日志, 和`LogRecordInterceptor`互不影响 |
| setSSLCertificate | 配置Https证书 |
| trustSSLCertificate | 信任所有Https证书 |
-| setConverter | [配置数据转换器](converter.md), 将网络返回的数据转换成你想要的数据结构 |
+| setConverter | [配置数据转换器](customizer-converter.md), 将网络返回的数据转换成你想要的数据结构 |
| setRequestInterceptor | [配置请求拦截器](interceptor.md), 适用于添加全局请求头/参数 |
| setErrorHandler | [配置全局错误处理](error-global.md) |
| setDialogFactory | [配置全局对话框](auto-dialog.md) |
diff --git a/docs/converter.md b/docs/converter.md
index d8d7f1fc3..9dd34c375 100644
--- a/docs/converter.md
+++ b/docs/converter.md
@@ -1,36 +1,16 @@
-Net可以通过自定义转换器支持任何数据类型转换, 甚至`List>`等嵌套泛型对象
+Net支持请求返回的数据类型取决于你自己的转换器实现(即理论上支持返回任何对象):
-例如请求动作Post`指定泛型为Model`, 则转换器NetConverter中的函数`onConvert返回值必须为Model`, 如果转换失败或者发生异常都算请求错误
+# Get<任何对象>("path").await()
-> 注意如果你在转换器里面返回null. 那么指定的泛型也应当是可空类型, 例如`Post("api")`
-
-```kotlin
-scopeNetLife {
- val userList = Get>("list") {
- converter = GsonConverter()
- }.await()
-}
-```
-
-
-
-如果你要返回映射好的数据模型对象, 那么肯定要求创建转换器的. 本框架由于低耦合原则不自带解析框架
-
-[常用的Json转换器-代码示例](https://github.com/liangjingkanji/Net/tree/master/sample/src/main/java/com/drake/net/sample/converter)
-
-
-
-## 默认返回数据类型
-
-Net支持请求返回的数据类型取决于你的转换器(也就是支持返回任何对象), 默认情况不创建转换器也支持返回以下数据类型
+如果不自定义转换器默认支持返回以下数据类型
| 函数 | 描述 |
|-|-|
| String | 字符串 |
| ByteArray | 字节数组 |
| ByteString | 内部定义的一种字符串对象 |
-| Response | 最基础的响应 |
| File | 文件对象, 这种情况其实应当称为[下载文件](download-file.md) |
+| Response | 最基础的, 包含全部响应信息的对象(响应体/响应头/请求信息等) |
使用示例
@@ -40,238 +20,32 @@ scopeNetLife {
}
```
-??? summary "默认使用的是: [NetConverter.DEFAULT](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/NetConverter.kt)"
- ```kotlin
- val DEFAULT = object : NetConverter {
-
- override fun onConvert(
- succeed: Type,
- response: Response
- ): R? {
- return when (succeed) {
- String::class.java -> response.body?.string() as R
- ByteString::class.java -> response.body?.byteString() as R
- ByteArray::class.java -> response.body?.bytes() as R
- Response::class.java -> response as R
- File::class.java -> response.file() as R
- else -> throw ConvertException(
- response,
- "The default converter does not support this type"
- )
- }
- }
- }
- ```
-
-假设这里没有你需要的数据类型请[自定义转换器](#_3)(例如返回Json或Protocol)
-
-## 设置转换器
-转换器分为全局和单例, 单例可以覆盖全局的转换器. 如果不设置转换器就会采用默认的转换器
-
-=== "全局"
- ```kotlin hl_lines="2"
- NetConfig.initialize("https://github.com/liangjingkanji/Net/", this) {
- setConverter(SerializationConverter())
- }
- ```
-=== "单例"
- ```kotlin hl_lines="3"
- scopeNetLife {
- tvFragment.text = Get("api"){
- converter = SerializationConverter()
- }.await()
- }
- ```
-
-## Json解析库转换器
-
-一般业务我们可以直接继承[JSONConverter](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/JSONConvert.kt)
-使用自己的JSON解析器解析数据, 完全自定义需求可以直接实现[NetConverter](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/NetConverter.kt)(比如直接转换IO流)
-
-=== "Gson"
-
- ```kotlin
- class GsonConvert : JSONConvert(code = "code", message = "msg", success = "200") {
- val gson = GsonBuilder().serializeNulls().create()
-
- override fun String.parseBody(succeed: Type): S? {
- return gson.fromJson(this, succeed)
- }
- }
- ```
-
-=== "kotlin-serialization"
-
- ```kotlin
- class SerializationConverter(
- val success: String = "0",
- val code: String = "code",
- val message: String = "msg"
- ) : NetConverter {
-
- private val jsonDecoder = Json {
- ignoreUnknownKeys = true // JSON和数据模型字段可以不匹配
- coerceInputValues = true // 如果JSON字段是Null则使用默认值
- }
-
- override fun onConvert(succeed: Type, response: Response): R? {
- try {
- // 此处是为了继承默认转换器支持的返回类型
- return NetConverter.onConvert(succeed, response)
- } catch (e: ConvertException) {
- val code = response.code
- when {
- code in 200..299 -> { // 请求成功
- val bodyString = response.body?.string() ?: return null
- val kType = response.request.kType() ?: return null
- return try {
- val json = JSONObject(bodyString) // 获取JSON中后端定义的错误码和错误信息
- if (json.getString(this.code) == success) { // 对比后端自定义错误码
- bodyString.parseBody(kType)
- } else { // 错误码匹配失败, 开始写入错误异常
- val errorMessage = json.optString(
- message,
- NetConfig.app.getString(com.drake.net.R.string.no_error_message)
- )
- throw ResponseException(response, errorMessage)
- }
- } catch (e: JSONException) { // 固定格式JSON分析失败直接解析JSON
- bodyString.parseBody(kType)
- }
- }
- code in 400..499 -> throw RequestParamsException(response, code.toString()) // 请求参数错误
- code >= 500 -> throw ServerResponseException(response, code.toString()) // 服务器异常错误
- else -> throw ConvertException(response)
- }
- }
- }
-
- fun String.parseBody(succeed: KType): R? {
- return jsonDecoder.decodeFromString(Json.serializersModule.serializer(succeed), this) as R
- }
- }
- ```
-
- SerializationConverter就是仿照JSONConverter代码实现
-
-=== "FastJson"
-
- ```kotlin
- class FastJsonConvert : JSONConvert(code = "code", message = "msg", success = "200") {
-
- override fun String.parseBody(succeed: Type): S? {
- return JSON.parseObject(this, succeed)
- }
- }
- ```
-
-=== "Moshi"
-
- ```kotlin
- class MoshiConvert : JSONConvert(code = "code", message = "msg", success = "200") {
- val moshi = Moshi.Builder().build()
-
- override fun String.parseBody(succeed: Type): S? {
- return moshi.adapter(succeed).fromJson(this)
- }
- }
- ```
-
-1. 使用转换器时请添加其依赖: [GSON](https://github.com/google/gson) | [kotlin-serialization](https://github.com/Kotlin/kotlinx.serialization) | [FastJson](https://github.com/alibaba/fastjson) | [Moshi](https://github.com/square/moshi)
-2. 推荐使用 `kotlinx.Serialization`, 其可解析[任何泛型](kotlin-serialization.md)
-3. Sample有完整代码示例
-
-以上转换器示例是建立在数据结构为以下表格的固定格式下, 如果有特殊的业务可能需要自行修改
-
-| 转换器参数 | 描述 |
-|-|-|
-| code | 即后端定义的`成功码`字段名 |
-| message | 即后端定义的`错误消息`字段名 |
-| success | 即`成功码`的值等于指定时才算网络请求成功 |
-
-
-
-比如截图中的意为, 当返回的Json中包含state字段且值为ok时请求才算是真正成功才会返回数据, 否则都会抛出异常. 其中message为错误信息字段名
-
-假设简单的指定名称不能满足你复杂的业务逻辑, 请复制`JSONConvert`源码到你项目中修改或者直接自己实现`NetConverter`
-
-> 注意解析器(Gson或者Moshi)的解析对象记得定义为类成员, 这样可以不会导致每次解析都要创建一个新的解析对象, 减少内存消耗
-
-
-## 自定义转换器
-
-通过实现`NetConverter`接口可以编写自己的逻辑网络请求返回的数据, `NetConvert.DEFAULT`为默认的转换器支持返回File/String/Response等
-
-
-
-框架中自带一个`JSONConverter`可以作为参考或者直接使用. 其可以转换JSON数据.
-
-??? summary "JSONConverter 源码"
- ```kotlin
- /**
- * 常见的JSON转换器实现, 如果不满意继承实现自定义的业务逻辑
- *
- * @param success 后端定义为成功状态的错误码值
- * @param code 错误码在JSON中的字段名
- * @param message 错误信息在JSON中的字段名
- */
- abstract class JSONConvert(
- val success: String = "0",
- val code: String = "code",
- val message: String = "msg"
- ) : NetConverter {
-
- override fun onConvert(succeed: Type, response: Response): R? {
- try {
- // 此处是为了继承默认转换器支持的返回类型
- return NetConverter.onConvert(succeed, response)
- } catch (e: ConvertException) {
- val code = response.code
- when {
- code in 200..299 -> { // 请求成功
- val bodyString = response.body?.string() ?: return null
- return try {
- val json = JSONObject(bodyString) // 获取JSON中后端定义的错误码和错误信息
- if (json.getString(this.code) == success) { // 对比后端自定义错误码
- bodyString.parseBody(succeed)
- } else { // 错误码匹配失败, 开始写入错误异常
- val errorMessage = json.optString(
- message,
- NetConfig.app.getString(com.drake.net.R.string.no_error_message)
- )
- throw ResponseException(response, errorMessage)
- }
- } catch (e: JSONException) { // 固定格式JSON分析失败直接解析JSON
- bodyString.parseBody(succeed)
- }
- }
- code in 400..499 -> throw RequestParamsException(response, code.toString()) // 请求参数错误
- code >= 500 -> throw ServerResponseException(response, code.toString()) // 服务器异常错误
- else -> throw ConvertException(response)
+??? summary "
+默认使用的是: [NetConverter.DEFAULT](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/NetConverter.kt)"
+```kotlin
+interface NetConverter {
+
+ @Throws(Throwable::class)
+ fun onConvert(succeed: Type, response: Response): R?
+
+ companion object DEFAULT : NetConverter {
+ /**
+ * 返回结果应当等于泛型对象, 可空
+ * @param succeed 请求要求返回的泛型类型
+ * @param response 请求响应对象
+ */
+ override fun onConvert(succeed: Type, response: Response): R? {
+ return when {
+ succeed === String::class.java && response.isSuccessful -> response.body?.string() as R
+ succeed === ByteString::class.java && response.isSuccessful -> response.body?.byteString() as R
+ succeed is GenericArrayType && succeed.genericComponentType === Byte::class.java && response.isSuccessful -> response.body?.bytes() as R
+ succeed === File::class.java && response.isSuccessful -> response.file() as R
+ succeed === Response::class.java -> response as R
+ else -> throw ConvertException(response, "An exception occurred while converting the NetConverter.DEFAULT")
}
}
}
-
- /**
- * 反序列化JSON
- *
- * @param succeed JSON对象的类型
- * @receiver 原始字符串
- */
- abstract fun String.parseBody(succeed: Type): R?
}
-
```
-JSONConvert的核心逻辑
-
-1. 判断服务器的错误码
-1. 判断后端自定义的错误码
-1. 如果判断发生错误则抛出一个包含错误信息的异常
-1. 如果都判断成功则开始解析数据并return数据对象
-
-在转换器中根据需要你可以在这里加上常见的解密数据, token失效跳转登录, 限制多端登录等逻辑. 日志信息输出请阅读: [日志记录器](log-recorder.md)
-
-如果是错误信息建议抛出异常, 就可以在全局异常处理器中统一处理, 请阅读:[全局错误处理](error-handle.md)
-
-
\ No newline at end of file
+假设这里没有你需要的数据类型请[自定义转换器](/converter/#_3)(例如返回Json或Protocol)
\ No newline at end of file
diff --git a/docs/coroutine-request.md b/docs/coroutine-request.md
index befff75b1..b5d5596a1 100644
--- a/docs/coroutine-request.md
+++ b/docs/coroutine-request.md
@@ -1,12 +1,9 @@
-Net在2.0开始引入协程来支持并发和异步, 虽然很多网络框架支持协程, 但是Net对于协程生命周期的控制算得上是独有.
-并且Net不仅仅网络请求, 其也支持创建任何异步任务.
+Net在2.0开始引入协程并发请求, 虽然很多网络框架支持协程, 但是唯有Net考虑到协程生命周期
-> 这里的`同时/并发/并行`统称为并发(具体是不是并行不需要开发者来考虑)
+并且不仅仅网络请求, 其也支持创建任何异步任务
-在上章节已经使用过了网络的并发请求
-
-这里再演示同时(并发)请求百度网站`一万次`并且一次取消
+在上章节已经介绍如何发起并发网络请求, 这里再演示同时(并发)网络请求`一万次`并且一次性全部取消
```kotlin
val job = scopeNetLife {
@@ -28,9 +25,10 @@ thread {
}
```
+
-Net主要推荐使用的是协程请求, 但是同时支持其他方式发起请求
+Net主要使用的协程请求, 但也支持其他方式发起请求
-- 协程请求
- [同步请求](sync-request.md)
-- [回调请求](callback.md)
\ No newline at end of file
+- [回调请求](callback.md)
+- 协程请求
diff --git a/docs/customizer-converter.md b/docs/customizer-converter.md
new file mode 100644
index 000000000..eca2107f5
--- /dev/null
+++ b/docs/customizer-converter.md
@@ -0,0 +1,287 @@
+Net可以通过自定义转换器支持任何数据类型转换, 甚至`List>`等嵌套泛型对象
+
+例如请求动作Post`指定泛型为Model`, 则转换器NetConverter中的函数`onConvert返回值必须为Model`,
+如果转换失败或者发生异常都算请求错误
+
+> 注意如果你在转换器里面返回null. 那么指定的泛型也应当是可空类型, 例如`Post("api")`
+
+```kotlin
+scopeNetLife {
+ val userList = Get>("list") {
+ converter = GsonConverter()
+ }.await()
+}
+```
+
+
+
+如果你要返回映射好的数据模型对象, 那么肯定要求创建转换器的. 本框架由于低耦合原则不自带解析框架
+
+[常用的Json转换器-代码示例](https://github.com/liangjingkanji/Net/tree/master/sample/src/main/java/com/drake/net/sample/converter)
+
+
+
+## 默认返回数据类型
+
+Net支持请求返回的数据类型取决于你的转换器(也就是支持返回任何对象), 默认情况不创建转换器也支持返回以下数据类型
+
+| 函数 | 描述 |
+|-|-|
+| String | 字符串 |
+| ByteArray | 字节数组 |
+| ByteString | 内部定义的一种字符串对象 |
+| Response | 最基础的响应 |
+| File | 文件对象, 这种情况其实应当称为[下载文件](download-file.md) |
+
+使用示例
+
+```kotlin
+scopeNetLife {
+ Get("api").await().headers("响应头名称") // 返回响应头
+}
+```
+
+??? summary "
+默认使用的是: [NetConverter.DEFAULT](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/NetConverter.kt)"
+```kotlin
+val DEFAULT = object : NetConverter {
+
+ override fun onConvert(
+ succeed: Type,
+ response: Response
+ ): R? {
+ return when (succeed) {
+ String::class.java -> response.body?.string() as R
+ ByteString::class.java -> response.body?.byteString() as R
+ ByteArray::class.java -> response.body?.bytes() as R
+ Response::class.java -> response as R
+ File::class.java -> response.file() as R
+ else -> throw ConvertException(
+ response,
+ "The default converter does not support this type"
+ )
+ }
+ }
+ }
+ ```
+
+假设这里没有你需要的数据类型请[自定义转换器](#_3)(例如返回Json或Protocol)
+
+## 设置转换器
+
+转换器分为全局和单例, 单例可以覆盖全局的转换器. 如果不设置转换器就会采用默认的转换器
+
+=== "全局"
+ ```kotlin hl_lines="2"
+ NetConfig.initialize("https://github.com/liangjingkanji/Net/", this) {
+ setConverter(SerializationConverter())
+ }
+ ```
+=== "单例"
+ ```kotlin hl_lines="3"
+ scopeNetLife {
+ tvFragment.text = Get("api"){
+ converter = SerializationConverter()
+ }.await()
+ }
+ ```
+
+## Json解析库转换器
+
+一般业务我们可以直接继承[JSONConverter](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/JSONConvert.kt)
+使用自己的JSON解析器解析数据,
+完全自定义需求可以直接实现[NetConverter](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/NetConverter.kt)(
+比如直接转换IO流)
+
+=== "Gson"
+
+ ```kotlin
+ class GsonConvert : JSONConvert(code = "code", message = "msg", success = "200") {
+ val gson = GsonBuilder().serializeNulls().create()
+
+ override fun String.parseBody(succeed: Type): S? {
+ return gson.fromJson(this, succeed)
+ }
+ }
+ ```
+
+=== "kotlin-serialization"
+
+ ```kotlin
+ class SerializationConverter(
+ val success: String = "0",
+ val code: String = "code",
+ val message: String = "msg"
+ ) : NetConverter {
+
+ private val jsonDecoder = Json {
+ ignoreUnknownKeys = true // JSON和数据模型字段可以不匹配
+ coerceInputValues = true // 如果JSON字段是Null则使用默认值
+ }
+
+ override fun onConvert(succeed: Type, response: Response): R? {
+ try {
+ // 此处是为了继承默认转换器支持的返回类型
+ return NetConverter.onConvert(succeed, response)
+ } catch (e: ConvertException) {
+ val code = response.code
+ when {
+ code in 200..299 -> { // 请求成功
+ val bodyString = response.body?.string() ?: return null
+ val kType = response.request.kType() ?: return null
+ return try {
+ val json = JSONObject(bodyString) // 获取JSON中后端定义的错误码和错误信息
+ if (json.getString(this.code) == success) { // 对比后端自定义错误码
+ bodyString.parseBody(kType)
+ } else { // 错误码匹配失败, 开始写入错误异常
+ val errorMessage = json.optString(
+ message,
+ NetConfig.app.getString(com.drake.net.R.string.no_error_message)
+ )
+ throw ResponseException(response, errorMessage)
+ }
+ } catch (e: JSONException) { // 固定格式JSON分析失败直接解析JSON
+ bodyString.parseBody(kType)
+ }
+ }
+ code in 400..499 -> throw RequestParamsException(response, code.toString()) // 请求参数错误
+ code >= 500 -> throw ServerResponseException(response, code.toString()) // 服务器异常错误
+ else -> throw ConvertException(response)
+ }
+ }
+ }
+
+ fun String.parseBody(succeed: KType): R? {
+ return jsonDecoder.decodeFromString(Json.serializersModule.serializer(succeed), this) as R
+ }
+ }
+ ```
+
+ SerializationConverter就是仿照JSONConverter代码实现
+
+=== "FastJson"
+
+ ```kotlin
+ class FastJsonConvert : JSONConvert(code = "code", message = "msg", success = "200") {
+
+ override fun String.parseBody(succeed: Type): S? {
+ return JSON.parseObject(this, succeed)
+ }
+ }
+ ```
+
+=== "Moshi"
+
+ ```kotlin
+ class MoshiConvert : JSONConvert(code = "code", message = "msg", success = "200") {
+ val moshi = Moshi.Builder().build()
+
+ override fun String.parseBody(succeed: Type): S? {
+ return moshi.adapter(succeed).fromJson(this)
+ }
+ }
+ ```
+
+1. 使用转换器时请添加其依赖: [GSON](https://github.com/google/gson)
+ | [kotlin-serialization](https://github.com/Kotlin/kotlinx.serialization)
+ | [FastJson](https://github.com/alibaba/fastjson) | [Moshi](https://github.com/square/moshi)
+2. 推荐使用 `kotlinx.Serialization`, 其可解析[任何泛型](kotlin-serialization.md)
+3. Sample有完整代码示例
+
+以上转换器示例是建立在数据结构为以下表格的固定格式下, 如果有特殊的业务可能需要自行修改
+
+| 转换器参数 | 描述 |
+|-|-|
+| code | 即后端定义的`成功码`字段名 |
+| message | 即后端定义的`错误消息`字段名 |
+| success | 即`成功码`的值等于指定时才算网络请求成功 |
+
+
+
+比如截图中的意为, 当返回的Json中包含state字段且值为ok时请求才算是真正成功才会返回数据, 否则都会抛出异常.
+其中message为错误信息字段名
+
+假设简单的指定名称不能满足你复杂的业务逻辑, 请复制`JSONConvert`
+源码到你项目中修改或者直接自己实现`NetConverter`
+
+> 注意解析器(Gson或者Moshi)的解析对象记得定义为类成员, 这样可以不会导致每次解析都要创建一个新的解析对象,
+> 减少内存消耗
+
+
+## 自定义转换器
+
+通过实现`NetConverter`接口可以编写自己的逻辑网络请求返回的数据, `NetConvert.DEFAULT`
+为默认的转换器支持返回File/String/Response等
+
+框架中自带一个`JSONConverter`可以作为参考或者直接使用. 其可以转换JSON数据.
+
+??? summary "JSONConverter 源码"
+```kotlin
+/**
+* 常见的JSON转换器实现, 如果不满意继承实现自定义的业务逻辑
+*
+* @param success 后端定义为成功状态的错误码值
+* @param code 错误码在JSON中的字段名
+* @param message 错误信息在JSON中的字段名
+*/
+abstract class JSONConvert(
+val success: String = "0",
+val code: String = "code",
+val message: String = "msg"
+) : NetConverter {
+
+ override fun onConvert(succeed: Type, response: Response): R? {
+ try {
+ // 此处是为了继承默认转换器支持的返回类型
+ return NetConverter.onConvert(succeed, response)
+ } catch (e: ConvertException) {
+ val code = response.code
+ when {
+ code in 200..299 -> { // 请求成功
+ val bodyString = response.body?.string() ?: return null
+ return try {
+ val json = JSONObject(bodyString) // 获取JSON中后端定义的错误码和错误信息
+ if (json.getString(this.code) == success) { // 对比后端自定义错误码
+ bodyString.parseBody(succeed)
+ } else { // 错误码匹配失败, 开始写入错误异常
+ val errorMessage = json.optString(
+ message,
+ NetConfig.app.getString(com.drake.net.R.string.no_error_message)
+ )
+ throw ResponseException(response, errorMessage)
+ }
+ } catch (e: JSONException) { // 固定格式JSON分析失败直接解析JSON
+ bodyString.parseBody(succeed)
+ }
+ }
+ code in 400..499 -> throw RequestParamsException(response, code.toString()) // 请求参数错误
+ code >= 500 -> throw ServerResponseException(response, code.toString()) // 服务器异常错误
+ else -> throw ConvertException(response)
+ }
+ }
+ }
+
+ /**
+ * 反序列化JSON
+ *
+ * @param succeed JSON对象的类型
+ * @receiver 原始字符串
+ */
+ abstract fun String.parseBody(succeed: Type): R?
+ }
+
+ ```
+
+JSONConvert的核心逻辑
+
+1. 判断服务器的错误码
+1. 判断后端自定义的错误码
+1. 如果判断发生错误则抛出一个包含错误信息的异常
+1. 如果都判断成功则开始解析数据并return数据对象
+
+在转换器中根据需要你可以在这里加上常见的解密数据, token失效跳转登录, 限制多端登录等逻辑.
+日志信息输出请阅读: [日志记录器](log-recorder.md)
+
+如果是错误信息建议抛出异常, 就可以在全局异常处理器中统一处理, 请阅读:[全局错误处理](error-handle.md)
+
+
\ No newline at end of file
diff --git a/docs/default-response.md b/docs/default-response.md
deleted file mode 100644
index f0986701c..000000000
--- a/docs/default-response.md
+++ /dev/null
@@ -1,50 +0,0 @@
-Net支持请求返回的数据类型取决于你自己的转换器实现(即理论上支持返回任何对象):
-
-# Get<任何对象>("path").await()
-
-如果不自定义转换器默认支持返回以下数据类型
-
-| 函数 | 描述 |
-|-|-|
-| String | 字符串 |
-| ByteArray | 字节数组 |
-| ByteString | 内部定义的一种字符串对象 |
-| File | 文件对象, 这种情况其实应当称为[下载文件](download-file.md) |
-| Response | 最基础的, 包含全部响应信息的对象(响应体/响应头/请求信息等) |
-
-使用示例
-
-```kotlin
-scopeNetLife {
- Get("api").await().headers("响应头名称") // 返回响应头
-}
-```
-
-??? summary "默认使用的是: [NetConverter.DEFAULT](https://github.com/liangjingkanji/Net/blob/master/net/src/main/java/com/drake/net/convert/NetConverter.kt)"
- ```kotlin
- interface NetConverter {
-
- @Throws(Throwable::class)
- fun onConvert(succeed: Type, response: Response): R?
-
- companion object DEFAULT : NetConverter {
- /**
- * 返回结果应当等于泛型对象, 可空
- * @param succeed 请求要求返回的泛型类型
- * @param response 请求响应对象
- */
- override fun onConvert(succeed: Type, response: Response): R? {
- return when {
- succeed === String::class.java && response.isSuccessful -> response.body?.string() as R
- succeed === ByteString::class.java && response.isSuccessful -> response.body?.byteString() as R
- succeed is GenericArrayType && succeed.genericComponentType === Byte::class.java && response.isSuccessful -> response.body?.bytes() as R
- succeed === File::class.java && response.isSuccessful -> response.file() as R
- succeed === Response::class.java -> response as R
- else -> throw ConvertException(response, "An exception occurred while converting the NetConverter.DEFAULT")
- }
- }
- }
- }
- ```
-
-假设这里没有你需要的数据类型请[自定义转换器](/converter/#_3)(例如返回Json或Protocol)
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 01ee9d217..e2138609b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -5,67 +5,65 @@
-## 前言
-
-1. 任何本文档没有提到的功能都可以通过搜索`"OkHttp如何**"`来解决, 因为本框架支持OkHttp所有功能/组件
-1. 建议创建一个Api.kt的`object`单例类存储所有请求路径常量
-1. `Post/Get等`函数属于请求动作. `scope**`等函数属于作用域, 假设你有某个请求需要重复使用建议封装`请求动作`而不是作用域
-1. 如果你觉得文档看不懂或者有歧义那肯定是作者问题, 请反馈给作者或者自我修订
+!!! tip "前言"
+ - Net没有的功能可以搜索`"OkHttp如何XX"`来实现
+ - 强烈建议下载仓库运行sample项目来学习/实践
+ - 如果觉得文档看不懂那肯定是作者问题, 请反馈给作者或者自我修订
## 使用
-这里演示发起网络`请求百度网站`内容的三个步骤
+这里演示发起网络`请求网站内容`的三个步骤
1. 创建作用域
-1. 发起请求
-1. 接收数据
+1. 发起请求动作
+1. 等待数据返回
-=== "单个请求"
+=== "简单请求"
```kotlin
- scopeNetLife { // 创建作用域
- // 这个大括号内就属于作用域内部
- val data = Get("https://github.com/liangjingkanji/Net/").await() // 发起GET请求并返回`String`类型数据
+ scopeNetLife { 创建作用域
+ // 这个大括号内就属于作用域内部
+ val data = Get("https://github.com/liangjingkanji/Net/").await() // 发起GET请求并返回`String`类型数据
}
```
-=== "串行请求"
+=== "同步请求"
```kotlin
scopeNetLife {
- val data = Get("http://www.baidu.com/").await() // 请求A 发起GET请求并返回数据
- val data = Get("https://github.com/liangjingkanji/Net/").await() // 请求B 将等待A请求完毕后发起GET请求并返回数据
+ val userInfo = Get("https://github.com/liangjingkanji/BRV/").await() // 立即请求
+ val config = Get("https://github.com/liangjingkanji/Net/"){
+ param("userId", userInfo.id) // 使用上个请求的数据作为参数
+ }.await() // 请求B 将等待A请求完毕后发起GET请求并返回数据
}
- ```
+```
=== "并发请求"
```kotlin
scopeNetLife {
- // 以下两个网络请求属于同时进行中
- val aDeferred = Get("https://github.com/liangjingkanji/Net/") // 发起GET请求并返回一个对象(Deferred)表示"任务A"
- val bDeferred = Get("https://github.com/liangjingkanji/Net/") // 发起请求并返回"任务B"
-
- // 随任务同时进行, 但是数据依然可以按序返回
- val aData = aDeferred.await() // 等待任务A返回数据
- val bData = bDeferred.await() // 等待任务B返回数据
- }
+ // 以下两个网络请求属于同时进行中
+ val getUserInfoAsync = Get("https://github.com/liangjingkanji/Net/") // 立即请求
+ val getConfigAsync = Get("https://github.com/liangjingkanji/BRV/") // 立即请求
+
+ val userInfo = getUserInfoAsync.await() // 等待数据返回
+ val config = getConfigAsync.await()
+ }
```
-多个网络请求放在同一个作用域内就可以统一控制, 如果你的多个网络请求毫无关联, 你可以创建多个作用域.
+多个网络请求在同一个作用域内可以统一控制, 如果多个网络请求之间毫无关联, 可以创建多个作用域来请求
-> 多进程或Xposed项目要求[初始化](config.md/#_1)
+> 多进程或Xposed项目要求先[初始化](config.md/#_1)
-> 当`Get`或`Post`等函数调用就会开始发起网络请求, `await`只是等待其请求成功返回结果, 所以如果你在`await`后执行的网络请求,这不属于并发(属于串行)
+并发请求错误示例
-并发的错误示例
```kotlin hl_lines="3"
scopeNetLife {
// 请求A
- val aDeferred = Get("https://github.com/liangjingkanji/Net/").await()
- // 请求B, 由于上面使用`await()`函数, 所以必须等待A请求返回结果后才会执行B
- val bDeferred = Get("https://github.com/liangjingkanji/Net/")
+ val userInfo = Get("https://github.com/liangjingkanji/Net/").await()
+ // 由于上面使用`await()`函数, 所以必须等待A请求返回结果后才会执行B
+ val getConfigAsync = Post("https://github.com/liangjingkanji/Net/")
- val bData = bDeferred.await() // 等待任务B返回数据
+ val config = getConfigAsync.await() // 等待任务B返回数据
}
```
@@ -81,38 +79,4 @@ scopeNetLife {
| Response | 最基础的响应 |
| File | 文件对象, 这种情况其实应当称为[下载文件](download-file.md) |
-非以上类型要求[自定义转换器](converter.md)
-
-> 转换器的返回值决定你的网络请求的返回结果类型, 你甚至可以返回null, 前提是泛型为可空类型
-
-
-## RestFul
-Net支持RestFul设计风格
-
-```kotlin
-scopeNetLife {
- tvFragment.text = Get("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Post("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Head("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Put("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Patch("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Delete("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Trace("https://github.com/liangjingkanji/Net/").await()
- tvFragment.text = Options("https://github.com/liangjingkanji/Net/").await()
-}
-```
-
-## 函数
-
-默认在IO线程执行网络请求(通过作用域参数可以控制Dispatch调度器), 要求在协程作用域内执行.
-
-|请求函数|描述|
-|-|-|
-| [Get](api/-net/com.drake.net/-get.html)|标准Http请求方法|
-| [Post](api/-net/com.drake.net/-post.html)|标准Http请求方法|
-| [Head](api/-net/com.drake.net/-head.html)|标准Http请求方法|
-| [Options](api/-net/com.drake.net/-options.html)|标准Http请求方法|
-| [Trace](api/-net/com.drake.net/-trace.html)|标准Http请求方法|
-| [Delete](api/-net/com.drake.net/-delete.html)|标准Http请求方法|
-| [Put](api/-net/com.drake.net/-put.html)|标准Http请求方法|
-| [Patch](api/-net/com.drake.net/-patch.html)|标准Http请求方法|
\ No newline at end of file
+详细查看[转换器](customizer-converter.md), 非以上类型要求[自定义转换器](customizer-converter.md)
\ No newline at end of file
diff --git a/docs/issues.md b/docs/issues.md
index 5c6bd24ce..d927868b8 100644
--- a/docs/issues.md
+++ b/docs/issues.md
@@ -1,8 +1,19 @@
-## 常见问题
-
-- [networkSecurityConfig导致无法打包](https://github.com/liangjingkanji/Net/issues/57)
-- [没有我需要的请求参数类型](https://github.com/liangjingkanji/Net/issues/56)
-- [没有我需要的功能](https://github.com/liangjingkanji/Net/issues/58)
-- [使用inline reified封装请求函数导致崩溃](https://github.com/liangjingkanji/Net/issues/54)
-- [错误提示 toast 内存泄漏](https://github.com/liangjingkanji/Net/issues/65)
-- [如何使用Cookie](https://github.com/liangjingkanji/Net/issues/51)
+Net最大的特点在于完美支持OkHttp的所有功能组件,
+而Android上大部分都是基于OkHttp的网络请求解决方案
+所以如果存在Net没有实现的功能可以百度/谷歌搜索`"OkHttp如何实现XX"`, 然后可以很容易在Net中使用
+
+## 低版本兼容
+
+如果你是在 Android 5 (API level 21)
+以上开发建议使用最新版本: [Net](https://github.com/liangjingkanji/Net)
+如果要求低至 Android 4.4 (API level 19)
+请使用兼容版本: [Net-okhttp3](https://github.com/liangjingkanji/Net-okhttp3)
+
+如果需更低版本支持建议拉取仓库修改`minSdkVersion`后编译成aar使用
+
+## 开发者交流
+
+- [反馈问题](https://github.com/liangjingkanji/Net/issues)
+- [其他开发者提及问题](https://github.com/liangjingkanji/Net/issues)
+- [交流社区](https://github.com/liangjingkanji/Net/discussions)
+-
diff --git a/docs/request.md b/docs/request.md
index 1577fafbb..8d37cb98b 100644
--- a/docs/request.md
+++ b/docs/request.md
@@ -1,73 +1,44 @@
-Net中关于请求的类只有两个类和他们共同的抽象父类
-```kotlin
-BaseRequest
- |- UrlRequest
- |- BodyRequest
-```
-
-
-根据请求方法不同使用的Request也不同
+!!! question "请求参数"
+ 根据请求方式不同请求参数分为两类
-```kotlin
-GET, HEAD, OPTIONS, TRACE, // Url request
-POST, DELETE, PUT, PATCH // Body request
-```
+ UrlRequest: GET, HEAD, OPTIONS, TRACE // Query(请求参数位于Url中)
+ BodyRequest: POST, DELETE, PUT, PATCH // Body(请求体为流)
-代码示例
+使用示例
```kotlin
scopeNetLife {
- Get("api") {
- // this 即为 UrlRequest
- }.await()
-
- Post("api") {
- // this 即为 BodyRequest
+ val userInfo = Post(Api.LOGIN) {
+ param("username", "drake")
+ param("password", "6f2961eb44b12123393fff7e449e50b9de2499c6")
}.await()
}
```
-## 请求参数
-
-```kotlin
-scopeNetLife { // 创建作用域
- // 这个大括号内就属于作用域内部
- val data = Get("https://github.com/liangjingkanji/Net/"){
- param("u_name", "drake")
- param("pwd", "123456")
- }.await() // 发起GET请求并返回`String`类型数据
-}
-```
-
-|请求函数|描述|
+|函数|描述|
|-|-|
-|`param`|支持基础类型/文件/RequestBody/Part|
-|`json`|请求参数为JSONObject/JsonArray/String|
-|`setQuery/addQuery`|设置/添加Url参数, 如果当前请求为Url请求则该函数等效于`param`函数|
+|`param`| Url请求时为Query, Body请求时为表单/文件|
+|`json`|JSON字符串|
+|`setQuery/addQuery`|Url中的Query参数, 如果当为Url请求则该函数等效`param`|
|`setHeader/addHeader`|设置/添加请求头|
-如果没有添加文件/流那么就是通过BodyRequest内部的`FormBody`发起请求. 反之就是通过`MultipartBody`发起请求.
-
-> 当然你可以完全自定义Body来请求, 譬如以下的Json请求
-
+## JSON请求
-## Json请求
+这里仅演示三种参数类型上传JSON, 详细请查看方法重载
-这里提供三种创建Json请求的示例代码. 酌情选用
-
-=== "JSON键值对(推荐)"
+=== "Pair(推荐)"
```kotlin
val name = "金城武"
val age = 29
val measurements = listOf(100, 100, 100)
-
- scopeNetLife {
- tvFragment.text = Post("api") {
- // 只支持基础类型的值, 如果值为对象或者包含对象的集合/数组会导致其值为null
- json("name" to name, "age" to age, "measurements" to measurements)
- }.await()
- }
+
+ scopeNetLife {
+ tvFragment.text = Post("api") {
+ // 只支持基础类型的值, 如果值为对象或者包含对象的集合/数组会导致其值为null
+ json("name" to name, "age" to age, "measurements" to measurements)
+ }.await()
+ }
```
=== "JSONObject"
@@ -87,34 +58,34 @@ scopeNetLife { // 创建作用域
}
```
-=== "自定义的body"
+=== "自定义RequestBody"
```kotlin
val name = "金城武"
val age = 29
val measurements = listOf(100, 100, 100)
-
+
scopeNetLife {
tvFragment.text = Post("api") {
- body = MyJsonBody(name, age, measurements)
+ body = CustomizerJSONBody(name, age, measurements)
}.await()
}
```
-对于某些可能JSON请求参数存在固定值:
+个别项目JSON中存在固定值, 开发者不想每次都写一遍:
-1. 可以考虑继承RequestBody来扩展出自己的新的Body对象, 然后赋值给`body`字段
-2. 添加请求拦截器[RequestInterceptor](/interceptor/#_1)
+1. 实现RequestBody默认添加参数
+2. 使用请求拦截器来添加全局参数 [RequestInterceptor](/interceptor/#_1)
-## 自定义请求函数
+## 自定义扩展函数
-前面提到`json(Pair)`函数不支持对象值, 因为框架内部使用的`org.json.JSONObject`其不支持映射对象字段
+前面提到`json()`不能传对象, 因为内部使用`org.json.JSONObject`不支持映射对象字段
-这里可以创建扩展函数来支持你想要的Json解析框架, 比如以下常用的Json解析框架示例
+那我们可以自己创建扩展函数来使用支持解析对象的序列化框架, 如下
=== "Gson"
```kotlin
fun BodyRequest.gson(vararg body: Pair) {
- this.body = Gson().toJson(body.toMap()).toRequestBody(MediaConst.JSON)
+ this.body = Gson().toJson(body.toMap()).toRequestBody(MediaConst.JSON)
}
```
=== "FastJson"
@@ -135,23 +106,25 @@ scopeNetLife {
}
```
-- 举一反三可以创建其他功能自定义的请求函数
-- 扩展函数要求为顶层函数, 即直接在文件中 (kotlin基础语法)
-
## 全局请求参数
-对于动态生成的全局请求头或参数都可以通过实现`RequestInterceptor`来设置全局的请求拦截器来添加, 如果RequestInterceptor不满足你的需求可以使用拦截器(Interceptor)来实现
+使用`RequestInterceptor`请求拦截器添加全局参数/请求头, 如果不满足需求可以使用更复杂的 Interceptor`
```kotlin
-NetConfig.initialize("https://github.com/liangjingkanji/Net/", this) {
- // 添加请求拦截器, 每次请求都会触发的, 可配置全局/动态参数
- setRequestInterceptor(MyRequestInterceptor())
+class GlobalHeaderInterceptor : RequestInterceptor {
+
+ /** 本方法每次请求发起都会调用, 这里添加的参数可以是动态参数 */
+ override fun interceptor(request: BaseRequest) {
+ request.setHeader("client", "Android")
+ request.setHeader("token", UserConfig.token)
+ }
}
```
-## 请求函数
-
-关于全部的请求配置选项推荐阅读函数文档或者阅读源码. Net提供清晰的函数结构浏览方便直接阅读源码
-
-
+```kotlin
+NetConfig.initialize(Api.HOST, this) {
+ setRequestInterceptor(GlobalHeaderInterceptor())
+}
+```
+更多请求参数相关请阅读Api文档/函数列表
\ No newline at end of file
diff --git a/docs/scope.md b/docs/scope.md
index 85d631e39..7cff2229d 100644
--- a/docs/scope.md
+++ b/docs/scope.md
@@ -1,28 +1,28 @@
-协程请求要求在协程的作用域中调用, 这里介绍如何创建不同的作用域获取不同的功能
+创建不同协程作用域可以实现不同的功能
-本质上Net的请求动作函数返回的是一个Deferred对象. 可以在任何协程作用域内执行. 但是考虑到完整的生命周期和错误处理等推荐使用Net内部定义的作用域.
+实际上Net的请求函数返回的一个`Deferred`, 可以在任何协程作用域内执行, 但是考虑到生命周期/错误处理等建议使用Net提供的作用域函数
-> 发生在Net作用域内的任何异常都会被捕获, 有效减少应用崩溃率. 如果配合[kotlin-serialization](kotlin-serialization.md)还可以解决因服务器返回null字段导致的崩溃
+!!! Success "减少崩溃"
+ Net所有作用域内抛出异常都会被捕获到全局错误处理器, 可以防止应用崩溃
## 异步任务的作用域
-创建可以捕捉异常的协程作用域, 但是不会触发`NetErrorHandler`(全局错误处理者). 该作用域于一般用于普通的异步任务
+可以捕捉异常的协程作用域, 但不会触发`NetErrorHandler`(全局错误处理器), 该作用域一般用于构建普通异步任务
|函数|描述|
|-|-|
-|`scope`|创建最基础的作用域, 所有作用域都包含异常捕捉|
-|`scopeLife`|创建跟随生命周期取消的作用域|
+|`scope`|创建最基础的作用域|
+|`scopeLife`|创建跟随生命周期自动取消的作用域|
|`ViewModel.scopeLife`|创建跟随ViewModel生命周期的作用域, [如何在ViewModel创建作用域](view-model.md)|
## 网络请求的作用域
-网络请求的作用域可以根据生命周期自动取消网络请求, 发生错误也会自动弹出吐司(可以自定义或者取消), 并且具备一些场景的特殊功能(例如加载对话框, 缺省页, 下拉刷新等)
+除异步任务外还适用于网络请求场景的作用域, 对比上面`异步任务的作用域`区别:
-网络请求的作用域比上面提到的异步任务的作用域多的区别就是
-
-1. 发生错误会触发全局错误处理`NetErrorHandler`
-2. 具备一些特殊场景功能, 比如自动下拉刷新, 自动显示加载库等
+1. 发生错误自动吐司(可以自定义或者取消)
+2. 发生错误会触发全局错误处理`NetErrorHandler`
+3. 具备一些特殊场景功能, 比如根据网络请求结果自动处理下拉刷新/上拉加载/缺省页/加载框的状态
| 函数 | 描述 |
|-|-|
@@ -33,23 +33,25 @@
|`PageRefreshLayout.scope`|创建跟随[PageRefreshLayout](https://github.com/liangjingkanji/BRV)生命周期的作用域|
|`StateLayout.scope`|创建跟随[StateLayout](https://github.com/liangjingkanji/BRV)生命周期的作用域|
-
-> PageRefreshLayout/StateLayout 属于[BRV](https://github.com/liangjingkanji/BRV)框架中的布局, 用于支持[自动化缺省页/下拉刷新](auto-state.md)
-
-
+!!! Failure "区分函数接受者"
+ 注意`StateLayout.scope`等存在`函数接受者`的方法和`scope`属于两个方法, 严禁混用
-> 如果想了解详细的协程使用方式, 可以查看一篇文章: [最全面的Kotlin协程: Coroutine/Channel/Flow 以及实际应用](https://juejin.im/post/6844904037586829320)
+!!! quote "第三方库支持"
+ PageRefreshLayout/StateLayout 属于第三方开源项目 [BRV](https://github.com/liangjingkanji/BRV)
+ 框架中的布局, 可用于支持[自动化缺省页/下拉刷新](auto-state.md)
-有时候可能面临嵌套的`scope*`函数或者作用域内有子作用域情况, 这个时候的生命周期是如何
+如果想更了解协程使用方式,
+可以阅读一篇文章: [最全面的Kotlin协程: Coroutine/Channel/Flow 以及实际应用](https://juejin.im/post/6844904037586829320)
+## 嵌套作用域
-## 嵌套Scope
+有时候可能面临内嵌`scopeXX`函数(嵌套作用域), 这时候生命周期如下
```kotlin hl_lines="5"
-scopeNet {
+scopeNetLife {
val task = Post("api0").await()
- scopeNet {
+ scopeNetLife {
val task = Post("api0").await() // 此时发生请求错误
}.catch {
// A
@@ -59,9 +61,9 @@ scopeNet {
}
```
-- 以下嵌套作用域错误将会仅发生在`A`处, 并被捕获, 同时不影响外部`scopeNet`的请求和异常捕获
-- 两个`scopeNet`的异常抛出和捕获互不影响
-- `scopeNet/scopeDialog/scope`等函数同理
+- 错误将在`A`处可以获取到, 且不影响外部`scopeNetLife`的请求
+- 两个`scopeNetLife`的异常抛出和捕获互不影响
+- `scopeXX()`等函数同理
## 子作用域
diff --git a/docs/sync-request.md b/docs/sync-request.md
index 569781cd1..6dcfd61e6 100644
--- a/docs/sync-request.md
+++ b/docs/sync-request.md
@@ -1,8 +1,13 @@
-Net支持在当前线程执行, 会阻塞当前线程的同步请求 -- `execute`
+Net支持在当前线程执行阻塞线程的同步请求
-这里介绍的是不使用协程的同步请求. 由于Android主线程不允许发起网络请求, 这里我们得随便创建一个子线程才可以开发起同步请求
+!!! question "什么是同步请求"
+ 即上个请求结束才会发起下个请求, 实际上协程也可以实现但是他不会阻塞线程
-=== "同步请求"
+ 同步请求应用场景一般是在拦截器(执行在子线程)中使用
+
+因为Android主线程不允许发起网络请求, 这里我们创建一个子线程来演示
+
+=== "返回数据"
```kotlin
thread {
@@ -12,31 +17,22 @@ Net支持在当前线程执行, 会阻塞当前线程的同步请求 -- `execute
}
}
```
-=== "toResult"
+
+=== "返回Result"
```kotlin
thread {
- val result = Net.post("api").toResult().getOrDefault("请求发生错误, 我这是默认值")
+ val result = Net.post("api").toResult().getOrDefault("请求发生错误, 我是默认值")
tvFragment?.post {
tvFragment?.text = result // view要求在主线程更新
}
}
```
-1. `execute`在请求发生错误时会抛出异常
-2. `toResult`不会抛出异常, 通过`exception*`函数来获取异常信息, 且支持默认值等特性
+1. `execute`在请求错误时会直接抛出异常
+2. `toResult`不会抛出异常, 可`getOrThrow/exceptionOrNull`等返回异常对象
+
+
-> 同步请求应用场景一般是在拦截器中使用, 拦截器默认是子线程
-作用域具体介绍可以看[创建作用域](scope.md)
-|请求函数|描述|
-|-|-|
-|Net.get|标准Http请求方法|
-|Net.post|标准Http请求方法|
-|Net.head|标准Http请求方法|
-|Net.options|标准Http请求方法|
-|Net.trace|标准Http请求方法|
-|Net.delete|标准Http请求方法|
-|Net.put|标准Http请求方法|
-|Net.patch|标准Http请求方法|
diff --git a/mkdocs.yml b/mkdocs.yml
index f155b67cf..813af00f1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -27,24 +27,33 @@ theme:
- search.suggest
- search.share
- content.code.copy
+ - content.code.annotate
plugins:
- offline
- search:
separator: '[\s\-,:!=\[\]()"/]+|(?!\b)(?=[A-Z][a-z])|\.(?!\d)|&[lg]t;'
lang:
- - en
- - zh
-
+ - en
+ - zh
markdown_extensions:
+ - attr_list
+ - def_list
+ - md_in_html
- toc:
permalink: true
- pymdownx.tasklist:
custom_checkbox: true
- admonition
+ - pymdownx.highlight
- pymdownx.details
- pymdownx.superfences
- pymdownx.inlinehilite
- - pymdownx.tabbed
+ - pymdownx.tabbed:
+ alternate_style: true
+ - pymdownx.caret
+ - pymdownx.keys
+ - pymdownx.mark
+ - pymdownx.tilde
nav:
- 使用: index.md
@@ -54,8 +63,8 @@ nav:
- 请求参数: request.md
- 全局配置: config.md
- 请求结果:
- - 默认结果: default-response.md
- - 自定义转换器: converter.md
+ - 转换器: converter.md
+ - 自定义转换器: customizer-converter.md
- 自定义结构解析: convert-special.md
- Kotlin-Serialization: kotlin-serialization.md
- 数据类生成插件: model-generate.md
@@ -92,7 +101,7 @@ nav:
- Callback: callback.md
- 轮询器/倒计时: interval.md
- 社区讨论: https://github.com/liangjingkanji/Net/discussions
- - 常见问题: https://github.com/liangjingkanji/Net/blob/master/docs/issues.md
+ - 常见问题: issues.md
- 项目实践: practice.md
- 更新日志: updates.md
- 3.x文档: api/index.html