一个朋友问了我一个问题,需求是这样的:他要用本地的H5资源 替换 链接资源,  但是判断链接资源时候 因为一些操作请求本地化了之后  一些操作比如请求服务器使用的是http开头,然而本地资源一直是以file://开头, 这样的

然后 shouldStart 方法中 的request(post请求)  body  是空的,  这样就无法到底知道是哪个链接了.于是就不能触发相应的资源方法.
 
我思考好一阵子,起初 我以为这个就是应该是 用 shouldStart 协议 根据 url 判断 是否需要本地处理. 最终
解决办法是 “通过URL加载系统 (URL Loading System),拦截需要的h5资源,把本地数据直接展示
 
原因:
(1)利用UIWebView来处理回调地址,或者做拦截操作 一般都是得请求shouldStart协议中,甚至 需要知道请求回调结果 
 
就是HTTP重定向的问题! 之前 真的没有用过这个NSURLProtocol 协议去处理过问题.今天学习一下.
 
HTTP重定向: (在网上查资料 了解到的一个比较系统的解释)
Redirect(客户端重定向 我们这里研究的是)
标准意义上的“重定向”指的是HTTP重定向,它是HTTP协议规定的一种机制。这种机制是这样工作的:当client向server发送一个请求,要求获取一个资源时,在server接收到这个请求后发现请求的这个资源实际存放在另一个位置,于是server在返回的response中写入那个请求资源的正确的URL,并设置reponse的状态码为301(表示这是一个要求浏览器重定向的response),当client接受到这个response后就会根据新的URL重新发起请求。重定向有一个典型的特症,即,当一个请求被重定向以后,最终浏览器上显示的URL往往不再是开始时请求的那个URL了。这就是重定向的由来。
 
我们在实际开发过程中 遇到过这种 服务端重定向的情况,就是 和第三方电商合作,需要展示一个订单列表,就是我们作为客户前端 向服务端发起请求,然后服务端发现对应资源在商城里,然后回调结果是301 /也有302,然后会继续请求商城的订单列表的url 然后就正常展示了.
我们这么做的好处是: 不需要在客户端写死 订单列表的请求,服务端可以动态修改订单列表的链接.
 
首先是这个注册 NSURLProtocol协议方法可以解决的问题:
 
笼统就是 上面提到的"Redirect(客户端重定向)",对上层的 NSURLRequest 进行拦截,然后按需求响应操作.
NSURLProtocol具体可以做:

(1)如果需要,可以对html页面中的图片做本地化处理

(2)Mock假的response

(3)对请求头做规范化处理

(4)在上层应用不感知情况下,实现一套代理机制

(5)过滤请求、响应中敏感信息

(6)对已有协议做改进、补充处理

这些是网上查得到的,总得来说就是拦截请求时候 可以高度自定义请求方式, 拦截请求结果 高度自定义处理方法. 在实际开发中,根据具体需求处理.

我写了一个 实例 参考SectionDemo 的CustomUrlProtocol

