79

I've just started using AFNetworking 2.0 and I was wondering how I put in headers into a HTTP Get request. The documentation sets up a GET like this:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
[manager POST:@"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];

But since we're not handling NSURLRequests I'm not sure how to set HTTP Headers.

Any help would be appreciated.
Regards,
Mike

Mackey18
  • 2,322
  • 2
  • 25
  • 39
  • possible duplicate of [How to add custom header to AFNetworking on a JSONRequestOperation](http://stackoverflow.com/questions/15141115/how-to-add-custom-header-to-afnetworking-on-a-jsonrequestoperation) – RyanR Oct 19 '13 at 13:05
  • 3
    @RyanR not a duplicate. That is from AFN 1.x not 2.0. Everything has completely changed since then. – Mackey18 Oct 19 '13 at 13:47
  • According to the [migration guide](https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-2.0-Migration-Guide) AFHttpClient still exists and still has the responsibility of executing Http requests for your app – RyanR Oct 19 '13 at 13:51
  • @RyanR using AFHTTPClient's `setDefaultHeader` method is a nasty way of proceeding. I'm in need of a way of setting headers on an individual request level. – Mackey18 Oct 19 '13 at 13:53
  • @RyanR besides AFHTTPClient is no longer included in 2.0 – Mackey18 Oct 19 '13 at 13:55
  • 2
    An open source project with conflicting documentation? NEVAR. AFHTTPClient -> AFHTTPSessionManager apparently. You're right, using `setDefaultHeader` sucks. A 30 second search of the docs and I find [AFHTTPRequestSerializer](http://cocoadocs.org/docsets/AFNetworking/2.0.0/Classes/AFHTTPRequestSerializer.html#//api/name/setValue:forHTTPHeaderField:) is responsible for HTTPHeaders on a per-request basis. – RyanR Oct 19 '13 at 13:58
  • 2
    @RyanR D'oh missed that! Found the correct method thanks to your finding: `manager.requestSerializer setValue:<#(NSString *)#> forHTTPHeaderField:<#(NSString *)#>` – Mackey18 Oct 19 '13 at 14:07
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/39567/discussion-between-ryanr-and-mackey18) – RyanR Oct 19 '13 at 17:01

7 Answers7

147

Here's an example using AFNetworking 2.0

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:@"calvinAndHobbesRock" forHTTPHeaderField:@"X-I do what I want"];

[manager GET:@"http://localhost:3000" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

The key are the following 2 lines:

manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:@"calvinAndHobbessRock" forHTTPHeaderField:@"X-I-do-what-I-want"];
danielbeard
  • 9,120
  • 3
  • 44
  • 58
Shaheen Ghiassy
  • 7,397
  • 3
  • 40
  • 40
84

The fantastic documentation for AFNetworking 2.0 makes this a little hard to find, but it is there. On the AFHTTPRequestSerializer is -setValue:forHTTPHeaderField:.

Alternatively, if you follow their recommended approach of creating a session manager that derives from AFHTTPSessionManager then that class can override a method to modify headers on each request -dataTaskWithRequest:completionHandler:. I use this to inspect requests and modify headers on a case-by-case basis, and prefer it to modifying the serializer as it keeps the responsibility for networking contained in that manager (and avoids mucking with singletons)

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLResponse *, id, NSError *))completionHandler
{
    static NSString *deviceId;
    if(!deviceId)
    {
        deviceId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    }

    NSMutableURLRequest *req = (NSMutableURLRequest *)request;
    // Give each request a unique ID for tracing
    NSString *reqId = [NSString stringWithFormat:@"%@+%@", deviceId, [[NSUUID UUID] UUIDString] ];
    [req setValue:reqId forHTTPHeaderField:"x-myapp-requestId"];
    return [super dataTaskWithRequest:req completionHandler:completionHandler];
}
RyanR
  • 7,728
  • 1
  • 25
  • 39
  • Thanks mate. Appreciated. – Mackey18 Oct 19 '13 at 14:29
  • 4
    u mind adding a snippet of how this would be used? im a android guy trying to learn ios and im not quite sure how to put this answer to use. – ChuckKelly Nov 30 '13 at 01:13
  • 1
    but why are the headers set in the serialiser??? i also noticed that this way they are persistent, so once you set a header field, it fill stay there forever! (i had to add my own method to remove them) – Peter Lapisu Jan 29 '14 at 13:43
  • 4
    @PeterLapisu calling this method with `nil` for `value` will remove it. You shouldn't be using headers to pass ephemeral values from the client to the server - that is part of your payload. Headers are for values that don't change frequently, like auth data, cache control, etc. Some servers will even determine whether to return cached data based on the header parameters matching, which you wouldn't want to prevent accidentally. If you need to set headers for single requests only, I suspect it is data that belongs in the payload. – RyanR Jan 29 '14 at 14:07
  • i was setting the custom auth headers each time before request (cause i thought the headers are for the current request)... after logging out, the headers were still present :/ later i figured out, the they are 'pernament'... but anyway dont know why they belong to the serializer – Peter Lapisu Jan 29 '14 at 15:05
  • 2
    @PeterLapisu I don't know what the AFN teams reasoning was, but it definitely makes sense from a design perspective. The Serializer is the thing which knows how to encode/decode the request & response for whatever protocol you're using. If it was over FTP you would serialize that info differently than over a Message Queue. This way only the component responsible for that type of transport knows the details of the transport (this is part of [encapsulation](http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming) ) – RyanR Jan 29 '14 at 16:39
  • 2
    still belive its a bad design issue https://github.com/AFNetworking/AFNetworking/issues/1793 – Peter Lapisu Feb 03 '14 at 23:30
  • 1
    I think an example and explanation in addition to just the link would be in its place here. – jake_hetfield Jul 16 '14 at 13:02
17

adding response and request serializer solved my problem.

manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.requestSerializer = [AFJSONRequestSerializer serializer];

[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
rickerbh
  • 9,731
  • 1
  • 31
  • 35
user2073541
  • 171
  • 1
  • 5
7

I have used this form to make an appointment with a specific header.

AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[operationManager.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

[operationManager POST:url
            parameters:params
               success:^(AFHTTPRequestOperation *operation, id responseObject) {

                   if (success) {
                       success(responseObject);
                   }

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

                   NSLog(@"Error: %@", [error description]);

               }
 ];
skypjack
  • 49,335
  • 19
  • 95
  • 187
Carlos Avalos
  • 247
  • 4
  • 8
  • Don't you think, that these headers will be sent with any request from the moment you've set them? – vahotm Feb 16 '16 at 11:28
6

Here's what i believe to be a best option. In a singleton somewhere, configure an AFHTTPSessionManager using an NSURLSessionConfiguration, and then use that AFHTTPSessionManager every time you want to make a request.

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPAdditionalHeaders = @{@"Accepts": @"application/json"};

mySingletonSessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:kMyBaseUrl] sessionConfiguration:config];
Axel Guilmin
  • 11,454
  • 9
  • 54
  • 64
Chris
  • 39,719
  • 45
  • 189
  • 235
3

I did this...for those that are passing token

[manager.requestSerializer setValue:[NSString stringWithFormat:@"Token token=\"%@\"", _userObj.oAuth] forHTTPHeaderField:@"Authorization"];
Serge Pedroza
  • 2,160
  • 3
  • 28
  • 41
-3

Use the following code to put any type of header value:

[[FRHTTPReqManager sharedManager].requestSerializer setValue:value forHTTPHeaderField:key];
Josh
  • 5,631
  • 1
  • 28
  • 54
Evana
  • 1,754
  • 13
  • 12