【问题标题】:jquery.form and cross-domain requestsjquery.form 和跨域请求
【发布时间】:2011-07-01 06:34:54
【问题描述】:

我很难通过跨域请求创建jquery.form。我在使用 Firefox 和 Chrome 时遇到问题(甚至还没有尝试过 IE)。

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

我的 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://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 请求(未发送电子邮件)。

尽管如此,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

我真的迷路了。

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

任何帮助将不胜感激。

【问题讨论】:

    标签: javascript jquery ajax jquery-plugins cross-domain


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2010-11-13
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      • 1970-01-01
      • 2017-06-15
      相关资源
      最近更新 更多