I am trying to post to a URL using AFNetworking and no matter what I do I keep getting the error:
Error Code: -1011 - Expected status code in (200-299), got 404
My code is as follows:
NSString *baseurl = #"http://mysiteurl";
NSString *path = #"/user/register/";
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:baseurl]];
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
//[client setAuthorizationHeaderWithUsername:#"myusername" password:#"mypassword"];
[client postPath:path parameters:[NSDictionary dictionaryWithObjectsAndKeys:_userName,#"user", _email, #"email",_password,#"password", nil] success:^(AFHTTPRequestOperation *operation, id JSON) {
//NSLog(#"sjson: %#", [JSON valueForKeyPath:#"entries"]);
NSLog(#"sjson: %#", JSON);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error Code: %i - %#",[error code], [error localizedDescription]);
}];
When I go to http://mysiteurl/user/register/ directly I am able to see JSON.
What am I doing wrong?
When I go to http://mysiteurl/user/register/ directly I am able to see JSON.
If you're doing this through a browser, you are making a GET request, whereas in your code, you are making a POST request.
A 404 is not just the visible address, it includes the HTTP method as well. You need to make sure that your server responds to a POST at http://mysiteurl/user/register/. Depending on your framework (e.g. Rails), you may have to add [client setDefaultHeader:#"Accept" value:#"text/json"] to get the correct route.
i usually use [client getPath: parameters:params success:] not Post but i guess this will work for both cases since your response is in a JSON format too
add these two lines
[client.parameterEncoding = AFJSONParameterEncoding;
[client setDefaultHeader:#"Accept" value:#"text/json"];
before
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
Related
In my app i am making different calls and they work except one call, that returns just a string in response as SUCCESS. I am getting this error
"The operation couldn’t be completed. (Cocoa error 3840.)", NSLocalizedDescription=Loaded an unprocessable response (200) with content type 'application/json'}
How can i tell the restkit to access the "Content-Type: text/plain"
This is a post call.
Short answer: you can't. RestKit is designed to work with JSON objects only, and so it expects a JSON response (keeping with the RESTful paradigm).
However, you can definitely post objects using AFNetworking, which RestKit actually includes. I use AFNetworking for non-coreData-related correspondence. Here's a code sample on how to get the AFHTTPClient from RestKit and make a POST, expecting a text/plain response.
AFHTTPClient *httpClient = [RKObjectManager sharedManager].HTTPClient;
NSDictionary *requestObject = #{#"label1":data1, #"label2":data2};
[httpClient setParameterEncoding:AFJSONParameterEncoding];
[httpClient setDefaultHeader:#"Accept" value:#"text/plain"];
[httpClient postPath:urlPath parameters:requestObject success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *response = (NSString*)responseObject;
if([response isEqualToString:#"SUCCESS"]) NSLog(#"It worked!");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//failure code goes here
}];
If that's your only call expecting text/plain, change the Accept header back after you're done:
[httpClient setDefaultHeader:#"Accept" value:#"application/json"];
I have tried several StackOverflow questions, and I caanot find the correct answer on this. I am using the POSTMAN plugin for Chrome to check my REST calls and I cannot figure out why I cannot read the response. In the comments you will see all the different attempts I have made to get the response.
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];
I think the most irritating thing is that the stuff I need is contained in the NSLocalizedRecoverySuggestion value. It is a session key I require.
OUTPUT:
E restkit.network:RKObjectRequestOperation.m:547 Object request failed: Underlying HTTP request operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html" UserInfo=0x1c52aed0 {NSLocalizedRecoverySuggestion=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw, AFNetworkingOperationFailingURLRequestErrorKey=, NSErrorFailingURLKey=http://..., NSLocalizedDescription=Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/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 "Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html" UserInfo=0x1c52aed0 {NSLocalizedRecoverySuggestion=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw, AFNetworkingOperationFailingURLRequestErrorKey=, NSErrorFailingURLKey=http://..., NSLocalizedDescription=Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=}
CODE THAT WORKED
Thanks to Wain for pointing me on the correct path there. I am a little disappointed that RestKit cannot handle such a simple request, and I need RestKit because this is just a session token to calling the other methods, but whatever works I guess:
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];
This bit:
"Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html"
tells you that you have told RestKit to expect form-urlencoded or json, but that the server is returning html.
You would probably want to use setAcceptHeaderWithMIMEType with JSON mime type to tell the server what you want back. But, in this case you probably just shouldn't be using RestKit.
RestKit is for mapping arbitrary JSON / XML data into your data model. You just have a key coming back. No mapping is required. So, don't use RestKit, use AFNetworking instead (which you have full access to because RestKit uses it internally.
Thanks to Wain and Quintin, this was quite useful to me :)
I think some names changed in more recent versions of Restkit or AFNetworking. I used AFNetworking as explained in other answers since the server did not return json but empty plain/text instead. This was only on a particular endpoint where I was looking for a token in the headers of the response.
Sharing my piece of code here too:
-(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];
}
Then I used something like this to get the header I was looking for:
-(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;
}
So all of this can simply be used like this:
- (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];
}
In other words, get_the_token takes a callback with the desired token and a failure callback.
Make sure you still include <RestKit/RestKit> so you have access to Restkit's AFNetowkring :)
Alternative working solution using restkit:
RestKit: How to handle empty response.body?
And you register a serializer for that kind of Mimetype like this:
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];
I have an odd problem... I'm doing this ios http/json post using AFNetworking against a rails server and the expected output is something like:
{"success":true,"auth_token":"4D8CyUsyGZdqo6X1TCeq"}
Sometimes it works as expected, but often on the rails side the request is not detected as a "JSON" request so it serves up HTML. Anyone have an idea on this? Is there something I'm doing wrong with regards to setting up the JSON request?
NSDictionary *parameter = #{#"email":#"philswenson#mymail.com", #"password":#"mypassword"};
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://localhost:3000"]];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
[httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[httpClient postPath:#"api/v1/sessions" parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *jsonString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Here is what we got %#", jsonString);
NSDictionary *loginResult = [jsonString objectFromJSONString];
NSNumber* success = [loginResult objectForKey:#"success"];
NSLog(#"success = %#", success);
NSLog(#"yay");
// sample output:
// {"success":true,"auth_token":"4D8CyUsyGZdqo6X1TCeq"}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self handleConnectionError:error];
}];
I know with my service, I need to add application/jsonrequest for accept to my parameters like this:
NSDictionary *parameter = #{#"email":#"philswenson#mymail.com", #"password":#"mypassword", #"accept:application/jsonrequest"};
The AFJSONParameterEncoding only tells it to send the parameters in a JSON file. I need to send a parameter to tell it how to send the data back.
Add:
[httpClient setDefaultHeader:#"Accept" value:#"application/json"];
I tried the suggestions - no dice.... the setDefaultHeader actually caused a crash (whatever the iOS term is for access violation)...
The "accept:application/jsonrequest"} didn't see any difference...
I ended up using this code:
NSDictionary *parameter = #{#"email" : #"phil#gmail.com", #"password" : #"mypw", #"format":#"json"};
This is my code:
NSURL *url = [NSURL URLWithString:#"http://wspublisherv2.skygiraffe.com/WSpublisherV2.svc/Authenticate"];
AFHTTPClient *client = [[AFHTTPClient alloc]initWithBaseURL:url];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:#"john#sgdemo.com", #"UserName", #"123", #"Password", nil];
NSLog(#"%#", parameters);
[client postPath:nil parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"failure: %#", error);
}];
It always triggers the failure block and I get the "Expected status code in (200-299), got 404" message.
When I try it through Fiddler it works.
You need more information. Use a proxy like Charles Proxy to watch the traffic between your device and the server. That'll let you see the actual request. You can compare that to a request that works, and the difference should give a pretty good idea of what's wrong. At the very least, it'll make your question much more specific.
I have strange issue with AFHTTPClient, I am sending POST request like
NSURL *u = [NSURL URLWithString:HTTP_SERVER];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL: u];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
[httpClient postPath:REGISTER
parameters:params
success:^(AFHTTPRequestOperation *operation, id JSON) {
int statusCode = [operation.response statusCode];
if(statusCode == 201){
[self performSegueWithIdentifier:#"register" sender:self];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
And server works fine ( in some cases server needs to answer me with code 409, API is made in that way), but I get error in XCode like Expected status code in (200-299), got 409
How to solve this problem ( my hands are tied, I cannot change API and error code) ?
Based on this:
You've got two options:
add status code 409 to the list of acceptable status codes, and receive it in the success block (bad)
deal with status code 409 in the failure block (good)
For the latter, if your [operation.response statusCode] is 409, you would use the responseData from AFURLConnectionOperation (superclass of AFHTTPRequestOperation, you would need to import its header for this to work).