How to set HTTP request body using AFNetwork's

2019-01-21 23:53发布

问题:

I am using AFHTTPRequestOperationManager (2.0 AFNetworking library) for a REST POST request. But the manager only have the call to set the parameters.

-((AFHTTPRequestOperation *)POST:(NSString *)URLString
                  parameters:(NSDictionary *)parameters
                     success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                     failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

I need to set HTTP request body with a string as well. How can I do it using the AFHTTPRequestOperationManager? Thanks.

回答1:

I had the same problem and solved it by adding code as shown below:

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL
              cachePolicy:NSURLRequestReloadIgnoringCacheData  timeoutInterval:10];

[request setHTTPMethod:@"POST"];
[request setValue:@"Basic: someValue" forHTTPHeaderField:@"Authorization"];
[request setValue: @"application/json" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody: [body dataUsingEncoding:NSUTF8StringEncoding]];

AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

    NSLog(@"JSON responseObject: %@ ",responseObject);

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", [error localizedDescription]);

}];
[op start];


回答2:

for AFHTTPRequestOperationManager

[requestOperationManager.requestSerializer setValue:@"your Content Type" forHTTPHeaderField:@"Content-Type"];
[requestOperationManager.requestSerializer setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];

// Fill parameters
NSDictionary *parameters = @{@"name"        : @"John",
                             @"lastName"    : @"McClane"};

// Customizing serialization. Be careful, not work without parametersDictionary
[requestOperationManager.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) {

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:nil];
    NSString *argString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    return argString;
}];

[requestOperationManager POST:urlString parameters:parameters timeoutInterval:kRequestTimeoutInterval success:^(AFHTTPRequestOperation *operation, id responseObject) {

    if (success)
        success(responseObject);

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

    if (failure)
        failure(error);
}];


回答3:

Check what that convenience method (POST:parameters:success:failure) is doing under the hood and do it yourself to get access to actual NSMutableRequest object.

I'm using AFHTTPSessionManager instead of AFHTTPRequestOperation but I imagine the mechanism is similar.

This is my solution:

  1. Setup Session Manager (headers etc)

  2. Manually create NSMutable request and add my HTTPBody, basically copying-pasting code inside that convenience method. Looks like this:

    NSMutableURLRequest *request = [manager.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:<url string>] absoluteString] parameters:parameters];
    
    [request setHTTPBody:[self.POSTHttpBody dataUsingEncoding:NSUTF8StringEncoding]];
    __block NSURLSessionDataTask *task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
           // error handling
        } else {
            // success
      }
    }];
    
    [task resume];
    


回答4:

If you dig a little in sources of AFNetworking you will find that in case of POST method parameters are set into body of your HTTP request.

Each key,value dictionary pair is added to the body in form key1=value1&key2=value2. Pairs are separated by & sign.

Search for application/x-www-form-urlencoded in AFURLRequestSerialization.m.

In case of a string which is only a string, not key value pair then you might try to use AFQueryStringSerializationBlock http://cocoadocs.org/docsets/AFNetworking/2.0.3/Classes/AFHTTPRequestSerializer.html#//api/name/setQueryStringSerializationWithBlock: but this is only my guess.



回答5:

You could create your own custom subclass of AFHTTPRequestSerializer, and set this as the requestSerializer for your AFHTTPRequestOperationManager.

In this custom requestSerializer, you could override

- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request         
                               withParameters:(id)parameters 
                                        error:(NSError *__autoreleasing *)error;

Inside your implementation of this method, you'll have access to the NSURLRequest, so you could do something like this

- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request     
                               withParameters:(id)parameters 
                                        error:(NSError *__autoreleasing *)error  
{    
    NSURLRequest *serializedRequest = [super requestBySerializingRequest:request withParameters:parameters
     error:error];
    NSMutableURLRequest *mutableRequest = [serializedRequest mutableCopy];          
    // Set the appropriate content type
    [mutableRequest setValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];              
    // 'someString' could eg be passed through and parsed out of the 'parameters' value
    NSData *httpBodyData = [someString dataUsingEncoding:NSUTF8StringEncoding];
    [mutableRequest setHTTPBody:httpBodyData];

    return mutableRequest;
}

You could take a look inside the implementation of AFJSONRequestSerializer for an example of setting custom HTTP body content.



回答6:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager POST:url parameters:jsonObject success:^(AFHTTPRequestOperation *operation, id responseObject) {
    //success
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    //fail
}];

This is the best and most concise way that I have found.



回答7:

May be we can use the NSMutableURLRequest, here is the code :

NSURL *url = [NSURL URLWithString:yourURLString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:60.0];

[request setHTTPMethod:@"POST"];
NSData *JSONData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:nil];
NSString *contentJSONString = [[NSString alloc] initWithData:JSONData encoding:NSUTF8StringEncoding];
[request setHTTPBody:[contentJSONString dataUsingEncoding:NSUTF8StringEncoding]];

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];