简体   繁体   English

IE8 - IE10跨域JSONP cookie令人头疼

[英]IE8 - IE10 cross domain JSONP cookie headache

Due to decisions that are completely outside of my control, I am in the following situation: 由于完全不受我控制的决定,我处于以下情况:

  • I have a product listing on catalog.org 我在catalog.org上有一个产品列表

  • Clicking the "Add to Cart" button on a product makes an AJAX JSONP request to secure.com/product/add/[productKey], which saves the cart record to the database, sets a cookie with the cart ID , and returns a true response (or false if it failed) 单击产品上的“添加到购物车”按钮会向Secure.com/product/add/[productKey发出AJAX JSONP请求,这会将购物车记录保存到数据库, 使用购物车ID设置cookie ,然后返回true响应(如果失败则为false)

  • Back on catalog.org, if the response is true, another AJAX JSONP request is made to secure.com/cart/info, which reads the cart ID cookie , fetches the record, and returns the number of items in the cart 回到catalog.org,如果响应为真,则向secure.com/cart/info发出另一个AJAX JSONP请求, 请求读取购物车ID cookie ,获取记录,并返回购物车中的商品数量

  • Back on catalog.org once again, the response is read and an element on the page is updated showing the number of items in the cart (if any) 再次返回catalog.org,读取响应并更新页面上的元素,显示购物车中的商品数量(如果有)

  • At this point, clicking the "Go to Cart" button on catalog.org displays the cart summary on secure.com 此时,单击catalog.org上的“转到购物车”按钮会在secure.com上显示购物车摘要

This works beautifully in Firefox 17, Chrome 32 and IE 11. It also works in IE8 - IE10 on our development and test environments, where catalog.org is catalog.development.com and catalog.test.com and secure.com is secure.development.com and secure.test.com respectively. 这在Firefox 17,Chrome 32和IE 11中运行良好。它也适用于我们开发和测试环境中的IE8 - IE10,其中catalog.org是catalog.development.com,catalog.test.com和secure.com是安全的。 development.com和secure.test.com分别。

However, after we deployed to production, this stopped working in IE8 - IE10. 但是,在我们部署到生产之后,这停止了在IE8 - IE10中工作。 After adding a product to the cart, the number of items in the cart is updated successfully on catalog.org. 将产品添加到购物车后,购物车中的商品数量会在catalog.org上成功更新。 Then, after clicking the "Go to Cart" button on catalog.org, the cart summary on secure.com shows nothing because it can't read the cookie. 然后,在单击catalog.org上的“转到购物车”按钮后,secure.com上的购物车摘要显示任何内容,因为它无法读取cookie。 Going to Cache > "View cookie information" in IE develeoper tools shows no cart ID cookie. 在IE开发人员工具中进入缓存>“查看cookie信息”显示没有购物车ID cookie。 It should be there, just like it is there in other browsers and in our development and test environments. 它应该存在,就像在其他浏览器和我们的开发和测试环境中一样。

I believe what's happening is IE is blocking third party cookies. 我相信正在发生的事情是IE阻止第三方cookie。 We have added a P3P compact policy header to all requests on secure.com, but the cookie is still not being set. 我们已经为secure.com上的所有请求添加了一个P3P精简策略标头,但cookie仍未设置。 The header we are setting is: 我们设置的标题是:

P3P: CP="CAO PSA OUR"

Why doesn't adding the compact policy header fix this in IE8 - IE10? 为什么不在IE8-IE10中添加紧凑的策略头修复此问题? How can I fix this to work in all versions of IE? 我怎样才能解决这个问题,以便在IE的所有版本中运行?

Solution

There are several good ideas posted below. 下面有几个好主意。 I accepted @sdecima's because it sounded the most promising. 我接受了@ sdecima's,因为它听起来最有希望。 We ended up combining some of these ideas but managed to avoid XDomainRequest: 我们最终结合了其中的一些想法,但设法避免了XDomainRequest:

  • Clicking the "Add to Cart" button on a product makes an AJAX JSONP request to secure.com/product/add/[productKey], which saves the cart record to the database, sets a cookie with the cart ID , and returns a true response (or false if it failed) 单击产品上的“添加到购物车”按钮会向Secure.com/product/add/[productKey发出AJAX JSONP请求,这会将购物车记录保存到数据库, 使用购物车ID设置cookie ,然后返回true响应(如果失败则为false)

We changed the action at secure.com/product/add to return a JSON object with a boolean indicating success or failure and the cart ID. 我们在secure.com/product/add上更改了操作,以返回一个JSON对象,其中包含指示成功或失败的布尔值以及购物车ID。

  • Back on catalog.org, if the response is true, another AJAX JSONP request is made to secure.com/cart/info, which reads the cart ID cookie , fetches the record, and returns the number of items in the cart 回到catalog.org,如果响应为真,则向secure.com/cart/info发出另一个AJAX JSONP请求, 请求读取购物车ID cookie ,获取记录,并返回购物车中的商品数量

We changed the callback function to check for both properties in the response object. 我们更改了回调函数以检查响应对象中的两个属性。 If success is true and the cart ID is present, we create a hidden iframe on the page. 如果成功,并且存在购物车ID,我们会在页面上创建隐藏的iframe。 The src attribute of the iframe is set to a new endpoint we added to secure.com. iframe的src属性设置为我们添加到secure.com的新端点。 This action accepts a cart ID parameter and saves the cart ID cookie. 此操作接受购物车ID参数并保存购物车ID Cookie。 We no longer need to save the cookie in the secure.com/product/add action. 我们不再需要在secure.com/product/add操作中保存cookie。

Next, we changed the action at secure.com/cart/info to accept a cart ID parameter. 接下来,我们更改了secure.com/cart/info上的操作以接受购物车ID参数。 This action will use the cart ID parameter if present to fetch the cart information, otherwise it will still attempt to read the cookie. 此操作将使用购物车ID参数(如果存在)来获取购物车信息,否则它仍将尝试读取cookie。 This extra check would be unnecessary if we could guarantee that the iframe had finished loading and the cookie had been saved on secure.com, but we have no way of knowing when the iframe has finished loading on catalog.org due to browser security restrictions. 如果我们可以保证iframe已经完成加载并且cookie已经保存在secure.com上,那么这个额外的检查将是不必要的,但是由于浏览器安全限制,我们无法知道iframe何时在catalog.org上完成加载。

Finally, the P3P header CP="CAO PSA OUR" is still required for this to work in IE7 - IE10. 最后,仍然需要P3P标题CP="CAO PSA OUR"才能在IE7-IE10中工作。 (Yes, this works in IE7 now too :) (是的,这也适用于IE7 :)

We now have a solution (albeit an incredibly complex one) for saving and accessing cross domain cookies that works in all major browser, at least as far back as we can reliably test. 我们现在有一个解决方案(尽管是一个非常复杂的解决方案),用于保存和访问适用于所有主流浏览器的跨域cookie,至少在我们能够可靠测试的时候。

We will probably refactor this some more. 我们可能会对此进行一些重构。 For one thing, the second AJAX JSONP request to secure.com/cart/info is redundant at this point since we can return all the information we need in the original request to secure.com/product/add action (a side benefit of changing that action to return a JSON object - plus we can return an error message indicating exactly why it failed if there was an error). 首先,此时对secure.com/cart/info的第二个AJAX JSONP请求是多余的,因为我们可以将原始请求中所需的所有信息返回到secure.com/product/add操作(更改的附带好处)该操作返回一个JSON对象 - 加上我们可以返回一条错误消息,指出如果出现错误则确切失败的原因)。

In short 简而言之

Cookies will NOT go through a cross-origin request on IE 8 and 9. It should work on IE 10 and 11 though. Cookie不会在IE 8和9上通过跨源请求。但它应该适用于IE 10和11。


IE 8 and 9 IE 8和9

On IE8/9 XMLHttpRequest partially supports CORS , and cross-origin requests are made with the help of the XDomainRequest object which does NOT send cookies with each request. 在IE8 / 9上, XMLHttpRequest部分支持CORS ,并且在XDomainRequest对象的帮助下进行跨源请求,该对象不向每个请求发送cookie。

You can read more about this on the following official MSDN Blog post: 您可以在以下官方MSDN博客文章中阅读有关此内容的更多信息:
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Particularly this part: 特别是这部分:

5 . 5。 No authentication or cookies will be sent with the request 不会随请求一起发送身份验证或Cookie

In order to prevent misuse of the user's ambient authority (eg cookies, HTTP credentials, client certificates, etc), the request will be stripped of cookies and credentials and will ignore any authentication challenges or Set-Cookie directives in the HTTP response . 为了防止滥用用户的环境权限(例如cookie,HTTP凭证,客户端证书等), 请求将被剥离cookie和凭据,并将忽略HTTP响应中的任何身份验证质询或Set-Cookie指令 XDomainRequests will not be sent on previously-authenticated connections, because some Windows authentication protocols (eg NTLM/Kerberos) are per-connection-based rather than per-request-based. XDomainRequests不会在以前经过身份验证的连接上发送,因为某些Windows身份验证协议(例如NTLM / Kerberos)是基于每个连接而不是基于请求的。

IE 10+ IE 10+

Starting with IE10, full CORS support was added to XMLHTTPRequest and it should work fine with a correct Access-Control-Allow-Origin header property on the response from the server (that wishes to set the cookie on the browser). 从IE10开始, XMLHTTPRequest中添加了完整的CORS支持,它应该可以正常使用来自服务器的响应的正确的Access-Control-Allow-Origin标头属性(希望在浏览器上设置cookie)。

More about this here: 更多相关信息:
http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx
And here: 和这里:
http://www.html5rocks.com/en/tutorials/cors/ http://www.html5rocks.com/en/tutorials/cors/

Workarounds on IE 8 and 9 IE 8和9的变通方法

The only way to go around this on IE8/9 is, quoting the same MSDN post as above: 在IE8 / 9上解决这个问题的唯一方法是引用与上面相同的MSDN帖子

Sites that wish to perform authentication of the user for cross-origin requests can use explicit methods (eg tokens in the POST body or URL) to pass this authentication information without risking the user's ambient authority. 希望对跨源请求执行用户身份验证的站点可以使用显式方法(例如POST正文或URL中的令牌)来传递此身份验证信息,而不会冒用户的环境权限。

Bottom line: third party cookies are commonly blocked by privacy/advertisement blocking extensions and should be considered unreliable. 结论:第三方cookie通常被隐私/广告拦截扩展程序阻止,应被视为不可靠。 You'll be shooting yourself in the foot leaving it in production. 你会在脚下射击,让它继续生产。

The syntax suggests that the endpoint has ambitions to one day become RESTful. 语法表明端点有一天会成为RESTful的野心。 The only problem with that is using cookies, which throws the whole "stateless" concept out of the window! 唯一的问题是使用cookie,它会将整个“无状态”概念抛到窗外! Ideally, changes should be made to the API. 理想情况下,应对API进行更改。 If you are not integrating with a third party (ie "secure.com" is operated by your company) this is absolutely the correct way to deal with the issue. 如果您没有与第三方集成(即“secure.com”由您的公司运营),这绝对是处理该问题的正确方法。

Move the cartId out of the secure.com cookie into its querystring: cartIdsecure.com cookie移到其查询字符串中:

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

Where to get a valid cartId value? 从哪里获得有效的cartId值? We can persist it in some secure-com-cart-id cookie set for catalog domain , which will avoid any cross-domain issues. 我们可以将其保留在目录域的一些secure-com-cart-id cookie集中,这将避免任何跨域问题。 Check that value and, if present, append to every secure.com request as above: 检查该值,如果存在,则附加到每个secure.com请求,如上所述:

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

If you don't have a valid cartId , treat it as a new user and make the request without the parameter. 如果您没有有效的cartId ,请将其视为新用户,并在没有参数的情况下发出请求。 Your API should then assign a new id and return it in the response. 然后,您的API应分配一个新ID并在响应中返回它。 The "local" secure-com-cart-id cookie can then be updated. 然后可以更新“本地” secure-com-cart-id cookie。 Rinse and repeat. 冲洗并重复。

Voila, you've just persisted an active user cart without polluting API calls with cookies. 瞧,你刚刚持有一个活跃的用户购物车而没有用cookie来污染API调用。 Go yell at your architect. 对你的建筑师大喊大叫。 If you can't do that (changing API syntax or yelling), you'll have to set up a tunnel to secure.com endpoint so that there will be no cross-domain request - basically something sitting at catalog.org/secure-com-endpoint which will channel the requests to secure.com verbatim. 如果你不能这样做(改变API语法或大喊大叫),你将不得不建立一个到secure.com端点的隧道,这样就不会有跨域请求 - 基本上就是在catalog.org/secure- com-endpoint将把请求逐字地传递secure.com It's a workaround specifically to avoid making changes to the API, just don't do it with code and have proper Apache/IIS/F5 rules set up to handle it instead. 这是一种专门用于避免对API进行更改的解决方法,只是不要使用代码并设置适当的Apache / IIS / F5规则来代替它。 A quick search comes up with several explanations, this one looks pretty good to me. 快速搜索提出了几个解释, 这个看起来对我很好。

PS: this is a classic XY problem in my opinion. PS:在我看来,这是一个经典的XY问题 The solution isn't necessarily about persisting 3rd party cookies but about passing necessary parameters to a 3rd party while persisting the data somewhere . 解决方案不一定是关于持久存在第三方cookie,而是将必要参数传递给第三方,同时将数据保存在某处

Although a correct solution would be a change of architecture, if you're looking for a quick, temporary solution: 虽然正确的解决方案是改变架构,但如果您正在寻找一种快速,临时的解决方案:

JSONP files are actually just javascript. JSONP文件实际上只是javascript。 You could add a line of code to set cookies to the front of your JSONP. 您可以添加一行代码以将Cookie设置到JSONP的前面。

eg instead of: 例如,而不是:

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

Your JSONP could look like: 您的JSONP可能如下所示:

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

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

Is there 1 database serving catalog.org and secure.com or can they communicate? 是否有1个数据库服务于catalog.org和secure.com,还是可以进行通信?

If so then, you got it. 如果是这样的话,你就明白了。

When catalog.org servers a cookie, save it in the db. 当catalog.org服务器cookie时,将其保存在db中。 When secure.com servers a cookie, save it in the db. 当secure.com服务器cookie时,将其保存在db中。 Then you can determine who's cart belongs to which user. 然后,您可以确定哪个购物车属于哪个用户。

This is a fun problem to consider......Update 2: 这是一个值得考虑的有趣问题......更新2:

When a user goes to catalog.org: 当用户访问catalog.org时:

  • check if he has a cat_org cookie, if not, then: 检查他是否有cat_org cookie,如果没有,则:

    • in catalog.org: 在catalog.org中:

      • create a key value pair and save in the db {cat_cookie_id, unique_number} 创建一个键值对并保存在db {cat_cookie_id,unique_number}中
      • set cat_cookie_id in browser 在浏览器中设置cat_cookie_id
      • instruct the browser to ajax visit secure.com/register/unique_number 指示浏览器访问ajax访问secure.com/register/unique_number
    • in secure.com 在secure.com

      • read unique_number from url 从url读取unique_number
      • create a secure_cookie id 创建secure_cookie id
      • save in the db {cat_cookie_id, unique_number, secure_cookie_id} 保存在db {cat_cookie_id,unique_number,secure_cookie_id}中
      • delete unique_number, as this is a one-time use key 删除unique_number,因为这是一次性使用密钥

Now the db can map cat_cookie_id to secure_cookie_id and vice versa. 现在,db可以将cat_cookie_id映射到secure_cookie_id,反之亦然。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM