iOS 和 RestKit:如何正确获取 text/html 响应?

Posted

技术标签:

【中文标题】iOS 和 RestKit:如何正确获取 text/html 响应?【英文标题】:iOS and RestKit: How to get a text/html response right? 【发布时间】:2014-02-17 13:17:48 【问题描述】:

我尝试了几个 *** 问题,但我找不到正确答案。我正在使用 Chrome 的 POSTMAN 插件来检查我的 REST 调用,但我无法弄清楚为什么我无法读取响应。在 cmets 中,您将看到我为获得响应所做的所有不同尝试。

NSDictionary* session_params = @SESSION_USERNAME_KEY:SESSION_USERNAME_VALUE, SESSION_PASSWORD_KEY:SESSION_PASSWORD_VALUE;
NSURL* url = [NSURL URLWithString:SESSION_URL];
RKObjectManager* objectManager = [RKObjectManager managerWithBaseURL:url];
//GET THE **** THING TO INTERPRET A TEXT response

//[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:RKMIMETypeTextXML];
//[objectManager setAcceptHeaderWithMIMEType:@"text/html"];
//[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeTextXML];
//[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:@"text/html"];
//[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"text/html"];
//[objectManager setRequestSerializationMIMEType:@"text/html"];

//END
NSMutableURLRequest* request = [objectManager requestWithObject:nil method:RKRequestMethodPOST path:SESSION_URL parameters:session_params];


RKObjectRequestOperation* operation = [objectManager
                                       objectRequestOperationWithRequest:request success:^(RKObjectRequestOperation* operation, RKMappingResult* result)
                                       
                                           NSLog(@"RESULT [%@]", result);
                                       
                                       failure:^(RKObjectRequestOperation *operation, NSError *error) 
                                           NSLog(@"ERROR [%@]", error);
                                       ];

    [operation start];

我认为最烦人的是我需要的东西都包含在 NSLocalizedRecoverySuggestion 值中。这是我需要的会话密钥。

输出:

E restkit.network:RKObjectRequestOperation.m:547 对象请求失败:基础 HTTP 请求操作失败并出现错误:错误域 = org.restkit.RestKit.ErrorDomain 代码 = -1016 “预期的内容类型 ( “应用程序/x-www-form-urlencoded”, “应用程序/json” ),得到的text / html”的UserInfo = 0x1c52aed0 = NSLocalizedRecoverySuggestion eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw,AFNetworkingOperationFailingURLRequestErrorKey =,= NSErrorFailingURLKey HTTP:// ...,NSLocalizedDescription =预期的内容类型( “应用程序/x-www-form-urlencoded”, “应用程序/json” ),得到文本/html,AFNetworkingOperationFailingURLResponseErrorKey= 2014-02-17 14:54:20.808 AppName[5600:6403] E restkit.network:RKObjectRequestOperation.m:213 POST 'http://...' (200 OK / 0 objects) [request=0.0000s mapping= 0.0000s total=0.1925s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "预期的内容类型( “应用程序/x-www-form-urlencoded”, “应用程序/json” ),得到的text / html”的UserInfo = 0x1c52aed0 = NSLocalizedRecoverySuggestion eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw,AFNetworkingOperationFailingURLRequestErrorKey =,= NSErrorFailingURLKey HTTP:// ...,NSLocalizedDescription =预期的内容类型( “应用程序/x-www-form-urlencoded”, “应用程序/json” ),得到文本/html,AFNetworkingOperationFailingURLResponseErrorKey=

有效的代码 感谢 Wain 为我指明了正确的路径。我有点失望 RestKit 无法处理如此简单的请求,我需要 RestKit 因为这只是调用其他方法的会话令牌,但我猜不管用什么:

NSDictionary* session_params = @SESSION_USERNAME_KEY:SESSION_USERNAME_VALUE, SESSION_PASSWORD_KEY:SESSION_PASSWORD_VALUE;

NSURL* url = [NSURL URLWithString:SESSION_URL];

AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:SESSION_URL parameters:session_params];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 
    NSString* response = [operation responseString];
    NSLog(@"response: %@",response);
 failure:^(AFHTTPRequestOperation *operation, NSError *error) 
    NSLog(@"error: %@", [operation error]);
];
[operation start];

【问题讨论】:

【参考方案1】:

