使用Ajax有两个月的时间了,从简单应用到复杂应用都做了一些,分别应用到了系统的两个模块中,趁着空闲时间,对Ajax使用中的问题和解决进行一下总结。
本文不对任何Ajax框架进行讨论,仅仅针对一些使用技巧和基本问题解决进行分析。同样不对Ajax技术进行讨论,因为对Ajax的技术介绍可以在网上搜索到一堆。
出现这个问题主要是因为发起Http请求的时候,IE包办了Cache策略,很多时候明明更新了数据,但却无法获得更新后的数据。
网上有一些解决此问题的方法,比如在URL后边加随机数,但这仍然不是一个好的解决办法。
比较好的解决方法是:前台在提交数据以后,需要强制更新数据的时候,给XMLHttp对象加入:
xmlhttp.setRequestHeader("If-Modified-Since", "0"); |
老生常谈的问题了,在Ajax中的中文问题,一般来说表现为两个方面:1.发送异步请求时参数的中文问题;2.请求响应数据的中文问题。
一般来说,参数的中文问题解决起来主要依赖于使用的环境,而且依赖于环境所使用的编码方式,而并不像网上的一些文章写的那样。
用XMLHTTP对象Post表单的时候,是默认的用UTF-8字符来发送的。如果你的网页本来就是用的UTF-8编码的话,那么接收到的数据是正常的;如果你的网页编码是GB2312的话,问题就来了,POST过来的数据是UTF-8,而你整个站点是用GB2312来显示,那么所有的中文字符将全部变成乱码。
当使用Servlet接收请求参数时,最好先加入:
response.setContentType("text/xml"); response.setCharacterEncoding("GB2312"); |
当提交方式为POST时,一定要设置成UTF-8,否则会出现乱码:
String name = new String(request.getParameter("name").getBytes("ISO-8859-1"), "utf-8"); |
当提交方式为GET时,则要设置成GB2312或者GBK,否则会出现乱码:
String name = new String(request.getParameter("name").getBytes("ISO-8859-1"), "GB2312"); |
当使用JSP接收请求参数时,需要先将请求接收页的编码方式修改为UTF-8,然后将中文请求参数进行两次encodeURI操作,如:encodeURI(encodeURI(form["name"].value))。最后使用下边的语句接收中文参数:
String name = java.net.URLDecoder.decode(request.getParameter("name"), "UTF-8"); |
另外,当使用Struts框架接收中文参数的时候,最好也使用上述双重encodeURI的方法。
responseText中的中文出现乱码,是因为xmlhttp在处理返回的responseText的时候,是把resposeBody按UTF-8编码进解码形成的,如果服务器送出的确实是UTF-8的数据流的时候汉字会正确显示,而送出了GBK编码流的时候就乱了。解决方法就是在送出的流里面加header,指明送出的是什么编码流,这样xmlhttp就正常了。
response.setHeader("Charset", "GB2312"); |
使用Ajax的时候,通常有一些页面可能会同时发送多个异步请求,在这里我把它叫做并发的异步请求,其实这并不能算做一个问题,但很多时候,编码者为了节省代码书写量,而只构造一次XMLHttpRequest对象,到处使用的话,这个问题就会出现,因为前面的请求还未完成,后面的请求就会把前面的请求覆盖掉。
最简单的解决方法是为每个异步请求分配XMLHttpRequest对象,并分别实例化(JavaScript也是可以面向对象的),这样就可以保证每个请求都有自己独立的XMLHttpRequest对象来进行异步访问。
但是每次都创建一个新的XMLHttpRequest对象,也会造成浪费。最好的办法就是创建一个XMLHttpRequset的对象池,如果池中有空闲的对象,则使用此对象,否则将创建一个新的对象。XMLHttpRequest对象池JavaScript代码在附件中.
很多时候,响应的数据希望用JavaScript处理,比如把响应的数据用对话框的形式弹出,或者将返回数据构造成下一步请求的参数,都需要把响应的数据构造成JavaScript代码并在需要的时机调用执行。但是我们会发现,当使用响应数据构造新的JavaScript后,使用innerHTML方法放入DHTML层中的JavaScript是无法执行的。这是因为,JavaScript是在页面加载的同时进行解析的,也就是说innerHTML中的JavaScript代码是无法被解析的。
解决这个问题需要把JavaScript代码在层中重新解析,解析代码在附件中.
由于Ajax不同于原始的Web请求/响应方式,所以提示是非常必要的,可以说可视化的提示越多越好。如果我点击的这个东西触发了Ajax一个动作,那么程序必须给我一个可视化的提示,告诉我有些动作正在执行,比如loading…、数据加载等等。这样明显的向用户提示出程序的动作,从而克服Ajax不再重载页面而带来的用户不知操作是否进行的不便,不要让用户发出“这个该死的程序究竟在干什么”的牢骚。
错误的操作或者执行可能是在所难免的,有的时候针对DOM的一些错误操作,Ajax是无法给出响应的。这样的话,我们参考第5点完美的给出了用户提示,如果接收不到响应的话,那么提示将一直持续下去。这时,请求超时就非常有必要了,我们可以通过在函数调用后设置一个timer(用Javascript的ontimeout函数)来建立一个超时机制。如果没有返回的话,这个timer就可以明确地执行abort()(终止操作),并且通知用户。
当Ajax操作时,为了方便程序的书写,我们可能需要引入很多css样式表或者类似JavaScript对象池和innerHTML解析等等JavaScript文件,或者prototype.js等工具性的JavaScript文件。这样可能打开某页面的时候,就需要下载很多的文件,这样就会造成加载页面的时候,需要有一个下载文件的过程。
优化的方案:
n 将多个JavaScript或者css文件整合成一个文件以减少HTTP连接数;
n 使用类似jsmin的工具移除注释、空白以及多余的空行等,以减少网络传输的数据量;
n 在web服务端应用gzip compression 压缩。
关于HTTP Compression,则是优化Ajax最为关键的部分。我们可以应用Web Server默认提供的机制,比如Tomcat5.x在 Connector 配置中提供的压缩选项,一个典型的Connector配置如下:
port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" compression="on" compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css" /> |
以上配置使用compression属性激活压缩,然后用compressableMimeType属性设置应用压缩的Mime Type类型。最著名的Apache服务器也提供了mod_deflate 等模块提供类似的压缩配置。
很多人都在网上说,Ajax不如修改为Ajaj,也就是把XML弄“下岗”,然后由JSon作为响应数据回传给用户。由于JSon组织简单、访问方便,正被很多人接受,使用JSon可参考以下代码:
<script language="javascript" type="text/javascript"> var d = { "msg":[{ "user":"dabao", "msg":"天才" }, { "user":"dirk nowitzki", "msg":"dallas mavericks #41" } ], "type":"dirk nowitzki" }; alert(d.type); alert(d.msg[0].msg); alert(d.msg.length); for (var o in d) { alert(d[o]); } </script><script language="javascript" type="text/javascript"> var d = { "msg":[{ "user":"dabao", "msg":"天才" }, { "user":"dirk nowitzki", "msg":"dallas mavericks #41" } ], "type":"dirk nowitzki" }; alert(d.type); alert(d.msg[0].msg); alert(d.msg.length); for (var o in d) { alert(d[o]); } </script> |
由于本人水平有限,文中一些问题解决是搜索得来,同时希望牛人高手们说出遇到的问题及解决方法:)