zoukankan      html  css  js  c++  java
  • JavaScript(9)--- 跨域

    JavaScript(9)--- 跨域

    一、跨域原理(同源策略)

    在项目搭建的初期,因为现在项目基本上都是前后端分离,所以不可避免地会遇到跨域问题,而造成跨域的罪魁祸首就是浏览器的同源策略。所以要解决跨域,

    我们必须知道什么是浏览器的同源策略。

    1、什么是同源策略

    概念 它是一个著名的安全策略。所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同

    当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。

    注意 跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了

    2、同源策略限制什么

    概念 同源策略限制 从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。它的存在可以保护

    用户隐私信息,防止身份伪造等(读取Cookie)。

    同源策略限制内容有

    1、Cookie、LocalStorage、IndexedDB 等存储性内容
    2、DOM 节点
    3、AJAX 请求不能发送
    

    但是有三个标签是允许跨域加载资源

    1.<script src=xxx>
    2.<img src=xxx>
    3.<link href=xxx>
    

    也就是说这三个标签可以不受同源策略限制,这也是为什么使用<img>标签的时候,可以引用外部的服务器图片。

    解决跨域的方式很多,这里介绍两种最简单的方式:JSONPCORS


    二、JSONP

    原理: <script>是可以跨域的,通过动态创建script标签,然后利用src属性进行跨域。

    1、JavaScript示例

    前端代码

    <html lang="en">
    <head>
        <title>jsoup</title>
        <script type="text/javascript" src="/jquery/jquery-2.1.3.min.js"></script>
        <script>
            // 1.定义方法 这个是会被回调的函数
            function coming(data) {
                console.log(data);
            }
        </script>
        <script>
           //  2.动态拼接<script>标签,把需要调用的本地方法名传递给后端
            let url = "http://localhost:8088/getUser/1?callback=coming";
            // 平时都是手写<script src="">,现在我们在代码中动态构造script标签并设置src属性
            let script = document.createElement('script');
            script.type = "text/javascript";
            script.src = url;
            // 把script标签加入head(因为script标签本来也是在html的head中),并发起请求,后端响应后浏览器会自动执行返回的script片段
            document.getElementsByTagName('head')[0].appendChild(script);
        </script>
    </head>
    </html>
    

    后段代码

    @RestController
    public class UserController {
        @GetMapping(value = "/getUser/{id}")
        public String getUser(@PathVariable("id") String id, String callback) {
            // 拼接方法名 + 参数(这就会调用上面script中的coming方法)
            return callback + "({"username": "小小","age": 4 "})";
    
        }
    }
    

    2、jquery示例

    上面说过了,JSONP其实算是一种对同源策略规则的投机取巧,实现方式可以多种多样。JQuery对JSONP也有实现

    <html lang="en">
    <head>
        <title>jquery示例</title>
        <script type="text/javascript" src="/jquery/jquery-2.1.3.min.js"></script>
    </head>
    <body>
    <input type="text" id="result">
    <input type="button" onclick="onClick()" value="点击">
    </body>
    <script>
        /**
         * 照常使用ajax,只要把dataType改为"jsonp"即可。
         * JQuery在前端替我们做了两件事:
         * 1.URL后拼接方法名(随机生成)
         * 2.解析从后端得到的js片段,把正确的值传入success:function()
         * 
         * 后端还是要按原来的做 JQuery自动帮我们在URL里加了callback参数。
         */
        function onClick() {
            $.ajax({
                type: "GET",
                url: "http://localhost:8088/getUser/1",
                dataType: "jsonp",
                success: function(data){
                    $('#result').val(data.name);
                }
            });
        }
    </script>
    </html>
    

    总结

    1、JSONP都是GET和异步请求的,不存在其他的请求方式和同步请求,且jQuery默认就会给JSONP的请求清除缓存。
    2、JSONP优点是 兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是 仅支持get方法具有局限性。
    

    三、CORS

    1、CORS原理

    浏览器认为只要后端没返回CORS头(Access-Control-Allow-Origin),就认为后端不允许跨域,返回的数据不可靠。所以只要后端能够返回浏览器需要的请求头,

    即可跨域(响应数据就不会被同源策略抛弃),这个是表层原理。

    不过目前不是所有浏览器都支持该功能(会自动带上请求头),IE浏览器不能低于IE10。所以最终来看,CORS这种方案不需要前端做任何事情,只需后端配合即可

    2、示例

    前端代码

    <html lang="en">
    <head>
        <script type="text/javascript" src="/jquery/jquery-2.1.3.min.js"></script>
    </head>
    <body>
    <input type="text" id="result">
    <input type="button" onclick="onButtonClick()" value="get_button">
    </body>
    <script>
        /**
         * 普通AJAX,没有设置jsonp
         */
        function onButtonClick() {
            $.ajax({
                type: "GET",
                url: "http://localhost:8080/getUser/1",
                success: function(data){
                    $('#result').val(data.name);
                }
            });
        }
    </script>
    </html>
    

    后段代码

    方式一 方法上加@CrossOrigin

    @RestController
    public class UserController {
        /**
         * 在跨域方法上加@CrossOrigin即可完美解决跨域问题
         */
        @CrossOrigin("http://localhost:8088")
        @GetMapping(value = "/getUser/{id}")
        public User getUser(@PathVariable("id") String id) {
            User user = new User();
            user.setName("小小");
            user.setAge(4);
            return user;
        }
    }
    

    方式二 Controller上加@CrossOrigin

    @CrossOrigin还可以加载Controller上,这样Controller的所有方法都支持跨域。

    @RestController
    @CrossOrigin("http://localhost:8088")
    public class UserController {
    
        @GetMapping(value = "/getUser/{id}")
        public User getUser(@PathVariable("id") String id) {
            User user = new User();
            user.setName("小小");
            user.setAge(4);
            return user;
        }
    }
    

    方式三 @Bean配置跨域Filter

    @Configuration
    public class CorsConfig {
        @Bean
        public CorsFilter corsFilter() {
            //1.添加CORS配置信息
            CorsConfiguration config = new CorsConfiguration();
            //1) 允许的域,如果写*,那么cookie就无法使用了
            config.addAllowedOrigin("http://localhost:8088");
            //2) 是否发送Cookie信息
            config.setAllowCredentials(true);
            //3) 允许的请求方式
            config.addAllowedMethod("*");
            // 4)允许的头信息
            config.addAllowedHeader("*");
            // 5) 有效时长
            config.setMaxAge(3600L);
    
            //2.添加映射路径,我们拦截一切请求
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
    
            //3.返回新的CorsFilter.
            return new CorsFilter(configSource);
        }
    }
    

    总结 本人在实际开发中都是通过CORS解决跨域问题,而且是通过第三种方式配置全局的bean对象。


    参考

    1、同源策略与跨域

    2、javascript跨域的四种方式介绍

    3、什么是JS跨域访问?



    ``` 别人骂我胖,我会生气,因为我心里承认了我胖。别人说我矮,我就会觉得好笑,因为我心里知道我不可能矮。这就是我们为什么会对别人的攻击生气。 攻我盾者,乃我内心之矛(7)。 ```
  • 相关阅读:
    spring boot中创建ElasticSearch索引
    spring boot项目16:ElasticSearch-基础使用
    spring cloud项目07:网关(Gateway)(2)
    spring cloud项目06:网关(Gateway)(1)
    Ubuntu上MySQL多实例部署
    MySQL常用命令、配置汇总
    spring boot项目15:安全-基础使用(2)
    spring boot项目14:安全-基础使用(1)
    docker-compose mongodb 副本
    关于golang slice切片的一个问题
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/12347155.html
Copyright © 2011-2022 走看看