【问题标题】:ASIFormDataRequest in AFNetworking?AFNetworking 中的 ASIFormDataRequest?
【发布时间】:2012-04-02 23:04:25
【问题描述】:

我在 ASIHTTP 中有一些代码,但我想继续使用 AFNetworking。 我将 ASIFormDataRequest 用于一些 POST 请求,这段代码运行良好:

NSURL *url = [NSURL URLWithString:@"http://someapiurl"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:@"123" forKey:@"phone_number"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
    NSLog(@"Response: %@", [[request responseString] objectFromJSONString]);

}

但是,当我尝试对 AFNetworking 做同样的事情时,我遇到了内容类型的问题(我猜)。

这是 AFNetworking 代码,它不起作用:

    NSURL *url = [NSURL URLWithString:@"http://dev.url"];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];

    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            @"123", @"phone_number",
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"/api/get_archive" parameters:params];
    [request setValue:@"application/x-www-form-urlencoded; charset=UTF8" forHTTPHeaderField:@"Content-Type"];

    AFHTTPRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest
*request, NSHTTPURLResponse *response, id JSON) {
                NSLog(@"Response: %@", JSON);
            } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
                NSLog(@"Error: %@", error);
            }];
            [operation start];

网址没问题,已检查。 我从服务器得到这个:

{NSErrorFailingURLKey=http://dev.thisapiurl, NSLocalizedDescription=Expected content type {(
    "text/json",
    "application/json",
    "text/javascript"
)}, got text/html}

