Hermod
基于 AFNetworking 的用户友好型 HTTP 客户端
安装
将 Hermod 导入项目的最简单方法是使用 Cocoa Pods
pod 'Hermod', '~> 1.0.0'
1. HTTP 客户端
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
的默认init方法,并将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格式的响应(响应对象将是以字典或列表形式返回的HMClientResponseSerializerTypeRaw
:原始响应(响应对象将是以数据样式返回的NSData
)。
默认情况下,请求和响应序列化器设置为JSON格式。但是,也可以将它们更改为其他类型。
HMetadataClient只支持上面列出的类型。如果需要其他类型,将需要扩展并实现该库。
1.4.3 响应调度队列
该库构建在AFNetworking之上。因此,在执行请求时,响应会在AFNetworking默认选取的dispatch_queue_t
上异步返回,通常是主线程。
HMClient
提供选项,可以设置自定义的dispatch_queue_t
以返回其请求的响应。这可以在全局或针对每个请求进行设置。
要针对每个请求设置,请在HMRequest
的completionBlockQueue
参数内设置一个dispatch_queue_t
。如果未设置(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 令牌持久化
所有从服务器收到的令牌都会自动安全地存储在 Keychain 中。连续应用执行将重用之前收到的令牌。
否则,请使用方法 -configureWithOAuth:forSessionAccess:
手动设置 OAuth 令牌(也将存储在 Keychain 中)。
使用方法 -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 应用令牌与用户令牌的区别
默认情况下,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.