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

Why is jquery's .ajax() method not sending my session cookie?

在通过$.ajax()登录到一个站点后,我试图向该站点发送第二个$.ajax()请求—但是当我检查使用firebug发送的头文件时,请求中没有包含会话cookie。

我做错什么了?


我正在跨域方案中操作。在登录期间,远程服务器将set cookie header和Access-Control-Allow-Credentials设置为true一起返回。

下一次对远程服务器的Ajax调用应该使用这个cookie。

CORS的Access-Control-Allow-Credentials允许跨域日志记录。查看https://developer.mozilla.org/en/http_access_control获取示例。

对于我来说,它看起来像jquery中的一个bug(或者至少在下一个版本中有这个特性)。

更新:

  • 不会从Ajax响应中自动设置cookie(引文:http://aleembarwany.com/2006/11/14/atomy-of-a-well-designed-ajax-login-experience/)

    为什么?

  • 无法从响应获取cookie的值以手动设置它(http://www.w3.org/tr/xmlhttprequest/dom xmlhttprequest getresponseHeader)

    我很困惑…

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

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

    文档中的示例是:

    1
    2
    3
    4
    5
    6
    $.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: *

    所以当请求是:

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

    服务器应响应:

    1
    2
    3
    4
    Access-Control-Allow-Origin: http://foo.example
    Access-Control-Allow-Credentials: true

    [payload]

    否则,有效负载将不会返回到脚本。请参见:https://developer.mozilla.org/en-us/docs/web/http/access-control-cors-requests-with-u-credentials


    Ajax调用仅在您调用的URL与调用脚本位于同一域时发送cookie。

    这可能是一个跨域问题。

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

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

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

    很高兴能帮上一点忙。


    使用

    1
    xhrFields: { withCredentials:true }

    作为jquery的一部分,Ajax调用只是解决方案的一部分。我还需要在我的资源的选项响应中返回头:

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

    重要的是,只有一个允许的"来源"位于选项调用的响应头中,而不是"*"。我通过从请求中读取源代码并将其填充回响应中实现了这一点——可能绕过了限制的原始原因,但在我的用例中,安全性并不重要。

    我认为有必要明确地提到只有一个源代码的要求,因为W3C标准允许使用一个空格分隔的列表——但Chrome不允许!http://www.w3.org/tr/cors/访问控制允许源站响应头注意"实践中"位。


    把它放到init函数中:

    1
    2
    3
    4
    5
    $.ajaxSetup({
      xhrFields: {
        withCredentials: true
      }
    });

    它会起作用的。


    对于这个问题已经有很多很好的回答,但是我认为澄清在哪里发送会话cookie可能会有所帮助,因为cookie域匹配,但是由于Ajax请求被发送到不同的子域,所以不会发送会话cookie。在本例中,我有一个分配给*.mydomain.com域的cookie,我希望它包含在对不同.mydomain.com的Ajax请求中"。默认情况下,不会发送cookie。您不需要在会话cookie上禁用httponly来解决此问题。您只需要按照Wombling的建议(https://stackoverflow.com/a/23660618/545223)执行以下操作。

    1)将以下内容添加到Ajax请求中。

    1
    xhrFields: { withCredentials:true }

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

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

    在尝试了其他的解决方案,但仍然没有使其发挥作用之后,我发现了我的案例中的问题所在。我将ContentType从"application/json"更改为"text/plain"。

    1
    2
    3
    4
    5
    6
    7
    8
    $.ajax(fullUrl, {
        type:"GET",
        contentType:"text/plain",
        xhrFields: {
             withCredentials: true
        },
        crossDomain: true
    });


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

    通过查看浏览器中的sessionid cookie值,我发现我的框架(django)正在以httponly作为默认值传递sessionid cookie。这意味着脚本不能访问sessionid值,因此不能与请求一起传递它。有点可笑的是,当这么多东西使用需要访问限制的Ajax时,httpOnly将成为默认值。

    为了解决这个问题,我更改了一个设置(session_cookie_httponly=false),但在其他情况下,它可能是cookie路径上的"httponly"标志。


    在本地主机和开发环境下设置phpsessid cookie问题只需2美分。我对locahost上的RESTAPI端点进行Ajax调用。假设它的地址是mysite.localhost/api/member/login/(我开发环境中的虚拟主机)。

    • 当我对邮递员执行这个请求时,一切都会好起来,phpsessid会随响应一起设置。

    • 当我通过Ajax从浏览器同步代理页面(例如从浏览器地址行中的122.133.1.110:3000/test/api/login.php请求此端点时,请注意域与mysite.localhost不同)phpsessid不会出现在cookie中。

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

    所以这是一个跨来源的请求cookie问题,如上文@flu answer中所述。


    如果您在localhost或本地主机(如localhost:8080上)上开发端口,除了上述答案中描述的步骤外,还需要确保您没有在set cookie头中传递域值。不能在set cookie头中将域设置为localhost,这是不正确的,只需省略该域即可。

    查看具有显式域的localhost上的cookies,为什么ASP.NET不在localhost中创建cookies?


    也许不是100%回答这个问题,但是当Ajax从innovastudio编辑器的AssetManager发布一个文件上传时,为了解决会话问题,我偶然发现了这个线程。最终解决方案很简单:他们有一个闪存上载程序。禁用(设置

    1
    var flashUpload = false;

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

    由于这些问题很难调试,我发现在上载处理程序中放入类似以下内容将使您(在本例中是我)进入正确的轨道:

    1
    2
    3
    4
    5
    6
    7
    $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。