How to use PromiseKit to handle header-only response? - ios

I'm using PromiseKit in an IOS app to communicate with a Rails RESTful backend,
and there're some calls that return only header, say by executing head 200 on the backend.
What I've tried is:
I used [NSURLConnection POST:url formURLEncodedParameters:parameters] to post data to backend, the backend did receive the data and responded with a head 200 message, but PromiseKit is reporting the following exception:
2014-07-31 11:19:39.501 HelloPOS[13223:60b] Error
Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be
completed. (Cocoa error 3840.)" (No value.) UserInfo=0xa4c5a90
{NSDebugDescription=No value., PMKURLErrorFailingDataKey={length = 1, capacity = 16, bytes = 0x20},
PMKURLErrorFailingURLResponseKey= { URL:
http://SOME_APP.SOME_HOST.com/api/v1/sales.json } { status code: 200,
headers {
"Cache-Control" = "max-age=0, private, must-revalidate";
Connection = "keep-alive";
"Content-Length" = 1;
"Content-Type" = "application/json";
Date = "Thu, 31 Jul 2014 03:19:25 GMT";
Etag = "\"7215ee9c7d9dc229d2921a40e899ec5f\"";
Server = "WEBrick/1.3.1 (Ruby/2.0.0/2014-05-08)";
Via = "1.1 vegur";
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = SAMEORIGIN;
"X-Request-Id" = "5a1c1aa1-4b42-41ea-8397-a5df8fa956bc";
"X-Runtime" = "0.013359";
"X-Xss-Protection" = "1; mode=block"; } }}
It's probably because header-only response has no body, and the error is caused
PS: I've changed the URL in the exception message

The problem is the server claims that the response has a JSON content of length 1 byte. But the response does not parse into JSON, so PromiseKit errors that promise.
PromiseKit doesn't provide a mechanism to ignore the response, but you could easily make your own promise here if you cannot fix the server to provide correct responses.
#import <OMGHTTPURLRQ.h>
- (PMKPromise *)myPromise:(id)args {
id rq = [OMGHTTPURLRQ POST:url:args];
id q = ;
return [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject){
[NSURLConnection sendAsynchronousRequest:rq queue:q completionHandler:^(id rsp, id data, NSError *urlError) {
if (urlError) {
reject(urlError)
} else {
fulfill(nil);
}
}];
}];
}
EDIT: PromiseKit now works around this specific situation, so you should no longer get this specific error.

Related

Handle non-JSON response from POST request with Alamofire