//
// MyURLProtocol.h
// NSURLProtocolExample
//
// Created by HF on 2017/5/3.
// Copyright © 2017年 HF. All rights reserved.
// #import <Foundation/Foundation.h> @interface MyURLProtocol : NSURLProtocol @property (nonatomic, strong) NSMutableData *mutableData;
@property (nonatomic, strong) NSURLResponse *response; @end
//
// MyURLProtocol.m
// NSURLProtocolExample
//
// Created by HF on 2017/5/3.
// Copyright © 2017年 HF. All rights reserved.
// #import "MyURLProtocol.h"
#import "AppDelegate.h"
#import "CachedURLResponseModel+CoreDataProperties.h" @interface MyURLProtocol () <NSURLConnectionDelegate> @property (nonatomic, strong) NSURLConnection *connection; @end @implementation MyURLProtocol /**
* 是否拦截处理指定的请求
*
* @param request 指定的请求
*
* @return 返回YES表示要拦截处理,返回NO表示不拦截处理
*/
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
static NSUInteger requestCount = 0;
NSLog(@"Request #%lu: URL = %@", (unsigned long)requestCount++, request);
//看看是否已经处理过了,防止无限循环
if ([NSURLProtocol propertyForKey:@"MyURLProtocolHandledKey" inRequest:request]) {
return NO;
}
return YES;
} #pragma mark - NSURLProtocol /**
重写这个协议 目的是按需求条件筛选出目标请求,同时对目标request进行进一步完整包装与定义 @param request request
@return NSURLRequest
*/
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
NSMutableURLRequest *mutableReqeust = [request mutableCopy];
mutableReqeust = [self redirectHostInRequset:mutableReqeust];
return mutableReqeust; //return request;
} + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
} - (void)startLoading {
//如果想直接返回缓存的结果,构建一个CachedURLResponse对象 // 1.
CachedURLResponseModel *cachedResponse = [self cachedResponseForCurrentRequest];
if (cachedResponse) {
NSLog(@"serving response from cache"); // 2.
NSData *data = cachedResponse.data;
NSString *mimeType = cachedResponse.mimeType;
NSString *encoding = cachedResponse.encoding; // 3.
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL
MIMEType:mimeType
expectedContentLength:data.length
textEncodingName:encoding]; // 4.
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
} else {
// 5.
NSLog(@"serving response from NSURLConnection"); NSMutableURLRequest *newRequest = [self.request mutableCopy];
//标记"tag",防止无限循环
[NSURLProtocol setProperty:@YES forKey:@"MyURLProtocolHandledKey" inRequest:newRequest]; self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
} - (void)stopLoading {
[self.connection cancel];
self.connection = nil;
} #pragma mark - NSURLConnectionDelegate - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; self.response = response;
self.mutableData = [[NSMutableData alloc] init];
} - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data]; [self.mutableData appendData:data];
} - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self]; [self saveCachedResponse];
} - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
} #pragma mark -- private +(NSMutableURLRequest*)redirectHostInRequset:(NSMutableURLRequest*)request
{
if ([request.URL host].length == 0) {
return request;
} NSString *originUrlString = [request.URL absoluteString];
NSString *originHostString = [request.URL host];
NSRange hostRange = [originUrlString rangeOfString:originHostString];
if (hostRange.location == NSNotFound) {
return request;
} //定向到bing搜索主页
NSString *ip = @"cn.bing.com"; // 替换host
NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip];
NSURL *url = [NSURL URLWithString:urlString];
request.URL = url; return request;
} - (void)saveCachedResponse {
NSLog(@"saving cached response"); // if (![self.request.URL.absoluteString isEqualToString:@"cn.bing.com"]) return; // 1.
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = delegate.managedObjectContext; // 2.
CachedURLResponseModel *cachedResponse = [NSEntityDescription insertNewObjectForEntityForName:@"CachedURLResponseModel"inManagedObjectContext:context];
cachedResponse.data = self.mutableData;
cachedResponse.url = self.request.URL.absoluteString;
cachedResponse.timestamp = [NSDate date];
cachedResponse.mimeType = self.response.MIMEType;
cachedResponse.encoding = self.response.textEncodingName; // 3.
NSError *error;
BOOL const success = [context save:&error];
if (!success) {
NSLog(@"Could not cache the response.");
}
} - (CachedURLResponseModel *)cachedResponseForCurrentRequest {
// 1.
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = delegate.managedObjectContext; // 2.
NSFetchRequest *fetchRequest = [CachedURLResponseModel fetchRequest]; // 3.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"url == %@", self.request.URL.absoluteString];
[fetchRequest setPredicate:predicate]; // 4.
NSError *error;
NSArray *result = [context executeFetchRequest:fetchRequest error:&error]; // 5.
if (result && result.count > 0) {
return result[0];
} return nil;
}
@end

然后在需要的请求前注册这个类

[NSURLProtocol registerClass:[MyURLProtocol class]];

请求结束 注销这个类

[NSURLProtocol unregisterClass:[MyURLProtocol class]];

在MyURLProtocol 里面 针对目标请求 具体按需处理

这里 我举得例子 是:

首先 :请求 "https://www.raywenderlich.com" 使用 "MyURLProtocol"  注册 拦截 该请求 然后重定向到 "cn.bing.com"上

其次:对重定向 对象 添加缓存

注意:

这里只是模拟过程  没有特此针对判断具体链接,真正使用的时候大家一定要逻辑严谨,并且根据具体需求要做适当优化,才能灵活达到举一反三目的。

参考:

1. http://blog.csdn.net/xanxus46/article/details/51946432
2 .http://blog.csdn.net/bluishglc/article/details/7953614
3.http://www.molotang.com/
4.https://www.raywenderlich.com/59982/nsurlprotocol-tutorial

