为什么jquery的.ajax()方法不发送我的会话cookie?


338

通过$.ajax()站点登录后,我尝试$.ajax()向该站点发送第二个请求-但是,当我检查使用FireBug发送的标头时,请求中没有会话cookie。

我究竟做错了什么?


2
Web cookie可能紧接ajax的cookie,而FireBug可能会捕获首页cookie。
克里斯,2010年

1
我没有明白你的意思,但是我可以说,如果我将请求URL粘贴到浏览器地址栏中,然后再次检查Firebug,我可以看到发送到服务器的headres中的cookie。有什么办法吗?
user345625'5

因此,我认为ajax也将以与浏览器相同的方式处理
user345625'5

您正在使用什么代码?
迪恩·哈丁

浏览器仍会在ajax请求,jquery或其他情况下创建服务器设置的cookie。您是否检查了对ajax请求的响应,并确保要设置的cookie从服务器返回?有可能是服务器代码的问题,使得它甚至没有设置cookie等
大卫·

Answers:


218

如果您要调用的URL与您的调用脚本位于同一域中,则AJAX调用仅发送Cookie。

这可能是跨域问题。

也许您www.domain-a.com是在调用脚本打开时尝试从url 调用的www.domain-b.com(换句话说:您进行了跨域调用,在这种情况下浏览器将不会发送任何cookie来保护您的隐私)。

在这种情况下,您的选择是:

  • 编写一个小代理,该代理位于域b上,并将您的请求转发到域a。您的浏览器将允许您调用代理,因为它与调用脚本位于同一服务器上。
    然后,您可以配置此代理以接受可以发送到domain-a的cookie名称和值参数。但是,要使其正常工作,您需要知道Cookie的名称并在域上对服务器进行估价-想要进行身份验证。
  • 如果您要获取JSON对象,请尝试使用JSONP请求。jQuery支持这些。但是您需要更改域-a上的服务,以便它返回有效的JSONP响应。

高兴的是,即使有所帮助。


19
还值得注意的是,可以将cookie设置为特定的路径,因此,如果您使用cookie进行设置,path=/something而您正在请求页面/another,则将不会发送该cookie。当您请求页面时/something,cookie将按预期发送。因此,还要检查设置cookie的代码。
styfle

2
jsonp请求发送coockies吗?
albanx 2014年

1
@albanx是的,如果设置了我提到的要求。就像其他请求一样,这只是正常请求,因此会发送Cookie。
2014年

1
@albanx这个其他相关问题包括如何使用自定义cookie进行JSONP请求的示例
AntonioHerraizS 2014年

4
根据Wikipedia 上的JSONP,此方法被放弃以支持CORS
Peter Dotchev 2015年

386

我在跨域情况下进行操作。登录期间,远程服务器将返回Set-Cookie标头以及将其Access-Control-Allow-Credentials设置为true。

对远程服务器的下一个ajax调用应使用此cookie。

CORS Access-Control-Allow-Credentials允许跨域日志记录。检查https://developer.mozilla.org/En/HTTP_access_control以获取示例。

对我来说,这似乎是JQuery中的错误(或至少在下一版本中是新功能)。

更新:

  1. 不会通过AJAX响应自动设置Cookie(引用:http : //aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/

    为什么?

  2. 您无法从响应中获取Cookie的值来手动设置它(http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader

    我糊涂了..

    应该有一种要求jquery.ajax()设置XMLHttpRequest.withCredentials = "true"参数的方法。

解答: 您应该使用http://api.jquery.com/jQuery.ajax/的xhrFields参数

文档中的示例为:

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

服务器正确响应此请求也很重要。在此处复制@Frédéric和@Pebbl的精彩评论:

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *

因此,当请求是:

Origin: http://foo.example
Cookie: pageAccess=2

服务器应响应:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true

[payload]

否则,有效负载将不会返回到脚本。请参阅:https//developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials


8
太好了!我添加使用此+在服务器端将Access-Control-Allow-Credentials标头设置为true
–Frédéric

以及在“标题自动化”中在请求正文中的那些凭据?
Francisco Corrales Morales 2014年

3
感谢您的回答:)只是一个快速此外,它可能是值得一提的Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: * developer.mozilla.org/en-US/docs/Web/HTTP/...
Pebbl

不幸的是,这些都不对我有用。如果我从AngularJS运行相同的请求,则可以运行,但从jQuery运行,即使有这些建议,会话Cookie也不会通过。(jQuery v2.1.1)
Geoidesic '16

(OO)您从各种痛苦的时刻中拯救了我。完美的答案!谢谢!我需要将这些添加到我的网站的公共根.htaccess中:<IfModule mod_headers.c>标头设置了Access-Control-Allow-Origin“ localhost ”标头设置了Access-Control-Allow-Credentials“ true” </ IfModule>
Vinay Vissh

48

使用

xhrFields: { withCredentials:true }

作为我的jQuery ajax调用的一部分,仅是解决方案的一部分。我还需要从资源中在OPTIONS响应中返回标头:

Access-Control-Allow-Origin : http://www.wombling.com
Access-Control-Allow-Credentials : true

重要的是在OPTIONS调用的响应标头中只有一个允许的“来源”,而不是 “ *”。我通过读取请求的来源并将其填充回响应中来实现此目的-可能绕过了限制的原始原因,但是在我的用例中,安全性不是最重要的。

我认为值得一提的是仅要求一个来源,因为W3C标准确实允许使用空格分隔的列表-但Chrome不允许! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header 注意“实践”位。


40

将其放在您的init函数中:

$.ajaxSetup({
  xhrFields: {
    withCredentials: true
  }
});

会的。


1
你救了我的一天!在方法级别,withCredentials对我不起作用。但是像这样的全局性终于可以了!谢谢。
Paulius Matulionis

要小心,因为它将向所有请求发送cookie,向其他域发送以太
devi

12

对于这个问题已经有很多好的回答,但是我认为澄清一下由于cookie域匹配而希望发送会话cookie的情况可能会有所帮助,因为AJAX请求是被设置到另一个子域。在这种情况下,我有一个分配给* .mydomain.com域的cookie ,并且希望将它包含在对different.mydomain.com的AJAX请求中。默认情况下,不会发送该cookie。您无需禁用会话cookie上的HTTPONLY即可解决此问题,只需执行建议的摇晃操作(https://stackoverflow.com/a/23660618/545223),然后执行以下操作。

1)将以下内容添加到您的ajax请求中。

xhrFields: { withCredentials:true }

2)将以下内容添加到您的响应头中,以获取不同子域中的资源。

