关于 XMLHttpRequest对象的onreadyStateChange方法

最近做了一个Ajax的demo,前台用HTML+javascript,后台用一个servlet来响应,流程如下:

页面点击链接事件,由js捕获,生成一个请求到后台,servlet处理后给出响应信息,并显示在页面上。

 

问题是,页面无法获取到servlet的响应信息。

 

初始代码

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Test H2</title>
    <style>
        #result{
            position:absolute;
            left:50px;
            top:300px;
        }
    </style>
    <!-- <script type="text/javascript" src="js/jquery-1.11.1.js"></script> -->
    <script>
        function handle(url){
            // Fetch the data, HERE i just give some dummy data
            var username = "joshua";
            var query = "query_test";
            var feature = url;
            var click_type = "clc_test";
            var rank = 1;
            var page_number = 1;
            var paras = "?query="+query+"&username="+username+"&feature="+feature+
                        "&click_type="+click_type+"&rank="+rank+"&page_number="+page_number;
            // transfer this data to servlet to save
            var xmlhttp;
            // code for IE7+, Firefox, Chrome, Opera, Safari
            if(window.XMLHttpRequest){
                xmlhttp = new XMLHttpRequest;
            // code for IE6, IE5
            }else{
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.open("POST","/WebDemo_H2/AjaxServlet"+paras+"&tip="+Math.random(),true);
            xmlhttp.send();
        document.getElementById("result").innerHTML = xmlhttp.responseText;
        }
    </script>
</head>
<body>
    <aside style="margin:10px;">
        <div>
            <p style="font-weight:bold;">Main Testing Page</p>
            <a href="index.html">Back</a>
        </div>
        <div style="height:20px"></div>
        <div>
            <a href="javascript:handle('test1.html')">test link 1</a><br/>
            <a href="javascript:handle('test2.html')">test link 2</a><br/>
            <a href="javascript:handle('test3.html')">test link 3</a>
        </div>
    </aside>
    <button onclick="">Clear Data</button>
    <div id="result">
    </div>
</body>
</html>

Servlet:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AjaxServlet extends HttpServlet {

    public Connection conn = null;

    public void init() {
        try {
            Class.forName("org.h2.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:h2:C:/Users/zhoum18/H2Test/db/test", "sa", "");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            request.setCharacterEncoding("GBK");
            response.setContentType("text/html;charset=GBK");
        // get the parameters
        try {
            PrintWriter out = response.getWriter();
            String userName = request.getParameter("username");
            String query = request.getParameter("query");
            String feature = request.getParameter("feature");
            String click_type = request.getParameter("click_type");
            String rank = request.getParameter("rank");
            String page_number = request.getParameter("page_number");
            String sql = "INSERT INTO CLICK_TRACKING SELECT ?,?,?,?,?,?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, query);
            pstmt.setString(2, userName);
            pstmt.setString(3, feature);
            pstmt.setString(4, click_type);
            pstmt.setInt(5, Integer.parseInt(rank));
            pstmt.setInt(6, Integer.parseInt(page_number));
            pstmt.executeUpdate();
            conn.commit();

            sql = "select feature,count(*) as num  from click_tracking group by feature";
            pstmt = conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            out.println("<table border='1'>");
            out.println("<tr>");
            out.println("<td>Link</td>");
            out.println("<td>Click Times</td>");
            out.println("</tr>");
            while (rs.next()) {
                out.println("<tr>");
                out.println("<td>" + rs.getString("feature") + "</td>");
                out.println("<td>" + rs.getString("num") + "</td>");
                out.println("</tr>");
            }
            out.println("</table>");
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void destroy() {
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
            }
        }
    }
}

可以看到在servlet中用PrintWriter对象返回了建立table的HTML语句,按照逻辑,应该在页面上打印出table的内容跟应有的值;

结果是,xmlhttp.responseText方法返回的值始终为空,没有任何值返回,用chrome浏览器调试,发现HTTP请求是有响应的,而且response tab里面有值:

 

 

经过代码查看,发现xmlhttp对象的readystate始终为1.

修改了下页面js的代码,将原有的写入改成了以下代码:

            xmlhttp.open("POST","/WebDemo_H2/AjaxServlet"+paras+"&tip="+Math.random(),true);
            xmlhttp.onreadystatechange = function(){
                if (xmlhttp.readyState == 4) {
                    document.getElementById("result").innerHTML = xmlhttp.responseText;
                }
            }
            xmlhttp.send();

成功显示出response的内容。

 

结论:

页面发送出请求后,往往无法得知什么时候才能完成这个请求并获得回应,所以要使用一个事件机制来捕获请求完成的状态。

XmlHttpRequest对象有一个方法,onreadystatechange这个函数实现这一个功能。

类似于回调函数,在readystate改变时,这个方法可以指定一个函数来判断和处理,比如上面的代码:

xmlhttp.onreadystatechange = function(){

  // 这里面的就是当readystate改变时,处理事件的代码,在我的例子中,判断了当readyState等于4的时候,再捕获相应的信息。

}

 

readyState的不同值,代表了不同的状态:

0:尚未初始化
1:正在加载
2:加载完毕
3:正在处理
4:处理完毕

当其变为4, 就可以访问从服务器返回的数据了。

另附http请求相应代码

200 请求成功
202 请求被接受但处理未完成
400 错误请求
404 请求资源未找到
500 内部服务器错误

 

posted @ 2014-07-07 10:06  啃苹果  阅读(8593)  评论(0编辑  收藏  举报