jquery.form 和跨域请求

我很难尝试使用跨域制作 jquery.form要求.我在使用 Firefox 和 Chrome 时遇到问题(甚至还没有尝试过 IE).

I'm having a hard time trying to make jquery.form with a cross-domain request. I'm having issues with Firefox and Chrome (didn't even try IE yet).

说明:我的整个网站都位于 http://www.mysite.com 内.但是,我的联系表单在另一台服务器上,由 http://contact.mysite.com 引用.我认为将其放在子域上会回避有关跨域请求的问题,但显然事实并非如此.http://contact.mysite.com 在 Sinatra.

Explanation: my whole site is located inside http://www.mysite.com. However, my contact form is on another server, referenced by http://contact.mysite.com . I thought that putting it on a subdomain would sidestep the issues regarding cross-domain requests, but apparently it didn't. http://contact.mysite.com is implemented in Sinatra.

我的 javascript 设置没有什么花哨的.表单的action指向http://contact.mysite.com,方法是POST:

My javascript setup is nothing fancy. The form's action points to http://contact.mysite.com and the method is POST:

<form id="contact" action="http://contact.mysite.com/" method="post">

jquery.form 配置有 ajaxForm 调用:

jquery.form is configured with an ajaxForm call:

$(document).ready(function() {

  $('#contact').ajaxForm({
    success: function() { $('#success').fadeIn("slow"); },
    error: function() {  $('#error').fadeIn("slow"); }
  });

});

我遇到的第一个问题是 Firefox 3.5 - 显然它发送了一个 OPTIONS 请求,期望服务器提供特定的答案.我使用 this question 来配置我的 Sinatra 应用程序,使其达到预期效果(似乎更多最新版本的 sinatra 包含一个选项动词):

The first problem I encountered was with Firefox 3.5 - apparently it sends an OPTIONS request expecting an specific answer from the server. I used this question to configure my Sinatra app so it did what was expected (it seems that more recent versions of sinatra include an options verb):

require 'rubygems'
require 'sinatra'
require 'pony'

# patch sinatra so it handles options requests - see https://stackoverflow.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 请求(未发送电子邮件).

With jquery 1.4.3, I saw on firebug an OPTIONS request followed by a POST request (status 200. The email was sent). With jquery 1.3.2 or 1.5, only the OPTIONS request was shown (the email was not sent).

尽管如此,error 回调总是会在我尝试过的所有 jquery 版本中触发.我将其追溯到 $.ajax(...) 调用,所以我不确定这个问题是来自 jquery.form 还是 jquery 本身.

Nevertheless, the error callback is always fired with all versions of jquery I tried. I traced that down to the $.ajax(...) call, so I'm not sure of whether this problem comes from jquery.form or jquery itself.

我尝试注销来自错误的信息:

I tried logging out the information coming from the error:

$('#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):

Output on jquery 1.4.3 (after the OPTIONS & POST requests are sent, both with status 200):

0
(empty string)

jquery 1.5 上的输出(在 OPTIONS 返回 200 状态后;从不发送 POST)

Output on jquery 1.5 (after OPTIONS returns with a 200 status; POST is never sent)

302
error

我真的迷路了.

  • 是否有插件可以处理这个问题?
  • 我是否在某处遗漏了什么?

任何帮助将不胜感激.

推荐答案

AJAX 请求无法跨域执行(UPD: 不再正确,所有现代浏览器都支持 CORS),但您可以使用 JSONP 代替.虽然 JSONP 可以跨域工作,但它不能用于 POST 请求,您需要将表单的方法更改为 get 并使用:

AJAX requests cannot be executed cross-domain (UPD: not true anymore, all modern browsers support CORS), but you can use JSONP instead. Although JSONP works cross-domain, it can't be used for POST requests, and you'll need to change you form's method to get and use this:

$('#contact').ajaxForm({
  success: function() { $('#success').fadeIn("slow"); },
  error: function() {  $('#error').fadeIn("slow"); },
  dataType: 'jsonp'
});

上述解决方案依赖于您的服务器以有效的 jsonp 响应进行响应,否则将不会执行 success 处理程序.例如:response.write(request.callback + '(' + result.to_json + ')')

The solution above relies on your server responding with a valid jsonp response, otherwise success handler won't be executed. e.g: response.write(request.callback + '(' + result.to_json + ')')

最新版本的 jQuery 可以在没有 ajaxForm 插件的情况下序列化表单.如果你不需要文件上传,你可以使用这个:

Latest versions of jQuery can serialize forms without the ajaxForm plugin. If you don't need file uploads you can use this:

$('form').submit(function() {
  var url = $(this).attr('action')
  var params = $(this).serialize()
  $.getJSON(url + '?' + params + "&callback=?", function(data) {
    // success
  })
  return false
});

相关文章