Hermod
基于 AFNetworking 的用户友好的 HTTP 客户端
安装
将 Hermod 导入项目的最简单方法是使用 Cocoa Pods
pod 'Hermod', '~> 1.0.0'
1. HTTP Client
1.1 定义实例
要创建一个新的API客户端,您必须指定主机域名以及所有请求将被发送到的API路径。
HMClient *client = [[HMClient alloc] initWithConfigurator:^(HMClientConfigurator *configurator) {
configurator.serverPath = @"http://www.domain.com";
configurator.apiPath = @"/api/v1";
}];
1.2 创建请求和上传请求
使用HMClient
创建请求非常简单。只需创建一个HMRequest
实例并对其进行配置。
HMRequest *request = [HMRequest requestWithPath:@"users/hobbies"];
request.HTTPMethod = HMHTTPMethodPUT;
request.parameters = @{"name": "kitesurfing",
"rating": 8,
};
默认情况下,请求使用HMHTTPMethodGET
。
要创建一个上传请求,实例化HMUploadRequest
并添加一个HMUploadTask
对象的数组,每个上传任务一个。上传请求默认使用HMHTTPMethodPOST
。
1.3 执行请求
为了执行请求,HMClient
提供了一个名为HMRequestExecutor
的协议,该协议定义了以下两个方法
- (void)performRequest:(HMRequest*)request completionBlock:(HMResponseBlock)completionBlock;
- (void)performRequest:(HMRequest*)request apiPath:(NSString*)apiPath completionBlock:(HMResponseBlock)completionBlock;
第一个方法使用默认的apiClient的apiPath
,第二个方法使用自定义的apiPath
。响应块包含一个HMResponse
。如果发生错误,它将被封装在HMResponse
中。
HMClient
实现了这个协议。因此,您可以直接使用它来执行请求。然而,您可以构建自己的请求执行器并在其中进行验证检查和其他自定义操作。一个好的例子是,HMClient
提供了一个名为HMOAuthSession
的OAuth会话处理器。该对象实现了HMRequestExecutor
协议,验证OAuth状态并使用正确的HTTP身份验证头配置HMClient
实例。有关该对象的更多信息,请参阅以下文档。
id <HMRequestExecutor> requestExecutor = _myApiClient;
HMRequest *request = [HMRequest requestWithPath:@"users/reset-password"];
request.httpMethod = HTTPMethodPOST;
request.parameters = @{@"email": email};
[requestExecutor performRequest:request completionBlock:^(HMResponse *response, NSInteger key) {
if (response.error == nil)
{
NSLog(@"Response object: %@", [response.responseObject description]);
}
else
{
NSLog(@"Response error: %@", [response.error description]);
}
}];
1.4 配置API客户端
1.4.1 管理URL缓存
HMClient通过URL缓存实现基本离线模拟。要配置它,使用HMClient
的默认初始化方法,并将HMClientConfigurator
的cacheManagement
设置为HMClientCacheManagementOffline
。配置后,应用程序将使用URL缓存回退到离线时已缓存的响应。默认情况下,cacheManagement
设置为HMClientCacheManagementDefault
(当离线时忽略URL缓存)。
HMClient *apiClient = [[HMClient alloc] initWithConfigurator:^(HMClientConfigurator *configurator) {
configurator.host = @"http://www.domain.com";
configurator.apiPath = @"/api/v1";
// Use the URLCache to return already cached responses when being offline.
configurator.cacheManagement = HMClientCacheManagementOffline;
}];
1.4.2 选择请求和响应序列化器
配置HMClient
实例时,可以自定义请求和响应序列化器。
HMClient *apiClient = [[HMClient alloc] initWithConfigurator:^(HMClientConfigurator * _Nonnull configurator) {
// Here goes the overall configuration
[...]
// Configuration of request and response serializers
configurator.requestSerializerType = HMClientRequestSerializerTypeJSON;
configurator.responseSerializerType = HMClientResponseSerializerTypeJSON;
}];
支持的序列化器有
请求序列化器
HMClientRequestSerializerTypeJSON
:JSON格式请求(内容类型application/JSON)HMClientRequestSerializerTypeFormUrlencoded
:URL编码请求(内容类型application/x-www-form-urlencoded,带utf8字符集)
响应序列化器
HMClientResponseSerializerTypeJSON
:JSON格式响应(响应对象将为NSDictionary
或NSArray
)HMClientResponseSerializerTypeRaw
:原始响应(响应对象将为NSData
)。
默认情况下,请求和响应序列化器设置为JSON格式。但是,可以将它们更改为其他类型。
HMClient仅支持上述列出类型。如果需要其他类型,则需要扩展和实现库。
1.4.3 响应分发队列
此库建立在AFNetworking之上。因此,在执行请求时,响应将在AFNetworking默认选择的dispatch_queue_t
上异步返回,通常是在主队列上。
HMClient
提供设置自定义dispatch_queue_t
以返回其请求响应的选项。这可以在全局或请求级别设置。
要按请求设置,请将dispatch_queue_t
设置在HMRequest
的completionBlockQueue
参数内部。如果没有设置(为nil),则响应块将在HMClient的全局队列上执行。
HMRequest *request = [HMRequest requestWithPath:@"user/12345"];
request.completionBlockQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
要设置全局队列,请使用初始化方法中的HMClientConfigurator
对象。如果没有设置,则响应块将在默认的AFNetworking响应块队列上执行。
HMClient *apiClient = [[HMClient alloc] initWithConfigurator:^(HMClientConfigurator *configurator) {
configurator.host = @"http://www.domain.com";
configurator.apiPath = @"/api/v1";
// Set a custom queue for all response blocks
configurator.completionBlockQueue = dispatch_queue_create("com.myapp.api.completion-queue", DISPATCH_QUEUE_SERIAL);
}];
1.5 错误处理
使用HMClientDelegate
对象创建特定于服务器的错误并管理它们。
在下面的方法中,可以根据HTTP响应的内容指定自定义错误。如果返回错误,则HMClient
将假设请求失败,并将错误包含在其HMResponse
中。
- (NSError*)apiClient:(HMClient*)apiClient errorForResponseBody:(id)responseBody httpResponse:(NSHTTPURLResponse*)httpResponse incomingError:(NSError*)error
{
if ([responseBody isKindOfClass:NSDictionary.class])
{
if (responseBody[@"error_code"])
{
NSInteger errorCode = [responseBody[@"error_code"] integerValue];
NSString *message = responseBody[@"error_message"];
NSDictionary *userInfo = @{CustomApiErrorDomainNameKey: @(errorCode),
NSLocalizedDescriptionKey: message,
};
error = [NSError errorWithDomain:@"CustomApiErrorDomain" code:errorCode userInfo:userInfo];
}
}
return error;
}
最后,使用HMClientDelegate
的方法-apiClient:didReceiveErrorInResponse:
来全局管理错误。通常,您可以使用它来记录错误、显示警报,甚至在没有授权的情况下注销登录用户。
- (void)apiClient:(HMClient*)apiClient didReceiveErrorInResponse:(HMResponse*)response
{
// Manage the error of the response.
}
2. HMOAuthSession (OAuth 支持)
为了支持OAuth,Hermod有一个名为HMOAuthSession
的类。此类将保持OAuth会话处于活动状态并执行令牌的获取和刷新。此外,它实现了HMRequestExecutor
协议以支持OAuth执行请求。
2.1 配置
要配置一个 HMOAuthSession
,只需创建一个新实例并使用 initWithConfigurator:
方法,如下所示
HMOAuthSession *oauthSession = [[HMOAuthSession alloc] initWithConfigurator:^(HMOAuthSesionConfigurator *configurator) {
configurator.apiClient = apiClient; // <-- configured `HMClient` instance
configurator.apiOAuthPath = @"/api/oauth2/token";
configurator.clientId = @"client_id";
configurator.clientSecret = @"client_secret";
}];
需要提供配置好的 HMClient
实例、OAuth 方法的 API 路径、客户端 ID 和客户端密钥。
这就完成了。现在该实例已经准备好可以使用
id <HMRequestExecutor> requestExecutor = _myOauthApiSession;
HMRequest *request = [HMRequest requestWithPath:@"users/reset-password"];
request.httpMethod = HMHTTPMethodPOST;
request.parameters = @{@"email": email};
[requestExecutor performRequest:request completionBlock:^(HMResponse *response, NSInteger key) {
if (response.error == nil)
NSLog(@"Response object: %@", [response.responseObject description]);
else
NSLog(@"Response error: %@", [response.error description]);
}];
OAuth 会话将负责获取令牌,将它们配置到 HTTP 头中,并在它们过期时进行续订。
2.2 令牌持久存储
从服务器接收到的所有令牌将自动安全地存储在密钥链中。连续的 app 执行将复用先前接收到的令牌。
否则,使用方法 -configureWithOAuth:forSessionAccess:
手动设置 OAuth 令牌(也会存储在密钥链中)。
使用方法 -validateOAuth:
强制进行 OAuth 令牌验证。
2.3 OAuth 登录 & 登出
使用方法 loginWithUsername:password:completionBlock:
进行 OAuth 用户登录。使用方法 -logout
进行 OAuth 用户登出。
[_oauthSession loginWithUsername:@"username" password:@"password" completionBlock:^(NSError *error) {
if (!error)
NSLog(@"OAuth login successful");
else
NSLog(@"OAuth login failed with error: %@", error.localizedDescription);
}];
2.4 App 令牌 vs 用户令牌
默认情况下,HMOAuthSession
使用两级令牌:应用和用户。这意味着当用户未登录时,会话将检索应用级令牌。如果用户已登录,会话将检索用户级令牌。
默认配置设置为使用应用令牌。但是,可以禁用
HMOAuthSession *oauthSession = [[HMOAuthSession alloc] initWithConfigurator:^(HMOAuthSesionConfigurator *configurator) {
// Configuration of the oauth session here
[...]
// Disable app token
configurator.useAppToken = NO;
}];
2.5 OAuth命名空间配置
如果OAuth服务器为包含OAuth令牌的响应使用特定的命名空间配置,可以使用HMOAuthConfiguration
类进行相应配置。
HMOAuthConfiguration *oauthConfiguration = [[HMOAuthConfiguration alloc] init];
oauthConfiguration.expiresInKey = @"expires_in";
oauthConfiguration.refreshTokenKey = @"refresh_token";
oauthConfiguration.accessTokenKey = @"token";
oauthConfiguration.scopeKey = @"scope";
oauthConfiguration.expiryDateBlock = ^NSDate*(id value) {
NSTimeInterval timeInterval = [value integerValue];
return [NSDate dateWithTimeIntervalSinceReferenceDate:timeInterval];
};
HMOAuthSession *oauthSession = [[HMOAuthSession alloc] initWithConfigurator:^(HMOAuthSesionConfigurator *configurator) {
// Configuration of the oauth session here
[...]
// Custom oauth namespace configuration
configurator.oauthConfiguration = oauthConfiguration;
}];
2.6 OAuth代表
OAuth会话类HMOAuthSession
有一个必须实现HMOAuthSessionDelegate
的代理对象。
- (void)session:(HMOAuthSession*)session didConfigureOAuth:(HMOAuth*)oauth forSessionAccess:(HMOAuthSesionAccess)sessionAccess
{
// OAuth session access did change
}
项目维护者
此开源项目由Joan Martin维护。
许可证
Copyright 2016 Mobile Jazz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://apache.ac.cn/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.