【问题标题】:Form Submit Not Caught By Javascript表单提交未被 Javascript 捕获
【发布时间】:2014-12-20 22:33:33
【问题描述】:

我正在尝试捕获 HTML 表单的提交(由 Django 呈现)并使用 ajax 处理它,而不是重定向到新页面,但是似乎从未调用过 javascript 函数。这是我渲染的 html:

<form action="" id="id_create_review" method="post">

<div id="div_id_session" class="form-group">
    <label for="id_session" class="control-label ">
        Session
    </label>
    <div class="controls ">
        <select class="select form-control" id="id_session" name="session">
            <option value="" selected="selected">---------</option>
            <option value="1">Rocky Balboa Boxing Club</option>
            <option value="2">All about the Box...ing</option>
        </select>
    </div>
</div>

<div id="div_id_rating" class="form-group">
    <label for="id_rating" class="control-label  requiredField">
        Rating<span class="asteriskField">*</span>
    </label>
    <div class="controls ">
        <select class="select form-control" id="id_rating" name="rating">
            <option value="0.0">0.0</option>
            <option value="0.5">0.5</option>
            <option value="1.0">1.0</option>
            <option value="1.5">1.5</option>
            <option value="2.0">2.0</option>
            <option value="2.5" selected="selected">2.5</option>
            <option value="3.0">3.0</option>
            <option value="3.5">3.5</option>
            <option value="4.0">4.0</option>
            <option value="4.5">4.5</option>
            <option value="5.0">5.0</option>
       </select>
   </div>
</div>

<div id="div_id_comments" class="form-group">
    <label for="id_comments" class="control-label  requiredField">
                    Comments<span class="asteriskField">*</span>
    </label>
    <div class="controls ">
        <textarea class="textarea form-control" cols="40" id="id_comments" name="comments" rows="10"></textarea>
    </div>
</div>

<div class="form-group">
    <div id="div_id_would_recommend" class="checkbox">
        <label for="id_would_recommend" class="">
            <input checked="checked" class="checkboxinput checkbox" id="id_would_recommend" name="would_recommend" type="checkbox">
            Would recommend
        </label>
    </div>
</div>

<div class="form-group">
    <div id="div_id_anonymous" class="checkbox">
        <label for="id_anonymous" class="">
            <input checked="checked" class="checkboxinput checkbox" id="id_anonymous" name="anonymous" type="checkbox">
             Anonymous
        </label>
    </div>
</div>

<div class="form-actions">
    <input type="submit" name="submit" value="Send Review" class="btn btn-primary" id="submit-id-submit"> 
</div>

</form>

这是我在底部的 javascript:

<script type="text/javascript">
$(document).ready(function() {
    $('#id_create_review').submit(function() { // catch the form's submit event
        console.log('Yeah, no?');
        $.ajax({ // create an AJAX call...
            data: $(this).serialize(), // get the form data
            type: $(this).attr('method'), // GET or POST
            url: $(this).attr('action'), // the file to call
            success: function(response) { // on success..
                $('#success_div').html(response); // update the DIV
            },
            error: function(e, x, r) { // on error..
                $('#error_div').html(e); // update the DIV
            }
        });
        return false;
    });
});
</script>

编辑

因此,由于 CSRF 保护失败,我收到了 403 错误。如果请求是使用 ajax 发出的,我有一些 javascript 应该可以防止这个 403 错误,我也没有看到“是的,不是吗?”登录到控制台,所以我认为必须通过标准 Http 提交表单。

也许我的问题是表单正在由 javascript 处理,但是 ajax 请求仍然导致 403 错误?但是为什么在我的 JS 中看不到控制台日志呢?

如果问题是我的 ajax 请求导致了 403 错误,为什么我的保护代码无法发送 csrf 令牌?我不能说我 100% 理解所有这些......我主要是从使用 django 处理 ajax 请求的在线教程中获取的。代码如下:

<script>
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

/*
The functions below will create a header with csrftoken
*/

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
    // test that a given url is a same-origin URL
    // url could be relative or scheme relative or absolute
    var host = document.location.host; // host + port
    var protocol = document.location.protocol;
    var sr_origin = '//' + host;
    var origin = protocol + sr_origin;
    // Allow absolute or scheme relative URLs to same origin
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
        (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
        // or any other URL that isn't scheme relative or absolute i.e relative.
        !(/^(\/\/|http:|https:).*/.test(url));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
            // Send the token to same-origin, relative URLs only.
            // Send the token only if the method warrants CSRF protection
            // Using the CSRFToken value acquired earlier
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});
</script>

【问题讨论】:

  • 你试过调试你的脚本吗?代码看起来很合理...很可能与您显示的代码无关(例如重复的 ID 或脚本中的语法错误)...
  • 我创建了这个 FIDDLE DEMO 。代码似乎运行良好,检查控制台。
  • 检查你的 jQuery 库脚本标签
  • 如果你没有得到初始的 console.log("yeah, no"),那么 jQuery 就没有被加载。您可以在 $(document).ready() 之后立即执行 console.log() 吗?我还会检查您的 Web 开发人员工具,以查看您的所有链接脚本或外部文件是否正在加载。一些防火墙可以阻止某些连接
  • 是的,正在加载 jQuery。我在页面上还有其他 jQuery 效果也可以正常工作。

标签: javascript jquery html ajax django


【解决方案1】:

试一试:

$(document).ready(function() {
    $('#id_create_review').submit(function() { // catch the form's submit event
        console.log('Yeah, no?');
        console.log($(this).serialize());
        var postdata = $(this).serializeArray();
        var url = $(this).attr('action');
        $.post(url , postdata, function(){
            //
        })
        return false;
    });
});

【讨论】:

    【解决方案2】:

    尝试创建一个隐藏的输入字段并将 csrftoken 放入其值中...类似这样:

    <input type="hidden" value="{% csrf_token %}">
    

    如果您的错误是由 csrf 保护引起的,那就足够了。

    【讨论】:

      【解决方案3】:

      感谢所有提供解决方案的人。我最终通过将我的脚本移动到表单所在的包含的 django 模板中解决了这个问题。

      我有一个主要的 django 模板,其中包含一个使用 {% include %} 标签的较小的 django 模板,并且表单在这个包含的模板中。最初我有我的 javascript 来捕捉主模板底部的表单提交。我认为这会很好,因为无论如何模板都会被渲染到一个大的 HTML 文件中,所以哪个代码在哪个模板中并没有真正的区别,但显然它确实......只要我移动了我的脚本在我的小型包含模板中,问题就消失了。不知道为什么会这样。

      【讨论】:

      • 脚本可能根本不在包含文件的正确部分。它包含在哪个块中?
      • 另外,如果您将 Javascript 放入 .js 文件中,您可以使用 {% static "path/to/file/in/static/files" %} 包含它,这样您就可以保留内容在它自己的文件中。
      • 实际上包含表单的视图是从包含的模板发送的 ajax 请求呈现的视图。但是,渲染后仍然是一个 HTML 文档,对吧?我的脚本就在 body 标记结束之前,在我称之为 {% block extra_scripts %} 的块中
      • From: docs.djangoproject.com/en/1.7/ref/templates/builtins include 标签应该被认为是“渲染这个子模板并包含 HTML”的实现,而不是“解析这个子模板并包含它的内容,就好像它是家长”。这意味着包含的模板之间没有共享状态——每个包含都是一个完全独立的渲染过程。编辑:猜猜这解决了一切。
      【解决方案4】:

      Django 文档on include template tags

      include 标签应该被认为是“渲染这个子模板并包含 HTML”的实现,而不是“解析这个子模板并包含它的内容,就好像它是父模板的一部分一样”。这意味着包含的模板之间没有共享状态——每个包含都是一个完全独立的渲染过程。

      这就是您必须移动脚本的原因。我以前没有意识到这一点。

      【讨论】:

      • 不应该只影响模板在服务器上的呈现方式吗?一旦它到达我的浏览器,它不会被视为相同的 HTML,因此所有 javascript 在任何部分的行为都应该相同,就好像它们都在服务器上的同一个模板中一样?
      • 真的。也许我只是很快假设,因为我似乎记得发生在我身上的类似事情。它似乎神奇地解释了它。顺便说一句,原始模板是如何布局的?包含表格的那个?可以发一下吗?
      猜你喜欢
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 2013-05-22
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      相关资源
      最近更新 更多