jQuery getJSON 不发送 cookie

Posted

技术标签:

【中文标题】jQuery getJSON 不发送 cookie【英文标题】:jQuery getJSON doesnt send cookies 【发布时间】:2011-10-19 07:52:03 【问题描述】:

我在 domain1 表单 domain2 上包含 JS

<script type="text/javascript" src="http://www.domain2.com/script.js"></script>

该脚本不会加载,并且在按钮上单击对 domain2 的 JSONP 请求

$.getJSON( 'http://www.domain2.com/process?callback=?',
    function(data)
        if ( data ) processData( data );
    
);

然后在 domain1 上显示数据。

所以这是我的问题: getJSON 请求不会向 domain2 发送 cookie。 最奇怪的是,它确实发送了半天的饼干,而另一半则没有。 :-)

这是请求不起作用时的样子:

Request details
GET /ajax/embed-user-library?detail=98&callback=jsonp1312398534998 HTTP/1.1 
User-Agent: Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50
Host: www.floowie.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,sk-SK;q=0.9,sk;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://www.sokker.cz/en/test2
Connection: Keep-Alive

Response details
HTTP/1.1 200 OK 
Date: Wed, 03 Aug 2011 19:06:51 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: php/5.3.5-0.dotdeb.1
Set-Cookie: SESSID=64292b70dc28d7c6c9f13f70070353d8; path=/; domain=.floowie.com
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 34
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/json

当它起作用时(脚本中没有任何改变):

Request details
GET /ajax/embed-user-library?detail=99&test=1&callback=jsonp1312398534999 HTTP/1.1 
User-Agent: Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50
Host: test1.floowie.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,sk-SK;q=0.9,sk;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://www.sokker.cz/en/test2
Cookie: __utma=254918925.1489796832.1301725317.1312260335.1312298033.44; __utmz=254918925.1312298033.44.11.utmcsr=sokker.cz|utmccn=(referral)|utmcmd=referral|utmcct=/en/test2; lang=en; FLWSESSID=ddd1bc696f83f5a70b5f0f3ae30b4691; __utma=121955676.1030804516.1282595153.1312390656.1312397285.194; __utmb=121955676.8.10.1312397285; __utmc=121955676; __utmz=121955676.1312397285.194.21.utmcsr=floowie.crmserver.cz|utmccn=(referral)|utmcmd=referral|utmcct=/index.php
Connection: Keep-Alive

Response details
HTTP/1.1 200 OK 
Date: Wed, 03 Aug 2011 19:07:45 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.5-0.dotdeb.1
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 20
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/json

有人看到这样的行为吗? 能解决吗?

谢谢

【问题讨论】:

【参考方案1】:

如果你想在不同的域/子域上使用 AJAX 请求,你必须实现跨域请求。

参考资料:

http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/ https://developer.mozilla.org/en/http_access_control

例子:

http://arunranga.com/examples/access-control/

您的服务器需要发送此标头:

Access-Control-Allow-Origin:test1.floowie.com Access-Control-Allow-Credentials: true // 允许 cookie/会话凭据 访问控制允许方法:GET、POST、PUT、DELETE、OPTIONS

您可以全局返回 Access-Control-Allow-Origin 或设置具体取决于您的输入 Origin ($_SERVER['HTTP_ORIGIN']) 请求标头。同时申请Access-Control-Allow-Methods

必须实施OPTIONS请愿书。在第一次 AJAX 调用之前,现代浏览器使用 OPTIONS 方法调用该 URL 以检索上述标头。

好的,这是第一部分,第二部分是 jQuery。仔细阅读本页:http://api.jquery.com/jQuery.ajax/

您需要为每个 AJAX 调用添加一些选项,您可以全局执行:

$(document).ajaxSend(function (event, xhr, settings) 
    settings.xhrFields = 
        withCredentials: true
    ;
);

或具体:

$.ajax(
    url: a_cross_domain_url,
    xhrFields: 
        withCredentials: true
    
);

这个问题让我损失了很多小时……希望对你有所帮助。

请注意,如果需要,您无需将 cookie 域设置为“.floowie.com”。

【讨论】:

