jquery.form 和跨域请求
Posted
技术标签:
【中文标题】jquery.form 和跨域请求【英文标题】:jquery.form and cross-domain requests 【发布时间】:2011-07-01 06:34:54 【问题描述】:我很难通过跨域请求创建jquery.form。我在使用 Firefox 和 Chrome 时遇到问题(甚至还没有尝试过 IE)。
解释:我的整个网站都位于http://www.mysite.com 内。但是,我的联系表格在另一台服务器上,由 http://contact.mysite.com 引用。我认为将它放在子域上会回避有关跨域请求的问题,但显然事实并非如此。 http://contact.mysite.com 在 Sinatra 中实现。
我的 javascript 设置没有什么花哨的。表单的action指向http://contact.mysite.com,方法是POST:
<form id="contact" action="http://contact.mysite.com/" method="post">
jquery.form 配置了ajaxForm 调用:
$(document).ready(function()
$('#contact').ajaxForm(
success: function() $('#success').fadeIn("slow"); ,
error: function() $('#error').fadeIn("slow");
);
);
我遇到的第一个问题是 Firefox 3.5 - 显然它发送了一个 OPTIONS 请求,期望服务器提供特定的答案。我使用this question 来配置我的 Sinatra 应用程序,使其达到预期效果(似乎更新版本的 sinatra 包含一个选项动词):
require 'rubygems'
require 'sinatra'
require 'pony'
# patch sinatra so it handles options requests - see https://***.com/questions/4351904/sinatra-options-http-verb
configure do
class << Sinatra::Base
def options(path, opts=, &block)
route 'OPTIONS', path, opts, &block
end
end
Sinatra::Delegator.delegate :options
end
# respond to options requests so that firefox can do cross-domain ajax requests
options '/' do
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'POST'
response['Access-Control-Max-Age'] = '2592000'
end
post '/' do
# use Pony to send an email
Pony.mail(...)
end
使用 jquery 1.4.3,我在 firebug 上看到一个 OPTIONS 请求,然后是一个 POST 请求(状态 200。电子邮件已发送)。使用 jquery 1.3.2 或 1.5,仅显示 OPTIONS 请求(未发送电子邮件)。
尽管如此,error
回调总是会在我尝试过的所有版本的 jquery 中触发。我将其追溯到$.ajax(...)
调用,所以我不确定这个问题是来自 jquery.form 还是 jquery 本身。
我尝试注销来自错误的信息:
$('#contact').ajaxForm(
success: function() $('#success').fadeIn("slow"); ,
error: function(jqXHR, textStatus, errorThrown)
console.log(jqXHR.status);
console.log(jqXHR.statusText);
);
jquery 1.4.3 上的输出(在发送 OPTIONS 和 POST 请求后,状态均为 200):
0
(empty string)
jquery 1.5 上的输出(在 OPTIONS 返回 200 状态后;从不发送 POST)
302
error
我真的迷路了。
是否有插件可以处理这个问题? 我是否在某处遗漏了什么?任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:AJAX 请求无法跨域执行(UPD: 不再适用,所有现代浏览器都支持CORS),但您可以改用 JSONP。虽然 JSONP 可以跨域工作,但它不能用于 POST 请求,您需要将表单的方法更改为 get
并使用:
$('#contact').ajaxForm(
success: function() $('#success').fadeIn("slow"); ,
error: function() $('#error').fadeIn("slow"); ,
dataType: 'jsonp'
);
上述解决方案依赖于您的服务器以有效的 jsonp 响应进行响应,否则将不会执行 success
处理程序。例如:response.write(request.callback + '(' + result.to_json + ')')
最新版本的 jQuery 可以在没有 ajaxForm
插件的情况下序列化表单。如果你不需要文件上传,你可以使用这个:
$('form').submit(function()
var url = $(this).attr('action')
var params = $(this).serialize()
$.getJSON(url + '?' + params + "&callback=?", function(data)
// success
)
return false
);
【讨论】:
感谢您的回答。我仍在努力解决这个 jsonp 业务。一个问题认为: $.ajax 似乎能够执行 jsonp 请求(或者它在文档中说,我仍然不确定它是如何工作的)。既然jquery.form内部使用了$.ajax,那它不也可以使用jsonp吗? 你知道吗,我查看了 $.ajaxForm 源代码,我认为它可以做到。我现在无法尝试该示例,但我希望它有效。 查看我的新更新,我测试过,如果您从服务器返回有效的 json 响应,它可以正常工作。 JSONP 通过将 您的解决方案效果很好。我最终放弃了 jquery.form 并直接使用 getJSON(你需要用+ '?' +
替换+ '/' +
;我已经在你的答案中改变了)【参考方案2】:
我认为 JSONP 是唯一可以跨域的 AJAX 请求。
http://en.wikipedia.org/wiki/JSON#JSONP
【讨论】:
感谢您的回答。这不是一个完整的答案,但至少给了我一个提示。我会调查 JSONP。【参考方案3】:您还可以使用本地代理 URL 来执行请求,因为服务器通常可以使用 HttpRequest 或 cURL 等方式进行跨域调用。所以基本上你使用 ajax 对本地域上的 URL 进行调用,然后将请求转发到跨域 URL,并将来自 HttpRequest/cURL 的响应在本地域的响应中传递回浏览器。
【讨论】:
这不是我当前设置的选项。服务于主应用程序的服务器不受我的控制。无论如何感谢您的回答。【参考方案4】:经过大量的战斗,在 Alexey 的帮助下,我终于战胜了它。这是我现在的解决方案:
Javascript(直接使用jquery,不用jquery.form):
$(document).ready(function()
$('#contact').submit(function()
$('#success').fadeOut("slow");
$('#bademail').fadeOut("slow");
var url = $(this).attr('action')
var params = $(this).serialize()
$.getJSON(url + '?' + params + "&callback=?", function(data)
if(data == true) // success
$('#success').fadeIn("slow");
$('#contact')[0].reset();
else // error
$('#bademail').fadeIn("slow");
);
return false;
);
);
对于 Sinatra,我使用了 sinatra-jsonp gem。我让 get 操作返回“true”或“false”,具体取决于是否可以发送电子邮件(例如,对于无效的电子邮件地址)。
require 'rubygems'
require 'sinatra'
require 'sinatra/jsonp'
require 'pony'
get '/' do
# check for blanks, etc
return jsonp false unless fields_valid(params)
Pony.mail(
...
)
return jsonp true
end
【讨论】:
以上是关于jquery.form 和跨域请求的主要内容,如果未能解决你的问题,请参考以下文章