CORS 问题:实际出现错误“不存在‘Access-Control-Allow-Origin’标头”

Posted

技术标签:

【中文标题】CORS 问题:实际出现错误“不存在‘Access-Control-Allow-Origin’标头”【英文标题】:CORS issue: Getting error "No 'Access-Control-Allow-Origin' header is present" when it actually is 【发布时间】:2014-01-10 13:06:45 【问题描述】:

我怀疑为我的应用程序提供服务的后端是否重要,但如果你关心的话,我将 rack-cors 与 Rails 4.0 应用程序一起使用。

使用 jQuery,我向我的应用发送 PATCH 请求,如下所示:

$.ajax(
  url: "http://example.com/whatever",
  type: "PATCH",
  data:  something: "something else" 
)

当我从 Chrome 触发此调用时,我看到一个成功的 OPTIONS 请求发出,它从我的服务器返回这些标头:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:accept, content-type
Access-Control-Allow-Methods:GET, PUT, PATCH, OPTIONS
Access-Control-Allow-Origin: http://sending-app.localhost:3000
Access-Control-Expose-Headers:
Access-Control-Max-Age:15

然后我看到一个PATCH 请求出去了,它抛出了这个错误:

XMLHttpRequest 无法加载 http://example.com/whatever。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问 Origin 'http://sending-app.localhost:3000'。

我尝试从PATCH 切换到PUT,结果相同。

这对我来说没有任何意义。怎么回事?

更新:我的 config/application.rb

我以为标题说明了整个故事,但由于人们感到困惑,这是我的 config/application.rb 文件,这是 Rails 的 rack-cors 插件的配置方式:

config.middleware.use Rack::Cors do
  allow do
    origins '*'
    resource '*',
      :headers => :any,
      :methods => [:get, :put, :patch, :options],
      :max_age => 15
  end
end

【问题讨论】:

你的application.rb是什么样的? @RichPeck 我已经添加了我的application.rb,这是值得的。 【参考方案1】:

在动作中排除 Rails CSRF 检查;)

也就是说,Rails 通过更新/创建请求检查真实性令牌。在您的 Rails 应用程序中,此令牌会添加到您的所有表单中。但是对于 javascript 请求,包括它是棘手的。

您可以通过将其添加到您的控制器来跳过检查它的操作:

skip_before_filter :verify_authenticity_token, :only => [:update]

顺便说一句,您的问题与 CORS 无关,您在浏览器中收到了错误消息。 Rails 日志讲述了真实的故事。

【讨论】:

-1 当您可以简单地将 csrf 令牌附加到所有 ajax 发送时,为什么要跳过 csrf(在下面发布答案) 为什么是-1?这是解决问题的方法。该请求来自一个不知道 CSRF 令牌的单独应用程序。 因为解决办法是禁用csrf。这听起来像是一个安全漏洞。但是,如果它是一个经过身份验证的请求,那听起来不错。 很公平。您不能期望外部服务的用户提供 CSRF 令牌。这是从一个应用程序触发的,而端点位于另一个应用程序中,因此它跨域。如果这一切都在同一个应用程序中,我会同意你的看法。 快进到 2018 年,现在 skip_before_action 使用 Rails 5(技术上也使用 Rails 4)。【参考方案2】:

您可能希望将此添加到您的 config/application.rb 文件中:

#config/application.rb
config.middleware.use Rack::Cors do
  allow do
    origins '*'
    resource '/*', :headers => :any, :methods => :patch
  end
end

resource 部分是您定义端点可以接受的方法/请求的地方!

希望对你有帮助

【讨论】:

对不起,我认为只显示返回的标题就表明我已经这样做了。这是 HTTP 标头的问题,而不是 Rails 配置的问题,所以我想让这个问题通常可以访问,而不是用不必要的 Rails 东西弄乱它。我现在添加了我在 config/application.rb 中的 rack-cors 设置。 感谢 bud - 您在什么环境下看到此错误?生产和/或开发?你能描述一下设置吗? 我在生产中看到了这个,它在 Heroku 上。它非常接近香草 Rails 4; rack-cors 是我添加的唯一 Rack 中间件。 奇怪 - 我们已经使用 Heroku 生产了一段时间,并且让这个功能正常工作。您是否设置了路由和控制器操作来处理请求? 我当然愿意!我有这个 PATCH 端点的规格,它可以做我想做的一切。【参考方案3】:

这是一些奇怪的东西。

A) 作为试用版,您应该尝试输入 * 作为您允许的来源。

B) 这是空格问题吗?冒号后面的某些选项中没有空格。

C) 这看起来像一个“预检请求”(https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS)。预检请求是不使用您应该使用的“application/x-www-form-urlencoded”的请求。 http://api.jquery.com/jquery.ajax/ 声明默认内容类型是 x-www-form-urlencoded,并且您没有覆盖内容类型。这意味着不需要有 2 个请求。

D) 如上所述,CSRF 可能是问题所在。我不是铁路人。如果这是您可能想要做的问题是将您的 CSRF 令牌附加到所有 ajax 发送,如下所示:

$.ajaxSetup( 
    beforeSend:function(xhr, settings)
        xhr.setRequestHeader('X-CSRF-Token', '<%= csrf_token_value %>');
     
);

还有其他几种方法可以做到这一点。这取决于您的框架/库需要什么。

【讨论】:

如果请求不是来自完全不同的应用程序,那就没问题了。我们在同一个团队中工作,CSRF 是这种情况下的问题。【参考方案4】:

这是我从旧的 SO 帖子中发现的解决 csrf 问题的方法:

# In application_controller.rb
protect_from_forgery

after_filter :set_csrf_cookie

def set_csrf_cookie
  cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end

protected

# In Rails 4.2 and above
def verified_request?
  super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
end

【讨论】:

以上是关于CORS 问题:实际出现错误“不存在‘Access-Control-Allow-Origin’标头”的主要内容,如果未能解决你的问题,请参考以下文章

调用我的 API 时在我的反应应用程序上出现此 CORS 错误 - 请求的资源上不存在“Access-Control-Allow-Origin”标头

CORS 错误:不存在“Access-Control-Allow-Origin”标头

CORS 已启用,但仍出现 CORS 错误

Javascript CORS - 不存在“Access-Control-Allow-Origin”标头

Angular JS Cors 请求的资源上不存在“Access-Control-Allow-Origin”标头错误

问题Cors:请求的资源上不存在“Access-Control-Allow-Origin”标头[关闭]