XmlHttpRequest CORS POST 未发送 cookie

Posted

技术标签:

【中文标题】XmlHttpRequest CORS POST 未发送 cookie【英文标题】:XmlHttpRequest CORS POST sent without cookies 【发布时间】:2013-11-15 05:27:19 【问题描述】:

我有一个 Rails 服务为我的 AngularJS 前端应用程序返回数据。该服务被配置为通过返回适当的标头来允许 CORS 请求。

当我发出 GET 请求以接收数据时,发送了 CORS 标头,以及我之前在登录时收到的会话 cookie,您可以自己查看:

Request URL:http://10.211.194.121:3000/valoradores
Request Method:GET
Status Code:200 OK

Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Cookie:_gestisol_session=BAh7B0kiDHVzZXJfaWQGOgZFRmkASSIPc2Vzc2lvbl9pZAY7AEZJIiVmYTg3YTIxMjcxZWMxNjZiMjBmYWZiODM1ODQzMjZkYQY7AFQ%3D--df348feea08d39cbc9c817e49770e17e8f10b375
Host:10.211.194.121:3000
Origin:http://10.211.194.121:8999
Pragma:no-cache
Referer:http://10.211.194.121:8999/
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/30.0.1599.101 Safari/537.36
X-Requested-With:XMLHttpRequest

Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin
Access-Control-Allow-Methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:http://10.211.194.121:8999
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Connection:Keep-Alive
Content-Length:5389
Content-Type:application/json; charset=utf-8
Date:Mon, 04 Nov 2013 14:30:51 GMT
Etag:"2470d69bf6db243fbb337a5fb3543bb8"
Server:WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30)
X-Request-Id:15027b3d323ad0adef7e06103e5aa3a7
X-Runtime:0.017379
X-Ua-Compatible:IE=Edge

一切正常,我找回了我的数据。

但是当我发出 POST 请求时,CORS 标头和会话 cookie 都不会随请求一起发送,并且 POST 在服务器上被取消,因为它没有会话标识符。这些是请求的标头:

Request URL:http://10.211.194.121:3000/valoraciones

