I am using ASIHTTPRequest to contact an API the problem is that it is returning html instead of JSON and i have no idea why. Everything has been working great for weeks and i can't seem to figure out what has broken..
What's strange is doing exactly the same request with a browser or postie returns the correct JSON response, but when i do the request via ASIHTTPRequest these are the response headers i get:
"Cache-Control" = "private, max-age=0, must-revalidate";
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html; charset=utf-8";
Date = "Tue, 05 Jul 2011 21:11:10 GMT";
Etag = "\"e467792713ac4124f055c1719f4ea6c2\"";
Server = "nginx/0.7.65";
Status = "200 OK";
"Transfer-Encoding" = Identity;
"X-Runtime" = 1;
And the html (which should be json)..
<div id="universal_meta" logged_in_user_id="removed" style="display:none"></div>
<div id="meta" screen="projects" logged_in_as="removed"></div>
<h1>9 projects with 50 open issues</h1>
<ul class="biglinks progressbars">
etc...
Here is the code used to do the request..
NSURL *url = [NSURL URLWithString:path];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
if(secure){
[request setUsername:self.username];
[request setPassword:self.password];
}
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestWentWrong:)];
[request setDownloadDestinationPath:destination];
[[self queue] addOperation:request]; //queue is an NSOperationQueue
I have triple checked all of the login details/url, everything is correct, i would really appreciate any help with this one as i am completely lost.
--
Update:
Lighthouse have acknowledged a bug regarding headers on their side. Waiting on a solution from them.
Did you check that the headers sent using your browser are also the same as when you send the request by code?
Especially did you try to add the "Accept" header to your request to define that you accept the json Content-Type?
[request addRequestHeader:#"Accept" value:#"application/json"];
Try using a tool like wireshark or charlesproxy to compare the working requests from your browser/postie, and compare them to the non-working requests from ASIHTTPRequest - once you spot what's different it should be easy to fix.
AliSoftware's suggestion is one of the most likely differences you'll see, but it's possible there are other things too.
Related
I am currently updating my app to .json from xml for Twitters new API v1.1. I currently have .json working and can log on, get me timelines, mentions, but when trying to get direct messages, lists, or user info it seems its looking for "cookies" but it is not stored.
This is the error message received by twitter when trying to make a simple GET user/show call:
Twitter request failed: 08AD12D3-0044-49AB-8D3D-4E61D8398550 with error:Error Domain=HTTP
Code=400 "The operation couldn’t be completed. (HTTP error 400.)" UserInfo=0xce90540
{response=<NSHTTPURLResponse: 0xce94bd0> { URL:
https://api.twitter.com/1.1/users/show.json?screen_name=FreeAppl3 } { status code: 400,
headers {
"Content-Encoding" = gzip;
"Content-Type" = "application/json; charset=utf-8";
Date = "Fri, 14 Jun 2013 09:25:40 UTC";
Server = tfe;
"Set-Cookie" = "guest_id=v1%3A137120194019582695; Domain=.twitter.com; Path=/;
Expires=Sun, 14-Jun-2015 09:25:40 UTC";
"Strict-Transport-Security" = "max-age=631138519";
"Transfer-Encoding" = Identity;
} }, body={"errors":[{"message":"Bad Authentication data","code":215}]}hjD4nzoeOUaTQ1Q%3D}
When I call [twitterEngine isAuthorized]; is returns YES and if I check for my access token string, I receive what was stored on initial login. I have searched and searched as to what is happening or how to fix the issues, but am simply stuck and any help would be greatly appreciated.
Twitter API - https://dev.twitter.com/docs/api/1.1/get/users/show
Twitter Error Codes - https://dev.twitter.com/docs/error-codes-responses
refer FHSTwitterEngine you can use newly FHSTwitterEngine and if you request this method without autenticating, the users status is removed... you need to send consumer key and token along with screen_name..
In FHSTwitterEngine
//get username pass to method. In Dictionary you can get all info
NSString *username = [[FHSTwitterEngine sharedEngine]loggedInUsername];
NSDictionary *data=[[FHSTwitterEngine sharedEngine]getUserProfile:username];
// method to get all user info
-(id)getUserProfile:(NSString *)username
{
if (username.length == 0) {
return getBadRequestError();
}
NSURL *baseURL = [NSURL URLWithString:url_users_show];
OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken];
OARequestParameter *usernameP = [OARequestParameter requestParameterWithName:#"screen_name" value:username];
NSArray *params = [NSArray arrayWithObjects:usernameP, nil];
id userShowReturn = [self sendGETRequest:request withParameters:params];
return userShowReturn;
}
I want to show the Progress from a Download.
I want to load an Document and show it in an Webview.
Everything is working, only my progress(the - (void)setProgress:(float)newProgress method) shows up 4 times and says value: 0.000000.
Even the -(void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes method jumps from received bytes 1 then to its original size.
What Iam doing wrong?
The Server sends me an Response Header:
{
"Cache-Control" = "private,max-age=0";
"Content-Length" = 22993;
"Content-Type" = "application/vnd.ms-word.document.12";
Date = "Tue, 28 Feb 2012 12:20:18 GMT";
Etag = "\"{EA1043C4-BE59-4775-AAC0-D25141572D94},2\"";
Expires = "Mon, 13 Feb 2012 12:20:18 GMT";
"Last-Modified" = "Wed, 13 Apr 2011 11:04:06 GMT";
MicrosoftSharePointTeamServices = "14.0.0.4762";
"Persistent-Auth" = true;
"Public-Extension" = "http://schemas.microsoft.com/repl-2";
ResourceTag = "rt:EA1043C4-BE59-4775-AAC0-D25141572D94#00000000002";
SPRequestGuid = "e4791157-4b6f-4961-84e1-2979d23bf5bc";
Server = "Microsoft-IIS/7.5";
"Set-Cookie" = "WSS_KeepSessionAuthenticated={d2e7fd96-aad9-429d-b85d-64a13026c693}; path=/, WSS_KeepSessionAuthenticated={d2e7fd96-aad9-429d-b85d-64a13026c693}; path=/, WSS_KeepSessionAuthenticated={d2e7fd96-aad9-429d-b85d-64a13026c693}; path=/";
"X-Content-Type-Options" = nosniff;
"X-Powered-By" = "ASP.NET";
"X-SharePointHealthScore" = 0;
}
ASIHTTPRequest *asiRequestTemp = [ASIHTTPRequest requestWithURL:[NSURL URLWithString: self.documentURL]];
[asiRequestTemp setTimeOutSeconds:10];
[self setAsiRequestDocumentViewer:asiRequestTemp];
[asiRequestDocumentViewer setDelegate:self];
[asiRequestDocumentViewer setUseKeychainPersistence:YES];
[asiRequestDocumentViewer setUseSessionPersistence:YES];
[asiRequestDocumentViewer setShowAccurateProgress:YES];
[asiRequestDocumentViewer setDownloadProgressDelegate:self];
[asiRequestDocumentViewer setDownloadDestinationPath:mediaPath];
[asiRequestDocumentViewer startAsynchronous];
Whats wrong with that, even the Content Length is shown up!
I experienced a similar problem. How large is the data you're downloading? Have you checked how it's coming in? ASIHTTPRequest does't start updating your progress download until it has successfully downloaded your headers, and I've noticed that if the data is small enough to come in in two or three bursts, setProgress will be called only with a value of 0.0 and 1.0.
I'm using a firefox tool call "Poster" to check that my web service is working. When I POST the request I send a JSON object in the content to send (also call HTTP body data).
When I press the POST button the result is fine.
Now I want to do exactly the same with RestKit in objective-c:
NSString *squery = #"{\"Sort\":\"Relevance\",\"DaysToSearch\":0,\"WorkType\":\"\",\"PageSize\":20,\"LastRunCount\":0,\"IndustryCodes\":[\"\"],\"AccountId\":27,\"Experience\":\"\",\"GetResultCount\":0,\"Keywords\":\"iOS\",\"PageIndex\":0,\"DistanceFromLocation\":\"250\",\"SalaryType\":\"\",\"JobQueryId\":\"\",\"JobTitleCodes\":[\"\"]}";
RKObjectLoader *objectLoader = [[RKObjectManager sharedManager] objectLoaderWithResourcePath:url delegate:performJobQueryHandler];
objectLoader.method = RKRequestMethodPOST;
objectLoader.objectMapping = s.jobQueryDataMapper;
objectLoader.HTTPBody = [squery dataUsingEncoding:NSUTF8StringEncoding];
objectLoader.serializationMIMEType = RKMIMETypeJSON;
[objectLoader send];
As a result I get: "An non-fault exception is occured."
In the FireFox extension "Poster" if I use a different mine-type than "application/json", let say "application/x-www-form-urlencoded" I get the same error: "An non-fault exception is occured."
Is something wrong with objectLoader.serializationMIMEType = RKMIMETypeJSON; ???
Martin Magakian
Ok I think I find out.
I activated RestKit debug with
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
And I get:
2012-02-14 11:55:48 [4048:207] T restkit.network:RKRequest.m:318 Prepared POST URLRequest '<NSMutableURLRequest http://servicestest.foo.com/jobservice/jobservice.svc/json/jobquery>'. HTTP Headers: {
Accept = "application/json";
"Content-Type" = "application/x-www-form-urlencoded";
}. HTTP Body: Sort=Relevance&DaysToSearch=0&WorkType=&SalaryType=&LastRunCount=0&IndustryCodes[]=&Experience=&AccountId=0&GetResultCount=0&PageIndex=0&DistanceFromLocation=250&PageSize=20&JobQueryId=&JobTitleCodes[]=.
So I think using RKObjectLoader object don't care about objectLoader.serializationMIMEType = RKMIMETypeJSON; because the Content-Type remain "Content-Type" = "application/x-www-form-urlencoded"; instead of "Content-Type" = "application/json";
Do you think it's a bug or the normal behavior ?
Sorry, a beginner's question: I have a very simple function in my Django application with which I can upload a file from a web browser to my server (works perfectly!). Now, instead of the web browser, I would like to use an iPhone.
I got a bit stuck as I don't really know how to provide Django with a valid form, i.e. we need a file name and enctype="multipart/form-data" as far as I understand.
Here is my upload function in Django:
class UploadFileForm(forms.Form):
file = forms.FileField()
def handle_uploaded_file(f):
destination = open('uploads/example.txt', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
print form
print request.FILES
return HttpResponse('Upload Successful')
else:
form = UploadFileForm()
return render_to_response('upload.html', {'form': form})
My template looks like this (upload.html):
<form action="" method="post" enctype="multipart/form-data">
{{ form.file }}
{{ form.non_field_errors }}
<input type="submit" value="Upload" />
</form>
Now, let's suppose that I want to send a simple txt file from my iPhone app to the sever.
I don't really know how to:
provide the file name
specify the enctype and
make sure that it's in a format Django can read
This is how far I got:
NSString *fileContents = [self loadTXTFromDisk:#"example.txt"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL
URLWithString:#"http://127.0.0.1:8000/uploadfile/"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"text/xml" forHTTPHeaderField:#"Content-type"];
[request setValue:[NSString stringWithFormat:#"%d", [fileContents length]]
forHTTPHeaderField:#"Content-length"];
[request setHTTPBody:[fileContents dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self];
However, Django will not except this as the form it expects is not valid. Cf. above:
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid(): #this will not be true ...
The enctype from the HTML form should be the Content-Type of the HTTP request. You are currently setting the content type to 'text/xml' instead.
You will also have to build up the body as a multipart mime object. The answers to this question seem to have some code for that: File Upload to HTTP server in iphone programming
Your other option, since you have complete control of the client, is to do an HTTP PUT request. That actually looks closer to what you were doing with your original code. Change the method to 'PUT', and don't use a Django form on the other end; just access request.raw_post_data to get the complete file data.
i want to send JSON with POST/PUT i don't know if it's the same think .
This is the json .
{"author":"mehdi","email":"email#hotmail.fr","message":"Hello2"}
this is my wadl .
<resource path="/messages/"><method id="get" name="GET"><request><param name="start" style="query" type="xs:int" default="0"/><param name="max" style="query" type="xs:int" default="10"/><param name="expandLevel" style="query" type="xs:int" default="1"/><param name="query" style="query" type="xs:string" default="SELECT e FROM Message e"/></request><response><representation mediaType="application/xml"/><representation mediaType="application/json"/></response></method><method id="post" name="POST"><request><representation mediaType="application/xml"/><representation mediaType="application/json"/></request><response><representation mediaType="*/*"/></response></method><resource path="{keyid}/"><param name="keyid" style="template" type="xs:int"/><method id="get" name="GET"><request><param name="expandLevel" style="query" type="xs:int" default="1"/></request><response><representation mediaType="application/json"/></response></method></resource></resource>
When i trie to post with netbeans "Test restful webservice " it work and this is wat the http monitor show
Status: 201 (Created)
Time-Stamp: Sat, 21 May 2011 20:30:33
GMT
Sent:
{"author":"mehdi","email":"email#hotmail.fr","message":"Hello2"}
Received:
Request: POST
http://localhost:8080/TRESTful/resources/messages/?
timestamp=1306009225785
Status: 201 (Created)
Time-Stamp: Sat, 21 May 2011 20:20:25
GMT
Sent:
{"author":"mehdi","email":"email#hotmail.fr","message":"Hello2"}
But now i dont know how it with ASIHttpRequest .first should i make [request setRequestMethod:#"PUT"]; ? and should i send all the json like a string , or put each value with hey key , like this :
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"Ben" forKey:#"author"];
[request setPostValue:#"Copsey" forKey:#"email"];
[request setPostValue:#"Hello2" message:#"author"];
[request startSynchronous];
or should i put the JSON string in one value ?
Help please .
Well if you want to send a json you have two options:
a) Send it in a file
-Use this if you have a lot of data in a json and you may want to store it on the server for later parsing.
b) Send it as string in one value
-Use this if your json is short and you want to parse it immediately
EDIT
c) Send it as seperate values if you want to skip parsing on the server and access data directly. This should be used if there is few data.