NSURLRequest 对象代表了一个url 加载请求,从某种程度上来说它是一个独立的协议和url体系。
一个NSURLRequest 必须包含 url 加载请求时的两个基本数据元素 :
- 加载时的url
- 实现url内容缓冲时所采用的缓冲策略。
NSURLRequest 设计的目的是通过添加提供访问自己指定协议属性方法的类别来支持附加协议。通过调用NSURLProtocol 的 propertyForKey:inRequest: and setProperty:forKey:inRequest:
注意: 下面的可设置值都是相对于NSURLMutableRequest来说的。
注意:NSURLRequest 只是包含 URL请求时的一些信息,如果想要发起URL请求必须使用NSURLSession or NSURLConnection
把请求发送到服务器。
方法:
+ (instancetype)requestWithURL:(NSURL *)theURL
用指定的url创建一个NSURLRequest。 缓冲策略是默认的
NSURLRequestUseProtocolCachePolicy。超时是默认的60秒。
缓冲策略:
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData=1,
NSURLRequestReturnCacheDataElseLoad=2,
NSURLRequestReturnCacheDataDontLoad= 3
缓冲策略第一种最为复杂,我们先来看后几种。
第二种是忽略一切缓冲,就相当于不做任何缓冲。每次都去server请求内容。
第三种是用指定的缓冲来响应来请求,不考虑缓冲的生命周期跟过期时间,如果指定的缓冲不存在,则去服务器请求数据。
第四种用指定的缓冲来响应来请求,不考虑缓冲的生命周期跟过期时间。但是如果没有相应的缓冲也不会去服务器获取相应的数据,会认为请求失败。
第一种比较麻烦,先上一个图
1. 如果缓冲不存在,去server请求新的数据。
2. 如果缓冲存在并且不需要每一次都与源服务器进行重新激活,并且缓冲没有过期则返回 缓冲。
3.如果需要每一次都进行重新激活或者已过期则向server发一个headRequst 查看一个服务器是否发生改变,如果改变则进行新的请求,如果没有则返回缓冲。
上面的判断条件都可在NSURLRequest 的header 中进行设置。
属性值:
BOOL 值标志在收到前一个请求的响应之前是否可以继续传输数据。 YES,可以,No 不可以,默认是NO.在URLRequest 中是readOnly,在URLRequest
中可以改变。 并不是HTTPShouldUsePipeling = YES都会起作用,它还会受到http 代理配置,服务器配置等原因的影响。
mainDocumentURL
Property
(一般用于js交互和cookie)
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
if ( [request.mainDocumentURL.relativePath isEqualToString:@"xx"] ) {
//页面跳转代码
return false;
}
allHTTPHeaderFields 返回request的header
[request setValue:@"application/x-apple-plist" forHTTPHeaderField:@"Content-type"]; [request setValue:@"no-cache" forHTTPHeaderField:@"cache-control"]; [request setValue:@"zh-cn,zh;q=0.5" forHTTPHeaderField:@"Accept-Language" ]; [request setValue:@"text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8" forHTTPHeaderField:@"Accept"];
结果为:
Accept = "text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8";
"Accept-Language" = "zh-cn,zh;q=0.5";
"Cache-Control" = "no-cache";
"Content-Type" = "application/x-apple-plist";
- (void)setValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
设置request的header
- (void)addValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
上面的setValue每次都设置一个新的值,而addValue可以在原来已存在的值是增加新的值
NSMutableString *body = [[NSMutableString alloc] initWithCapacity:0]; [body appendString:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"]; [body appendString:@"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"]; NSData *data = [body dataUsingEncoding:NSUTF8StringEncoding]; [request setHTTPBody:data];
@property(copy) NSData*setHTTPBody
@property(copy) NSData*HTTPBody
设置获取 HTTPBody. 如果我们使用POST的时候参数就在这个body中。
@property(retain) NSInputStream*HTTPBodyStream
接受者的HTTP主体流,如果没有被设置的话就是nil。返回的流仅供检验,所有对这个流的操作都是不安全的。
接收者的请求主体将会是这个输入流。在POST请求中,整个流对象内容都会被当作主体来发送。输入流不应该不打开,接收者会作为代理来接收输入流。
NSURLRequest的setHTTPBodyStream接受的是一个NSInputStream*参数,那我们要自定义inputStream的话,创建一个NSInputStream的子类传给它是不是就可以了?实际上不行,这样做后用NSURLRequest发出请求会导致crash,提示[xx _scheduleInCFRunLoop:forMode:]: unrecognized selector。
这是因为NSURLRequest实际上接受的不是NSInputStream对象,而是CoreFoundation的CFReadStreamRef对象,因为CFReadStreamRef和NSInputStream是toll-free bridged,可以自由转换,但CFReadStreamRef会用到CFStreamScheduleWithRunLoop这个方法,当它调用到这个方法时,object-c的toll-free
bridging机制会调用object-c对象NSInputStream的相应函数,这里就调用到了_scheduleInCFRunLoop:forMode:,若不实现这个方法就会crash。