网络通信 (Session)

Session

Session是服务器端使用一种类似散列表的结构来保存信息的机制。当应用程序请求建立Session连接时,服务器首先会检测请求头是否包含SessionID,如果已经包含,服务器会去散列表里查询响应的Session并进行行为关联。如果没有,则会先创建一个Session,生成一个SessionID,并在本次响应中返回给客户端。

System Session

NSURLSession

理解Session的原理后,我们先来看一下iOS的NSURLSession类,看一下苹果是如何提供接口的。

首先来看一下如何生成一个NSURLSession对象。

// The Shard session uses the currently set global NSURLCache, NSHTTPCookieStorage and NSURLCredentialStorage objects.
@property (class, readonly, strong) NSURLSession *shareSession;

+ (NSURLSession *)sesionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id<NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
复制代码

苹果提供了三种构造方式,对于shareSession的定义,可以学习一下。

@property (readonly, retain) NSOperationQueue *delegateQueue;
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
@property (readonly, copy) NSURLSessionConfiguration *configuration;
复制代码

从代码可以看出,三个属性都是只读,delegateQueue和delegate是retain,引用计数加一,release交由autoreleasePool,delegate可空,configuration的copy(copy = 堆上复制 + strong)。

- (void)finishTaskAndInvalidate;
- (void)invalidateAndCancel;

- (void)resetWithCompletionHandler:(void (^)(void))completionHandler;
- (void)flushWithCompletionHandler:(void (^)(void))completionHandler;

- (void)getTasksWithCompletionHandler:(void (^)(NSArray <NSURLSessionDataTask *> *dataTasks, NSArray<NSURLSessionUploadTask *> *uploadTasks, NSArray<NSURLSessionDownloadTask *> *downloadTasks))completionHandler;
- (void)getAllTasksWithCompletionHandler:(void (^)(NSArray<__kindof NSURLSessionTask *> tasks))completionHandler;
复制代码

对于后两个方法,由于NSURLSessionDataTask、NSURLSessionUploadTask(NSURLSessionDataTask)、NSURLSessionDownloadTask都是NSURLSessionTask的子类,所以使用了__kinfof来修饰NSURLSessionTask。

// NSURLSession 提供通过resumeData创建downloadTask的方式。
- (NSURLSessionDownloadTask *)downloadTaskResumeData:(NSData *)resumeData;
复制代码
NSURLSessionTask

接下来我们来看一下NSURLSessionTask。

@property (readonly)                    NSUInteger      taskIdentifier;
@property (nullable, readonly, copy)    NSURLRequest    *originalRequest;
@property (nullable, readonly, copy)    NSURLRequest    *currentRequest;
@property (nullable, readonly, copy)    NSURLResponse   *response;
... ...
@property (readonly)                    int64_t         countOfBytesReceived;
@property (readonly)                    int64_t        countOfBytesSent;
@property (readonly)                    int64_t        countOfBytesExpectedToSend;
@property (readonly)                    int64_t        countOfBytesExpectedToReceive;

- (void)cancel;

@property (readonly)                    NSURLSessionTaskState   state;

- (void)suspend;
- (void)resume;
复制代码

任务的重启与暂停,数据传输的信息,请求和响应等。

NSURLSessionConfiguration

下面我们来看一下什么是NSURLSessionConfiguration?

@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;

+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier;
复制代码

NSURLSessionConfiguration提供了三种构造方式,ephemeralSessionConfiguration不会保存用户的浏览信息,可以用来做无痕浏览。

@property NSURLRequestCachePolicy requestCachePolicy;

@property NSTimeInterval timeoutIntervalForRequest;
@property NSTimeInterval timeoutIntervalForResource;
@property NSURLRequestNetworkServiceType networkServiceType;

... ...

@property (nullabel, copy) NSDictionary *connnectionProxyDictionary;
@property SSLProtocol TLSMinimumSupportedProtocol;
@property SSLProtocol TLSMaximumSupportedProtocol;

