I'm sending POST data via XMLHttpRequest as follows:-
xhr = new XMLHttpRequest()
... callback omitted
xhr.open( "POST", url, true ) - where url is /contr/func
xhr.send( data ) - where data is "?parm1=value1&parm2=value2"
When I try to retrieve the values in the controller function using:-
usr = request.params['parm1']
I get this error:-
Error - exceptions.KeyError: "'parm1'"
Do I need to change the formatting of the data I send?
s = request.body.read(int(request.environ['CONTENT_LENGTH']))
print s
gives me this
?parm1=value1&parm2=value2
Can someone shed some light here please?
I am using 0.9.4 and calling from Firefox
In the form handling document it states that if POST is used the data
is available in request.params just as for a GET operation the only
difference being that the data is sent in the body and not in the url.
I'm sending POST data via XMLHttpRequest as follows:-
xhr = new XMLHttpRequest()
... callback omitted xhr.open( "POST", url, true ) - where url is
/contr/func
xhr.send( data ) - where data is a string
Try removing the ? and keeping the &, i.e.
data = "parm1=value1&parm2=value2";
xhr.send( data );
HTH
Robert
PS You might also benefit from using a higher level js library, less things to
code/worry about yourself. I'm a big fan of YUI from Yahoo -
http://developer.yahoo.com/yui/ - great documentation, used on some of the
highest loaded/profile sites on the net, great support.
>
> I sent this by e-mail 24 hours ago and it hasn't appeared - not sure
> why. Sorry if it gets here twice.
>
Your first one just arrived before this one, for some reason. =]
> In the form handling document it states that if POST is used the data
> is available in request.params just as for a GET operation the only
> difference being that the data is sent in the body and not in the url.
>
> I'm sending POST data via XMLHttpRequest as follows:-
>
> xhr = new XMLHttpRequest()
> ... callback omitted xhr.open( "POST", url, true ) - where url is
> /contr/func
> xhr.send( data ) - where data is a string
> "?parm1=value1&parm2=value2"
Just this data would be an invalid POST request. You need a Content-
Type header set, and I'd recommend having a valid Content-Length
header as well. Google should have plenty of XMLHTTPRequest POST
examples.
Also, consider adding those params, unencoded, onto the end of your
URL, and making a GET request (access them via request.GET). This
would be easier if you're not sending lots of data.
--
Philip Jenvey
The problem appears to be somewhere in Pylons I think. It doesn't seem
to be decoding the parms correctly from an XMLHttpRequest when the data
is sent vis .send() which is what I need. If I append the data to the
url it works fine, however, I may need to send more than the 512byte
limit and I also don't want the data on the url for security reasons.
Any other suggestions? Where should I look?
> PS You might also benefit from using a higher level js library, less
> things to code/worry about yourself. I'm a big fan of YUI from Yahoo -
> http://developer.yahoo.com/yui/ - great documentation, used on some of
> the highest loaded/profile sites on the net, great support.
I've been thinking about using one of these libraries but I want to keep
the js lean and on purpose. I reserve the right to change my mind if it
proves too difficult. ;-)
Thanks Philip - any other thoughts?
I missed this before, but you want to omit the leading '?'. What
you've been POSTing will result in 'value1' being set for the param
named '?param1'.
Also, you don't want to encode the parameters when POSTing either.
--
Philip Jenvey
Set the content type to "application/x-www-form-urlencoded" to get the data
available in request.params. As "application/xml", Pylons/Paste won't try and
decode the incoming data.
Robert
One more gotcha for anyone trying this at home is that the content-type
can only be set after the .open() call in the XMLHttpRequest.
The working request code:-
function xhrpost( url, data, callback ) {
xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
// note setRequestHeader must appear after .open
xhr.setRequestHeader( "Content-Type",
"application/x-www-form-urlencoded" );
if ( callback ) {
xhr.onreadystatechage = function() {
if ( xhr.readyState==4 ) {
callback( xhr.responseText );
}
}
}
if ( data ) {
xhr.send( data );
} else {
xhr.send( null );
}
};
Data is passed in as a string "parm1=val&parm2=val2"
Now to get the callback working.
I'm sending back a simple text status at the end of the controller
method with:-
resp = Response()
resp.write('ok')
return resp
But this has now stopped working since changing the request type from
GET to POST.
A call via GET works but since I changed the request to POST it's not
sending anything back to javascript even though I've registered a callback.
Any clues?
In these sorts of situations the LiveHTTPHeaders extension for FF is a big help.
If you run it and look at the captured information after issuing the POST you
might find a hint, i.e. an error status is being returned or similar, some
condition that the js is not handling.
> xhr.onreadystatechage = function() {
^^
Also, is that an email typo or is it incorrect in the real code?
What happens if you use:
if ( xhr.readyState==4 ) {
alert(xhr.status) and/or alert(xhr.responseText);
...
HTH
Robert
The original request....
POST /xul/c_user HTTP/1.1
Host: localhost:5000
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.0.9)
Gecko/20070102 Ubuntu/dapper-security Firefox/1.5.0.9
Accept:
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 25
Pragma: no-cache
Cache-Control: no-cache
uname=asdasd&pword=asdasd
The response...
HTTP/1.x 200 OK
Server: PasteWSGIServer/0.5 Python/2.4.3
Date: Fri, 05 Jan 2007 06:39:12 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
There is no content.
Robert Leftwich wrote:
> In these sorts of situations the LiveHTTPHeaders extension for FF is a
> big help. If you run it and look at the captured information after
> issuing the POST you might find a hint, i.e. an error status is being
> returned or similar, some condition that the js is not handling.
>
>> xhr.onreadystatechage = function() {
> ^^
> Also, is that an email typo or is it incorrect in the real code?
At the moment the code reads
xhr.onreadystatechage = function() {
if ( xhr.readyState==4 ) {
alert( xhr.responseText );
}
};
Which would normally read
xhr.onreadystatechage = function() {
if ( xhr.readyState==4 ) {
func( xhr.responseText );
}
};
where func is the passed in callback function.
And you are sure that the correct controller is being called? Maybe the mappings
aren't setup quite right?
What happens if you use Python to call the controller using POST? e.g.
import urllib2
u = urllib2.urlopen("http://localhost:5000/xul/c_user", "uname=asdasd&pword=asdasd")
u.read()
FWIW I added the following to a controller called 'home',
def test(self):
print request.params['uname'], request.params['pword']
resp = Response()
resp.write('ok')
return resp
called it with:
u = urllib2.urlopen("http://localhost:8000/home/test",
"uname=asdasd&pword=asdasd")
u.read()
and it printed
'ok'
as expected.
>
> At the moment the code reads
>
> xhr.onreadystatechage = function() {
...snip
>
> Which would normally read
>
> xhr.onreadystatechage = function() {
...snip
That should be *onreadystatechange* not onreadystatechage, i.e. there is a
missing n in change.
Robert
..snip
> That should be *onreadystatechange* not onreadystatechage, i.e. there
> is a missing n in change.
Isn't peer programming wonderful. Thanks Robert.
I've been looking at that code all day and just couldn't see the typo.
New glasses needed perhaps.
It's all working now thanks.
xhr.onreadystatechange = function()
What is this function() ??
I'm fighting with the same problem and it'll be very useful if I could
learn with you!
Thanks in advance.
Marcus
On 5 jan, 22:48, Uwe Feldtmann <u...@microshare.com.au> wrote:
> Robert Leftwich wrote:..snip> That should be *onreadystatechange* not onreadystatechage, i.e. there
> > is a missing n in change.Isn't peer programming wonderful. Thanks Robert.
Hi Markus.
I see that Bob Ippolito has already explained the function() { ... }
definition - thanks Bob.
Most of the code I used was only to test out sending data back and forth
between the server and the browser without using html forms and would be
more confusing than it's worth so I'll sum up what I've learned from
experimentation and with the patient assistance of others on this list
(thank you all). If anything here is incorrect or could be done better
then please let us all know.
Simple rules I read somewhere:-
Use GET if the data you are sending to the server is less than 512 bytes
and can be sent on the url.
Use the POST method if the data is more than 512 bytes or needs to be
more secure.
---------------
Sending from the browser using GET:-
function toServerByGET(url, fct) {
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if ( xmlhttp.readyState==4 ) {
fct( xmlhttp.responseText );
}
};
xmlhttp.open("GET",url);
xmlhttp.send(null);
}
and is called like this
urlAndData = "/controllerName/methodName/?parm1=" + value1 +
"&parm2=" + value2;
toServer( urlAndData, responseHandler )
---------------
Sending from the browser using POST:-
function toServerByPOST( url, data, fct ) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open( "POST", url, true );
// note setRequestHeader must appear after .open and is used
// to encode the data as though it came from a form (thanks Robert)
xmlhttp.setRequestHeader( "Content-Type",
"application/x-www-form-urlencoded" );
xmlhttp.onreadystatechange = function() {
if ( xmlhttp.readyState==4 ) {
fct( xmlhttp.responseText );
}
}
xmlhttp.send( data );
};
and is called like this
var data = {
id: 1,
parm1: "value1"
parm2: "value2"
}
toServerByPOST( "/controllerName/methodName", data, responseHandler );
---------------
The method in the controller is the same in both instances:-
class ControllerNameController(BaseController):
def methodName(self):
value1 = request.params['parm1']
value2 = request.params['parm2']
return Response( "responseData" )
---------------
Hope this helps in some way.
Uwe.
On 26 jan, 03:45, Uwe Feldtmann <u...@microshare.com.au> wrote:
> Markm wrote:
> > I am just begining here ... do you mind if I see that your complete (I
> > mean your controller and defs) code? For eg, I did not understand this
> > piece of code:
>
> > I'm fighting with the same problem and it'll be very useful if I could
> > learn with you!Hi Markus.
>
> I see that Bob Ippolito has already explained the function() { ... }
> definition - thanks Bob.
>
> Most of the code I used was only to test out sending data back and forth
> between the server and the browser withoutusinghtml forms and would be
> more confusing than it's worth so I'll sum up what I've learned from
> experimentation and with the patient assistance of others on this list
> (thank you all). If anything here is incorrect or could be done better
> then please let us all know.
>
> Simple rules I read somewhere:-
> Use GET if the data you are sending to the server is less than 512 bytes
> and can be sent on the url.
> Use the POST method if the data is more than 512 bytes or needs to be
> more secure.
>
> ---------------
>
> Sending from the browserusingGET:-
>
> function toServerByGET(url, fct) {
> xmlhttp = new XMLHttpRequest();
>
> xmlhttp.onreadystatechange = function() {
> if ( xmlhttp.readyState==4 ) {
> fct( xmlhttp.responseText );
> }
> };
>
> xmlhttp.open("GET",url);
> xmlhttp.send(null);
>
> }and is called like this
>
> urlAndData = "/controllerName/methodName/?parm1=" + value1 +
> "&parm2=" + value2;
> toServer( urlAndData, responseHandler )
>
> ---------------
>
> Sending from the browserusingPOST:-