5

由于我完全无法控制的决定,我处于以下情况:

  • 我在 catalog.org 上有一个产品列表

  • 单击产品上的“添加到购物车”按钮向 secure.com/product/add/[productKey] 发出 AJAX JSONP 请求,该请求将购物车记录保存到数据库,使用购物车 ID 设置 cookie,并返回 true响应(如果失败,则返回 false)

  • 返回catalog.org,如果响应为真,则向secure.com/cart/info 发出另一个AJAX JSONP 请求,读取购物车ID cookie,获取记录,并返回购物车中的商品数量

  • 再次返回 catalog.org,读取响应并更新页面上的元素,显示购物车中的商品数量(如果有)

  • 此时,单击 catalog.org 上的“转到购物车”按钮会在 secure.com 上显示购物车摘要

这在 Firefox 17、Chrome 32 和 IE 11 中运行良好。它也适用于我们的开发和测试环境中的 IE8 - IE10,其中 catalog.org 是 catalog.development.com,catalog.test.com 和 secure.com 是安全的。 development.com 和secure.test.com 分别。

但是,在我们部署到生产环境后,这在 IE8 - IE10 中停止工作。将产品添加到购物车后,购物车中的商品数量会在 catalog.org 上成功更新。然后,单击 catalog.org 上的“转到购物车”按钮后,secure.com 上的购物车摘要什么也没有显示,因为它无法读取 cookie。在 IE 开发者工具中转到缓存 >“查看 cookie 信息”显示没有购物车 ID cookie。它应该在那里,就像它在其他浏览器以及我们的开发和测试环境中一样。

我相信正在发生的事情是 IE 正在阻止第三方 cookie。我们已为secure.com 上的所有请求添加了一个P3P 紧凑策略标头,但仍未设置cookie。我们设置的标题是:

P3P: CP="CAO PSA OUR"

为什么在 IE8 - IE10 中添加紧凑策略标头不能解决此问题?如何解决此问题以在所有版本的 IE 中工作?

解决方案

下面有几个好主意。我接受了@sdecima,因为它听起来最有希望。我们最终结合了其中一些想法,但设法避免了 XDomainRequest:

  • 单击产品上的“添加到购物车”按钮向 secure.com/product/add/[productKey] 发出 AJAX JSONP 请求,该请求将购物车记录保存到数据库,使用购物车 ID 设置 cookie,并返回 true响应(如果失败,则返回 false)

我们更改了 secure.com/product/add 上的操作以返回一个 JSON 对象,其中包含一个指示成功或失败的布尔值购物车 ID。

  • 返回catalog.org,如果响应为真,则向secure.com/cart/info 发出另一个AJAX JSONP 请求,读取购物车ID cookie,获取记录,并返回购物车中的商品数量

我们更改了回调函数以检查响应对象中的两个属性。如果成功并且购物车 ID 存在,我们会在页面上创建一个隐藏的 iframe。iframe的src属性设置为我们添加到 secure.com 的新端点。此操作接受购物车 ID 参数并保存购物车 ID cookie。我们不再需要将 cookie 保存在 secure.com/product/add 操作中。

接下来,我们更改了 secure.com/cart/info 上的操作以接受购物车 ID 参数。此操作将使用购物车 ID 参数(如果存在)来获取购物车信息,否则仍会尝试读取 cookie。如果我们可以保证 iframe 已完成加载并且 cookie 已保存在 secure.com 上,则无需进行额外检查,但由于浏览器安全限制,我们无法知道 iframe 何时完成在 catalog.org 上的加载。

最后,CP="CAO PSA OUR"仍然需要 P3P 标头才能在 IE7 - IE10 中工作。(是的,这现在也适用于 IE7 :)

我们现在有一个解决方案(尽管是一个非常复杂的解决方案),用于保存和访问在所有主要浏览器中都可以使用的跨域 cookie,至少在我们可以可靠测试的情况下。

我们可能会对此进行更多重构。一方面,此时对secure.com/cart/info 的第二个AJAX JSONP 请求是多余的,因为我们可以将原始请求中所需的所有信息返回到secure.com/product/add 操作(更改的附带好处该操作返回一个 JSON 对象——另外,如果出现错误,我们可以返回一条错误消息,指出它失败的确切原因)。

4

5 回答 5

7

简而言之

Cookie 不会在 IE 8 和 9 上通过跨域请求。但它应该可以在 IE 10 和 11 上运行。


IE 8 和 9

在 IE8/9 XMLHttpRequest部分支持CORS ,并且在XDomainRequest 对象的帮助下进行跨域请求,该对象不会随每个请求发送 cookie。

您可以在以下官方 MSDN 博客文章中阅读有关此内容的更多信息:http:
//blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

特别是这部分:

5. 不会随请求发送任何身份验证或 cookie

