实际示例:
- 没有AJAX
- 使用AJAX(单击"给我们发电子邮件"链接)
当我查看源页面时,一切都很好,但当我通过AJAX请求加载时,在reCAPTCHA应该的地方,我看到。。。
<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>
显然,除非我的用户禁用了JS,否则这不会有任何作用。在此过程中,不会引发任何错误。
查看代码上的非AJAX请求的速度,我看到。。。
<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX"></script>
<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>
请注意脚本顶部的附加行,该行针对启用JS的用户。
所以我想问题有两个方面。WTF正在发生,我该如何解决?
我发现有人含糊地提到了这个问题,但没有像样的答案。我发现有人提到使用document.write
的reCAPTCHA API,但我不知道这是否有效。如果我忽略了一些显而易见的东西,请随时指出。
根据请求,AJAX调用是…
$(document).ready(function() {
$.get('/inc/email.php',
function(data){
console.log('Get success!');
$('#email-form').html(data);
console.log('Get added to #email-form!');
$('#email-form form').submit( function(){
$.ajax({
type: "POST",
url: "/inc/email.php",
data: $('#email-form form').serialize(),
success: function() {
console.log('Submit success!');
$('#email-form').html(data);
}
});
return false;
});
}
);
});
到目前为止我所尝试的:
- 重写代码以获取远程JS文件,将document.write()子句替换为对我设置为特定ID的元素的追加,然后在页面上内联运行修改后的代码
- 显示没有插件的reCAPTCHA而不是PHP reCAPTCHA库
说明:
在使用AJAX时,这种情况之所以会中断,是因为jQuery在将HTML附加到DOM之前,会从HTML中剥离出任何script
标记,并在全局上下文中对其进行评估。它不会将它与HTML的其余部分一起插入到DOM中。
在您的代码中:
代码中的罪魁祸首是这一行:
$('#email-form').html(data);
您正在获取从服务器接收的原始HTML字符串,并将其附加到DOM中。但是,jQuery首先从data
变量中删除script
标记,并在全局上下文中对其进行求值。
由于recaptcha.js
脚本使用document.write
将其内容添加到DOM,因此它会中断;document.write
必须精确地运行在您希望它输出HTML的地方。
解决方案:
有两种可能的解决方案。
解决方案1:
不完全依赖jQuery,您可以使用普通JavaScript自己插入script
标记,这将导致document.write
在您想要的地方运行——就在DOM:中
success: function() {
var form = $('#email-form')[0],
script = $('<script src="http://www.google.com/recaptcha/api/challenge?k=6LfwkccSAAAAALr_z6vDBqkySowo5KIiR0mVM1BX" />')[0];
form.appendChild(script);
}
注意这些行末尾的[0]
。它们用于访问底层的原生DOM对象,这样我们就可以使用DOM的原生appendChild
。
解决方案2:
与其通过AJAX加载数据,不如考虑将其放在自己的页面中,然后在页面中插入一个iframe
:
success: function() {
$('#email-form').html('<iframe src="path/to/reCAPTCHA/page.html" />');
}
您可以echo/inc/email.php文件中的所有内容!你必须事先包括所有必要的文件。