The documentation for AFNetworking notes that you should create subclass of AFHTTPClient and use it as a singleton per web-service.
If I have 2 endpoints at www.example.com, one that allows for 'application/json' in HTTP_ACCEPT and another that needs text/html, what parameter would I configure in my singleton AFHTTPClient class so that it configures the correct HTTP_ACCEPT value?
Implementation details:
#interface MyAFHTTPClient : AFHTTPClient
+ (MyAFHTTPClient *)sharedClient;
#end
[[MyAFHTTPClient sharedClient] getPath:#"endPoint_json"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}]
At a later time, I need to invoke the html endpoint:
[[MyAFHTTPClient sharedClient] getPath:#"endPoint_html"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}]
It seems that both of these calls cause "HTTP_ACCEPT"=>"application/json" when the server receives the request.
getPath:... and all of those convenience methods construct a request with requestWithMethod:path:parameters:, and then pass that into HTTPRequestOperationWithRequest:success:failure:, which is then enqueued into an operation queue.
If you need to do a one-off request for HTML or the like, do these steps manually rather than using the convenience method: create the request, set the Accept (HTTP_ACCEPT) is not an HTTP header) header to text/html, and then create and enqueue the operation.
Related
Trying to debug AFNetworking in my application. I need to capture the time of both request and response time to get the duration.
The duration will help me to set a reasonable timeout for the GET operation. The default 60 seconds timeout is not enough.
How do I get the request and response time? Is it part of the AFHTTPRequestOperation object?
[[AFHTTPRequestOperationManager new] GET:#"http://www.example.com"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"startTime={} endTime={}");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"startTime={} endTime={}");
}
];
I have a class called API helper with a Method that looks like this:
+(RKObjectManager*) getRestObjectManager{
NSURL *baseURL = [NSURL URLWithString:BASE_URL];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
// initialize RestKit
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
return objectManager;
}
And I will create classes like API_User , API_Group etc. Each of these classes will have methods like
+(void)getDetails:(void (^)(User* user) )onSuccess{
//fetch object manager from api helper and perform request, on success, call the onSuccess block from the function parameter.
onSuccess(user); //if it was successful, i will create a user object and //return.
}
There will be several methods like getDetails , each which require an authentication token to be sent to work. The token can expire , and needs to be refreshed.
How do I :
Define some sort of an interceptor in API helper , so that when a request fails , it will fetch a new token (my token expired response itself provides a new token) ,and retry the request that had failed? I don't want to handle this for each and every endpoint that I define.
What I did was Extend RKObject Manager and handled failures there like so :
#implementation MYOWNObjectManager
#pragma mark - RKObjectManager Overrides
- (void)getObjectsAtPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(RKObjectRequestOperation *operation,
RKMappingResult *mappingResult))success failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure {
[super getObjectsAtPath:path parameters:parameters success:success failure:^(RKObjectRequestOperation *operation, NSError *error) {
//check if failure was due to token expiry, if yes call the code to refresh token. otherwise just call failure(operation, error);
[super getObjectsAtPath:path parameters:parameters success:success failure:failure]; //this line performs the request again.
}];
}
This snippet is for GET only. You will also need to override PUT/POST etc with the same logic
As titled, and how to check HTTP status of response?
For example, if the server returns http status code 403, I need to send a recall mail request again to take new access token.
Take a look at the below. In the failure block, retry/resend your query X number of times. Be sure to add logic to end retries at some point, so you don't end up with an infinite loop.
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.response.statusCode == 403) {
// retry
}
}
];
This answer may also be helpful.
I'm attempting to set custom headers on a per-request basis using AFNetworking, but occasionally the headers will seemingly disappear after being set. Below is the code used to make a request...
+ (void) getWithURI: (NSString*) uri header: (NSDictionary*) header success: (NSString*) successCallback failure: (NSString*)errorCallback dispatch: (NSString*)dispatchedId
{
createManagerInstance();
AFHTTPRequestOperation* operation = [manager GET:uri
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[RestWrapper succeededWithJson:operation.responseString dispatchedId:dispatchedId successCallback:successCallback];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[RestWrapper failedWithJson:operation.responseString dispatchedId:dispatchedId errorCallback:errorCallback];
}];
NSMutableURLRequest* request = (NSMutableURLRequest*)operation.request;
for (NSString* key in header)
{
if([request valueForHTTPHeaderField:key] != nil)
{
[request setValue:header[key] forHTTPHeaderField:key];
}
else
{
[request addValue:header[key] forHTTPHeaderField:key];
}
}
NSLog(#"Headers: %#", request.allHTTPHeaderFields);
[operation start];
}
For 95% of my requests, they go through as anticipated. Sporadically, however, some will fail and indicate a header is missing. This has been confirmed by capturing the requests in question using Fiddler and seeing that the headers are actually missing. Despite this, the console log of request.allHTTPHeaderFields always shows the headers in place.
The only other thing I noticed is that in general Fiddler reports the caching policy as "max-age=0, private, must-revalidate" for each request. However, whenever a request loses the custom headers, it's caching policy is "no-cache".
This is because you're adding HTTP Header fields in wrong way.
You should add it before request. You may try something like this :
+ (void) getWithURI: (NSString*) uri header: (NSDictionary*) header success: (NSString*) successCallback failure: (NSString*)errorCallback dispatch: (NSString*)dispatchedId{
createManagerInstance();
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:header[key] forHTTPHeaderField:key];
AFHTTPRequestOperation* operation = [manager GET:uri
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[RestWrapper succeededWithJson:operation.responseString dispatchedId:dispatchedId successCallback:successCallback];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[RestWrapper failedWithJson:operation.responseString dispatchedId:dispatchedId errorCallback:errorCallback];
}];
[operation start];
}
I can't find where is the body of my request? In what property?
[[RKObjectManager sharedManager] postObject:object
path:path
parameters:parameters
success:success
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"???");
}
Now how to print whole body of request? I'd like to see the path with header and parameters.
I was able to see output of everything via setting:
RKLogConfigureByName("RestKit/Network*", RKLogLevelTrace);
Body of your request is in object, as it is specified here: https://github.com/RestKit/RestKit#post-patch-and-delete-an-object
If you want to log your requests and responses you can use AFHTTPRequestOperationLogger.