【发布时间】:2021-10-12 11:47:53
【问题描述】:
我遇到了 Alamofire 请求和拦截器的问题。
我的服务器有两种类型的响应 -> 成功响应是一种对象,而错误响应始终是消息什么是错的。 我创建了一个示例代码来创建一个非常自己的函数来解码两种类型的响应,这似乎运作良好。
在调用 Alamofire 适配函数后出现问题(为每个请求添加一个 cookie)-> 在我的 .responseTwoDecodable 中,我将始终得到响应为 nil,但状态码为 200,一切正常,服务器返回对象但 alamofire 忽略了它。
这是我的每个请求的代码:
func request<T: Decodable>(
_ url: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
decoder: JSONDecoder = JSONDecoder(),
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil
) -> Future<T, ServerError> {
return Future({ promise in
AF.request(
url,
method: method,
parameters: parameters,
encoding: JSONEncoding.default,
headers: headers
interceptor: interceptor ?? self
)
.validate(statusCode: [200, 201, 204, 401]
.responseTwoDecodable(of: T.self) { response in
switch response {
case .success(let value):
promise(.success(value))
case .failure(let error):
promise(.failure(error))
}
}
})
}
这里是适配函数:
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, ServerError>) -> Void) {
let request = urlRequest
if let accessToken = UserDefaults.standard.string(forKey: Constants.accessToken), let refreshToken = UserDefaults.standard.string(forKey: Constants.refreshToken) {
let access = [
HTTPCookiePropertyKey.domain: Constants.cookieDomain,
HTTPCookiePropertyKey.path: Constants.cookieAccessPath,
HTTPCookiePropertyKey.name: Constants.accessToken,
HTTPCookiePropertyKey.value: accessToken
]
let refresh = [
HTTPCookiePropertyKey.domain: Constants.cookieDomain,
HTTPCookiePropertyKey.path: Constants.cookieRefreshPath,
HTTPCookiePropertyKey.name: Constants.refreshToken,
HTTPCookiePropertyKey.value: refreshToken
]
if let accessCookie = HTTPCookie(properties: access), let refreshCookie = HTTPCookie(properties: refresh) {
AF.session.configuration.httpCookieStorage?.setCookie(accessCookie)
AF.session.configuration.httpCookieStorage?.setCookie(refreshCookie)
completion(.success(request))
}
}
completion(.success(request))
}
这是我的两个可解码的解码代码:
struct ErrorMessage: Error, Decodable {
let message: String
}
struct ServerError: Error {
var message: String
var code: ServerErrorCodes
let args: [String]?
}
enum ServerErrorCodes: Int {
case unauthorized = 401
case forbidden = 403
case internalServerError = 500
case notFound = 404
case conflict = 409
case unknown
case emptyResponse
case unserialized
case userInput
case coreData
}
final class TwoDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
lazy var decoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return decoder
}()
private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: decoder)
private lazy var errorSerializer = DecodableResponseSerializer<ErrorMessage>(decoder: decoder)
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Result<T, ServerError> {
guard error == nil else { return .failure(ServerError(message: "Unknown error", code: .unknown, args: [])) }
guard let response = response else { return .failure(ServerError(message: "Empty response", code: .emptyResponse, args: [])) } // HERE I AM GETTING A NIL AS A RESPONSE, BUT SERVER RESPONDED WITH CORRECT BODY AND 200 AS STATUS CODE
do {
print(response.debugDescription)
if response.statusCode < 200 || response.statusCode >= 300 {
let serverMessage = try errorSerializer.serialize(request: request, response: response, data: data, error: nil)
let responseCode: ServerErrorCodes
if let code = ServerErrorCodes(rawValue: response.statusCode) {
responseCode = code
} else {
responseCode = .unknown
}
let result = ServerError(message: serverMessage.message, code: responseCode, args: nil)
return .failure(result)
} else {
let result = try successSerializer.serialize(request: request, response: response, data: data, error: nil)
return .success(result)
}
} catch(let err) {
return .failure(ServerError(message: "Could not serialize body", code: .unserialized, args: [String(data: data!, encoding: .utf8)!, err.localizedDescription]))
}
}
}
extension DataRequest {
@discardableResult func responseTwoDecodable<T: Decodable>(queue: DispatchQueue = DispatchQueue.global(qos: .userInitiated), of t: T.Type, completionHandler: @escaping (Result<T, ServerError>) -> Void) -> Self {
return response(queue: .main, responseSerializer: TwoDecodableResponseSerializer<T>()) { response in
switch response.result {
case .success(let result):
completionHandler(result)
case .failure(let error):
completionHandler(.failure(ServerError(message: "Other error", code: .unknown, args: [error.localizedDescription])))
}
}
}
}
我是 Alamofire 的新手,所以如果可以以更好的方式完成某些事情,我将感谢您的帮助或分享您的想法!有谁知道为什么会发生这种情况?谢谢!
【问题讨论】:
-
您是否检查过
error值以查看您是否因其他原因而失败?另外,您可以尝试使用其中一种内置响应处理程序,例如responseString,看看它是否打印出您预期的响应? -
这似乎是一个非常奇怪的问题......我只需重新启动 Xcode 并且无需更改一行代码即可获得预期的结果。删除派生数据后,我得到了同样的错误,但是 responseString 中充满了良好的数据,错误和响应为零。我仍然坚持这一点,没有任何进展:
ERROR: nilREQUEST: Optional(https://admin.eu/backend_develop/api/user?)RESPONSE: nil`DATA: Optional(142 bytes)RESPONSE AS STRING: success("{\"admin\": true, \"name\": \"Peter\", \"id\": 35, \"registered\": true, \"registered_on\": \"2021-07-17\"\n")
标签: swift error-handling alamofire