使用NSURLProtocol和NSURLSession拦截UIWebView的HTTP请求(包括ajax请求)
问题:服务器端有一个网站需要AD认证,整站都开了Basic认证,包括图片,CSS等资源,我在HTTP请求头里面添加认证所需的用户名和密码,传递到服务器端可以认证通过。我在UIWebView的shouldStartLoadWithRequest代理方法中拦截WebView的请求,然后在请求的Header中添加认证所需的用户名和密码,然后使用NSURLSession重新发出HTTP的请求,这种方法可以解决大部分的网络请求,但是无法拦截到网页内部的ajax请求,所以所有的ajax请求都会失败,一旦遇到ajax请求,认证都会失败,并且网页会失去响应?
解决思路:使用NSURLProtocol拦截UIWebView内部的所有请求,包括Ajax请求,在所有的请求头中添加认证所需的用户名和密码。
注意:NSURLProtocol只能拦截UIWebView、NSURLConnection、NSURLSession和基于NSURLConnenction、NSURLSession实现的第三方框架(如AFNetworking)发出的网络请求,无法拦截WKWebview、CFNetwork以及基于CFNetwork实现的第三方框架(如MKNetworkit)发出的网络请求。 //update on 2017-02-28
下面提供一个完整的NSURLProtocol的实现类:
RichURLSessionProtocol.h
#import <Foundation/Foundation.h> @interface RichURLSessionProtocol : NSURLProtocol @end
RichURLSessionProtocol.m
#import "RichURLSessionProtocol.h" static NSString * const RichURLProtocolHandledKey = @"RichURLProtocolHandledKey"; @interface RichURLSessionProtocol()<NSURLSessionDelegate> @property (atomic,strong,readwrite) NSURLSessionDataTask *task;
@property (nonatomic,strong) NSURLSession *session; @end @implementation RichURLSessionProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request
{
//只处理http和https请求
NSString *scheme = [[request URL] scheme];
if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
[scheme caseInsensitiveCompare:@"https"] == NSOrderedSame))
{
// NSLog(@"====>%@",request.URL); //看看是否已经处理过了,防止无限循环
if ([NSURLProtocol propertyForKey:RichURLProtocolHandledKey inRequest:request]) {
return NO;
} return YES;
}
return NO;
} + (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
/** 可以在此处添加头等信息 */
NSMutableURLRequest *mutableReqeust = [request mutableCopy];
return mutableReqeust;
}
- (void)startLoading
{
NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//打标签,防止无限循环
[NSURLProtocol setProperty:@YES forKey:RichURLProtocolHandledKey inRequest:mutableReqeust]; NSURLSessionConfiguration *configure = [NSURLSessionConfiguration defaultSessionConfiguration]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; self.session = [NSURLSession sessionWithConfiguration:configure delegate:self delegateQueue:queue];
self.task = [self.session dataTaskWithRequest:mutableReqeust];
[self.task resume];
} - (void)stopLoading
{
[self.session invalidateAndCancel];
self.session = nil;
} - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error != nil) {
[self.client URLProtocol:self didFailWithError:error];
}else
{
[self.client URLProtocolDidFinishLoading:self];
}
} - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; completionHandler(NSURLSessionResponseAllow);
} - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
[self.client URLProtocol:self didLoadData:data];
} - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable))completionHandler
{
completionHandler(proposedResponse);
} //TODO: 重定向
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest *))completionHandler
{
NSMutableURLRequest* redirectRequest;
redirectRequest = [newRequest mutableCopy];
[[self class] removePropertyForKey:RichURLProtocolHandledKey inRequest:redirectRequest];
[[self client] URLProtocol:self wasRedirectedToRequest:redirectRequest redirectResponse:response]; [self.task cancel];
[[self client] URLProtocol:self didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]];
} - (instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client
{ NSMutableURLRequest* redirectRequest;
redirectRequest = [request mutableCopy]; //添加认证信息
NSString *authString = [[[NSString stringWithFormat:@"%@:%@", kGlobal.userInfo.sAccount, kGlobal.userInfo.sPassword] dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString];
authString = [NSString stringWithFormat: @"Basic %@", authString];
[redirectRequest setValue:authString forHTTPHeaderField:@"Authorization"];
NSLog(@"拦截的请求:%@",request.URL.absoluteString); self = [super initWithRequest:redirectRequest cachedResponse:cachedResponse client:client];
if (self) { // Some stuff
}
return self;
} - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{ NSLog(@"自定义Protocol开始认证...");
NSString *authMethod = [[challenge protectionSpace] authenticationMethod];
NSLog(@"%@认证...",authMethod); if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSURLCredential *card = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,card);
} if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM]) {
if ([challenge previousFailureCount] == ) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:kGlobal.userInfo.sAccount password:kGlobal.userInfo.sPassword persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}else{
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,nil);
}
} NSLog(@"自定义Protocol认证结束");
} @end
使用自定义NSURLProtocol类的方法:
1.在单个的UIViewController中使用
//导入自定义NSURLProtocol类
#import "RichURLSessionProtocol.h"
//在ViewDidLoad中添加拦截网络请求的代码
//注册网络请求拦截
[NSURLProtocol registerClass:[RichURLSessionProtocol class]];
//在ViewWillDisappear中添加取消网络拦截的代码
//取消注册网络请求拦截
[NSURLProtocol unregisterClass:[RichURLSessionProtocol class]];
2.拦截整个App中所有的网络请求
//直接在AppDelegate中的didFinishLaunchingWithOptions注册网络拦截代码
//注册Protocol
[NSURLProtocol registerClass:[RichURLSessionProtocol class]];
使用NSURLProtocol和NSURLSession拦截UIWebView的HTTP请求(包括ajax请求)的更多相关文章
- Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求
Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求 Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 java ...
- ajax请求响应中用window.open打开新窗口会被浏览器拦截的解决方式
一.问题描述 ajax 异步请求成功后需要新开窗口打开 url,使用的是 window.open() 方法,但是会被浏览器给拦截了,需要用户点下. 二.问题分析 浏览器之所以拦截新开窗口是因为该操作并 ...
- $.ajax 请求 拦截器 重定向 无效 解决办法
在ajax 异步请求下 拦截器过滤器中使用 重定向 页面响应无效 我这里用的是springboot框架,用拦截器实现 对请求的拦截 ,session超时直接跳转到login.html页面. 后台代码: ...
- java端拦截器判断客户的的请求是否是ajax请求
java端拦截器判断客户的的请求是否是ajax请求 发表于 2014-08-22 23:38:08 普通请求与ajax请求的报文头不一样,通过如下 String requestType = reque ...
- ajax请求成功后打开新开窗口(window.open())被拦截的解决方法
问题:今天在做项目时需要在ajax请求成功后打开一个新的窗口,此时遇到浏览拦截了新窗口的问题,尝试在ajax 回调函数中模拟执行 click 或者 submit 等用户行为(trigger('clic ...
- 通过配置http拦截器,来进行ajax请求验证用户登录的页面跳转
在.NET中验证用户是否登录或者是否过期,若需要登录时则将请求转向至登录页面. 这个流程在进行页面请求时是没问题的,能正确进行页面跳转. 然而在使用xmlhttprequest时,或者jq的getJs ...
- ajax请求成功后新开窗口window.open()被拦截解决方法
ajax 异步请求成功后需要新开窗口打开 url,使用的是 window.open() 方法,但是很可惜被浏览器给拦截了,怎么解决这个问题呢 问题: 前面开发项目时碰到一个问题,ajax 异步请求 ...
- ajax请求成功后新窗口window.open()被拦截的解决方法
ajax 异步请求成功后需要新开窗口打开 url,使用的是 window.open() 方法,但是该操作并不是用户主动触发的,所以它认为这是不安全的就拦截了(不过如果是 _self 的话就不会有这个限 ...
- ajax请求后弹开新页面被浏览器拦截
window.open()我想应该很多人都不陌生吧,它可以实现除用a标签以外来实现打开新窗口! 最近开发项目用到时,却遇到了麻烦,本来好好的弹出窗口,结果被浏览器无情的给拦截了! 代码如下: $.ge ...
随机推荐
- php修改密码
为了让页面更为好看一些,我一般会选择bootstrap,写起来虽然看着麻烦,但是我们真正需要的只有中间的内容 下面是html的内容 <div id="tbx"" ...
- 记录-spring MultipartFile 文件上传
注意:以下上传和下载方法未必完全正确,不同浏览器效果不同,建议不要使用IE /** * 简单的文件上传 * @author:qiuchen * @createTime:2012-6-19 * @par ...
- delete 和 truncate 的 区别
如果要清空表中的所有记录,可以使用下面的两种方法: DELETE FROM table1 TRUNCATE TABLE table1 以下 为之区别: 1)执行速度和灵活性 trunca ...
- Nodejs课堂笔记-第四课 Dynamodb为何物
本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原创,转载请标明.谢谢! 我喜欢带着目标来学习新知识.因此学习nodejs过程中,不喜欢只看枯燥的语法 ...
- H5 Video 去除 下载按钮 禁用右键
<style type="text/css"> video::-webkit-media-controls-enclosure { overflow:hidden; } ...
- python学习-4-类的使用
class Animal: def __init__(self, name): # Constructor of the class self.name = name def talk(self): ...
- 编写你的第一个django应用程序4
本教程上接教程3,我们将继续开发网页投票应用,本部分将主要关注简单的表单处理以及如何对代码进行优化 写一个简单的表单 让我们更新一下在上一个教程中编写的投票详细页面的模板(‘polls/detail. ...
- 更改node版本
npm install -g n n stable 或 n v4.5.0
- action extension添加图标
最近在做ios的action extension,这里记录一下添加图标的方法. 在Action Extension的target里面的Build Settings,里面的Asset Catalog C ...
- 关于 haproxy keepalived的测试
可以阅读的一篇文章(http://blog.csdn.net/xyang81/article/details/52554398) 以下测试的配置都是基本的,简单化的,达到了效果滴,没有参考上面文档 准 ...