如何始终使用 Moya/Alamofire 在 HTTP 请求中发送默认参数?
How to always send default parameters in HTTP request using Moya/Alamofire?
我的服务器端总是需要客户端发送令牌。作为开发人员,我可以忘记它。现在,我想提出一些解决方案,迫使我不要忘记发送这样一个必需的参数(它们可以在未来增长,例如,服务器可以需要设备的语言)。解决方案似乎很简单:我应该有一些 ServerManager
获取参数(例如,["user": "John"])和 URL 路径。并且它还应该附加必需的参数,例如 ["token": "abscsdcds"]。伪代码如下所示:
struct ServerManager {
func request(params: [String: Any], path: String, completion: (ResponseModel) -> Void) {
/// appending required default params
var paramsToSend = params
paramsToSend["token"] = Token.token
/// making request here
}
}
每当我进行网络调用时,我都可以毫无疑问地使用 ServerManager
发送所有必需的参数和 return 响应。
但事情变得复杂,因为我使用 Moya
进行联网。它由 enumerations
制作,应该实现 TargetType
协议。我可以有几十个 enums
,比如 RateAPI
、MovieAPI
等等......这意味着我的 ServerManager
应该接受 TargetType
和使用 [=24 的 HTTP 请求=].这是:
func request<T>(type: TargetType, completion: (ResponseModel<T>) -> Void) {
/// appending required default params
moyaProvider.request(MultiTarget(type)) { response in
/// parse it
}
}
我可以简单地使用上面的函数传递 TargetType
,它 return 是我的回应。我可以使用上面的函数如下:
ServerManager.shared.request(target: MovieApi.list(params)) { (response) in
}
但是params
上面的变量应该总是包含token。这意味着每当我发出网络请求时,我都应该写 params["token"] = "myToken"
。是代码重复。我想创建一些包含我所需参数的基础 RequestModel
。然后我可以拥有 RequestModel
的不同子 classes,将其字段附加到所需的参数。但是这个解决方案很容易被误导(例如,subclass 可以发送自己的参数而忘记父 class 参数)。
看来是我设计的问题。是否有解决上述问题的设计模式?或者我们是否在 Moya/Alamofire 中内置了默认发送一些参数给每个请求的解决方案?
通常服务器 api 从 TTPHeaderFields 获取令牌,使用 Moya,您可以轻松地在一些 class 中更改您的 defaultEndpointMapping,例如 ApiGenerator 一些方法如:
static func request<T : Decodable, E: TargetType>(targetApi : E, responseModel : T.Type, success successCallBack: @escaping (Response<T>) -> Void, error errorCallBack: @escaping (Error) -> Void) -> Disposable {
...
}
在这个方法中:
let endpointClosure = { (target: E ) -> Endpoint in
let defaultEndpoint = MoyaProvider.defaultEndpointMapping(for: target)
let cookie = String(format: "JSESSIONID=%@;SPRING_SECURITY_REMEMBER_ME_COOKIE=%@", AppSettings.shared.setting.sessionId, AppSettings.shared.setting.rememberMeCookie )
return defaultEndpoint.adding(newHTTPHeaderFields:
[
"X-Client": "ios",
"Cookie" : cookie
]
)
}
并将其添加到:
let provider = MoyaProvider<E>(endpointClosure: endpointClosure, plugins: [
NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))])
然后完成剩下的工作。但在你的情况下,我建议创建你的 ApiGenerator class 并在其中自定义你的 TargetApi.Task ,如下所示:
switch defaultEndpoint.task {
case .requestParameters(parameters: /*Append new params here*/ , encoding: JSONEncoding.default):
...
default:
...
}
我的服务器端总是需要客户端发送令牌。作为开发人员,我可以忘记它。现在,我想提出一些解决方案,迫使我不要忘记发送这样一个必需的参数(它们可以在未来增长,例如,服务器可以需要设备的语言)。解决方案似乎很简单:我应该有一些 ServerManager
获取参数(例如,["user": "John"])和 URL 路径。并且它还应该附加必需的参数,例如 ["token": "abscsdcds"]。伪代码如下所示:
struct ServerManager {
func request(params: [String: Any], path: String, completion: (ResponseModel) -> Void) {
/// appending required default params
var paramsToSend = params
paramsToSend["token"] = Token.token
/// making request here
}
}
每当我进行网络调用时,我都可以毫无疑问地使用 ServerManager
发送所有必需的参数和 return 响应。
但事情变得复杂,因为我使用 Moya
进行联网。它由 enumerations
制作,应该实现 TargetType
协议。我可以有几十个 enums
,比如 RateAPI
、MovieAPI
等等......这意味着我的 ServerManager
应该接受 TargetType
和使用 [=24 的 HTTP 请求=].这是:
func request<T>(type: TargetType, completion: (ResponseModel<T>) -> Void) {
/// appending required default params
moyaProvider.request(MultiTarget(type)) { response in
/// parse it
}
}
我可以简单地使用上面的函数传递 TargetType
,它 return 是我的回应。我可以使用上面的函数如下:
ServerManager.shared.request(target: MovieApi.list(params)) { (response) in
}
但是params
上面的变量应该总是包含token。这意味着每当我发出网络请求时,我都应该写 params["token"] = "myToken"
。是代码重复。我想创建一些包含我所需参数的基础 RequestModel
。然后我可以拥有 RequestModel
的不同子 classes,将其字段附加到所需的参数。但是这个解决方案很容易被误导(例如,subclass 可以发送自己的参数而忘记父 class 参数)。
看来是我设计的问题。是否有解决上述问题的设计模式?或者我们是否在 Moya/Alamofire 中内置了默认发送一些参数给每个请求的解决方案?
通常服务器 api 从 TTPHeaderFields 获取令牌,使用 Moya,您可以轻松地在一些 class 中更改您的 defaultEndpointMapping,例如 ApiGenerator 一些方法如:
static func request<T : Decodable, E: TargetType>(targetApi : E, responseModel : T.Type, success successCallBack: @escaping (Response<T>) -> Void, error errorCallBack: @escaping (Error) -> Void) -> Disposable {
...
}
在这个方法中:
let endpointClosure = { (target: E ) -> Endpoint in
let defaultEndpoint = MoyaProvider.defaultEndpointMapping(for: target)
let cookie = String(format: "JSESSIONID=%@;SPRING_SECURITY_REMEMBER_ME_COOKIE=%@", AppSettings.shared.setting.sessionId, AppSettings.shared.setting.rememberMeCookie )
return defaultEndpoint.adding(newHTTPHeaderFields:
[
"X-Client": "ios",
"Cookie" : cookie
]
)
}
并将其添加到:
let provider = MoyaProvider<E>(endpointClosure: endpointClosure, plugins: [
NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))])
然后完成剩下的工作。但在你的情况下,我建议创建你的 ApiGenerator class 并在其中自定义你的 TargetApi.Task ,如下所示:
switch defaultEndpoint.task {
case .requestParameters(parameters: /*Append new params here*/ , encoding: JSONEncoding.default):
...
default:
...
}