Request Headers
Accept:application/json, text/plain, */*
Cache-Control:no-cache
Content-Type:application/json;charset=UTF-8
Origin:http://10.211.194.121:8999
Pragma:no-cache
Referer:http://10.211.194.121:8999/
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
X-Requested-With:XMLHttpRequest

Request Payload
valoracione:revisiones_id:1, valoradores_id:1
valoracione: revisiones_id:1, valoradores_id:1

并且服务以 403 响应,因为请求不包含会话 cookie。

我不知道为什么 POST 请求失败,因为 $resource 的配置就像另一个一样,并且我已经为 $httpProvider 定义了默认值来发送凭据(并且它在 GET 请求成功时正常工作):

  .config(['$httpProvider', function($httpProvider) 
     $httpProvider.defaults.withCredentials = true;
    ])

这是我在实例上调用 $save() 时失败的资源:

'use strict';

angular.module('gestisolApp')
  .service('ValoracionesService', ['$resource', 'API_BASE_URL', function ValoracionesService($resource, API_BASE_URL) 
    this.valoraciones = $resource(API_BASE_URL + '/valoraciones');
  ]);

这是通过 query() 调用成功的服务:

'use strict';

angular.module('gestisolApp')
  .service('ValoradoresService', ['$resource', 'API_BASE_URL', function ValoradoresService($resource, API_BASE_URL) 
    this.valoradores = $resource(API_BASE_URL + '/valoradores');
  ]);

它们很像。

有人知道为什么在没有会话 cookie 的情况下发送 POST 吗?

编辑

只是为了补全信息,preflight是通过下面的方法处理的,因为POST失败前的请求是OPTIONS成功,响应码为200,所以处理OK:

def cors_preflight_check
        headers['Access-Control-Allow-Origin'] = 'http://10.211.194.121:8999'
        headers['Access-Control-Allow-Methods'] = 'GET,POST,OPTIONS'
        headers['Access-Control-Allow-Headers'] = 'X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin'
        headers['Access-Control-Allow-Credentials'] = 'true'
        headers['Access-Control-Max-Age'] = '1728000'
        render :nothing => true, :status => 200, :content_type => 'text/html'
end

这是失败的 POST 之前的 CORS OPTIONS 请求/响应交换:

Request URL:http://10.211.194.121:3000/valoraciones
Request Method:OPTIONS
Status Code:200 OK

Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, x-requested-with, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:10.211.194.121:3000
Origin:http://10.211.194.121:8999
Referer:http://10.211.194.121:8999/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36

Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin
Access-Control-Allow-Methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:http://10.211.194.121:8999
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Connection:Keep-Alive
Content-Length:1
Content-Type:text/html; charset=utf-8
Date:Mon, 04 Nov 2013 15:57:38 GMT
Etag:"7215ee9c7d9dc229d2921a40e899ec5f"
Server:WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30)
X-Request-Id:6aa5bb4359d54ab5bfd169e530720fa9
X-Runtime:0.003851
X-Ua-Compatible:IE=Edge

编辑 2:我已更改标题以清楚地反映我的问题

【问题讨论】:

这里有点黑暗,但您是否正在处理飞行前请求(在服务器上)?这是使用OPTIONS 动词发送的。 编辑:嗯,不是 100% 确定飞行前适用于 POST,但可能取决于标题。 应用预检,或者至少预检已正确完成并返回响应代码 200。问题是以下 POST 没有任何“Allow-*”标头或 cookie。 【参考方案1】:

我遇到了类似的问题,并在 angular $http CORS 请求解决问题之前添加了以下内容。 $http.defaults.withCredentials = true;

更多详情请参考https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Requests_with_credentials。

【讨论】:

这是正确的,同时确保后端允许凭据并指定特定允许的来源(即不是'*') 这为我解决了!确保您还从服务器返回“Access-Control-Allow-Credentials”标头,并将值设置为 true 这行得通。而设置配置对象“configObj = withCredentials: true ;”作为 $http 的参数没有。谢谢!【参考方案2】:

当涉及到 CORS 时,你的浏览器会在 POST 请求之前发送一个 OPTIONS 请求。

我不知道 Rails 的具体细节,但我猜你必须配置 Rails 才能使用适当的 CORS 标头实际响应 OPTIONS 请求。

以下代码仅用于比较 - 它显示了您将如何解决 Java 中的问题:

public void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
    resp.setHeader("Access-Control-Allow-Origin", "http://10.211.194.121:8999");
    resp.setHeader("Access-Control-Allow-Credentials", "true");
    resp.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET");
    resp.setHeader("Access-Control-Allow-Headers", "X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin");
    resp.setHeader("Access-Control-Max-Age", "600");
    resp.setHeader("Access-Control-Expose-Headers","Access-Control-Allow-Origin");
    super.doOptions(req, resp);

但它可能会让你走上正确的轨道,如何在 Rails 中配置它。

【讨论】:

我已经在我的 Rails 控制器中实现了所有的 CORS 东西,这部分工作正常。唯一不同的部分是我的 CORS 响应中没有 Access-Control-Expose-Headers 标头。 所有支持 CORS 的浏览器都会在发出您尝试发出的实际跨域请求之前发出 OPTIONS 请求。这是为了检查服务器上的功能并避免发送可能不允许的有效负载。 @Marty 是正确的,您需要在服务器上启用此功能。更多内容:html5rocks.com/en/tutorials/cors/… 是的,正如我在上面对问题所评论的那样,预检已成功完成并返回响应代码 200,但以下 POST 请求没有“Allow-*”标头,也没有 cookie。 我已包含其他信息:CORS 处理方法以及 POST 之前的 OPTIONS 请求和响应交换 可能值得检查@JStark 在***.com/questions/12111936/… 中的回复【参考方案3】:

好吧,我终于弄清楚发生了什么。

根据this question 上发布的答案,我从 cookie 中删除了 HttpOnly 参数,并让它在 Firefox 上运行。稍后对于 Chrome,只需应用答案中的其余建议即可使其正常工作,例如为 cookie 设置域。

【讨论】:

以上是关于XmlHttpRequest CORS POST 未发送 cookie的主要内容,如果未能解决你的问题,请参考以下文章

CORS XMLHttpRequest 使用 POST 将多部分表单数据发送到 Softlayer 对象存储失败

从源访问 XMLHttpRequest 已被 CORS 策略阻止

用于 XmlHttpRequest 的带有 WebAPI 的 CORS

Cors 不适用于 XMLhttprequest 节点/快递

CORS XMLHttpRequest 不允许我设置标头

CORS 跨域 node |XMLHttpRequest 跨域提交数据 node