我想做类似sina博客的评论系统,注册用户可以无刷新同时登陆并发表评论,成功后刷新评论列表,思路是利用xmlhttprequest做异步调用,前段js代码如下:
function createXmlHttp() {
    var xmlHttp = null;    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
    try {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    catch (e) { throw new Error("您的浏览器版本过低,请更新浏览器"); }
}
return xmlHttp; 
}//获得评论数据
function getList()
{
 var mid = GetID();//获得当前书籍的ID
 var url = "http://localhost/tcshu/bookCommentServer.aspx?action=getList&bookID="+ mid;
 var gbxmlhttp = createXmlHttp();
 gbxmlhttp.onreadystatechange=function()
 {
     if(gbxmlhttp.readyState==4&&gbxmlhttp.status==200)
     {         $get("commentList").innerHTML = gbxmlhttp.responseText;//获得数据并填充评论列表
     }
 }
 gbxmlhttp.open('GET',url,true);
 gbxmlhttp.send(null);
}//发布评论
function PostComment(userName,body)
{
 
 if(userName==null){ window.alert("昵称不能为空!");return;}
 var id = GetID();
 //var params="action=postComment&userName="+ encodeURIComponent(userName)+ "&body=" + encodeURIComponent(body)+ "&bookID=" + encodeURIComponent(id);
 var url = "bookCommentServer.aspx?action=postComment&userName="+ encodeURIComponent(userName)+ "&body=" + encodeURIComponent(body)+ "&bookID=" + encodeURIComponent(id);
 var gbxmlhttp2 = createXmlHttp();
 gbxmlhttp2.open('GET',url,true);
 //gbxmlhttp2.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
 //gbxmlhttp2.send(params);
 $get("commentArea").value= "";
 getList();
}//判断用户是否登录
function IsVali(){
 var vali;    
 var url = "CheckLoginServer.aspx?action=isVali";
 var gbxmlhttp3 = createXmlHttp();
 gbxmlhttp3.onreadystatechange=function()
 {
     if(gbxmlhttp3.readyState==4&&gbxmlhttp3.status==200)
     {          vali = gbxmlhttp3.responseXML.getElementsByTagName("isVali")[0].firstChild.data;
          
     }
 }
 gbxmlhttp3.open('GET',url,true);
 gbxmlhttp3.send(null); 
 return vali;
}//获得注册用户名
function GetUserName(){
var uname;
 var url = "CheckLoginServer.aspx?action=getName";
 var gbxmlhttp4 = createXmlHttp();
 gbxmlhttp4.onreadystatechange=function()
 {
     if(gbxmlhttp4.readyState==4&&gbxmlhttp4.status==200)
     {          uname = gbxmlhttp4.responseXML.getElementsByTagName("userName")[0].firstChild.data;
          
     }
 }
 gbxmlhttp4.open('GET',url,true);
 gbxmlhttp4.send(null);
 
 return uname;
}//用户登陆
function CheckUser(){
    var userName=$get("login_name").value;
    var password=$get("login_pass").value;
    var url = "CheckLoginServer.aspx?action=validateUser&userName="+ encodeURIComponent(userName)+ "&password=" + encodeURIComponent(password);
    var xmlCheckUser=createXmlHttp();
    
    xmlCheckUser.onreadystatechange=function()
   {
if(xmlCheckUser.readyState==4&&xmlCheckUser.status==200)  
{
             var mes=xmlCheckUser.responseXML.getElementsByTagName("message")[0].firstChild.data;
             var val=xmlCheckUser.responseXML.getElementsByTagName("passed")[0].firstChild.data;
             if(val=="True")
             {  //若登陆则获得注册用户名
                $get("ctl00_ContentPlaceHolder1_BookComment1_registerName").innerText=GetUserName();
                $get("ctl00_ContentPlaceHolder1_BookComment1_userInfo").style.display="none";
                return true;
             }
             else
             {
                $get("errorText").innerHTML=mes;
                return false;
             }
             

    }
   xmlCheckUser.open("GET",url,true);
   xmlCheckUser.send(null); 
}//发布评论按钮调用此函数
function sendBookComment(){
    var userName;
    var hasVali=IsVali();
    var ck=$get("anonymity");
    if(hasVali=="True")
    {
        if(ck!=null&&ck.checked==true)
        {
            window.alert("您已登录!");
            getList();
            $get("ctl00_ContentPlaceHolder1_BookComment1_registerName").innerText=GetUserName();
            $get("ctl00_ContentPlaceHolder1_BookComment1_userInfo").style.display="none";
        }else{
        userName=GetUserName();
        
        }
        
    }
    else if(hasVali=="False")
    {
        var ck=$get("anonymity");
        if(ck!=null&&ck.checked==true)
        {
            userName=$get("comment_anonyous").value;
                         
        }else{
           var hasLogin = CheckUser();
           if(hasLogin==true)
           {
            userName=GetUserName();
           }
        }
    }
    var ubody=$get("commentArea");
    if(ubody.value=="")
    {
     alert('留言不能为空');
     return;
     }
    PostComment(userName,ubody.value);
}
运行后可以无刷新登陆,也可以发布,但是总会出现“灵异现象”:总会出现登陆却没有发布,或者发布了评论列表却没有刷新,或者干脆连验证是否登录与获得登陆用户名都会返回undefined,但若调试时设置断点却有返回值;FF浏览器下却根本无法执行,这样一些莫名其妙的问题。
经分析应该是应用了太多异步调用机制,导致有些值还没有传递,接着就执行下步操作了。
那么如何进行多次异步操作时保证数据一致呢?
(第一步、无刷新登陆)
(第二步、发布评论)
(第三步、刷新评论列表)

解决方案 »

  1.   

    这种情况可以不用ajax,将用户名、密码和发布评论信息一起提交后台,先进行登录认证,如果认证成功做发布评论信息并返回列表
      

  2.   

    浪尖赏花
    你的提议很好,将多步操作并作一步提交由服务器做判断。我将尝试将登陆与发布一并操作。
    但是我考虑的情况比这个稍显复杂:
    1.注册用户可以无刷新登陆并发布评论
    2.登陆后用户直接发布评论(不再有用户名与密码)
    3.匿名用户通过匿名发布评论(没有密码)
    ps特殊情况
    1.若用户在其它页面登陆此页面仍未显示登陆状态时发布信息,则会弹出错误,确定后动态刷新为登录状态。
    2.若登陆session过期或其它页面注销登录此页面仍显示登录状态发布信息,则会弹出用户名错误并什么都不做。
    (后期会加入session验证码)
      

  3.   

    同样一个页面,你可以加一个标志位以区别登陆时评论,未登陆时评论,还有匿名用户评论
    在后台处理时,判断这个标志位就行了
    if(未登陆){
        //todo:登陆操作,取用户名密码校验
         //成功则发表评论
         //失败则提示用户错误
    }else{
        if(登陆时){
             //发表评论
        }else{//匿名
              //发表评论
        }
    }PS:这个功能还可以直接放在过滤器中
      

  4.   

    采用ajax,将登陆与发布一并传递到服务器端,然后在服务器端判断操作(登陆验证,保存session,以及发布评论,没有通过验证的匿名发表)
    最后返回状态,刷新列表
      

  5.   

    为什么不用一些现成库里面的ajax方法呢 比如jquery,mootools方便简洁也不至于出那么多问题~
      

  6.   

    我已经修改了代码,现在可以实现需求。但是代码出奇的丑陋。
    function sendBookComment2(){
        var userName;
        var pass;
        var lag;
        var ck=$get("anonymity");
        if(ck!=null){
            if(ck.checked==true){
                userName=$get("comment_anonyous").value;
                lag=0;
            }else if(ck.checked==false){
                userName=$get("login_name").value;
                pass=$get("login_pass").value;
                lag=1;
            }
        }else if(ck==null){
            lag=2;
        }
        var ubody=$get("commentArea");
        if(ubody.value=="")
        {
         alert('留言不能为空');
         return;
         }
         postComment2(userName,pass,ubody.value,lag);
    }function postComment2(userName,pass,body,lag){
         //if(userName==null){ window.alert("昵称不能为空!");return;}
         var id = GetID();
         //var params="action=postComment&userName="+ encodeURIComponent(userName)+ "&body=" + encodeURIComponent(body)+ "&bookID=" + encodeURIComponent(id);
         var url = "http://localhost/tcshu/bookCommentServer.aspx?action=postComment&userName="+ encodeURIComponent(userName)+"&pass="+encodeURIComponent(pass)+ "&body=" + encodeURIComponent(body)+ "&bookID=" + encodeURIComponent(id)+"&lag="+encodeURIComponent(lag);
         var gbxmlhttp2 = createXmlHttp();
         gbxmlhttp2.onreadystatechange=function()
         {
             if(gbxmlhttp2.readyState==4&&gbxmlhttp2.status==200)
             {
                //接收4个参数passed-是否通过登录mes-登陆错误信息success-是否发布成功errortext-发布错误信息
                var passed=gbxmlhttp2.responseXML.getElementsByTagName("passed")[0].firstChild.data;
                var mes=gbxmlhttp2.responseXML.getElementsByTagName("message")[0].firstChild.data;
                var success=gbxmlhttp2.responseXML.getElementsByTagName("success")[0].firstChild.data;
                 var errortext=gbxmlhttp2.responseXML.getElementsByTagName("errortext")[0].firstChild.data;
                 if(passed!=null&&passed=="True")
                 {
                    $get("<%=registerName.ClientID %>").innerText=$get("login_name").value;
                    $("ul").remove("<%=userInfo.ClientID %>");//用jQuery移除掉了,display掉还会被找到。
                    //$get("<%=userInfo.ClientID %>").style.display="none";
                 }else if(passed!=null&&passed=="False")
                 {
                    $get("errorText").innerHTML=mes;
                 }
                 if(success!=null&&success=="True")
                 {
                    getList();
                 }else if(success!=null&&success=="False")
                 {
                    alert(errortext);
                 }
             }
         }
         gbxmlhttp2.open('GET',url,true);
         gbxmlhttp2.send(null);
         //gbxmlhttp2.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
         //gbxmlhttp2.send(params);
         $get("commentArea").value= "";
         
    }
    由于要从responseXML里接受数据,但有时会没有不分返回数据如:用户匿名发布就不会有登陆成功的信息,但是必须接收此信息,不然会产生“未知对象”的错误。所以迫不得已,server的代码就变成下面这个丑样了:
    if (Request.QueryString["userName"] == "undefined" && Request.QueryString["pass"] == "undefined")
                        {
                            if (HttpContext.Current.User.Identity.IsAuthenticated)
                            {
                                if (!string.IsNullOrEmpty(Request.QueryString["lag"]) && Request.QueryString["lag"] == "2")
                                {
                                    string userName = HttpContext.Current.User.Identity.Name;
                                    string body = Request.QueryString["body"];
                                    PostComment(userName, body);
                                    Response.ContentType = "text/xml";
                                    Response.Write("<response>" + "<passed>" + "hasVali" + "</passed>" + "<message>" + "hasVali" + "</message>" + "<success>" + "True" + "</success>" + "<errortext>" + "登陆用户发布!" + "</errortext>" + "</response>");
                                }
                            }
                            else
                            {
                                Response.ContentType = "text/xml";
                                Response.Write("<response>" + "<passed>" + "noVali" + "</passed>" + "<message>" + "noVali" + "</message>" + "<success>" + "False" + "</success>" + "<errortext>" + "昵称不能为空!" + "</errortext>" + "</response>");                        }
                        }
                        else if (Request.QueryString["userName"] != "undefined" && Request.QueryString["pass"] == "undefined")
                        {
                            if (HttpContext.Current.User.Identity.IsAuthenticated)
                            {
                                Response.ContentType = "text/xml";
                                Response.Write("<response>" + "<success>" + "False" + "</success>" + "<errortext>" + "用户已登录!" + "</errortext>" + "<passed>" + "hasVali" + "</passed>" + "<message>" + "hasVali" + "</message>" + "</response>");
                            }
                            else
                            {
                                if (!string.IsNullOrEmpty(Request.QueryString["lag"]) && Request.QueryString["lag"] == "0")
                                {
                                    string userName = Request.QueryString["userName"];
                                    string body = Request.QueryString["body"];
                                    PostComment(userName, body);
                                    Response.ContentType = "text/xml";
                                    Response.Write("<response>" + "<passed>" + "anony" + "</passed>" + "<message>" + "anony" + "</message>" + "<success>" + "True" + "</success>" + "<errortext>" + "匿名用户!" + "</errortext>" + "</response>");
                                }
                            }
                        }
                        else if (Request.QueryString["userName"] != "undefined" && Request.QueryString["pass"] != "undefined")
                        {
                            if (HttpContext.Current.User.Identity.IsAuthenticated)
                            {
                                Response.ContentType = "text/xml";
                                Response.Write("<response>" + "<passed>" + "hasVali" + "</passed>" + "<message>" + "hasVali" + "</message>" + "<success>" + "False" + "</success>" + "<errortext>" + "用户已登录!" + "</errortext>" + "</response>");
                            }
                            else
                            {
                                if (!string.IsNullOrEmpty(Request.QueryString["lag"]) && Request.QueryString["lag"] == "1")
                                {
                                    Response.ContentType = "text/xml";
                                    string userName = Request.QueryString["userName"];
                                    string pass = Request.QueryString["pass"];
                                    bool isValidate = ValidateUser(userName, pass);
                                    string message = "用户名或密码错误!登录失败!";
                                    if (isValidate)
                                    {
                                        message = "登陆成功!";
                                        string body = Request.QueryString["body"];
                                        PostComment(userName, body);
                                        
                                        
                                    }
                                    string textxml;                                textxml = "<response>" + "<success>" + isValidate.ToString() + "</success>" + "<errortext>" + "登陆发布!" + "</errortext>" + "<passed>" + isValidate.ToString() + "</passed>" + "<message>" + message + "</message>" + "</response>";
                                    Response.Write(textxml);
                                }
                            }
                        }
    为了避免客户端没有返回值的错误,所有的response的数据都必须包含这四个数据,即使没用也要硬编出来。
    而if判断还变成了与“undefined”比较这种难看的格式。