【问题讨论】:

    标签: objective-c ios asihttprequest afnetworking


    【解决方案1】:

    您遇到的问题是因为您正在实例化一个 AFJSONRequestOperation,默认情况下它需要一个 JSON 友好的响应类型。您期待 JSON 响应吗?如果没有,您应该使用不太具体的 Request 类。例如,您可以使用 HTTPRequestOperationWithRequest: .

    NSURL *url = [NSURL URLWithString:@"http://dev.url"];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            @"123", @"phone_number",
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"/api/get_archive" parameters:params];
    [request setValue:@"application/x-www-form-urlencoded; charset=UTF8" forHTTPHeaderField:@"Content-Type"];
    
    //Notice the different method here!
    AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request 
        success:^(AFHTTPRequestOperation *operation, id responseObject) {
                NSLog(@"Response: %@", responseObject);
            } 
        failure:^(AFHTTPRequestOperation *operation, NSError *error){
                NSLog(@"Error: %@", error);
            }];
    //Enqueue it instead of just starting it.
    [httpClient enqueueHTTPRequestOperation:operation];
    

    如果您有更具体的请求/响应类型(JSON、XML 等),您可以使用那些特定的 AFHTTPRequestOperation 子类。否则,只需使用普通的 HTTP。

    【讨论】:

    • 是的,这正是我所需要的。谢谢!
    • “期望 JSON 友好的响应类型”是什么意思?我的 Web 服务返回 JSON 响应。你能看看this question
    • @jagill “期望 JSON 友好的响应类型”是什么意思?它是否检查 Content-Type=application/json ?
    【解决方案2】:

    我最近经历了和你一样的事情。这是我编写的一个自定义类,用于处理几乎所有的网络请求。

    NetworkClient.h:

    //
    //  NetworkClient.h
    //
    //  Created by LJ Wilson on 3/8/12.
    //  Copyright (c) 2012 LJ Wilson. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    extern NSString * const ACHAPIKey;
    
    @interface NetworkClient : NSObject
    
    +(void)processURLRequestWithURL:(NSString *)url 
                          andParams:(NSDictionary *)params 
                              block:(void (^)(id obj))block;
    
    +(void)processURLRequestWithURL:(NSString *)url 
                          andParams:(NSDictionary *)params 
                        syncRequest:(BOOL)syncRequest
                              block:(void (^)(id obj))block;
    
    +(void)processURLRequestWithURL:(NSString *)url 
                          andParams:(NSDictionary *)params 
                        syncRequest:(BOOL)syncRequest
                 alertUserOnFailure:(BOOL)alertUserOnFailure
                              block:(void (^)(id obj))block;
    
    +(void)handleNetworkErrorWithError:(NSError *)error;
    
    +(void)handleNoAccessWithReason:(NSString *)reason;
    @end
    

    NetworkClient.m:

    //
    //  NetworkClient.m
    //
    //  Created by LJ Wilson on 3/8/12.
    //  Copyright (c) 2012 LJ Wilson. All rights reserved.
    //
    
    #import "NetworkClient.h"
    #import "AFHTTPClient.h"
    #import "AFHTTPRequestOperation.h"
    #import "SBJson.h"
    
    NSString * const APIKey = @"APIKeyIfYouSoDesire";
    
    @implementation NetworkClient
    
    +(void)processURLRequestWithURL:(NSString *)url 
                          andParams:(NSDictionary *)params 
                              block:(void (^)(id obj))block {
    
        [self processURLRequestWithURL:url andParams:params syncRequest:NO alertUserOnFailure:NO block:^(id obj) {
            block(obj);
        }];
    }
    
    +(void)processURLRequestWithURL:(NSString *)url 
                          andParams:(NSDictionary *)params 
                        syncRequest:(BOOL)syncRequest
                              block:(void (^)(id obj))block {
        if (syncRequest) {
            [self processURLRequestWithURL:url andParams:params syncRequest:YES alertUserOnFailure:NO block:^(id obj) {
                block(obj);
            }];
        } else {
            [self processURLRequestWithURL:url andParams:params syncRequest:NO alertUserOnFailure:NO block:^(id obj) {
                block(obj);
            }];
        }
    }
    
    
    +(void)processURLRequestWithURL:(NSString *)url 
                          andParams:(NSDictionary *)params 
                        syncRequest:(BOOL)syncRequest
                 alertUserOnFailure:(BOOL)alertUserOnFailure
                              block:(void (^)(id obj))block {
    
        // Default url goes here, pass in a nil to use it
        if (url == nil) {
            url = @"MyDefaultURLGoesHere";
        }
    
        NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:params];
        [dict setValue:APIKey forKey:@"APIKey"];
    
        NSDictionary *newParams = [[NSDictionary alloc] initWithDictionary:dict];
    
        NSURL *requestURL;
        AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:requestURL];
    
        NSMutableURLRequest *theRequest = [httpClient requestWithMethod:@"POST" path:url parameters:newParams];
    
        __block NSString *responseString = [NSString stringWithString:@""];
    
        AFHTTPRequestOperation *_operation = [[AFHTTPRequestOperation alloc] initWithRequest:theRequest];
        __weak AFHTTPRequestOperation *operation = _operation;
    
        [operation  setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            responseString = [operation responseString];
    
            id retObj = [responseString JSONValue];
    
            // Check for invalid response (No Access)
            if ([retObj isKindOfClass:[NSDictionary class]]) {
                if ([[(NSDictionary *)retObj valueForKey:@"Message"] isEqualToString:@"No Access"]) {
                    block(nil);
                    [self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:@"Reason"]];
                }
            } else if ([retObj isKindOfClass:[NSArray class]]) {
                NSDictionary *dict = [(NSArray *)retObj objectAtIndex:0];
                if ([[dict valueForKey:@"Message"] isEqualToString:@"No Access"]) {
                    block(nil);
                    [self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:@"Reason"]];
                }
            }
            block(retObj);
        } 
                                          failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                              NSLog(@"Failed with error = %@", [NSString stringWithFormat:@"[Error]:%@",error]);
                                              block(nil);
                                              if (alertUserOnFailure) {
                                                  [self handleNetworkErrorWithError:operation.error];
                                              }
    
                                          }];
    
        [operation start];
    
        if (syncRequest) {
            // Only fires if Syncronous was passed in as YES.  Default is NO
            [operation waitUntilFinished];
        } 
    
    
    }
    
    
    +(void)handleNetworkErrorWithError:(NSError *)error {
        NSString *errorString = [NSString stringWithFormat:@"[Error]:%@",error];
    
        // Standard UIAlert Syntax
        UIAlertView *myAlert = [[UIAlertView alloc] 
                                initWithTitle:@"Connection Error" 
                                message:errorString 
                                delegate:nil 
                                cancelButtonTitle:@"OK" 
                                otherButtonTitles:nil, nil];
    
        [myAlert show];
    
    }
    
    +(void)handleNoAccessWithReason:(NSString *)reason {
        // Standard UIAlert Syntax
        UIAlertView *myAlert = [[UIAlertView alloc] 
                                initWithTitle:@"No Access" 
                                message:reason 
                                delegate:nil 
                                cancelButtonTitle:@"OK" 
                                otherButtonTitles:nil, nil];
    
        [myAlert show];
    
    }
    
    @end
    

    这增加了一些您可能不需要或不想要的功能,只要版权部分保持不变,请随时根据需要对其进行修改。我使用该 APIKey 来验证请求来自我的应用程序,而不是试图破解的人。

    调用它(假设您已包含 NetworkClient.h:

    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                                @"ParamValue1", @"ParamName1",
                                @"ParamValue2", @"ParamName2",
                                nil];
    
    
        [NetworkClient processURLRequestWithURL:nil andParams:params block:^(id obj) {
            if ([obj isKindOfClass:[NSArray class]]) {
                // Do whatever you want with the object.  In this case, I knew I was expecting an Array, but it will return a Dictionary if that is what the web-service responds with.
            }
        }];    
    

    也可以:

    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                                @"ParamValue1", @"ParamName1",
                                nil];
    
        NSString *urlString = @"https://SuppliedURLOverridesDefault";
        [NetworkClient processURLRequestWithURL:urlString 
                                      andParams:params 
                                    syncRequest:YES 
                             alertUserOnFailure:NO 
                                          block:^(id obj) {
                                              if ([obj isKindOfClass:[NSArray class]]) {
                                                  // Do stuff
                                              }
                                          }];
    

    因此,它会接受任意数量的参数,如果您愿意,可以注入 APIKey 或其他任何内容,并根据 Web 服务返回字典或数组。这确实需要 SBJson BTW。

    【讨论】:

    • EIJay,谢谢你的回答,但我想使用 AFNetworking 框架,因为我知道它会被维护并且会变得更好。这就是我离开 ASIHTTP 的原因
    • 我离开 ASI 的原因是因为 AFNetworking 使用块而不是委托方法,而且如果不覆盖,它永远不会与 ARC 兼容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多