- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个自定义的 NSURLProtocol
(“UrlProtocol”),用于在导航到特定网站时拦截来自 UIWebView
的请求,并在发送前应用额外的 HTTP header 。我关注了https://www.raywenderlich.com/59982/nsurlprotocol-tutorial对于一个 worker 类(Class)。我的问题是从已弃用的 NSURLConnection
切换到 NSURLSession
:我测试了一个非常简单的单文件 html 页面,它加载成功。但是,具有 js 文件、图像等资源的稍微复杂的站点将超时,而使用 NSURLConnection
整个站点将在几秒钟内加载。
我将使用 NSURLConnection
粘贴原始 UrlProtocol
,然后使用 NSURLSession
粘贴新类。原文:
#import "UrlProtocol.h"
#import "Globals.h"
@implementation UrlProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if (![request.URL.absoluteString hasPrefix:@"http"]) return NO; //No need to intercept non-http requests
if ([NSURLProtocol propertyForKey:@"handled" inRequest:request]) {
return NO;
}
return YES;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
NSString* key = @"custom-auth-header";
Globals* globals = [Globals getInstance];
NSString* token = [globals token];
NSMutableURLRequest *newRequest = [request mutableCopy]; //Create a mutable copy that can be modified
[newRequest setValue:token forHTTPHeaderField:key];
return [newRequest copy]; //return a non-mutable copy
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
- (void)stopLoading {
NSLog(@"stopLoading");
[self.connection cancel];
self.connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
@end
新的 UrlProtocol
对每个请求使用 NSURLSessionDataTasks
:
#import "UrlProtocol.h"
#import "Globals.h"
@implementation UrlProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest * _Nonnull) request {
if (![request.URL.absoluteString hasPrefix:@"http"]) return NO; //No need to intercept non-http requests
if ([NSURLProtocol propertyForKey:@"handled" inRequest:request]) {
return NO;
}
return YES;
}
+ (NSURLRequest * _Nonnull)canonicalRequestForRequest:(NSURLRequest * _Nonnull)request {
NSString* key = @"custom-auth-header";
Globals* globals = [Globals getInstance];
NSString* token = [globals token];
NSMutableURLRequest *newRequest = [request mutableCopy]; //Create a mutable copy that can be modified
[newRequest setValue:token forHTTPHeaderField:key];
return [newRequest copy]; //return a non-mutable copy
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest * _Nonnull)a toRequest:(NSURLRequest * _Nonnull)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest];
[Globals setUrlSessionDelegate:self];
Globals* globals = [Globals getInstance];
self.dataTask = [globals.session dataTaskWithRequest:newRequest];
[self.dataTask resume];
}
- (void)URLSession:(NSURLSession * _Nonnull)session dataTask:(NSURLSessionDataTask * _Nullable)dataTask didReceiveData:(NSData * _Nullable)data{
[self.client URLProtocol:self didLoadData:data];
}
- (void)URLSession:(NSURLSession * _Nonnull)session dataTask:(NSURLSessionDataTask * _Nullable)dataTask didReceiveResponse:(NSURLResponse * _Nullable)response
completionHandler:(void (^ _Nullable)(NSURLSessionResponseDisposition))completionHandler{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task didCompleteWithError:(NSError * _Nullable)error{
if (error){
[self.client URLProtocol:self didFailWithError:error];
} else {
[self.client URLProtocolDidFinishLoading:self];
}
}
- (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task willPerformHTTPRedirection:(NSHTTPURLResponse * _Nonnull)response
newRequest:(NSURLRequest * _Nonnull)request completionHandler:(void (^ _Nonnull)(NSURLRequest * _Nullable))completionHandler {
completionHandler(request);
}
- (void)stopLoading {
[self.dataTask cancel];
self.dataTask = nil;
}
@end
“Globals”是一个单例,我已经在其中初始化了一个 NSURLSession
,以便在应用程序的整个运行时使用。它还包含我为所有请求设置为自定义 HTTP header 的 token :
#import "Globals.h"
#import "UrlProtocol.h"
@implementation Globals
@synthesize token;
@synthesize session;
static Globals *instance = nil;
+(Globals*) getInstance
{
@synchronized(self)
{
if (instance == nil)
{
instance = [Globals new];
}
}
return instance;
}
//UrlProtocol class has no init method, so the NSURLSession delegate is being set on url load. We will ensure only one NSURLSession is created.
+(void) setUrlSessionDelegate:(UrlProtocol*) urlProtocol{
Globals* globals = [Globals getInstance];
if (!globals.session){
globals.session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration delegate:urlProtocol delegateQueue:nil];
}
}
@end
最佳答案
通过为每个 NSURLSessionDataTask 创建一个新的默认 NSURLSession 解决了我的问题。我尝试为所有任务共享一个 NSURLSession 的方式出了点问题。 URLProtocol 的 startLoading 方法现在如下:
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest];
NSURLSessionConfiguration* config = NSURLSessionConfiguration.defaultSessionConfiguration;
NSURLSession* session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
self.dataTask = [session dataTaskWithRequest:newRequest];
[self.dataTask resume];
}
之前简单的 HTML 页面测试肯定是有效的,因为加载页面只需要一个任务
关于ios - 将 NSURLConnection 切换到 NSURLSession 后自定义 NSURLProtocol 变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41477434/
我实现了一个自定义 NSURLProtocol,它允许我使用网站的静态压缩版本作为 webView 的目标。它可以随时打开 zip 并加载所需的数据。但问题是 NSURLProtocol 似乎无法正确
我正在通过“http://”和“https://”进行通信。何时以及为何使用 NSURLProtocol? 我读到它用于新的/自定义方案,对于上述方案我们不需要使用 NSURLProtocol。 最佳
我正在尝试创建 NSURLProtocol 的子类。但是,我注意到当我注册我的子类时我似乎失去了缓存功能,即使它不应该做任何事情。例如,如果我对同一个 URL 多次执行 [NSURLConnectio
我在通过 NSURLProtocol 子类中的特殊协议(protocol)方案处理视频请求时遇到了一些问题。所有其他资源(图像/文本)都得到了正确处理,但是,当发送视频请求时,我只收到对“canIni
我一直在我的应用程序中使用自定义 NSURLProtocol 来检测资源并从缓存目录加载(如果可用),或者重定向回我的应用程序的服务器。但是,我发现缺少有关抽象方法的文档,而且我不确定如何处理我们需要
我已经编写了 NSURLProtocol 的自定义子类,但是似乎每当我使用该协议(protocol)在 UIWebView 中加载请求时,它都会假设数据是内容类型“text/html”。有没有办法指定
我想加载远程url并使用本地资源(image,css,js...),所以我继承了NSURLProtocol。 import Foundation class MyURLProtocol: NSURLP
我正在尝试在我的应用程序中实现一个 NSURLProtocol,它将获取以 myApp://... 开头的 URL 我在新的 SWIFT 文件中创建了协议(protocol)并在 AppDelegat
我的应用程序中的 UIWebviews 和一些自定义 NSURLProtocols 存在问题。 我所有的非 web View 请求都是用 NSURLSession 调用的,所以为了让这些请求通过协议(
确定当前在应用程序中注册的所有 NSURLProtocol 子类的正确方法是什么? In the docs ,我只看到 + (BOOL)registerClass:(Class)protocolCla
自升级到 iOS 9.1 后,我的自定义 NSURLProtocol 将不再调用 -(void)startLoading。还有其他人遇到过这种情况吗? 在 iOS 8 上一切正常...... 代码:
我的应用程序使用 NSURLProtocol 的子类。应用程序中有多个 UIWebView,对于 NSURLProtocol 中实现的特定算法,我需要知道哪一个 UIWebView 发送了请求。 我的
我想使用自定义 NSURLProtocol类为测试提供静态数据,我已经在应用程序本身中实现了协议(protocol)并将其注册到 NSURLSessionConfiguration.protocolC
我使用 NSURLProtocol 为所有从 UIWebview 发出的请求添加自定义 header 。 在此 WebView 上执行某些操作时,会触发 AJAX 调用以显示消息。此显示消息的操作使用
我正在使用 MonoTouch 构建 iOS 应用程序并尝试实现自定义 NSUrlProtocol。 当我注册自己的协议(protocol)实现时,出现以下错误: WebKit discarded a
首先是服务器端:有一个内部可访问的 apache 服务器,带有多个虚拟主机。对于 http(无 's'!) 请求,我使用 IP 作为 URL,并在 Host-Header 字段中添加主机名。 效果非常
这是NSURLProtocol中的canInitWithRequest: + (BOOL)canInitWithRequest:(NSURLRequest *)request { // only
我已经将 NSURLProtocol 子类化并使用以下代码在 didFinishLaunchingWithOptions 中注册它: + (void) registerProtocol { st
我已经实现了 NSURLProtocol 的子类。我需要它来模拟单元测试的 URL 响应。我已在单元测试的 setUp 方法中注册了我的类。 - (void)setUp { [NSURLPro
我尝试按照以下教程中的说明实现 NSURLProtocol:http://www.raywenderlich.com/76735/using-nsurlprotocol-swift 在 iOS8 中一
我是一名优秀的程序员,十分优秀!