ios 使用 UIWebView loadRequest 发送自定义标头

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12844598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:42:12  来源:igfitidea点击:

Send custom headers with UIWebView loadRequest

iphoneiosuiwebviewnsurlrequest

提问by Thomas Clayson

I want to be able to send some extra headers with my UIWebView loadRequestmethod.

我希望能够使用我的 UIWebViewloadRequest方法发送一些额外的标头。

I have tried:

我试过了:

NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.reliply.org/tools/requestheaders.php"]];
[req addValue:@"hello" forHTTPHeaderField:@"aHeader"];

[self.theWebView loadRequest:req];

I have also tried subclassing the UIWebViewand intercepting the - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationTypemethod.

我也尝试过子类化UIWebView和拦截- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType方法。

In that method I had a block of code which looked like this:

在那个方法中,我有一个如下所示的代码块:

NSMutableURLRequest *newRequest = [request mutableCopy];
for(NSString *key in [customHeaders allKeys]) {
    [newRequest setValue:[customHeaders valueForKey:key] forHTTPHeaderField:key];
}
[self loadRequest:newRequest];

But for some unknown reason it was causing the web view to not load anything (blank frame) and the error message NSURLErrorCancelled (-999)comes up (all known fixes don't fix it for me).

但是由于某种未知原因,它导致 Web 视图无法加载任何内容(空白帧)并且出现错误消息NSURLErrorCancelled (-999)(所有已知的修复程序都不能为我修复它)。

So I am at a loss as to what to do. How can I send a custom header along with a UIWebViewrequest?

所以我不知道该怎么做。如何在UIWebView请求的同时发送自定义标头?

Many thanks!

非常感谢!

回答by Thomas Clayson

I found that this was the way to add headers to my UIWebView request - override this delegate method:

我发现这是向我的 UIWebView 请求添加标头的方法 - 覆盖此委托方法:

- (BOOL) webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType) navigationType

With this code:

使用此代码:

BOOL headerIsPresent = [[request allHTTPHeaderFields] objectForKey:@"my custom header"]!=nil;

if(headerIsPresent) return YES;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSURL *url = [request URL];
        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];

        // set the new headers
        for(NSString *key in [self.customHeaders allKeys]){
            [request addValue:[self.customHeaders objectForKey:key] forHTTPHeaderField:key];
        }

        // reload the request
        [self loadRequest:request];
    });
});
return NO;

回答by msk

The answer by Thomas will not work for (most of the) webpages with multiple iFrames. The solution will load an iFrame request over the full UIWebView. E.g. in case it calls loadRequest for a Google advt. (which is in some small iFrame) the advt. is loaded all over the UIWebView & nothing else.

Thomas 的答案不适用于(大多数)具有多个 iFrame 的网页。该解决方案将通过完整的 UIWebView 加载 iFrame 请求。例如,如果它为 Google 广告调用 loadRequest。(在一些小的 iFrame 中)advt。整个 UIWebView 都加载了,没有别的。

回答by u5229677

I find another way, Can use NSURLProtocol.

我找到了另一种方法,可以使用NSURLProtocol.

-(BOOL)webView:(IMYVKWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSMutableDictionary* mapObject = [NSMutableDictionary dictionary];
    mapObject[@"headers"] = request.allHTTPHeaderFields;
    mapObject[@"navigationType"] = @(navigationType);
    [webViewRequestMap setObject:mapObject forKey:request.URL.absoluteString];
    return YES;
}

webViewRequestMapis Static NSMutableDictionary*

webViewRequestMap是静态 NSMutableDictionary*

in Your Custom NSURLProtocol code:

在您的自定义 NSURLProtocol 代码中:

    @interface IMYCustomURLProtocol : NSURLProtocol
@end
@implementation IMYCustomURLProtocol 
+(void)load
{
     [NSURLProtocol registerClass:self];
}
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    NSString* urlString = request.URL.absoluteString;
    NSDictionary* dictionary = webViewReuqestMap[urlString];
    if (dictionary)
    {
        [webViewRequestMap removeObjectForKey:urlString];
        if ([request isKindOfClass:[NSMutableURLRequest class]]) {
           [(id)request setValue:@"HAHA" forHTTPHeaderField:@"MeiYou Co.,Ltd"];
        }
    }
    return NO;
}
@end

回答by Blago

Here is a complete implementation using NSURLProticol. You can put this code anywhere you like (e.i. its own or add to existing source file) and it should work. The two key methods to customize are canInitWithRequest:and canonicalRequestForRequest:.

这是使用 NSURLProticol 的完整实现。您可以将此代码放在您喜欢的任何位置(即它自己的或添加到现有源文件中),它应该可以工作。自定义的两个关键方法是canInitWithRequest:canonicalRequestForRequest:

static NSString * const NSURLProtocolHandledKey = @"NSURLProtocolHandledKey";

@interface WTCURLProtocol : NSURLProtocol<NSURLSessionDelegate>
@property (atomic,strong,readwrite) NSURLSessionDataTask *task;
@property (nonatomic,strong) NSURLSession *session;
@end

@implementation WTCURLProtocol
+(void)load
{
  [NSURLProtocol registerClass:self];
}

+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
  // customize here by returning true for URLs that you want to handle
  return [request.URL.absoluteString hasPrefix:WEB_BASE_URL];
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
  NSMutableURLRequest *newRequest = request.mutableCopy;
  [NSURLProtocol setProperty:@YES forKey:NSURLProtocolHandledKey inRequest:newRequest];

  // customize here by setting your custom headers
  [newRequest setValue:@"ABCDEFGHIJKLMNOPQRSTUVWXYZ" forHTTPHeaderField:@"API-TOKEN"];

  return newRequest;
}

- (void)startLoading
{
  NSURLSessionConfiguration *configure = [NSURLSessionConfiguration defaultSessionConfiguration];
  NSOperationQueue *queue = [[NSOperationQueue alloc] init];

  self.session  = [NSURLSession sessionWithConfiguration:configure delegate:self delegateQueue:queue];
  self.task = [self.session dataTaskWithRequest:self.request];
  [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);
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest *))completionHandler
{
  NSMutableURLRequest *redirectRequest = [newRequest mutableCopy];
  [[self class] removePropertyForKey:NSURLProtocolHandledKey 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]];
}

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
  if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
    NSURLCredential *card = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
    completionHandler(NSURLSessionAuthChallengeUseCredential,card);
  }
}

@end