zoukankan      html  css  js  c++  java
  • 简单说说什么是跨域

    发表日期:2019年8月15日


    跨域警告的发生

    如果你做了一些前后端分离的项目,由于此时前端所在的服务地址与后端所在的服务地址不一样,你可能会遇到一个请求被浏览器拦截了的问题,浏览器在检测到当前页面发起的请求不属于当前域就会将其拦截,这是因为浏览器的“同源策略”。


    那么,什么是同源策略呢?
    同源策略用于限制页面发起不同域(源)的请求,用于提高请求的安全性。
    如果两个页面的协议、端口、IP地址(域名)都相同的话,那么这两个页面就是同源,也就是同一个域。

    举例:
    以http://192.168.10.1:8080/index.html为对照源,
    http://192.168.10.1:8080/auth/login.html与它是同源
    http://192.168.10.1:8181/index.html与它不是同源,因为端口不一样;
    http://192.168.10.30:8080/index.html与它不是同源,因为IP地址不一样。



    有些人会问,既然域不一样就会拦截,为什么我用了xxxCDN的css文件,这个请求没有被拦截呢?
    这里要提一些并不是所有的跨域请求都会被拦截的。
    1.通常浏览器不会拦截一些跨域资源嵌入的请求。
    这种所谓的资源嵌入,就是类似于<img>标签中的src,<script>中的src,<link>中的href这样的请求,这样的请求是直接请求资源嵌入到你的页面中的。所以你使用某个cdn的css文件不会被拦截。【所以有种方式就是通过这种嵌入的方式来进行解决跨域的问题】
    2.通常浏览器不会拦截一些跨域写资源的请求。
    这种所谓的跨域写资源,就是所谓的超链接请求,页面重定向,非XMLHttpRequest方式的表单提交(普通的form表单提交)等等。
    3.通常浏览器会拦截跨域读资源的请求。
    XMLHttpRequest提交表单,XMLHttpRequest请求资源,【常见于异步操作】

    除此之外,要再次强调的是,同源策略是浏览器的安全策略。所以如果你直接通过postman这些能够不借助浏览器来发http请求的软件来发请求的话,它是不会拦截你的跨域请求的。



    一个可以用于测试的例子:
    (当我把下面的html文件部署到一个web服务器(tomcat,apache等)中的时候,此时这个网页处于的域应该是我的本机地址localhost:80,此时我根据上述的三个方面来测试浏览器是否拦截。结果是只有最后一个是被拦截的。【不要不部署就直接打开这个页面,否则的话它只是一个普通的本地文件,而非网络文件,此时浏览器不会认为这是一个域】)

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8" />
        <title>用于测试跨域</title>
    
    </head>
    <body>
        <!-- 跨域资源嵌入,允许 -->
        <img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565884598468&di=bb6ccc7a3280b183e4e13c852bc8353c&imgtype=0&src=http%3A%2F%2Fs04.lmbang.com%2FM00%2FCA%2FDE%2FDpgiA1uPAOKAXmJfAADir1hWa-A750.gif" alt="">
    
        <!-- 跨域资源写操作,允许 -->
        <a href="http://www.baidu.com">百度</a>
    
        <form action="http://www.baidu.com" method="post" >
            用户名:<input type="text" name="username" value="" placeholder="">
            <input type="submit" name="提交" value="提交">
        </form>
    
        <!-- 跨域资源读操作,禁止 -->
        <button onclick="senddata()">XMLHttpRequest请求</button>
    
        <script type="text/javascript">
        var xmlhttp=new XMLHttpRequest();
    
        function senddata(){
            xmlhttp.open("GET","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565884598468&di=bb6ccc7a3280b183e4e13c852bc8353c&imgtype=0&src=http%3A%2F%2Fs04.lmbang.com%2FM00%2FCA%2FDE%2FDpgiA1uPAOKAXmJfAADir1hWa-A750.gif",true);
            xmlhttp.send();
        </script>
    </body>
    </html>
    


    补充:

    为什么浏览器会使用同源策略?它想解决什么问题?
    首先,先谈一下cookie吧,cookie主要用于存储一些当前网站的一些数据,在一些旧的web开发中有的还会把用户登录信息存储到cookie中。那么,从安全的角度来考虑的话,你应该希望你的网站的cookie不能被另外一个网站使用(不然cookie中的数据就非常容易被别人窃取了),所以这就引入了域的概念,通过域来限制资源的使用,拦截跨域的资源请求。


    如何允许跨域



    有很多手段来解决跨域,但常见的用于解决跨域调用接口的问题就是CORS

    CORS

    • 如何允许跨域,一种解决方法就是目的域告诉请求者允许什么来源域来请求,那么浏览器就会知道B域是否允许A域发起请求。
    • CORS("跨域资源共享"(Cross-origin resource sharing))就是这样一种解决手段。

    CORS使得浏览器在向目的域发起请求之前先发起一个OPTIONS方式的请求到目的域获取目的域的信息,比如获取目的域允许什么域来请求的信息。

    此时目的域通常需要在响应头中添加以下信息:

    • Access-Control-Allow-Origin:用来声明什么域可以向当前域发起请求。
    • Access-Control-Allow-Methods:用来声明可以向当前域发起什么类型的请求。
    • Access-Control-Max-Age:用来指定本次OPTIONS请求的有效期,单位为秒,在此期间不用发出另一条OPTIONS请求。
    • Access-Control-Allow-Headers:用来允许你附加什么特殊的请求头来发起请求。【有些前后端分离项目会把token放到header中,这时候这个请求头就需要Access-Control-Allow-Headers来声明了】
      【在OPTIONS请求成功后,浏览器会把这些信息记录下来,用来判断发往目的域的请求是否需要拦截。如果OPTIONS请求失败,那么原本要发起的请求就不会发送。】


    但有时候发请求是不会触发OPTIONS请求的。如果这个请求符合以下条件的话:
    1.请求的方式是GET、POST或HEAD。
    2.请求头属于Accept,Accept-Language,Content-Language,Content-Type ,Viewport-Width。
    3.请求头中Content-Type属于application/x-www-form-urlencoded、multipart/form-data、text/plain中的一个。

    这种请求也被称为“简单请求”。



    简单请求的测试:

    下面的例子可以用于测试简单和非简单请求是否会发OPTIONS请求

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8" />
        <title>用于测试简单请求</title>
    </head>
    <body>
        <button onclick="senddata()">XMLHttpRequest请求</button>
        <script type="text/javascript">
        var xmlhttp=new XMLHttpRequest();
    
        function senddata(){
            xmlhttp.open("GET","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565884598468&di=bb6ccc7a3280b183e4e13c852bc8353c&imgtype=0&src=http%3A%2F%2Fs04.lmbang.com%2FM00%2FCA%2FDE%2FDpgiA1uPAOKAXmJfAADir1hWa-A750.gif",true);
    xmlhttp.send();
    
            //如果你有一个可以用来测试的接口,可以尝试把这一段注释了,来测试是否发送OPTIONS请求。
      //       xmlhttp.open("POST","http://localhost:8080/hello",true);
             //下面通过加了一个请求头,使得这个请求不是一个不发OPTIONS的请求。
    		// xmlhttp.setRequestHeader("Content-Type", "application/json")
      //       xmlhttp.send();
        }
        </script>
    </body>
    </html>
    


    后端的处理

    下面基于Spring MVC框架来说明后端如何返回返回CORS响应头(注:在spring mvc中,你可以直接使用@CrossOrigin来简单返回CORS响应头。)。
    前端请求测试代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8" />
        <title>用于测试OPTIONS</title>
    </head>
    <body>
        <!-- 跨域资源读操作,禁止 -->
        <button onclick="senddata()">XMLHttpRequest请求</button>
    
        <script type="text/javascript">
        var xmlhttp=new XMLHttpRequest();
    
        function senddata(){
            //如果你有一个可以用来测试的接口,可以尝试把这一段注释了,来测试是否发送OPTIONS请求。
            xmlhttp.open("POST","http://localhost:8080/hello",true);
             //下面通过加了一个请求头,使得这个请求不是一个不发OPTIONS的请求。
    		xmlhttp.setRequestHeader("Content-Type", "application/json")
            xmlhttp.send();
        }
        </script>
    </body>
    </html>
    

    当我们没有部署接口的时候,我们就可以看到,页面是发了一个OPTIONS请求的:

    而且,浏览器控制台也提示以下信息:



    当我们部署了接口的时候,我们先尝试不返回正规的CORS响应头。



    由于没有返回CORS响应头,所以OPTIONS没有请求到合适的CORS信息,所以请求就会被拦截,所以就会报下图的两个警告。



    当我们在响应中添加CORS响应头后,我们可以看到我们刚刚设置的CORS响应头被OPTIONS请求成功了。

    而且请求也被发出去了:



    对于不同编程语言的如何使用CORS,可以自查。



    补充:

    • 除了正常的,例如通过js来处理跨域的。还有一些沙雕的手法,通过修改浏览器来不进行同源策略就是其中一种(治标不治本)。

  • 相关阅读:
    nginx-1.8.1的安装
    ElasticSearch 在3节点集群的启动
    The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files
    sqoop导入导出对mysql再带数据库test能跑通用户自己建立的数据库则不行
    LeetCode 501. Find Mode in Binary Search Tree (找到二叉搜索树的众数)
    LeetCode 437. Path Sum III (路径之和之三)
    LeetCode 404. Sum of Left Leaves (左子叶之和)
    LeetCode 257. Binary Tree Paths (二叉树路径)
    LeetCode Questions List (LeetCode 问题列表)- Java Solutions
    LeetCode 561. Array Partition I (数组分隔之一)
  • 原文地址:https://www.cnblogs.com/progor/p/11361146.html
Copyright © 2011-2022 走看看