-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前端跨域问题及解决方案 #2
Comments
@MinJieLiu 两码事吧 |
@justjavac 失误😓 |
随手搜的,能看到justjavac 大佬 |
有好文章的时候,jjc总会出现,总结的很好,赞一个~ |
https协议域名下可以发送跨域请求吗 |
@suyunxue https 我还没实践过,从 mdn 文档上看应该是可以的,但是注意有些浏览器不允许从 HTTPS 的域跨域访问 HTTP,比如 Chrome 和 Firefox,这些浏览器在请求还未发出的时候就会拦截请求。 |
总结得很棒,学习了! |
一个问题:ajax跨域请求的cookie是能带过去了,但是返回结果的 set-cookie 却不能被浏览器保存,请问需要怎么处理呢? |
@foxpsd 有没有试过 Access-Control-Expose-Headers |
不同域名跨域,浏览器默认开启禁止第三方 cookies,这种情况下非常麻烦 |
浏览器里有cookie 但是服务端收到的request里没有cookie 这个有谁遇到过吗 应该朝哪方面考虑? |
1、同源策略
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
一个源的定义:如果协议,端口(如果指定了一个)和主机对于两个页面是相同的,则两个页面具有相同的源。
下表给出了相对 http://store.company.com/dir/page.html 同源检测的示例:
2、主域相同的跨域
页面可能会更改其自己的来源,但有一些限制。脚本可以将 document.domain的值设置为其当前域或其当前域的超级域。如果将其设置为其当前域的超级域,则较短的域将用于后续原始检查。例如,假设文档中的一个脚本在 http://store.company.com/dir/other.html 执行以下语句:
这条语句执行之后,页面将会成功地通过对 http://company.com/dir/page.html 的同源检测。
3、完全不同源的跨域(两个页面之间的通信)
3.1、通过location.hash跨域
假设域名a.com下的文件cs1.html要和jianshu.com域名下的cs2.html传递信息。
1、cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向jianshu.com域名下的cs2.html页面。
2、cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据。
3、同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值。
优点:1.可以解决域名完全不同的跨域。2.可以实现双向通讯。
缺点:location.hash会直接暴露在URL里,并且在一些浏览器里会产生历史记录,数据安全性不高也影响用户体验。另外由于URL大小的限制,支持传递的数据量也不大。有些浏览器不支持onhashchange事件,需要轮询来获知URL的变化。
3.2、通过window.name跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的。window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。
如果是与iframe通信的场景就需要把iframe的src设置成当前域的一个页面地址。
3.3、通过window.postMessage跨域
HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。postMessage的兼容性如下:
可以看到 Internet Explorer 8+, chrome,Firefox , Opera 和 Safari 都将支持这个功能。但是Internet Explorer 8和9以及Firefox 6.0和更低版本仅支持字符串作为postMessage的消息。
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
父窗口和子窗口都可以通过message事件,监听对方的消息。message事件的事件对象event,提供以下三个属性:
一个例子:
4、AJAX请求不同源的跨域
4.1、通过JSONP跨域
基本原理:网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。例子如下:
优点:简单适用,老式浏览器全部支持,服务器改造小。不需要XMLHttpRequest或ActiveX的支持。
缺点:只支持GET请求。
4.2、通过WebSocket跨域
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
4.3、通过CORS跨域
当一个资源请求一个其它域名的资源时会发起一个跨域HTTP请求(cross-origin HTTP request)。比如说,域名A的某 Web 应用通过标签引入了域名B的某图片资源,域名A的 Web 应用就会导致浏览器发起一个跨域 HTTP 请求。在当今的 Web 开发中,使用跨域 HTTP 请求加载各类资源(包括CSS、图片、JavaScript 脚本以及其它类资源),已经成为了一种普遍且流行的方式。
正如大家所知,出于安全考虑,浏览器会拦截跨域请求的返回结果。比如,使用XMLHttpRequest对象和Fetch发起 HTTP 请求就必须遵守“同源策略”。 具体而言,Web 应用程序通过XMLHttpRequest对象或Fetch能且只能向同域名的资源发起 HTTP 请求,而不能向任何其它域名发起请求。为了能开发出更强大、更丰富、更安全的Web应用程序,开发人员渴望着在不丢失安全的前提下,Web 应用技术能越来越强大、越来越丰富。比如,可以使用 XMLHttpRequest 发起跨站 HTTP 请求。
隶属于 W3C 的 Web 应用工作组推荐了一种新的机制,即跨源资源共享(Cross-Origin Resource Sharing ) CORS。这种机制让Web应用服务器能支持跨站访问控制,从而使得安全地进行跨站数据传输成为可能。需要特别注意的是,这个规范是针对API容器的(比如说XMLHttpReques 或者 Fetch),以减轻跨域HTTP请求的风险。
跨源资源共享标准( cross-origin sharing standard) 使得以下场景可以使用跨站 HTTP 请求:
所有浏览器都支持该功能,IE浏览器不能低于IE10。通过 XMLHttpRequest 对象发起。但Internet Explorer 8 和 9 可以通过 XDomainRequest 对象来实现CORS。可以把CORS分为:简单请求、预请求和附带凭证信息的请求。
4.3.1、简单请求
所谓的简单,是指:
(1)只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。
(2)不会使用自定义请求头(类似于 X-Modified 这种)。
一个例子:
如上,通过使用 Origin 和 Access-Control-Allow-Origin 就可以完成最简单的跨站请求。不过服务器需要把 Access-Control-Allow-Origin 设置为 * 或者包含由 Origin 指明的站点。
4.3.2、预请求
不同于上面讨论的简单请求,“预请求”要求必须先发送一个 OPTIONS 请求给目的站点,来查明这个跨站请求对于目的站点是不是安全可接受的。这样做,是因为跨站请求可能会对目的站点的数据造成破坏。 当请求具备以下条件,就会被当成预请求处理:
(1)请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,但请求数据为 application/x-www-form-urlencoded, multipart/form-data 或者 text/plain 以外的数据类型。比如说,用 POST 发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。
(2)使用自定义请求头(比如添加诸如 X-PINGOTHER)
一个例子:
如上,以 XMLHttpRequest 创建了一个 POST 请求,为该请求添加了一个自定义请求头(X-PINGOTHER: pingpong),并指定数据类型为 application/xml。所以,该请求是一个“预请求”形式的跨站请求。浏览器使用一个 OPTIONS 发送了一个“预请求”。Firefox 3.1 根据请求参数,决定需要发送一个“预请求”,来探明服务器端是否接受后续真正的请求。 OPTIONS 是 HTTP/1.1 里的方法,用来获取更多服务器端的信息,是一个不应该对服务器数据造成影响的方法。 随同 OPTIONS 请求,以下两个请求头一起被发送:
假设服务器成功响应返回部分信息如下:
4.3.3、附带凭证信息的请求
XMLHttpRequest 和访问控制功能,最有趣的特性就是,发送凭证请求(HTTP Cookies和验证信息)的功能。一般而言,对于跨站请求,浏览器是不会发送凭证信息的。但如果将 XMLHttpRequest 的一个特殊标志位设置为true,浏览器就将允许该请求的发送。
一个例子:
如上,第七行代码将 XMLHttpRequest 的withCredentials标志设置为true,从而使得Cookies可以随着请求发送。因为这是一个简单的GET请求,所以浏览器不会发送一个“预请求”。但是,如果服务器端的响应中,如果没有返回Access-Control-Allow-Credentials: true的响应头,那么浏览器将不会把响应结果传递给发出请求的脚本程序,以保证信息的安全。
假设服务器成功响应返回部分信息如下:
如果bar.other的响应头里没有Access-Control-Allow-Credentials:true,则响应会被忽略.。特别注意: 给一个带有withCredentials的请求发送响应的时候,服务器端必须指定允许请求的域名,不能使用“*”。上面这个例子中,如果响应头是这样的 Access-Control-Allow-Origin:* ,则响应会失败。在这个例子里,因为Access-Control-Allow-Origin的值是 http://foo.example 这个指定的请求域名,所以客户端把带有凭证信息的内容被返回给了客户端。另外注意,更多的cookie信息也被创建了。
CORS的优点:CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案。
The text was updated successfully, but these errors were encountered: