Ajax 高级功能之ajax向服务器发送数据
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 id="fruitform" method="post" action="http://127.0.0.1:8080/form"> <div class="lable"> <div class="row"> <div class="cell lable">apples:</div> <div class="cell"><input name="apples" value="5" /></div> </div> <div class="row"> <div class="cell lable">bananas:</div> <div class="cell"><input name="bananas" value="2" /></div> </div> <div class="row"> <div class="cell lable">cherries:</div> <div class="cell"><input name="cherries" value="20" /></div> </div> <div class="row"> <div class="cell lable">total:</div> <div id="results" class="cell">0 items</div> </div> </div> <button id="submit" 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 id="fruitform" method="post" action="http://127.0.0.1:8080/form"> <div class="lable"> <div class="row"> <div class="cell lable">apples:</div> <div class="cell"><input name="apples" value="5" /></div> </div> <div class="row"> <div class="cell lable">bananas:</div> <div class="cell"><input name="bananas" value="2" /></div> </div> <div class="row"> <div class="cell lable">cherries:</div> <div class="cell"><input name="cherries" value="20" /></div> </div> <div class="row"> <div class="cell lable">total:</div> <div id="results" class="cell">0 items</div> </div> </div> <button id="submit" 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数据
ajax不止用来发送表单数据,几乎可以发送任何数据,包括javascript对象表示法(javascript object notation,json)数据,而它几乎已经成为一种流行的数据格式了。ajax扎根于xml,但这一格式很繁琐。当运行的web应用程序必须传输大量xml文档时,繁琐就意味着带宽和系统容量方面的实际成本。
json经常被称为xml的“脱脂”替代品。json易于阅读和编写,比xml更紧凑,而且已经获得了广泛支持。json发源于javascript,但它的发展已经超越了 javascript,被无数的程序包和系统理解并使用。
以下是一个简单的javascript对象用json表达的例子:
{"bananas":"2","apples":"5","cherries":"20"}
这个对象有三个属性:bananas、apples和cherries。这些属性的值分别是2、5和20。
json的功能不如xml丰富,但对许多应用程序来说,那些功能是用不到的。json简单、轻量和富有表现力。下面例子演示了发送json数据到服务器有多简单,修改前例的javascript部分如下:
<script> document.getelementbyid("submit").onclick = handlebuttonpress; var httprequest; function handlebuttonpress(e){ e.preventdefault(); var form = document.getelementbyid("fruitform"); var formdata = new object(); 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; httprequest.open("post",form.action); httprequest.setrequestheader("content-type","application/json"); httprequest.send(json.stringify(formdata)); } function handleresponse(){ if(httprequest.readystate == 4 && httprequest.status == 200){ document.getelementbyid("results").innerhtml = httprequest.responsetext; } } </script>
这段脚本,创建了一个新的object,并定义了一些属性来对应表单内各个input元素的name属性值。可以使用任何数据,但 input元素很方便,而且能和之前的例子保持一致。
为了告诉服务器正在发送json数据,把请求的content-type标头设为 application/json,就像这样:
httprequest.setrequestheader("content-type","application/json");
用json对象和json格式进行相互的转换。(大多数浏览器能直接支持这个对象,但也可以用下面的网址里的脚本来给旧版的浏览器添加同样的功能:https://github.com/douglascrockford/json-js/blob/master/json2.js )json对象提供了两个方法:
在上面的例子中,使用了stringify方法,然后把结果传递给xmlhttprequest 对象的send方法。此例中只有数据的编码方式发生了变化。提交表单的效果还是一样。
4. 使用formdata对象发送表单数据
另一种更简洁的表单收集方式是使用一个formdata对象,它是在xmlhttprequest的第二级规范中定义的。
由于原来的node.js代码有点问题,此处用c#新建文件 fruitcalc.aspx作为处理请求的服务器。其cs代码如下:
using system; namespace web4luka.web.ajax.html5 { public partial class fruitcalc : system.web.ui.page { protected void page_load(object sender, eventargs e) { int total = 0; if (request.httpmethod == "post") { if (request.contenttype.indexof("multipart/form-data") > -1) { for (int i = 0; i < request.form.count; i++) { total += int32.parse(request.form[i]); } } writeresponse(response, total); } } private void writeresponse(system.web.httpresponse response, int total) { string strhtml; response.addheader("access-control-allow-origin", "http://localhost:63342"); strhtml = total + " item ordered"; response.write(strhtml); } } }
4.1 创建 formdata 对象
创建formdata对象时可以传递一个htmlformelement对象,这样表单里所有的元素的值都会被自动收集起来。示例如下:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>使用formdata对象</title> <style> .row{display: table-row;} .cell{display: table-cell;padding: 5px;} .lable{text-align: right;} </style> </head> <body> <form id="fruitform" method="post" action="http://localhost:53396/ajax/html5/fruitcalc.aspx"> <div class="lable"> <div class="row"> <div class="cell lable">apples:</div> <div class="cell"><input name="apples" value="5" /></div> </div> <div class="row"> <div class="cell lable">bananas:</div> <div class="cell"><input name="bananas" value="2" /></div> </div> <div class="row"> <div class="cell lable">cherries:</div> <div class="cell"><input name="cherries" value="20" /></div> </div> <div class="row"> <div class="cell lable">total:</div> <div id="results" class="cell">0 items</div> </div> </div> <button id="submit" type="submit">submit form</button> </form> <script> document.getelementbyid("submit").onclick = handlebuttonpress; var httprequest; function handlebuttonpress(e){ e.preventdefault(); var form = document.getelementbyid("fruitform"); var formdata = new formdata(form); httprequest = new xmlhttprequest(); httprequest.onreadystatechange = handleresponse; httprequest.open("post",form.action); httprequest.send(formdata); } function handleresponse(){ if(httprequest.readystate == 4 && httprequest.status == 200){ document.getelementbyid("results").innerhtml = httprequest.responsetext; } } </script> </body> </html>
当然,关键的变化是使用了formdata对象:
var formdata = new formdata(form);
其他需要注意的地方是不再设置content-type标头的值了。如果使用formdata对象,数据总是会被编码为multipart/form-data 。本例提交表单后,显示效果如下:
4.2 修改formdata对象
formdata对象定义了一个方法,它允许给要发送到服务器的数据添加名称/值对。
可以用append方法增补从表单中收集的数据,也可以在不使用htmlformelement的情况下创建formdata对象。这就意味着可以使用append方法来选择向客户端发送哪些数据值。修改上一示例的javascript代码如下:
<script> document.getelementbyid("submit").onclick = handlebuttonpress; var httprequest; function handlebuttonpress(e){ e.preventdefault(); var form = document.getelementbyid("fruitform"); var formdata = new formdata(); var inputelements = document.getelementsbytagname("input"); for(var i=0;i<inputelements.length;i++){ if(inputelements[i].name != "cherries"){ formdata.append(inputelements[i].name,inputelements[i].value); } } httprequest = new xmlhttprequest(); httprequest.onreadystatechange = handleresponse; httprequest.open("post",form.action); httprequest.send(formdata); } function handleresponse(){ if(httprequest.readystate == 4 && httprequest.status == 200){ document.getelementbyid("results").innerhtml = httprequest.responsetext; } } </script>
此段脚本里,创建formdata对象时并没有提供htmlformelement对象。随后用dom找到文档里所有的input元素,并为那些name属性的值不是cherries的元素添加名称/值对。此例提交表单后,显示效果如下:
5. 发送文件
可以使用formdata 对象和type 属性为 file 的input 元素向服务器发送文件。当表单提交时,formdata对象会自动确保用户选择的文件内容与其他的表单值一同上传。下面的例子展示了如何以这种方式使用formdata对象。
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>使用formdata对象发送文件到服务器</title> <style> .row{display: table-row;} .cell{display: table-cell;padding: 5px;} .lable{text-align: right;} </style> </head> <body> <form id="fruitform" method="post" action="http://localhost:53396/ajax/html5/fruitcalc.aspx"> <div class="lable"> <div class="row"> <div class="cell lable">apples:</div> <div class="cell"><input name="apples" value="5" /></div> </div> <div class="row"> <div class="cell lable">bananas:</div> <div class="cell"><input name="bananas" value="2" /></div> </div> <div class="row"> <div class="cell lable">cherries:</div> <div class="cell"><input name="cherries" value="20" /></div> </div> <div class="row"> <div class="cell lable">file:</div> <div class="cell"><input type="file" name="file" /></div> </div> <div class="row"> <div class="cell lable">total:</div> <div id="results" class="cell">0 items</div> </div> </div> <button id="submit" type="submit">submit form</button> </form> <script> document.getelementbyid("submit").onclick = handlebuttonpress; var httprequest; function handlebuttonpress(e){ e.preventdefault(); var form = document.getelementbyid("fruitform"); var formdata = new formdata(form); httprequest = new xmlhttprequest(); httprequest.onreadystatechange = handleresponse; httprequest.open("post",form.action); httprequest.send(formdata); } function handleresponse(){ if(httprequest.readystate == 4 && httprequest.status == 200){ document.getelementbyid("results").innerhtml = httprequest.responsetext; } } </script> </body> </html>
此例里,最明显的变化发生在 form元素上。添加了input元素后,formdata对象就会上传用户所选的任意文件。
修改 fruitcalc.aspx 的cs文件如下:
using system; using system.web; namespace web4luka.web.ajax.html5 { public partial class fruitcalc : system.web.ui.page { protected void page_load(object sender, eventargs e) { int total = 0; if (request.httpmethod == "post") { if (request.contenttype.indexof("multipart/form-data") > -1) { for (int i = 0; i < request.form.count; i++) { total += int32.parse(request.form[i]); } if (request.files["file"] != null) { httppostedfile file = request.files["file"]; file.saveas(server.mappath("/upload/pictures/" + file.filename)); } } writeresponse(response, total); } } private void writeresponse(system.web.httpresponse response, int total) { string strhtml; response.addheader("access-control-allow-origin", "http://localhost:63342"); strhtml = total + " item ordered"; response.write(strhtml); } } }
此例的显示效果如下:
以上所述是小编给大家介绍的ajax 高级功能之ajax向服务器发送数据,希望对大家有所帮助
推荐阅读
-
jQuery通过Ajax向PHP服务端发送请求并返回JSON数据
-
Ajax 高级功能之ajax向服务器发送数据
-
前端笔记知识点整合之服务器&Ajax(上)服务器&PHP&数据交互&HTTP
-
前端笔记知识点整合之服务器&Ajax(中)MySQL基础操作&PHP操作数据库&Ajax
-
前端笔记知识点整合之服务器&Ajax(下)数据请求&解决跨域&三级联动&session&堆栈
-
使用jquery的ajax向highchart+echart发送请求,并获得动态数据(实例讲解)
-
Ajax 向数据库修改和添加功能(较简答)
-
Go语言服务器开发之客户端向服务器发送数据并接收返回数据的方法
-
Ajax对象 向 服务器发送数据请求的有关问题 新手求解答
-
jQuery通过Ajax向PHP服务端发送请求并返回JSON数据