关于这个问题这是我在互联网上找到的最好的解决方案/解释!还要记住将 Access-Control-Allow-Origin 设置为特定域而不是“*”,否则您将收到此错误:“当凭据标志为 true 时,无法在 Access-Control-Allow-Origin 中使用通配符。” 谢谢!那么,不能将 CORS 与 "Access-Control-Allow-Origin: *" 一起使用吗?使用本地 HTML 并连接到 API 的 web 应用程序怎么样,您需要指定通配符... :S 你确定吗? 只需要自己处理这个问题。 "Access-Control-Allow-Origin: *" 仅适用于凭证请求 - 请参阅 link。没有凭据的请求可以使用 *。 明确一点,在发送实际要求。 developer.mozilla.org 上的文档明确指出:“在以下情况下预检请求:它使用 GET、HEAD 或 POST 以外的方法。或者它在请求中设置自定义标头。”如果您的请求只是使用 GET,则无需进行预飞行。【参考方案2】:

您必须使用凭据正确实现 CORS 请求,才能通过 Ajax 发送和接收 cookie。请参阅developer.mozilla.org,特别是在标题为“带有凭据的请求”部分下。

首先,这是一个使用 jQuery 1.5.1+ 的带有凭据的简单 CORS Ajax 请求:

$.ajax(
    url: "http://www.domain2.com/process",
    xhrFields: 
        withCredentials: true
    
).done(function (data)  console.log(data); );

注意 xhrFields 中的 withCredentials 标志。此标志告诉浏览器发送带有 external 域请求的 cookie,而不是 origin 域。在您的情况下,将发送 www.domain2.com 的 cookie,您将可以在服务器端访问它们。

在服务器端,您需要在响应中添加某些标头:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: www.domain1.com

重要提示: 带有凭据的请求不能将 Access-Control-Allow-Origin 标头设置为全局 (Access-Control-Allow-Origin: *)。它必须指定域 (Access-Control-Allow-Origin: www.domain1.com)。

如果您为 Access-Control-Allow-Origin 标头指定域,显然会更好。但是,如果您不知道或不关心 CORS 请求的来源,您可以使用请求中的 Origin 标头并简单地设置响应的 Access-Control-Allow-Origin 标头到那个。在 C# 中,我们是这样做的:

this.Response.AddHeader("Access-Control-Allow-Origin", this.Request.Headers["Origin"]);

完成所有这些操作后,您在服务器端设置的 cookie 将与响应一起返回,浏览器将能够正确处理它们并将它们插入到浏览器的 www.domain2 cookie 存储中。 com。您发送的任何后续 CORS 请求也会在请求中发送这些 cookie。

如果您发送的请求不是使用 GET、POST 或 HEAD 方法,则需要实现 Preflighted requests(请参阅标题为“预检请求”的部分):

与简单的请求(上面讨论过)不同,“预检”请求首先通过 OPTIONS 方法向另一个域上的资源发送 HTTP 请求,以确定实际请求是否可以安全发送。跨站点请求是这样预检的,因为它们可能对用户数据有影响。特别是,在以下情况下会预检请求:

它使用 GET、HEAD 或 POST 以外的方法。此外,如果 POST 用于发送 Content-Type 不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 的请求数据,例如如果 POST 请求使用 application/xml 或 text/xml 将 XML 有效负载发送到服务器,则请求被预检。

它在请求中设置自定义标头(例如,请求使用诸如 X-PINGOTHER 之类的标头)

关于 IE8 和 IE9 的旁注: 上面的 Ajax 调用将在 IE8 和 9 中失败。我在我的页面上包含了来自 MoonScript/jQuery-ajaxTransport-XDomainRequest 的 JS 文件,这自动允许 CORS 请求在那些旧的 IE 版本中工作。但遗憾的是,MS 为 IE8 和 9 创建的 XDomainRequest 对象不允许发送或接收 cookie。 (更多信息请参见this MSDN blog post)

【讨论】:

【参考方案3】:

您有不同的主机。在第一个示例中,主机是“主机:www.floowie.com”。第二个是“主机:test1.floowie.com”。

我猜 cookie 最初是由 'test1.floowie.com' 设置的,而您没有指定它们应该对 '.floowie.com' 可用(即整个域和所有子域)。

你能发布一开始设置 cookie 的代码吗?

如果你解决了这个问题,它至少应该表现出一致的行为。但是,IE 可能仍然不会跨子域传递 cookie。这就是我目前正在努力解决的问题,这就是我可以解决您的问题的方法。

【讨论】:

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

在 Flask 应用程序中通过 jquery (getjson) 在字典中发送 Plotly 图表

jQuery中$.getJSON

关于Jquery的 $.getJSON()函数

jquery使用$.getJson()跨域大数据量请求方法

jQuery之getjson信息展示

为啥 jQuery 的 .ajax() 方法不发送我的会话 cookie?