I'm using Alamofire 3 and the end point I'm calling (I don't own the server) accepts a POST request and returns HTML as a response.
I am able to get the HTML response when using curl in the command line, however Alamofire doesn't return the response body, but only the header.
This is my code:
let headers = [
"Referer": "SOMEURL"
]
Alamofire.request(.POST, url, headers: headers)
.validate()
.response { request, response, data, error in
// do something with response
}
response is:
Optional(<NSHTTPURLResponse: 0x7f9ba3759760> { URL: SOMEURL } { status code: 200, headers {
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html";
Date = "Thu, 22 Sep 2016 15:19:20 GMT";
Server = nginx;
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
} })
and data is:
Optional<NSData>
- Some : <>
Any thoughts?

Get the value of Error-Message in failure block of AFHTTPRequestOperation

I need to get the value of Error-Message in the failure block of my request.
Here's the error:
Error Domain=com.alamofire.error.serialization.response Code=-1011
"Request failed: bad request (400)" UserInfo=0x165151b0
{NSErrorFailingURLKey=http://203.125.112.203:8090/megumi01/api/zipData?lastSynced=1441161682,
com.alamofire.serialization.response.error.response= { URL:
http://203.125.112.203:8090/megumi01/api/zipData?lastSynced=1441161682
} { status code: 400, headers {
"Access-Control-Allow-Headers" = "x-requested-with, Authorization, Content-Type, Accept";
"Access-Control-Allow-Methods" = "POST, GET, OPTIONS, DELETE, PUT";
"Access-Control-Allow-Origin" = "*";
"Access-Control-Max-Age" = 3600;
"Cache-Control" = "no-cache, no-store, max-age=0, must-revalidate";
Connection = close;
"Content-Type" = "application/json;charset=UTF-8";
Date = "Wed, 02 Sep 2015 10:38:57 GMT";
"Error-Code" = 0808;
"Error-Message" = "No updates available";
Expires = 0;
Pragma = "no-cache";
Server = "Apache-Coyote/1.1";
"Transfer-Encoding" = Identity;
"X-Application-Context" = "application:9090";
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = DENY;
"X-XSS-Protection" = "1; mode=block"; } }, NSLocalizedDescription=Request failed: bad request (400)}
I have tried putting "error" into NSData so I could convert it to NSDictionary but it becomes nil.
May I know how could I get the value of the custom header "Error-Message"?
TYIA!
below code may help you. try it.
NSLog(#"status code :%ld",(long)[operation.response statusCode]);
NSLog(#"Failure Response %#, %#", error, operation.response.description);
After thinking straightly, I was able to get the proper way to get the custom header in failure block of AFHTTPRequestOperation.
NSDictionary *userInfo = [error userInfo];
NSHTTPURLResponse *alamofireResponse = [userInfo objectForKey:#"com.alamofire.serialization.response.error.response"];
NSDictionary *allHeaders = [alamofireResponse allHeaderFields];
NSString *customMessage = [allHeaders objectForKey:#"Error-Message"];

How to set Content-Type in AFNetworking?

I want to set "application/x-www-form-urlencoded" with post method
So ,I set request.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") But When I set the request to the server the Content-Type is not change what happen?
this is error
{com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7c166450> { URL: http://test.com } { status code: 404, headers {
Connection = "keep-alive";
"Content-Length" = 434;
"Content-Type" = "text/html";
Date = "Mon, 13 Jul 2015 11:18:18 GMT";
Server = "nginx/1.0.15";
} }, NSErrorFailingURLKey=http://text.com, NSLocalizedDescription=Request failed: not found (404),
this is my code:
var request = AFHTTPRequestOperationManager();
request.requestSerializer = AFHTTPRequestSerializer()
request.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.POST(url, parameters: parameters, success: { (oper,obj) -> Void in
// do something
}) { (oper, error) -> Void in
// do something with error
}
It's exactly what the error says: your server is sending back a webpage (HTML) for a 400 status code, when you were expecting JSON.
A 400 status code is used a bad request, which is probably generated because you're sending URL-form-encoded text as application/json. What you really want is to use AFJSONRequestSerializer for your request serializer.
manager.requestSerializer = [AFJSONRequestSerializer serializer];
I am not doing any code of AFNetworking in Swift so I can't tell you code of that but you can get idea from objective-c code.
I hope it will help you.

Request failed: internal server error (500) and Cocoa error 3840, Invalid value around character 0 responses AFNetworking

It appears to be working in web:
Web Response Headers:
Connection:keep-alive
Content-Length:394
Content-Type:application/json
Date:Sun, 22 Mar 2015 18:36:06 GMT
Server:nginx/1.6.2
Vary:Accept-Encoding
X-Powered-By:Express
Web Request Headers:
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NDVjYzNjYzQ2N2I3YjAyMDBhMWNkOWEiLCJpYXQiOjE0MjcwNDM3Mzk1NjQsImV4cCI6MTQ5MDExNTczOTU2NH0.Xqm-b12QWcEa6MPXyKa1E8m88hGZI9KfJl7Img3mACU
Connection:keep-alive
Content-Length:225
Content-Type:application/json;charset=UTF-8
Web Request Payload:
{"id":"550f15122cc2708c2d9c65b8","users":["xiruken#gmail.com"],"welcomeMessage":"Hi there. We’ll be using Next24 to keep track of our daily high priority items as a group during this project.","newUser":"xiruken#gmail.com"}
But not working in my native iOS project using objective-C...
Same parameters:
NSDictionary query:
{
id = 550f15122cc2708c2d9c65b8;
newUser = "xiruken#gmail.com";
users = (
"xiruken#gmail.com"
);
welcomeMessage = "Hi there. We will be using Next24 to keep track of our daily high priority items as a group during this project.";
}
AFNetworking code:
-(AFHTTPSessionManager *)sessionManager2{
if(!_sessionManager2){
_sessionManager2 = [[AFHTTPSessionManager alloc] initWithBaseURL: [NSURL URLWithString:API_URL]];
AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
[securityPolicy setAllowInvalidCertificates:YES];
[_sessionManager2 setSecurityPolicy:securityPolicy];
_sessionManager2.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions: NSJSONReadingAllowFragments];
NSArray *acceptedTypes = #[#"text/html", #"application/json", #"text/plain"];
_sessionManager2.responseSerializer.acceptableContentTypes = [NSSet setWithArray:acceptedTypes];
//add token
if([Helpers isLoggedIn]){
UserDM *user = [UserDM loadCustomObjectWithKey:DEFAULT_CURRENT_USER];
[self.sessionManager2.requestSerializer setValue:[NSString stringWithFormat:#"Bearer %#", user.accessToken] forHTTPHeaderField:#"Authorization"];
}
}
return _sessionManager2;
}
Using AFJSONResponseSerializer is giving me this error:
2015-03-23 03:28:26.773 Next25[5801:302572] Failed! Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.) UserInfo=0x7fdbb252a6e0 {NSDebugDescription=Invalid value around character 0., NSUnderlyingError=0x7fdbb252c410 "Request failed: internal server error (500)"}
I even allowFragments and even set acceptableContentTypes
And changing it to AFHTTPResponseSerializer is giving me a different error:
2015-03-23 03:30:30.797 Next25[5852:303849] Failed! Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: internal server error (500)" UserInfo=0x7fb129e4e930 {com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7fb129e36320> { URL: https://myproject.com/api/projects/550f15122cc2708c2d9c65b8/invite_users } { status code: 500, headers {
Connection = "keep-alive";
"Content-Length" = 21;
"Content-Type" = "text/html";
Date = "Sun, 22 Mar 2015 19:26:56 GMT";
Server = "nginx/1.6.2";
Vary = "Accept-Encoding";
"X-Powered-By" = Express;
} }, NSErrorFailingURLKey=https://myproject.com/api/projects/550f15122cc2708c2d9c65b8/invite_users, com.alamofire.serialization.response.error.data=<496e7465 726e616c 20536572 76657220 4572726f 72>, NSLocalizedDescription=Request failed: internal server error (500)}

NSURLConnection, NSURLAuthenticationChallenge failure response

When trying to log in to my app with iOS7 I'm getting a failure response with some description. This is NSLog of NSURLAuthenticationChallenge failureResponse:
<NSHTTPURLResponse: 0xa383570> { URL: <URL> } { status code: 401,headers {
"Content-Length" = 1385;"Content-Type" = "text/html;charset=utf-8";
Date = "Fri, 13 Jun 2014 12:14:24 GMT";
Server = "Apache-Coyote/1.1";
"Www-Authenticate" = "Basic realm=\"booo\"";
"x-errorCode" = 02;
"x-errorDescription" = "com.idealination.core.server.client.http.ServerException:
Request failed: <URL> Status: CLIENT_ERROR_UNAUTHORIZED
Error: #Unauthorized :: Invalid userid or password.";
} }
and I need that last line to know what error do I get. But when I use iOS6 and iPhone 3gs I get only:
<NSHTTPURLResponse: 0x1c507ae0>
What should I do to get a response like using iOS7? And why I'm getting a different response?
You should not be looking for the last line, you should be looking for the HTTP Status Code, in this case 401.
if(urlResponse.statusCode == 401) { }
If you need to convert that into what the status code means as a string use
NSString *status = [NSHTTPURLResponse localizedStringForStatusCode:urlResponse.statusCode];

Resources