Access-Control-Allow-Origin : http://original.mydomain.com
Access-Control-Allow-Credentials : true

7

在尝试了其他解决方案并且仍然无法使之工作之后,我发现了我的问题所在。我将contentType从“ application / json”更改为“ text / plain”。

$.ajax(fullUrl, {
    type: "GET",
    contentType: "text/plain",
    xhrFields: {
         withCredentials: true
    },
    crossDomain: true
});

4

我遇到了同样的问题,做了一些检查我的脚本只是根本没有获取sessionid cookie。

通过查看浏览器中的sessionid cookie值,我发现我的框架(Django)正在使用默认的HttpOnly传递sessionid cookie。这意味着脚本无法访问sessionid值,因此不会将其与请求一起传递。荒谬的是,当许多东西使用Ajax且需要访问限制时,HttpOnly将成为默认值。

为了解决这个问题,我更改了设置(SESSION_COOKIE_HTTPONLY = False),但在其他情况下,它可能是cookie路径上的“ HttpOnly”标志


2
不要这样做。它允许客户端脚本访问会话cookie,这是最常见的XSS攻击媒介。owasp.org/index.php/HttpOnly
Jason Elkin


0

在本地主机和开发环境下,仅花2美分就可以设置PHPSESSID Cookie。我在locahost上对我的REST API端点进行AJAX调用。说它的地址是mysite.localhost/api/member/login/(我的开发环境中的虚拟主机)。

  • 当我在Postman上执行此请求时,一切正常,并在响应中设置了PHPSESSID。

  • 当我从Browsersync代理页面通过AJAX请求此终结点时(例如,122.133.1.110:3000/test/api/login.php在我的浏览器地址行中,看到域与相对mysite.localhost),PHPSESSID不会出现在cookie中。

  • 当我直接从同一域(即mysite.localhost/test/api/login.php)上的页面发出此请求时,PHPSESSID设置就很好。

因此,这是跨域来源请求Cookie的问题,如上面 @flu 答案中所述


0

添加我的方案和解决方案以防其他人使用。使用RESTful API时遇到类似情况。我托管HTML / Script / CSS文件的Web服务器和Application Server公开API托管在同一域中。但是,路径是不同的。

网络服务器-mydomain / 网页 /abc.html

使用abc.js设置名为mycookie的 cookie

应用服务器-mydomain / webapis / servicename。

对其进行了api调用

我期望mydomain / webapis / servicename中的cookie并尝试读取它,但未发送。从答案中读取评论后,我签入了浏览器的开发工具,将mycookie的路径设置为“ / webpages ”,因此在对的服务调用中不可用

mydomain / webapis / servicename

因此,从jquery设置cookie时,这就是我所做的-

$.cookie("mycookie","mayvalue",{**path:'/'**});

-5

也许不是100%回答这个问题,但是我偶然发现了这个线程,希望当ajax从innovastudio编辑器的assetmanager发布文件上传时解决会话问题。最终,解决方案很简单:他们有一个flash-uploader。禁用它(设置

var flashUpload = false;   

在asset.php中),指示灯开始再次闪烁。

由于这些问题很难调试,因此我发现在上传处理程序中放置类似以下内容的代码将使您(在这种情况下为我)处于正确的轨道:

$sn=session_name();
error_log("session_name: $sn ");

if(isset($_GET[$sn])) error_log("session as GET param");
if(isset($_POST[$sn])) error_log("session as POST param");
if(isset($_COOKIE[$sn])) error_log("session as Cookie");
if(isset($PHPSESSID)) error_log("session as Global");

深入日志,我很快发现了丢失的会话,没有发送任何cookie。


我认为上面的示例不起作用,因为当没有会话cookie时,$ sn的值是多少?(随机一个,也可能为空),或者用户可以从例如GET值设置会话名称session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();就这样,他们会得到一个工作的事情
钢脑

这正是我发现问题的方式:从此Flash上​​传器发布内容时没有会话。由于使用GET变量会话标识符不是一个好主意,并且cookie无法正常工作,因此我将其丢弃。谁在乎,闪光灯反正已经成为过去。
Ellert van Koperen 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.