@property BOOL HTTPShouldUsePipeling;
@property BOOL HTTPShouldSetCookies;

@property NSHTTPCookieAcceptPolicy HTTPCockieAcceptPolicy;

@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;

@property NSInteger HTTPMaximumConnectionsPerHost;

@property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage;
@property (nullable, retain) NSURLCredentialStorage;
@property (nullable, retain) NSURLCache *URLCache;

... ...
复制代码

NSURLSessionConfiguration是有很多属性需要设置的,像超时,SSL的处理,cookie的设置,是否允许pipe,最大连接数,credentials的存储等等。

上文我们大致了解了NSURLSession相关的属性和方法后,接下来我们来看一下如何构造一个NSURLRequest对象,他有哪些属性和方法。

NSURLRequest
+ (instancetype)requestWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval;

- (instancetype)requestWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval;
复制代码

从构造方法中可以看出,request包含URL、cachePolicy和超时时间。

@interface NSURLRequest (NSHTTPURLRequest)

@property (nullable, readonly, copy) NSString *HTTPMethod;
@property (nullable, readonly, copy) NSDictionary <NSStirng *, NSString *>allHTTPHeaderFields;

@property (nullable, readonly, copy) NSData *HTTPBody;
@property (nullable, readonly, retain) NSInputStream *HTTPBodyStream;
@property (readonly) BOOL HTTPShouldHandleCookies;
@property (readonly) BOOL HTTPShouldUSePipelining;

- (nullable, NSString *)valueForHTTPHeaderFiled:(NSString *)field;

@end
复制代码

从类别可以看出,主要设置请求头,设置请求体,设置请求方式,是否添加cookie等。

NSURLResponse

设置完请求后,我们来看一下响应。

NSURLResponse
- (instancetype)initWithURL:(NSURL *)URL MIMEType:(nullable NSString *)MIMEType expectedContentLength:(NSInteger)length textEncodingName:(nullable NSString *)name;

@property (nullable, readonly, copy) NSString *suggestedFilename;;
复制代码

NSURLResponse类包含contentLength,编码格式,建议文件名字等。

NSHTTPURLResponse
- (nullable instancetype)initWithURL:(NSURL *)url statuscode:(NSInteger)statusCode HTTPVersion:(nullable NSString *)HTTPVersion headerFields:(nullable NSDictionary<NSString *, NSString *>)headerFields;

+ (NSString *)localizedStringForStatusCode:(NSInteger)statusCode;
复制代码

NSHTTPURLResponse包含状态码,HTTPVersion,响应头信息。

NSURLCredential

接下来谈一谈证书

@property (readonly) NSURLCredentialPersistence persistence;
复制代码

证书的持有方式有不保存,由session保存,永久保存,同步四种方式。

NSURLCredential(NSInternetPasscode)
- (instancetype)initWithUser:(NSString *)user password:(NSString *)passcode persistence:(NSURLCredentialPersistence)persistence;
复制代码
NSURLCredential(NSClientCertificate)
- (instancetype)initWithIdentity:(SecIdentityRef)identity certificates:(nullable NSArray *)certArray persistence:(NSURLCredentialPersistence)persistence;
复制代码
NSURLCredential(NSServerTrust)
- (instancetype)initWithTrust:(SecTrustRef)trust;
复制代码
NSURLAuthenticationChallenge
@protocol NSURLAuthenticationChallengeSender <NSObject>
- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)
challenge;
- (void)continueWithOutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

