项目需求
公司后端API调用,经历多次302重定向,初始请求需在请求头中携带Referer,调用成功后,可进行数据下载。
实际问题
使用NSURLSession进行网络下载请求,跳转两次后cookie丢失及请求头中Referer消失,导致请求失败返回认证失败网页。
解决思路
拦截跳转请求,获取下次跳转的URL,强制添加消失的cookie及请求头的Referer,再进行跳转。
实现方法
- 项目文档中注册代理类(我的项目为DownloadManager,请自行替换)
@interface DownloadManager()<NSCopying, NSURLSessionDelegate>
- 继承代理方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
//此函数为不进行任何操作直接用返回的request进行下一步跳转,
//若使用completionHandler(nil),则不会进行跳转
completionHandler(request);
//返回的task具有唯一性,可用来识别是哪个发送的请求:task.taskIdentifier
//返回的response中可以获取到服务器返回的Set-Cookie
//返回的request中可以获取到即将跳转的链接地址
}
- 实际代码
以下为项目需要进行的操作,实际可以根据自己需求进行更改,定义了一个SessionModel来存储对应的task.taskIdentifier及相应的Referer等信息,我实际遇到的问题为跳转请求的cookie中LID的value丢失,所以代码内进行了LID的赋值
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
NSLog(@"cookie%@", cookie);
//手动设置LID (实际需求可以和后端开发协商
if([cookie.name isEqualToString:@"LID"]) {
NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary]; // 创建cookie属性字典
[cookieProperties setObject:cookie.name forKey:NSHTTPCookieName]; // 手动设置cookie的name
[cookieProperties setObject:@"LID" forKey:NSHTTPCookieValue];//手动设置cookie的value
[cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieProperties setObject:@"HOST" forKey:NSHTTPCookieDomain];//设置cookie的host地址
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];//保存cookie
}
}
//用返回的request.URL初始化请求,因为公司下载服务不稳定,故设置超时时间为100s
//NSURLRequestReloadRevalidatingCacheData:验证本地数据与远程数据是否相同,如果不同则下载远程数据,否则使用本地数据
NSMutableURLRequest *nextRequest = [NSMutableURLRequest requestWithURL:request.URL
cachePolicy:NSURLRequestReloadRevalidatingCacheData
timeoutInterval:100];
//getSessionModel:为自定义方法,并设置Referer
SessionModel *sessionModel = [self getSessionModel:task.taskIdentifier];
[nextRequest setValue:sessionModel.refer forHTTPHeaderField:@"Referer"];
//发送下个请求
completionHandler(nextRequest);
}