如何结合NWPathMonitor与Alamofire实现全局网络校验及请求拦截逻辑
实现方案
这里提供两种落地成本低、兼容性强的方案,你可以根据现有项目的代码存量选择:
方案1:统一请求入口加前置校验(推荐新项目使用)
把所有业务层的请求调用收敛到NetworkManager的统一公共方法里,在方法最开始插入网络状态校验逻辑,后续所有新增请求自动复用逻辑,无需重复写判断:
import Alamofire class NetworkManager { static let shared = NetworkManager() private init() {} // 所有业务请求必须走这个统一入口 func request( url: String, method: HTTPMethod, parameters: Parameters? = nil, headers: HTTPHeaders? = nil, success: @escaping (Any) -> Void, failure: @escaping (Error) -> Void ) { // 前置校验网络状态 guard MonitorManager.shared.isReachable else { // 弹全局无网络提示 showNoNetworkAlert() // 返回标准无网络错误,业务层可统一识别处理 let noNetworkError = NSError( domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: [NSLocalizedDescriptionKey: "当前无网络连接,请检查网络设置"] ) failure(noNetworkError) return } // 网络正常才发起实际请求 AF.request(url, method: method, parameters: parameters, headers: headers) .validate() .responseJSON { response in switch response.result { case .success(let value): success(value) case .failure(let error): failure(error) } } } // 全局无网络弹窗 private func showNoNetworkAlert() { DispatchQueue.main.async { // 确保UI操作在主线程执行 guard let topVC = UIApplication.shared.keyWindow?.rootViewController?.topMostVC() else { return } let alert = UIAlertController(title: "网络异常", message: "当前无可用网络,请检查后重试", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) topVC.present(alert, animated: true) } } } // 工具扩展:获取当前顶层控制器用于弹窗 extension UIViewController { func topMostVC() -> UIViewController { if let presentedVC = self.presentedViewController { return presentedVC.topMostVC() } if let navVC = self as? UINavigationController { return navVC.visibleViewController?.topMostVC() ?? navVC } if let tabVC = self as? UITabBarController { return tabVC.selectedViewController?.topMostVC() ?? tabVC } return self } }
这个方案的优势是逻辑可控,后续要加公共参数、签名、统一响应解析等逻辑都可以直接在入口方法里扩展。
方案2:用Alamofire拦截器实现底层拦截(适合存量请求多的老项目)
如果你的项目已经有大量零散的Alamofire请求,不想逐个改调用入口,可以用Alamofire自带的RequestInterceptor机制,在请求发出的底层统一拦截校验:
// 自定义网络拦截器 class NetworkCheckInterceptor: RequestInterceptor { func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) { guard MonitorManager.shared.isReachable else { // 无网络直接返回错误,不会发起实际网络请求 let noNetworkError = NSError( domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: [NSLocalizedDescriptionKey: "当前无网络连接,请检查网络设置"] ) // 弹全局提示 DispatchQueue.main.async { NetworkManager.shared.showNoNetworkAlert() } completion(.failure(noNetworkError)) return } // 网络正常放行请求 completion(.success(urlRequest)) } }
然后在NetworkManager里初始化绑定了拦截器的Alamofire Session,替换掉默认的全局AF实例:
class NetworkManager { static let shared = NetworkManager() // 自定义Session,绑定拦截器 private let session: Session = { let config = URLSessionConfiguration.af.default let interceptor = NetworkCheckInterceptor() return Session(configuration: config, interceptor: interceptor) }() private init() {} // 后续所有请求都用这个session发起即可自动触发网络校验 func request(/* 请求参数 */) { session.request(/* 传参 */).responseJSON { /* 处理响应 */ } } }
注意事项
- 如果有离线缓存类的特殊请求,可以加白名单机制,无网络时跳过校验直接走本地缓存逻辑
- MonitorManager的网络状态建议用系统
NWPathMonitor或Alamofire自带的NetworkReachabilityManager实现,确保状态实时性 - 所有UI相关操作(弹窗)必须切换到主队列执行,避免子线程调用UI导致崩溃
内容的提问来源于stack exchange,提问作者Dogan Altinbas
相关产品推荐
相关产品推荐

