Swift Moya刷新过期Token

2,332 阅读1分钟

1、设置在Moya的API文件中添加validationType,设置为successCodes,不设置的话401会被Moya识别为正常网络请求,无法触发func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)

public var validationType: ValidationType {
    return .successCodes
}

2、设置拦截器 设置401为failure触发func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)

import UIKit
import Moya
import SwiftyJSON
import Alamofire

class OAuthPluginType: PluginType {
    // 准备发起请求。我们可以在这里对请求进行修改,比如再增加一些额外的参数。
    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        return request
    }

    // 开始发起请求。我们可以在这里显示网络状态指示器。
    func willSend(_ request: RequestType, target: TargetType) {
    
    }

    // 收到请求响应。我们可以在这里根据结果自动进行一些处理,比如请求失败时将失败信息告诉用户,或者记录到日志中。
    func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {

    }

    // 处理请求结果。我们可以在 completion 前对结果进行进一步处理。
    func process(_ result: Result<Response, MoyaError>, target: TargetType) -> Result<Response, MoyaError> {
        switch result {
        case .success(let response):
            let newResponse = getResponse(response: response)
            if newResponse.statusCode == 401 {
                return .failure(MoyaError.jsonMapping(newResponse))
            } else {
                return .success(newResponse)
            }
        case .failure(_):
            break
        }
        return result
    }
    // 非标准rest返回需要加工一下
    func getResponse(response: Response) -> Response {
        let json = JSON(response.data)
        do {
            let data = try json["data"].rawData()
            return Response(statusCode: json["code"].intValue, data: data, request: response.request, response: response.response)
        } catch {
            return Response(statusCode: json["code"].intValue, data: Data(), request: response.request, response: response.response)
        }
    }
}

3、设置RequestInterceptor

let requestInterceptor = RequestInterceptor()
let session = Session(interceptor: requestInterceptor)
class RequestInterceptor: RequestInterceptor {
    let disposeBag = DisposeBag()
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        var request = urlRequest
        if let token = AuthManager.shared.token?.token {
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            print(request.headers)
        }
        completion(.success(request))
    }

    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
            completion(.doNotRetry)
            return
        }

        // 确保只重试一次,否则就无限重试下去了
        guard request.retryCount == 0 else { return completion(.doNotRetry) }

        if let refreshToken = AuthManager.shared.token?.refreshToken {
            let restApi = RestApi(provider: Networking.defaultNetworking())
            restApi.refreshToken(refreshToken: refreshToken).asObservable().subscribe(onNext: { token in
                AuthManager.setToken(token: token)
                completion(.retry)
            }).disposed(by: disposeBag)
        } else {
            completion(.doNotRetry)
        }
    }
}