AJAX Form POST Request to Google App Engine Python


This post shows how to send data of HTML form in client browsers to GAE Python server, and receive response data from the server. This technique is common in the communication of client-server web applications.

Client side (HTML): Users fill the HTML form.

index.html | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>AJAX HTML Form POST on Google App Engine Python example</title>
</head>
<body>

<form action="javascript:ajaxformpost();">
  <input id="input1" type="text" size='110'
     value="<example1>用 HashMap &lt Name, LinkedList &lt NameDistancePair &gt &gt 的 Java data structure 畫出此 directed weighted graph。</example1>">
  <br />
  <input id="input2" type="text" size='110'
     value="<example2>用 HashMap &lt Name, LinkedList &lt NameDistancePair &gt &gt 的 Java data structure 畫出此 directed weighted graph。</example1>">
  <br />
  <input type="submit" value="Submit">
</form>

<script src="post.js"></script>
</body>
</html>

Client side (JavaScript): Send form data to server by HTTP POST request. Note that the data are encoded by JavaScript encodeURIComponent() function to send the data with special characters to servers robustly. ([4], [5], [6], [7], [8])

post.js | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * Cross-browser HTTP POST request
 * @param {string} url The url of HTTP POST request
 * @param {object} keyValuePairs The object which contains data of key-value
 *                 pair(s) to be POSTed. For example, object {'name': 'Bob',
 *                 'age': '21'} represents "name=Bob&age=21".
 * @param {function} callback The callback function if HTTP POST succeeds
 * @param {function} failCallback The callback function if HTTP POST fails
 */
HTTPPOST = function(url, keyValuePairs, callback, failCallback) {
  var xmlhttp;

  if (window.XMLHttpRequest) {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
  } else {
    // code for IE6, IE5
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }

  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
      if (xmlhttp.status == 200)
        callback(xmlhttp.responseText, url);
      else
        failCallback(url);
    }
  };

  xmlhttp.open("POST", url, true);
  xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  var kvpairs = '';
  for (var key in keyValuePairs) {
    if (kvpairs == '')
      kvpairs = encodeURIComponent(key) + '=' +
                encodeURIComponent(keyValuePairs[key]);
    else
      kvpairs = kvpairs + '&' + encodeURIComponent(key) + '=' +
                encodeURIComponent(keyValuePairs[key]);
  }

  xmlhttp.send(kvpairs);
};


function ajaxformpost() {
  var keyValuePairs = {
    'input1': document.getElementById('input1').value,
    'input2': document.getElementById('input2').value
  };

  var callback = function(responseText, url) {
    alert('responseText from url ' + url + ':\n'
          + responseText);
  };

  var failCallback = function(url) {
    // write your own handler for failure of HTTP POST
    alert('fail to post ' + url);
  }

  HTTPPOST("/post", keyValuePairs, callback, failCallback);
}

Server side (GAE Python): The data from client browsers are decoded by urllib2.unquote() function. ([9], [10])

post.py | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import webapp2
import urllib2


class PostPage(webapp2.RequestHandler):
  def post(self):
    input1 = urllib2.unquote(self.request.get('input1'))
    input2 = urllib2.unquote(self.request.get('input2'))

    self.response.out.write("input1: %s\ninput2: %s" % (input1, input2))


application = webapp2.WSGIApplication([
    ('/post', PostPage),
], debug=True)

Server side (GAE Python config):

app.yaml | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
application: ajax-form-post-gae-python
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /
  static_files: index.html
  upload: index.html

- url: /post.js
  static_files: post.js
  upload: post.js

- url: /post
  script: post.application

References:

[1]AJAX Tutorial - W3Schools
[2]AJAX Form POST Request - HTML Form POST/Submit with AJAX/Javascript Example/Tutorial
[3]Python Runtime Environment - Python — Google Cloud Platform
[4]A Complete Guide to URL Escape Characters | We Rock Your Web
[5]xkr.us / javascript / escape(), encodeURI(), encodeURIComponent()
[6]javascript - Best practice: escape, or encodeURI / encodeURIComponent - Stack Overflow
[7]javascript - encodeURI or encodeURIComponent - Stack Overflow
[8]javascript - What is the difference between decodeURIComponent and decodeURI? - Stack Overflow
[9]google app engine - How to decode encodeURIComponent in GAE (python)? - Stack Overflow
[10]Equivalent Javascript Functions for Python's urllib.quote() and urllib.unquote() - Stack Overflow