iOS URL Loading System / HTTP 重定向 认识与学习的更多相关文章

  1. http编程体系结构URL loading system

    https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadi ...

  2. Express URL跳转(重定向)的实现

    Express URL跳转(重定向)的实现   Express是一个基于Node.js实现的Web框架,其响应HTTP请求的response对象中有两个用于URL跳转方法res.location()和 ...

  3. iOS URL Schemes与漏洞的碰撞组合

    iOS URL Schemes与漏洞的碰撞组合 前言 iOS URL Schemes,这个单词对于大多数人来说可能有些陌生,但是类似下面这张图的提示大部分人应该都经常看见: 今天要探究的就是:了解iO ...

  4. ios Url Encode

    //ios Url Encode //有时候在请求的参数里里特殊符号比如“+”等.而如果没有encode的话那么传过去的还是” ”,面实际上是%2B. -(NSString*)UrlValueEnco ...

  5. android eclipse 报error loading /system/media/audio/ xxx 错的解决办法。

    只针对 报错..error   loading /system/media/audio/ xxx.ogg 一步操作 解决烦恼..把 模拟器声音 关了..所有的错 都没了. 包括 关闭按键声音,触摸声音 ...

  6. .htaccess技巧: URL重写(Rewrite)与重定向(Redirect) (转)

    目录 Table of Contents 一.准备开始:mod_rewrite 二.利用.htaccess实现URL重写(rewrite)与URL重定向(redirect) 将.htm页面映射到.ph ...

  7. 新浪sae url rewrite(伪静态、重定向)详解

    新浪sae url rewrite(伪静态.重定向)详解 http://www.veryhuo.com phpclubs 2011-11-14 投递稿件 sae全程Sina App Engine,真是 ...

  8. JavaWeb——JSP内置对象request,response,重定向与转发 学习总结

    什么是JSP内置对象 九大内置对象 requestJSP内置对象 request对象常用方法 request练习 responseJSP内置对象 response练习 response与request ...

  9. 【转】iOS超全开源框架、项目和学习资料汇总

    iOS超全开源框架.项目和学习资料汇总(1)UI篇iOS超全开源框架.项目和学习资料汇总(2)动画篇iOS超全开源框架.项目和学习资料汇总(3)网络和Model篇iOS超全开源框架.项目和学习资料汇总 ...

随机推荐

  1. centos 源码安装apache 之apr、apr-util

    apr 和 apr-util官网下载地址: http://apr.apache.org/download.cgi 安装顺序是先安装apr然后再安装 apr-util,因为安装apr-util需要apr ...

  2. Java并发编程(九)安全发布

    之前讨论是如何将对象封闭在线程之中,这样可以减少一些并发带来的同步和可见性问题.但是在有些时候,我们希望在多个线程间共享对象,此时必须确保安全地进行共享. [不安全发布的示例] 可见性问题:其他线程看 ...

  3. error: xslt-config not found. Please reinstall the libxslt >= 1.1.0 distribution

    解决编译php扩展xsl时出现 error: xslt-config not found. Please reinstall the libxslt >= 1.1.0 distribution ...

  4. shell实现倒计时功能

    #!/bin/bash ############################################################## # File Name: oldboyedu.sh ...

  5. Erlang 和 Elixir的差异

    原文: http://elixir-lang.org/crash-course.html 函数调用 Elixir允许你调用函数的时候省略括号, Erlang不行. Erlang Elixir some ...

  6. 结构体成员管理AVClass AVOption之2AVOption,设置选项值

    AVOption用于在FFmpeg中描述结构体中的成员变量.一个AVOption可以包含名称,简短的帮助信息,取值等. 上篇文章中概括了AVClass,AVOption和目标结构体之间的关系.以AVF ...

  7. PDO drivers no value in Windows

    学习php编程遇到 Uncaught exception 'PDOException' with message 'could not find driver' 或者 Undefined class ...

  8. Ajax工作原理及实例

    1.关于ajax的名字 ajax 的全称是Asynchronous JavaScript and XML,其中,Asynchronous 是异步的意思,它有别于传统web开发中采用的同步的方式. 2. ...

  9. JS 插件 fastclick.js 解决手机端click点击延迟

    FastClick 是一个简单,易于使用的JS库用于消除在移动浏览器上触发click事件与一个物理Tap(敲击)之间的300延迟. 对于非移动浏览器不启作用,禁用缩放标签. <meta name ...

  10. 【python】-- Ajax

    Ajax AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案. 异步的JavaScript:使用 ...