【问题标题】:Ajax form only submitting sometimesAjax 表单有时只提交
【发布时间】:2013-02-28 18:31:15
【问题描述】:

在 SO 上有几个这样的问题,但没有一个答案对我有用。我都试过了。

我试图最小化我正在粘贴的代码,但是这个脚本有点困难

我有一个评论表单,它通过 ajax 提交到一个 php 脚本,该脚本保存评论,然后获取所有 cmets 并重新显示它们,以便在不刷新页面的情况下显示新评论。

只有在某些时候,cmets 才能成功提交到数据库并正确重新显示。 通常几乎所有其他提交的评论都会被保存。每隔一段时间似乎什么都没有发生。

我真正的问题是每次提交时都没有保存 cmets。

这里是 javascript 和 ajax 调用:

$(document).ready(function(){
    var working = false;

    $('#commentForm').submit(function(e){

        if(working) return false;

        working = true;
        $('#submitComment').val('Working..');
        $('span.error').remove();

        $.post('/ajax/comment.process.php',$(this).serialize(),function(msg){

            working = false;
            $('#submitComment').val('Submit');

            if(msg.status){

                $('#commentArea').slideDown().$(msg.html).prepend('#commentArea');
            $('#blogComment').val('');
            }
            else {

                $.each(msg.errors,function(k,v){
                    $('label[for='+k+']').append('<span class="error">'+v+'</span>');
                });
            }
        },'json');
    });
});

这里是提交评论的函数:

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = $_POST['blogComment'];
    $blog_id = intval($_POST['blogID']);
    $photoSubmit = $_POST['comPhoto'];

    $newComQuery = $this->mysqli->query("INSERT INTO b_comments (blog_id, user_id, date, content, photo) VALUES ('".$blog_id."', '".$user_id."', Now(), '".$newCom."', '".$photoSubmit."')");

    if($newComQuery === false) {
        echo "Query failed";
    }else{

        $returnCom = $this->comMarkup($blog_id);
        echo $returnCom;

    }           
}

这是与 cmets 相呼应的 comMarkup() 函数的一部分(它只是重要的部分):

//  This method outputs the XHTML markup of the comment
public function comMarkup($blog_id) {

    $sql = $this->mysqli->query("SELECT * FROM b_comments WHERE blog_id = '".$blog_id."' ORDER BY date DESC");

    while($d = $sql->fetch_assoc()) {

        $d = $validate->sanitize($d);

        echo "

            <div class='comment-block'>
                <span class='com-img'><img src='".$photo_path."' /></span>
                <h3 style='display: inline;'><a href='".$profile."'>".$userName."</a></h3>
                <div class='com-date'>".$d['date']."</div>
                <p>".$comContent."</p>
            </div>
        ";
    }
}

编辑:这是所要求的comment.process.php代码:

    session_start();

include_once('../classes/comment.class.php');
include_once('../classes/db.class.php');
include_once('../classes/user.class.php');

$user_id = $_SESSION['user_id'];

$db = new DBConnection;
$comments = new Comment($db);
$user = new User($db);

$blogID = intval($_POST['blogID']);

$addCom = $comments->addComment($user_id);

echo json_encode(array('status'=>1,'html'=>$addCom));

【问题讨论】:

  • 变量“working”似乎有问题。你确定它执行正确吗?
  • 我想我不确定它是不是,但是我完全删除了它,它仍然无法正常工作。
  • 你在哪里使用$('#blogComment').val()
  • @Amir 我不明白你在问什么?
  • 当您打开浏览器的开发者工具时,您是否看到单击提交按钮时发出的 ajax 请求。如果是这样,Web 服务器会返回 200,还是其他一些错误代码(如 500)?尝试首先找出问题所在。您总是可以通过使用提交到 /ajax/comment.process.php 的普通 html 表单创建一些简单的测试页面来消除 js/ajax

标签: php javascript jquery mysql ajax


【解决方案1】:

你在使用 json_encode() 吗?如果不是所有的回声都将作为“文本”而不​​是作为您在 jquery 中访问的 json 对象接收到