为了防止滥用用户的环境权限(例如 cookie、HTTP 凭据、客户端证书等),请求将被剥离 cookie 和凭据,并将忽略 HTTP 响应中的任何身份验证挑战或 Set-Cookie 指令。XDomainRequests 将不会在先前经过身份验证的连接上发送,因为某些 Windows 身份验证协议(例如 NTLM/Kerberos)是基于每个连接而不是基于每个请求的。

IE 10+

从 IE10 开始,向XMLHTTPRequest添加了完整的CORS支持,并且它应该可以在来自服务器的响应(希望在浏览器上设置 cookie)上使用正确的 Access-Control-Allow-Origin 标头属性正常工作。

更多关于这里:http:
//blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx
在这里:
http ://www.html5rocks.com /zh/教程/cors/

IE 8 和 9 上的解决方法

在 IE8/9 上解决此问题的唯一方法是引用与上述相同的MSDN 帖子

希望对跨域请求执行用户身份验证的站点可以使用显式方法(例如 POST 正文或 URL 中的令牌)来传递此身份验证信息,而不会危及用户的周围权限。

于 2014-01-10T03:28:18.260 回答
3

底线:第三方 cookie 通常被隐私/广告阻止扩展程序阻止,应被视为不可靠。您将在生产中留下自己的脚。

语法表明端点有朝一日成为 RESTful 的野心。唯一的问题是使用 cookie,它把整个“无状态”概念抛到了窗外!理想情况下,应该对 API 进行更改。如果您不与第三方集成(即“secure.com”由您的公司运营),这绝对是处理问题的正确方法。

secure.comcartId cookie移出到它的查询字符串中:

secure.com/product/add/9876?cartId=1234    //should be a POST

从哪里获取有效值cartId?我们可以将它保存在目录域secure-com-cart-id的一些cookie 集中,这将避免任何跨域问题。检查该值,如果存在,则附加到上述每个secure.com请求:

$.post('secure.com/product/add/9876', {    //needs jQuery.cookie
  cartId: $.cookie('secure-com-cart-id')
});

如果您没有 valid cartId,请将其视为新用户并在不带参数的情况下发出请求。然后,您的 API 应该分配一个新的 id 并在响应中返回它。secure-com-cart-id然后可以更新“本地” cookie。冲洗并重复。

瞧,您刚刚保留了一个活跃的用户购物车,而没有使用 cookie 污染 API 调用。去对你的建筑师大喊大叫。如果您不能这样做(更改 API 语法或大喊大叫),则必须设置一条到secure.com端点的隧道,这样就不会有跨域请求 - 基本上是位于catalog.org/secure- com-endpoint将请求逐字传送到secure.com。这是一种专门用于避免更改 API 的解决方法,只是不要使用代码进行更改,而是设置适当的 Apache/IIS/F5 规则来处理它。快速搜索有几个解释,这个对我来说看起来不错。

PS:在我看来,这是一个经典的 XY 问题。解决方案不一定是关于持久化第 3 方 cookie,而是关于将必要的参数传递给第 3 方,同时将数据持久保存在某处

于 2014-01-07T22:58:06.437 回答
0

虽然正确的解决方案是改变架构,但如果您正在寻找一个快速的临时解决方案:

JSONP 文件实际上只是 javascript。您可以在 JSONP 前面添加一行代码来设置 cookie。

例如,而不是:

callback({"exampleKey": "exampleValue"});

您的 JSONP 可能如下所示:

document.cookie="cartID=1234";
callback({"exampleKey": "exampleValue"});
于 2014-01-12T09:11:23.037 回答
0

如果您控制 DNS 记录,请创建一个新条目,以便两台服务器位于同一个域中。

于 2014-01-13T05:45:02.120 回答
0

是否有 1 个数据库为 catalog.org 和 secure.com 提供服务,或者它们可以通信吗?

如果是这样,那么你明白了。

当 catalog.org 提供 cookie 时,将其保存在数据库中。当secure.com 提供cookie 时,将其保存在数据库中。然后您可以确定谁的购物车属于哪个用户。

这是一个值得考虑的有趣问题......更新2:

当用户访问 catalog.org 时:

  • 检查他是否有 cat_org cookie,如果没有,则:

    • 在目录.org:

      • 创建一个键值对并保存在 db {cat_cookie_id, unique_number}
      • 在浏览器中设置 cat_cookie_id
      • 指示浏览器 ajax 访问 secure.com/register/unique_number
    • 在secure.com

      • 从 url 读取 unique_number
      • 创建一个secure_cookie id
      • 保存在数据库 {cat_cookie_id, unique_number, secure_cookie_id}
      • 删除 unique_number,因为这是一次性使用密钥

现在数据库可以将 cat_cookie_id 映射到 secure_cookie_id ,反之亦然。

于 2014-01-14T17:15:30.520 回答