实现原理
绝大部分的网络请求在 iOS 中通过 NSURLProtocol 抽象类进行处理。通常,我们可以通过重载 NSURLProtocol 实现网络请求的拦截和过滤,这是一种常见的做法。然而,尽管 NSURLProtocol 能够拦截基于 NSURLSession 和 NSURLConnection 的网络请求,但并非所有网络请求问题都能被其完全解决。
这是因为 NSURLProtocol 只能拦截 NSURLSession 和 NSURLConnection 相关的网络请求。目前主流的 iOS 网络库(如 AFNetworking、Alamofire 等)都建立在 NSURLSession 或 NSURLConnection 的基础之上,这些网络库发起的网络请求都可以被 NSURLProtocol 拦截。
不过,值得注意的是,基于 CFNetwork 或 WKWebView 的网络请求无法被 NSURLProtocol 拦截。比如 ASIHTTPRequest、MKNetworkKit 等网络库就是基于 CFNetwork 的,因此这些网络库发出的请求无法被 NSURLProtocol 拦截。
实现步骤
创建NSURLProtocol子类
#import "ReplaceURLProtocol.h"
// 为了避免canInitWithRequest和canonicalRequestForRequest的死循环
static NSString *const URLProtocolHandledKey = @"URLProtocolHandledKey";
// 老url网址
static NSString *const old_url = @"baidu.com";
// 新url网址
static NSString *const new_url = @"google.com";
@interface ReplaceURLProtocol()<NSURLSessionDelegate>
@property(nonatomic,strong)NSURLSession * session;
@end
@implementation ReplaceURLProtocol
+(BOOL)canInitWithRequest:(NSURLRequest *)request
{
return YES;
}
//改变请求request
+(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
// 业务逻辑写这里
return request;
}
//开始请求
-(void)startLoading
{
//业务逻辑写这里
}
//停止请求
-(void)stopLoading
{
}
#pragma mark ---- NSURLSessionDelegate
/*
NSURLSessionDelegate接到数据后,通过URLProtocol传出去
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error)
{