这一点:

"预期的内容类型 ("application/x-www-form-urlencoded", "application/json"),得到 text/html"

告诉你你已经告诉 RestKit 期待 form-urlencodedjson,但是服务器正在返回 html。

可能想要使用带有 JSON mime 类型的 setAcceptHeaderWithMIMEType 来告诉服务器您想要返回什么。但是,在这种情况下,您可能不应该使用 RestKit。

RestKit 用于将任意 JSON / XML 数据映射到您的数据模型中。你只有一把钥匙回来了。不需要映射。因此,不要使用 RestKit,而是使用 AFNetworking(您可以完全访问它,因为 RestKit 在内部使用它。

【讨论】:

谢谢您 - 我已将工作代码与问题放在一起,以便我保留它以备不时之需,或者其他人有同样的问题。非常感谢您的帮助!【参考方案2】:

感谢 Wain 和 Quintin,这对我很有用 :)

我认为在RestkitAFNetworking 的较新版本中某些名称发生了变化。我使用了AFNetworking,正如其他答案中所解释的那样,因为服务器没有返回json,而是空的plain/text。这只是在一个特定的端点上,我在响应的标头中寻找一个令牌。

在这里也分享我的一段代码:

-(void) find_some_token_with_success:(void (^)(AFRKHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFRKHTTPRequestOperation *operation, NSError *error))failure 

    NSURL *baseURL = [NSURL URLWithString:@"https://example.com"];

    AFRKHTTPClient *client = [AFRKHTTPClient clientWithBaseURL:baseURL];
    [client setDefaultHeader:@"Accept" value:RKMIMETypeJSON];
    [client setDefaultHeader:@"some_custom_header" value:@"some_custom_value"];

    NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/api/v1/some_non_json_endpoint" parameters:nil];

    AFRKHTTPRequestOperation *operation = [[AFRKHTTPRequestOperation alloc] initWithRequest:request];

    [operation setCompletionBlockWithSuccess:success failure:failure];
    [operation start];

然后我用这样的东西来获取我正在寻找的标题:

-(void) get_the_token:(void (^)(NSString *token))withTokenCallback failure:(void (^)(AFRKHTTPRequestOperation *operation, NSError *error))failure 
    [self xsrftoken_with_success:^(AFRKHTTPRequestOperation *operation, id responseObject) 
        NSString *token = [self get_the_token_from_response:[operation response]];
        withTokenCallback(token);
     failure:failure];


-(NSString *) get_the_token_from_response: (NSHTTPURLResponse *) response;

    NSDictionary *headerDictionary = response.allHeaderFields;
    NSString *token = [headerDictionary objectForKey:@"SOME-TOKEN-KEY"];
    return token;

所以所有这些都可以像这样简单地使用:

- (void)testGetSometokenInARequest

    XCTestExpectation *expectation = [self expectationWithDescription:@"Query timed out."];

    [[SomeRequestWithoutJsonResponse alloc]
     get_the_token:^(NSString *token) 
         [expectation fulfill];
         NSLog(@"token: %@", token);
         // this token should be 100 characters long
         XCTAssertTrue([token length] == 100);
     
     failure:^(AFRKHTTPRequestOperation *operation, NSError *error) 
         NSLog(@"error: %@", [operation error]);
     ];

    [self waitForExpectationsWithTimeout:10.0 handler:nil];

换句话说,get_the_token 接受带有所需令牌的回调和失败回调。

确保您仍然包含 <RestKit/RestKit>,以便您可以访问 Restkit 的 AFNetowkring :)


使用 restkit 的替代工作解决方案:

RestKit: How to handle empty response.body?

然后您为这种 Mimetype 注册一个序列化程序,如下所示:

[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"text/plain"];

【讨论】:

以上是关于iOS 和 RestKit:如何正确获取 text/html 响应?的主要内容,如果未能解决你的问题,请参考以下文章

使用 iOS 5 和 RestKit 设置 CoreData 应用程序的正确方法是啥

iOS RestKit 自定义错误处理

RestKit 和核心数据 - 如何发布数据?

如何使用 Restkit 和 Core Data 存储对象和种子预加载数据

对于使用 RestKit v0.20.0 的键 Text,此类不符合键值编码

无法使用 RestKit 处理成功的 204 响应并正确映射失败的响应