I have some trouble getting a response using ASIHTTPRequest which is quite nerve-wrecking.
I am sending a SOAP Request inside the POST-Body of an ASIHTTPRequest to a server.
The Request is sending fine so far but the Response String is "(null)" according to the Console and the Length of the response Data is 0.
However, when I send the SOAP-Body String, that I put in the Console using NSLog(); to the server with the Firefox Plugin "POSTER" I get the response that i want. And on the other hand, as soon if there'S an error in the SOAP-Request is get a response in ASIHTTPRequest.
So far I'm completely out of ideas and it would be very kind if somebody got an idea to help.
Here'S my Code.
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:myURL];
[request addRequestHeader:#"Content-Type" value:#"text/xml"];
NSLog(#"XML: %#",[carInsurance buildXMLString]); //Debug output
NSMutableData *theData = [[carInsurance buildXMLString] dataUsingEncoding:NSUTF8StringEncoding];
[request addRequestHeader:#"Content-Length" value:[NSString stringWithFormat:#"%d",[theData length]]];
[request setPostBody:theData];
[request setRequestMethod:#"POST"];
NSLog(#"Headers before: %#",[[request requestHeaders] description]); //Debug output
[request startSynchronous];
NSLog(#"Headers after: %#",[[request requestHeaders] description]);
For the more curious one here are my Debug headers.
2010-10-12 14:39:11.945 appname[12484:207] Headers before: {
"Content-Length" = 1944;
"Content-Type" = "text/xml";
}
Install a tool like wireshark and use it to sniff the request and the response (using the iphone simulator).
Presuming the response is empty there too, sniff the request as sent by POSTER and compare that to the one sent by the iphone.
If it's still not obvious what's wrong add the wireshark "follow tcp stream" output into your question.
Related
I'm trying to to send some post data to a Apache server from iPad application using the ASIHttp library.
actually I need to send huge data to the server and that means I need to compress the request body so I write some code to send the data and compress the request BUT there are no parameters received on the server !!!
the iOS code is :
NSURL * URL = [NSURL URLWithString:myURL];
ASIFormDataRequest *ASIRequest = [ASIFormDataRequest requestWithURL:URL];
ASIRequest.shouldCompressRequestBody=YES;
ASIRequest setPostValue:data forKey:#"data"];
[ASIRequest startSynchronous];
NSError *error = [ASIRequest error];
if (!error) {
NSString *response = [ASIRequest responseString];
NSLog(#"response %#" , response);
}
PS: if I removed the ASIRequest.shouldCompressRequestBody=YES; everything works fine and I can see the data but when use it I see nothing on the server
the request can be seen on the server but with no parameter
noway to send such data over GET method.
the server configuration are fine.
any solution ? any comment or idea can help ?
By default, most web servers do not support compression on POSTs. The accepted answer here does a really good job explainining it: Why can't browser send gzip request?
According to official documentation, this feature has only been tested with Apache servers.
EDIT:
Here is a code snipt that compresses the actual post data:
if ([self shouldCompressRequestBody]) {
NSError *err = nil;
NSData *compressedBody = [ASIDataCompressor compressData:[self postBody] error:&err];
if (err) {
[self failWithError:err];
return;
}
[self setCompressedPostBody:compressedBody];
[self setPostLength:[[self compressedPostBody] length]];
}
Source: http://forums.three20.info/discussion/77/tturlrequest-vs-asihttprequest/p1
I am using ASIFormDataRequest to call a web service with video file. it workes fine if video is small but if video is about 30 seconds or above then its response return as __NSCFString or sometime __NSCFConstantString
my code is as below.
__block ASIFormDataRequest *request=[[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:APP_APIURL]];
[request setPostValue:strVal forKey:#"jsonRequest"];
if (videoData) {
[request setData:videoData withFileName:videoName andContentType:nil forKey:#"videoFile"];
}
[request startSynchronous];
request.timeOutSeconds=999999999;
// response
NSString *strResponse=[request responseString];
if (strResponse) {
SBJsonParser *parser=[[SBJsonParser alloc] init];
NSMutableDictionary *dicData=[[parser objectWithString:strResponse] valueForKey:#"uploadVideo"];
Please help me to solve this issue.
Shivam
Here are few solutions to your problem:
Use introspection and check the returned object for it's class. If you're getting a "constant" string, probably it's not what you're expecting. Print it or check it's contents.
If you're receiving a video file - use [request responseData] or better, use the file saving techniques described in ASIHTTPRequest library. How can you download a file and parse json response at the same time?
Use JSONKit - IMHO the fastest json parser.
i have a weird problem. so i've been working on an iphone app where a user can login, and upon logging in, the app would authorize the user by making an http GET request to the server. if the username and password is correct it return an authorization token (typical stuff).
the weird part is that when i test this locally, pointing the http request url to my local machine, it works fine. everything authorizes correctly and all data is returned correctly.
but today, i got the app stable enough that i decided to deploy rest api to my server, but when changed the http request url to my server url, the requests fails.
i thought maybe the server wasn't deployed correctly so i tested the http endpoints with the firefox rest client and everything seems to be working, authorization works, and data gets returned.
does anyone have any thoughts? i'm lost as to what the problem might be.
i'm using AFNetworking library to make the requests.
here's my code:
self.apiHttpClient = [[TKRHttpClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://mywebsite.com/api"]];
--------------
NSString *username = [usernameField text];
NSString *password = [passwordField text];
TKRHttpClient *httpClient = [TKRHttpClient sharedInstance];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"/user/auth" parameters:nil];
[request addValue:username forHTTPHeaderField:#"username"];
[request addValue:password forHTTPHeaderField:#"password"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if(response.statusCode == 200){
NSDictionary * headers = [response allHeaderFields];
NSString *token = [headers objectForKey:#"auth_token"];
NSLog(#"token was %#", token);
[[AppController sharedAppController] initializeDataForUserToken:token];
}else{
NSLog(#"upload failed!");
}
} failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , id JSON ) {
NSLog(#"code was: %i", response.statusCode);
if(response.statusCode == 401){
[errorMessage setText:#"Incorrect password or username"];
}
}];
[operation start];
i put in break points, and it seems that the request goes straight to the failure block. the line that says "NSLog(#"code was: %i", response.statusCode);" in the failure block prints out 200. but when i tail the logs on my server, no request was received.
any help would be greatly appreciated. can't figure out for the life of my why it would work against my local tomcat, but won't work when deployed to my server.
thanks in advance!
i found the reason for my problem thanks to #Brad's suggestion.
upon inspecting the request in charles, i found that the request was made as "http://mywebsite.com", then for path it was /user/auth. so the "/api" part was missing.
maybe this is the standard, i don't know, but it appears that AFHTTPClient's (my TKRHttpClient extends AFHTTPClient) initWithBaseURL really means the host URL. the "/api" part gets lopped off.
and the reason why it was working locally is because i deployed the app locally as root, so there was no "/api"
so two ways to fix this. 1. redeploy as app to server as root. or 2. change the line of code from:
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"/user/auth" parameters:nil];
TO:
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"api/user/auth" parameters:nil];
hopefully this helps anyone using AFNetworking in the future.
I'm developing iPhone app and manually constructing POST requests. Currently, need to compress JSON data before sending it, so looking how to tell a server the content is compressed. Setting content type header to gzip might be not acceptable because server expects JSON data. I'm looking for transparent solution, something like just to add some header telling JSON data is compressed into gzip.
I know, the standard way is to tell the server that the client accepts encoding, but you need to make GET request with accept encoding header first. In my case, I want to post the data already encoded.
Include a Obj-C gzip wrapper, for example NSData+GZip, and use it to encode the body of your NSURLRequest. Also remember to set the Content-Encoding accordingly, so the webserver will know how to treat your request.
NSData *requestBodyData = [yourData gzippedData];
NSString *postLength = [NSString stringWithFormat:#"%d", requestBodyData.length];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"gzip" forHTTPHeaderField:#"Content-Encoding"];
[request setHTTPBody:requestBodyData];
Implmenting some general Method such as follows and setting appropriate Header might help you.
// constructing connection request for url with no local and remote cache data and timeout seconds
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:callingWebAddress]];// cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:timoutseconds];
[request setHTTPMethod:#"POST"];
NSMutableDictionary *headerDictionary = [NSMutableDictionary dictionary];
[headerDictionary setObject:#"application/json, text/javascript" forKey:#"Accept"];
[headerDictionary setObject:#"application/json" forKey:#"Content-Type"];
//Edit as #centurion suggested
[headerDictionary setObject:#"Content-Encoding" forKey:#"gzip"];
[headerDictionary setObject:[NSString stringWithFormat:#"POST /Json/%# HTTP/1.1",method] forKey:#"Request"];
[request setAllHTTPHeaderFields:headerDictionary];
// allocation mem for body data
self.bodyData = [NSMutableData data];
[self appendPostString:[parameter JSONFragment]];
// set post body to request
[request setHTTPBody:bodyData];
NSLog(#"sending data %#",[[[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding]autorelease]);
// create new connection for the request
// schedule this connection to respond to the current run loop with common loop mode.
NSURLConnection *aConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
//[aConnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
self.requestConnenction = aConnection;
[aConnection release];
I'm creating a JSON POST request from Objective C using the JSON library like so:
NSMutableURLRequest *request;
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/%#/", host, action]]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json-rpc" forHTTPHeaderField:#"Content-Type"];
NSMutableDictionary *requestDictionary = [[NSMutableDictionary alloc] init];
[requestDictionary setObject:[NSString stringWithString:#"12"] forKey:#"foo"];
[requestDictionary setObject:[NSString stringWithString#"*"] forKey:#"bar"];
NSString *theBodyString = requestDictionary.JSONRepresentation;
NSData *theBodyData = [theBodyString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:theBodyData];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
When I read this request in my Django view the debugger shows it took the entire JSON string and made it the first key of the POST QueryDict:
POST QueryDict: QueryDict: {u'{"foo":"12","bar":"*"}': [u'']}> Error Could not resolve variable
I can read the first key and then reparse using JSON as a hack. But why is the JSON string not getting sent correctly?
This is the way to process a POST request with json data:
def view_example(request):
data=simplejson.loads(request.raw_post_data)
#use the data
response = HttpResponse("OK")
response.status_code = 200
return response
I have already dealt with this issue. I found a temporary solution as reading the request.body dict. I assume you have imported the json/simplejson library already.
In my view:
post = request.body
post = simplejson.loads(post)
foo = post["foo"]
This code block helped me to pass post issue. I think posting querydict in request.POST has not properly developed on NSMutableURLRequest yet.
My cruel hack to work around my problem is:
hack_json_value = request.POST.keys()[0]
hack_query_dict = json.loads(hack_json_value)
foo = hack_query_dict['foo']
bar = hack_query_dict['bar']
So this will allow me to extract the two JSON values with an extra step on server side. But it should work with one step.