1. 准备向服务器发送数据
Ajax 最常见的一大用途是向服务器发送数据。最典型的情况是从 客户端发送表单数据,即用户在form元素所含的各个 input 元素里输入的值。下面代码展示了一张简单的表单:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>基本表单</title> <style> .table{display: table;} .row{display: table-row;} .cell{display: table-cell;padding: 5px;} .lable{text-align: right;} </style> </head> <body> <form method="post" action="http://127.0.0.1:8080/form"> <div> <div> <div>Apples:</div> <div><input value="5" /></div> </div> <div> <div>Bananas:</div> <div><input value="2" /></div> </div> <div> <div>Cherries:</div> <div><input value="20" /></div> </div> <div> <div>Total:</div> <div>0 items</div> </div> </div> <button type="submit">Submit Form</button> </form> </body> </html>
这个例子中的表单包含三个input元素和一个提交button 。这些input元素让用户可以指定三种不同的说过各自要订购多少,button则会将表单提交给服务器。
1.1 定义服务器
显而易见,这里需要为这些示例创建处理请求的服务器。这里再一次使用Node.js,原因主要是它很简单,而且用的是Javascript。新建 fruitcalc.js脚本文件如下:
var http = require('http'); var querystring = require('querystring'); function writeResponse(res,data){ var total = 0; for(fruit in data){ total += Number(data[fruit]); } res.writeHead(200,"OK",{ "Content-Type":"text/html", "Access-Control-Allow-Origin":"http://localhost:63342" }); res.write('<html><head><title>Fruit Total</title></head><body>'); res.write('<p>'+total+' item ordered</p></body></html>'); res.end(); } http.createServer(function(req,res){ console.log("[200] "+req.method+" to "+req.url); if(req.method == "OPTIONS"){ res.writeHead(200,"OK",{ "Access-Control-Allow-Header":"Content-Type", "Access-Control-Allow-Methods":"*", "Access-Control-Allow-Origin":"*" }); res.end(); }else if(req.url == '/form'&& req.method == 'POST'){ var dataObj = new Object(); var contentType = req.headers["content-type"]; var fullBody = ''; if(contentType){ if(contentType.indexOf("application/x-www-form-urlencode") > -1){ req.on('data',function(chunk){ fullBody += chunk.toString(); }); req.on('end',function(){ var dBody = querystring.parse(fullBody); dataObj.apples = dBody["apples"]; dataObj.bananas = dBody["bananas"]; dataObj.cherries = dBody["cherries"]; writeResponse(res,dataObj); }); }else if(contentType.indexOf("application/json") > -1){ req.on('data',function(chunk){ fullBody += chunk.toString(); }); req.on('end',function(){ dataObj = JSON.parse(fullBody); writeResponse(res,dataObj); }); } } } }).listen(8080);
脚本中高亮部分:writeResponse函数。这个函数会在提取请求的表单值之后调用,它负责生产对浏览器的响应。当前,这个函数会创建简单的HTML文档,效果如下:
这个响应很简单,实现效果是让服务器计算出了用户通过form中各个input元素所订购的水果总数。服务器得端脚本的其余部分负责解码客户端用Ajax发送的各种可能数据格式。
1.2 理解问题所在
上面的图片清楚的描述了想要用Ajax解决的问题。
当提交表单后,浏览器会在新的页面显示结果。这意味着两点:
* 用户必须等待服务器处理数据并生成响应;
* 所有文档上下文信息都丢失了,因为结果是作为新文档进行显示的。
这就是应用Ajax的理想情形了。可以异步生成请求,这样用户就能在表单被处理时继续与文档进行交互。
2. 发送表单
向服务器发送数据的最基本方式是自己收集并格式化它。下面代码展示了添加到前面的HTML文档 example.html 的一段脚本。用的就是这种方式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>手动收集和发送数据</title> <style> .table{display: table;} .row{display: table-row;} .cell{display: table-cell;padding: 5px;} .lable{text-align: right;} </style> </head> <body> <form method="post" action="http://127.0.0.1:8080/form"> <div> <div> <div>Apples:</div> <div><input value="5" /></div> </div> <div> <div>Bananas:</div> <div><input value="2" /></div> </div> <div> <div>Cherries:</div> <div><input value="20" /></div> </div> <div> <div>Total:</div> <div>0 items</div> </div> </div> <button type="submit">Submit Form</button> </form> <script> document.getElementById("submit").onclick = handleButtonPress; var httpRequest; function handleButtonPress(e){ //对表单里的button元素而言,其默认行为是用常规的非Ajax方式提交表单。这里不想让他发生,所以调用了preventDefault方法 e.preventDefault(); var form = document.getElementById("fruitform"); //收集并格式化各个input的值 var formData =""; var inputElements = document.getElementsByTagName("input"); for (var i = 0; i < inputElements.length; i++){ formData += inputElements[i].name + "=" + inputElements[i].value +"&"; } httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = handleResponse; //数据必须通过POST方法发送给服务器,并读取了HTMLFormElement的action属性获得了请求需要发送的URL httpRequest.open("POST",form.action); //添加标头来告诉服务器准备接受的数据格式 httpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //把想要发送给服务器的字符串作为参数传递给send方法 httpRequest.send(formData); } function handleResponse(){ if(httpRequest.readyState == 4 && httpRequest.status == 200){ document.getElementById("results").innerHTML = httpRequest.responseText; } } </script> </body> </html>
效果图如下:
服务器响应表单提交后返回的HTML文档会显示在同一页,而且该请求是异步执行的。
3. 发送JSON数据