【讨论】:

  • comMarkup($blog_id) 不会像您期望的那样返回任何东西: $returnCom = $this->comMarkup($blog_id);回声 $returnCom;
  • 我应该在哪里使用json_encode?为什么这会阻止它显示?即使只是作为文本回来?
  • 无论您在哪里将 php 的结果返回给 jquery。在您的代码中,您希望所有数据都以 json 格式返回到一个变量 (msg) 中(请参阅 $.post(.."json") 的最后一个参数。进一步测试属性 msg.status。这意味着您必须从 php 返回一个带有键“status”和值 true/false 的数组。接下来,如果成功,您将访问 msg.html。这需要将您的 php 函数 comMarkup 创建的所有 html 存储在同一状态在“html”键下的数组。
  • 现在您没有在任何数组中保存任何内容,您只需回显 html,这将导致输出不是有效的 json 编码的数据字符串。最后,您应该将所有返回的数据存储在一个 php 数组 $result 中,其中 $result['status'] = true/false 和 $result['html'] = 'allyourcreated html'。通过 echo json_encode($result) 返回全部;在你的脚本结束时一次
  • 好的,所以我现在使用这个echo json_encode(array('status'=&gt;1,'html'=&gt;$returnCom())); 将状态和 html 放入一个数组中,但我仍然遇到同样的问题。
【解决方案2】:

根据您的描述,我的猜测是它与您的working 变量有关,并且它没有在您的$.post() 末尾设置为false

但是,您制定流程的方式存在一些逻辑、效率和可管理性问题。我建议查看official jQuery docs for $.post(),特别是.done().fail().always() 链式方法。

我还建议您将 PHP 变量命名为 $_POST 以外的名称,这样它就不会与 PHP 超级全局变量混淆。

最后,我建议将您的评论视为一个对象并使用PDO(这是指向 PDO:query 的链接,作为一种“沉浸式”方法,但请务必阅读所有文档)。它将为您节省大量数据库交互方面的麻烦。

【讨论】:

  • 我对这个项目太深入了,无法切换到 PDO。感谢您的提示,我将进一步研究文档。截至目前,即使删除 working 变量,我仍然无法正常工作
【解决方案3】:

我猜您应该使用encodeURIComponent($('#blogComment').val()) somwhere 将您的博客评论值传递给 PHP 文件以进行插入。

编辑 1:

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = rawurlencode($_POST['blogComment']);

如果rawurlencode() 不起作用。使用以下功能:

function encodeURIComponentNew($str) {

    $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
    return strtr(rawurlencode($str), $revert);
}

(来自What is the equivalent of JavaScript's encodeURIcomponent in PHP?的函数)

然后

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = encodeURIComponentNew($_POST['blogComment']);

【讨论】:

    【解决方案4】:

    怀疑这是相关的,但我过去在函数内使用“echo”执行 ajax 时遇到问题,然后尝试再次回显返回的值。

    尝试将所有函数中的回声更改为“返回”,而不是像这样:

    public function addComment($user_id) {
    
        $validate = new data_validation;
    
        $_POST = $validate->sanitize($_POST);
    
        $newCom = $_POST['blogComment'];
        $blog_id = intval($_POST['blogID']);
        $photoSubmit = $_POST['comPhoto'];
    
        $newComQuery = $this->mysqli->query("INSERT INTO b_comments (blog_id, user_id, date, content, photo) VALUES ('".$blog_id."', '".$user_id."', Now(), '".$newCom."', '".$photoSubmit."')");
    
        if($newComQuery === false) {
            return "Query failed";
        }else{
            $returnCom = $this->comMarkup($blog_id);
            return $returnCom;
        }           
    }
    

    【讨论】:

      【解决方案5】:

      如果用户使用' 发送评论,可能会发生错误。当您发送评论时,该字符串将破坏 mmysqli_query。它可以帮助你,也许。

      公共函数 addComment($user_id) {

      $validate = new data_validation;
      
      $_POST = $validate->sanitize($_POST);
      
      $newCom = htmlspecialchars($_POST['blogComment'], ENT_QUOTES);
      $blog_id = intval($_POST['blogID']);
      $photoSubmit = htmlspecialchars($_POST['comPhoto'], ENT_QUOTES);
      
      $newComQuery = $this->mysqli->query("INSERT INTO b_comments (blog_id, user_id, date, content, photo) VALUES ('".$blog_id."', '".$user_id."', Now(), '".$newCom."', '".$photoSubmit."')");
      
      if($newComQuery === false) {
          echo "Query failed";
      }else{
      
          $returnCom = $this->comMarkup($blog_id);
          echo $returnCom;
      
      }           
      

      }

      【讨论】:

        【解决方案6】:

        这可能是 浏览器 cookie 的原因。因此,在您的 URL 中,只需为唯一的 URL 模式添加额外的 queryString。

        示例:

           $.post('/ajax/comment.process.php?random=randamnumber');
        

        【讨论】:

          【解决方案7】:

          您似乎遇到了由working 标志引起的竞争条件。由于您只是使用该标志来显示“工作...”消息并防止在处理请求时提交,我将只使用正常的 $.ajax 调用并将“工作”逻辑放入 beforeSend 选项.这是一个例子:

          $(document).ready(function(){
              $('#commentForm').submit(function(e){
                  $.ajax({
                      type: 'POST'
                      url: '/ajax/comment.process.php',
                      dataType: 'json',
                      beforeSend: function(jqXHR, settings) {
                          $('#submitComment').val('Working..');
                          $('span.error').remove();
                      },
                      data: $(this).serialize(),
                      complete: function(jqXHR, textStatus) {
                          var msg = jqXHR.responseText;
                          $('#submitComment').val('Submit');
          
                          if(msg.status){
                              $('#commentArea').slideDown().$(msg.html).prepend('#commentArea');
                              $('#blogComment').val('');
                          }
                          else {
                              $.each(msg.errors,function(k,v){
                                  $('label[for='+k+']').append('<span class="error">'+v+'</span>');
                              });
                          }
                      };
                  });
              });
          });
          

          【讨论】:

            【解决方案8】:

            所以,如果我对问题的理解正确,您提交的评论并没有插入到数据库中,而且它大概没有向您显示数据库错误或打印出您的Query failed字符串?

            您的 PHP 脚本似乎根本没有被执行?

            如果是这种情况,我通常会说像这样的间歇性错误最可能的罪魁祸首是您的浏览器缓存。您的浏览器正在查看 URL,认为它已经知道该 URL 附带的内容,并返回该内容,甚至无需将您的信息发送到服务器。最简单的方法是在文件调用中添加一个随机查询字符串,例如:

            cachebuster = new Date();
            '/ajax/comment.process.php?cachebuster='.cachebuster.getTime();
            

            ...我说“通常”,因为您使用的是 POST,并且在“正常”情况下,浏览器不会缓存 POST 请求。但这是可能的,而且战斗起来很简单,所以试一试。如果您使用 Chrome,也可以通过按 f12 键,转到“网络”选项卡,然后运行您的表单来诊断这种情况。它应该告诉您结果是否从缓存中检索到。

            除此之外,如果您依赖于magic_quotes(或者更糟的是,您依赖于magic_quotes),您需要学习处理SQL 注入的正确方法。您永远不应该将来自浏览器的不受信任的数据直接插入数据库。转义它或使用参数化查询。如果您的查询遇到间歇性问题,这可能与您的评论内容有关,在某些情况下会引发查询,如上所述,很可能是在缩略词中包含撇号。通过背靠背提交两个表格进行诊断:trythis,然后是try'this。如果第一个成功而第二个失败,您可能已经找到了答案。正确转义您的输入将解决此问题。

            最终,上面已经给出了所有这些建议,但希望这能提供一些背景信息来帮助理解原因和原因。


            编辑:我看到,现在我仔细观察,您实际上是在使用您未在此处共享的方法逃避您的查询。假设它工作正常,那么不应该成为问题。

            尝试在脚本开头回显一个有效响应,甚至不执行任何操作。如果总是返回,那么你至少知道脚本被成功调用了。

            如果 ajax 调用返回错误,您的working 变量可能有问题。在这种情况下,它永远不会将其设置回 false。

            您的 #1 盟友是 Chrome 开发人员工具中的“网络”选项卡,或者在 Firefox Firebug 扩展程序的控制台选项卡中查看响应。


            编辑 2:

            $.post('/ajax/comment.process.php',$(this).serialize(),function(msg){
                // post stuff, REMOVING the working variable set, cuz it won't be necessary here...
            },'json').always(function() { working = false; });
            

            【讨论】:

            • 澄清一下,您应该在提交结束时将working 设置为 false,但是(根据 $.post 文档)而是这样写:( nm,请参阅第二次编辑作为回应,它的格式会更好)
            【解决方案9】:

            您的 PHP 代码中存在 SQL 注入漏洞,请确保您正确转义变量或使用准备好的查询。

            至于JS部分,一定要返回true;在 .submit() 函数的末尾。 (对你来说,它会在 $.post() 调用之后)

            此外,如果您的 php 脚本中存在错误,您的“工作”变量可以永远设置为 true,这很可能在 SQL 注入漏洞到位的情况下发生。

            说明你将它设置为true,成功回调可能不会因为PHP后端的错误500而被调用,所以它永远不会被你的回调设置为false,然后在下一页刷新之前,您永远无法提交

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-05-26
              • 1970-01-01
              • 2011-06-17
              • 1970-01-01
              • 2014-02-19
              相关资源
              最近更新 更多