【问题标题】:IE8 - IE10 cross domain JSONP cookie headacheIE8 - IE10 跨域 JSONP cookie 头痛
【发布时间】:2014-01-07 03:51:14
【问题描述】:

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

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

  • 单击产品上的“添加到购物车”按钮会向 secure.com/product/add/[productKey] 发出 AJAX JSONP 请求,这会将购物车记录保存到数据库中,设置一个 cookie使用购物车 ID,并返回 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分别是secure.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:

  • 单击产品上的“添加到购物车”按钮会生成 AJAX JSONP 请求secure.com/product/add/[productKey],它会保存购物车 记录到数据库,设置一个带有购物车 ID 的 cookie,并返回一个 true 响应(如果失败则为 false)

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

  • 返回catalog.org,如果响应为真,另一个AJAX JSONP 向secure.com/cart/info发出请求,读取购物车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 何时完成加载到目录中。 org 由于浏览器安全限制。

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

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

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

【问题讨论】:

  • 用html的LocalStorage怎么样?
  • LocalStorage 我相信也有每个域的限制。

标签: javascript ajax cookies jsonp p3p


【解决方案1】:

总之

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


IE 8 和 9

在 IE8/9 上 XMLHttpRequest 部分支持 CORS,并且在 XDomainRequest object 的帮助下进行跨域请求,它不会随每个请求发送 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 支持,并且它应该可以在来自服务器的响应中使用正确的 Access-Control-Allow-Origin 标头属性(希望在浏览器)。

在此处了解更多信息:
http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx
在这里:
http://www.html5rocks.com/en/tutorials/cors/

IE 8 和 9 上的解决方法

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

希望对用户进行跨域身份验证的站点 请求可以使用显式方法(例如 POST 正文中的标记或 URL) 以传递此身份验证信息而不会冒险 用户的环境权限。

【讨论】:

  • 唯一的问题是缺乏 IE7 支持。 (我有没有提到我们也必须支持那个 POS?)但是,这听起来像是 IE8 - IE10 的一个有前途的解决方案。当它在 IE7 中失败时,我们可能会退回到一个不太优雅的方法。
  • Cookies 不会在 IE7 和 IE 8 或 9 上跨域。您需要在这些浏览器上找到替代解决方案。在 URL 或 POST 正文上使用令牌/查询参数的解决方法只是一个建议的解决方案;顺便说一句,它无处不在。
  • 接受,因为我必须接受一些东西。这个答案很简洁,并提供了几个可行的想法。
【解决方案2】:

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

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

cartIdsecure.com 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')
});

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

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

P.S.:我认为这是a classic XY problem。解决方案不一定是关于持久化第 3 方 cookie,而是关于将必要的参数传递给第 3 方,同时将数据持久保存在某处

【讨论】:

  • 嗯,它适用于我们的测试环境,因为在该上下文中它不是跨域请求,因为两个站点都以 test.com 结尾。在我们的开发环境中,两个站点都以 development.com 结尾。
  • 当用户访问secure.com 时,我不能指望总是有可用的购物车ID。我们所有的网站都以某种方式链接到购物车,而且用户可以直接去那里。隧道的事情听起来像是一个重大的 API 更改(基本上完成了在 catalog.org 上设置购物车的所有工作,而无需向 secure.com 发出任何 AJAX 请求),这可能是我们必须要做的。
  • @davidkennedy85:跨域与跨子域与此解决方案无关,我们甚至不必使用 jsonp!不过,我会稍微扩展一下“不总是有购物车 ID”的答案。
  • 我们可以将此解决方案用于相关网站 (catalog.org),但它不适用于我们的其他网站。
【解决方案3】:

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

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

例如,而不是:

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

您的 JSONP 可能如下所示:

document.cookie="cartID=1234";
callback({"exampleKey": "exampleValue"});

【讨论】:

  • 问题不是从catalog.org 读取cookie,而是在用户返回secure.com 时读取它。
  • 打开一个 iframe 到secure.com,详细信息在 URL 中,例如。 http://secure.com/cookieSetter?exampleKey=exampleValue 并有一个 javascript 读取它并设置 cookie。
  • 我们最终不得不使用 iframe。我会将其余的详细信息添加到问题中。
【解决方案4】:

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

【讨论】:

  • 这是一个面向公众的网站。
  • 许多面向公众的网站都有多个 dns 条目。您是说这是一个您无法控制 dns 记录的面向公众的网站吗?
  • 我刚刚提到了这一点,因为它是一个简单的解决方案,如果你能掌握 dns 记录的话......
  • 这不是一个选项,因为域是一项业务策略。
【解决方案5】:

是否有 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}
      • 删除唯一号码,因为这是一次性使用密钥

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

【讨论】:

  • 它必须在没有身份验证的情况下工作(想想亚马逊是如何工作的)。如果用户未登录,我考虑保留 IP 地址,但是,唉,服务器位于负载均衡器后面,并且每个请求都来自该 IP。此外,我们有许多共享 IP 地址的客户(想想公司)。
  • 所以你不能给每个catalog.org用户一个cookie?他们不需要登录或其他任何东西,如果他们还没有唯一的 cookie,只需给他们一个唯一的 cookie。我确信 Amazon.com 会这样做。 IP 地址不可靠——尽管开箱即用是好的想法。
猜你喜欢
  • 2012-10-07
  • 2013-02-13
  • 2023-03-29
  • 2012-06-12
  • 2014-09-05
  • 2013-03-11
  • 1970-01-01
  • 2014-05-31
  • 2013-04-04
相关资源
最近更新 更多