@optional
- (void)performDefaultHandlingForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
- (void)rejectProtectionSpaceAndContinueWithChallenge:(NSURLAuthenticationChallenge *)challenge;
@end
复制代码
- (instancetype)initWithProtectionSpace:(NSURLProtectionSpace *)space proposedCredential:(nullable NSURLCredential *)credential previousFailureCount:(NSInteger)previousFailureCount failureResponse:(nullable NSURLResponse *)response error:(nullable NSError *)error sender:(id<NSURLAuthenticationChallengeSender>)sender;
- (instancetype)initWithAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge sender:(id<NSURLAuthenticationChallengeSender>)sender;
@property (readonly, copy) NSURLProtectionSpace *protectionSpace;
@property (nullable, readonly, copy) NSURLCredential *proposedCredential;
... ...
@property (nullable, readonly, retain) id<NSURLAuthenticationChallengeSender> sender;
复制代码
NSURLProtectionSpace
- (instancetype)initWithHost:(NSString *)host port:(NSInteger)port protocol:(nullable NSString *)protocol realm:(nullable NSString *)realm authenticationMethod:(nullable NSString *)authenticationMethod;
- (instancetype)initWithProxyHost:(NSString *)host port:(NSInteger)port type:(nullable NSString *)type realm:(nullable NSString *)realm  authenticationMethod:(nullable NSString *)authenticationMethod;

@property (readonly) BOOL receivesCredentialSecurely;
@property (readonly) BOOL isProxy;
... ... 
复制代码

从上述文章来看,要完整构造一个网络请求,需要涉及方方面面,还是蛮复杂的。接下来我们就来看一个第三方库:AFNetWorking。

AFNetWorking

上文分析过系统处理网络请求的类之后,我们来看一下AFNetWorking做了些什么?

AFURLSessionManager
@property (readonly, nonatomic, strong) NSURLSession *session;
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, strong) id <AFURLResponseSerialization>responseSerializer;
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
复制代码

manager包含有NSURLSession对象,operationQueue,遵循自定义协议AFURLResponseSerialization的代理responseSerializer,自定义类AFSecurityPolicy的对象。

#if !TARGET_OS_WATCH
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
#endif
复制代码

manager包含网络监听类AFNetWorkReachabilityManager的对象。

@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;
复制代码

队列completionQueue,组completionGroup,是否允许在后台创建上传任务。

- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration;
复制代码

构造方法

- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;
复制代码

注销session同时根据传参决定是否取消任务。

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)reuqest
                            uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                          downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                         completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
复制代码

创建dataTask,通过Block回调处理返回信息。

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullabel error))completionHandler;

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         framData:(nullable NSData *)bodyData
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                    completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                       progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                    completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
复制代码

三种创建uploadTask的方式,上传文件,上传数据,将数据整合进httpRequest上传。

- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                            destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                        completionHandler:(nullable void (^)(NSURLRepsonse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                             destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                        completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler
复制代码

创建downloadTask,提供断点下载方法。

- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
复制代码

获取上传、下载的进度。

AFNetWorking将系统提供的delegate方法封装成block块执行,block相比于delegate,因为返回处理的代码和初始化的代码在一块,更易于也理解。但是也会造成代码结构不清晰。 如:- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;

AFURLRequestSerialization
AFHTTPRequestSerializer

除了编码格式(stringEncoding),是否允许蜂窝通信(allowsCellularAccess),cachePolicy,是否添加cookie,是否使用管道流(HTTPShouldUsePipeling),networkServiceType,超时(timeoutInterval),请求头(HTTPRequestHeaders)等,我们来看一下AFHTTPRequestSerializer的方法。

+ (instancetype)serializer;

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                 parameters:(nullable id)parameters
                                      error:(NSError * _Nullable __autoreleasing *)error;
- (NSMutableURLRequest *)multipartFromRequestWithMethod:(NSString *)method
                                                URLString:(NSString *)URLString
                                               parameters:(nullable NSDictionary <NSString *, id> *)parameters
                                        constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                                                     error:(NSError * _Nullable __autoreleasing *)error;
复制代码
AFJSONRequestSerializer
+ (instancetype)serializerWithWritingOptions:(NSJSONWritingOptions)writingOptions;
复制代码

相较于AFHTTPRequestSerializer,AFJSONRequestSerializer多了一个NSJSONWritingOptions

AFPropertyListRequestSerializer
+ (instancetype)serializerWithFormat:(NSPropertyListFormat)format
                        writeOptions:(NSPropertyListWriteOptions)writeOptions;
复制代码

属性列表的序列化

AFURLResponseSerialization

看完请求序列化后,我们来看一下响应序列化

AFHTTPResponseSerializer
 + (instancetype)serializer;
@property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;
复制代码

状态码,contentTypes

AFJSONResponseSerializer
+ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions;

@property (nonatomic, assign) BOOL removesKeysWithNullValues;
复制代码
AFXMLParserResponseSerializer
AFXMLDocumentResponseSerializer
+ (instancetype)serializerWithXMLDoxumentOptions:(NSUinteger)mask;
复制代码
AFPropertyListResponseSerializer
+ (instancetype)serializerWithFormat:(NSPropwertyListFormat)format
                         readOptions:(NSPropertyListReadOptions)readOptions;
复制代码

和AFPropertyListRequestSerializer一样

AFImageResponseSerializer
@property (nonatomic, assign) CGFloat imageScale;
@property (nonatomic, assign) BOOL automaticallyInflateResponseImage;
复制代码
AFSecurityPolicy

添加SSL证书可以帮助应用阻止中间人攻击,应用在处理用户敏感信息或者是金融交易时强烈建议使用HTTPS。

@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
复制代码

验证方式AFSSLPinningModeNone(不验证) AFSSLPinningModePublicKey(通过公钥) AFSSLPiningModeCertificate(通过证书)

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                forDomain:(nullable NSString *)domain;
复制代码
AFHTTPSessionManager

在我们的应用中,主要是使用AFHTTPSessionManager进行网络请求,我们来看一下他里面有什么属性和方法?

// URL
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
// 请求序列化
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
// 响应序列化
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
// 安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
复制代码
+ (instancetype)manager;
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
- (instancetype)initWithBaseURL:(nullable NSURL *)url
           sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration;
复制代码

三种初始化方法

- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
                            parameters:(nullable id)parameters
                              progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
                               success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                               failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
                    parameters:(nullable id)parameters
                       success:(nullable void (^)(NSURLSessionDataTask *task))success
                       failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(nullable id)parameters
                               progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
                                success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(nullable id)parameters
              constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                               progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
                                success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
                   parameters:(nullable id)parameters
                      success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                      failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
                     parameters:(nullable id)parameters
                        success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                        failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
                      parameters:(nullable id)parameters
                         success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                         failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
复制代码

经过AFNetWorking封装后,我们在进行网络编程是只需要面向AFHTTPSessionManager进行编程,网络请求任务繁重程度减轻了不少。

HTTPS

HTTPS(Hyptertext Transfer Protocol over Secure Socket Layer),所以HTTPS = HTTP + SSL。 接下来我们先认识一下加解密。

对称加密

对称加密在对信息进行加密和解密是使用相同的密钥。常见的对称加密有:DES(Data Encryption Standard)、AES(Advances Encryption Standard), RC4、IDEA。

非对称加密

客户端C生成一对公钥(CL)和私钥(CK),服务器端(S)生成了一对公钥(SL)和私钥(SK),C想S发信息时用SL加密,S收到信息后,用SK解密;同样,S向C发消息时,用CL加密,C收到信息后用CK解密。公钥就是锁,私钥就是钥匙。信息被拦截后,由于拦截者没有私钥,也打不开锁。信息依然是安全的。一句话来说。非对称加密就是用对方的锁加密信息,整个过程存在两把锁,而对称加密使用一把锁。

摘要算法

采用Hash算法将需要加密的铭文"摘要"成一串固定长度(128位)的密文,不同明文摘要成密文,结果不同。可以确保信息完整性、防止信息被篡改。

数字签名

明文-> hash运算 -> 摘要 -> 私钥加密 -> 数字签名 确保信息确实是由发送方签名并发出的。数字签名确保信息的完整性。

数字证书

简单来说,第三方机构确保SL的确是S的锁,AL的确是A的锁。 通信过程如下:

参考文章:详解https是如何确保安全的?

转载请注明出处。

转载于:https://juejin.im/post/5ada899c518825671775deb1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值