一个朋友问了我一个问题,需求是这样的:他要用本地的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. python 循环结构

    for循环 list或tuple可以表示一个有序集合.如果我们想依次访问一个list中的每一个元素呢?比如 list: L = ['Adam', 'Lisa', 'Bart'] print L[0] ...

  2. (Nhibernate )XML配置文件的智能感知(IntelliSense)功能

      XML配置文件的智能感知(IntelliSense)功能 在使用一些第三方的程序库(Nhibernate,Ibatis...)常常需要手工编写比较复杂的配置文件,如果没有像VS IDE那样的Int ...

  3. pdfBox 读取pdf文件

    1.引入maven依赖 <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pd ...

  4. makefile变量定义应用到c语言

    makefile是为组织程序工程的,其定义的宏怎样应用到c程序中呢? 我们知道Makefile中可定义变量或导出变量,make命令可定义变量:编译器(如gcc)可通过CFLAGS定义宏. 但如何才能使 ...

  5. IOS设计模式浅析之建造者模式(Builder)

    定义 "将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现". 最初的定义出现于<设计模式>(Addison-Wesley,1994). 看这个概 ...

  6. LeetCode447. Number of Boomerangs

    Description Given n points in the plane that are all pairwise distinct, a "boomerang" is a ...

  7. SHA信息摘要

    SHA算法是在MD4的基础上演进而来的,通过SHA算法能够获得一个固定长度的摘要信息.   SHA算法系列有SHA-1(也成为SHA),SHA-224,SHA-256,SHA-384和SHA-512这 ...

  8. [已解决]windows下python3.x与python2.7共存版本pip使用报错问题

    > 由于最近要更新插件,突然发现没法使用pip来安装升级插件,查了一圈才找到解决办法,特记录在此,便于其它人查询. 报错信息如下: Fatal error in launcher: Unable ...

  9. python django -3 视图

    视图 视图接受Web请求并且返回Web响应 视图就是一个python函数,被定义在views.py中 响应可以是一张网页的HTML内容,一个重定向,一个404错误等等 响应处理过程如下图: URLco ...

  10. CBV流程

    django CBV 源码分析 FBV和CBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以不再赘述. ...