zoukankan      html  css  js  c++  java
  • JS跨域:jsonp、跨域资源共享、iframe+window.name

    JS中的跨域

    请求跨域有好多种,

    一、跨域资源共享:

    也就是设置服务端的header,可以指定哪些域名可以请求,也是最简单的跨域方式(自我感觉),并且可以支持post等等。

    //指定允许其他域名访问
    'Access-Control-Allow-Origin:*'//或指定域
    //响应类型
    'Access-Control-Allow-Methods:GET,POST'
    //响应头设置
    'Access-Control-Allow-Headers:x-requested-with,content-type'

    二、jsonp

    由于浏览器的同源策略,所以ajax不能直接跨域请求数据,我们把浏览器的安全策略组关掉(也就是关掉同源策略)就可以啦,当然这是开个玩笑。想了解可以访问这个网站:https://www.cnblogs.com/zhongxia/p/5416024.html

    上面说的是ajax会被同源策略拦截下来,但是script中的src并不会被拦截,我们可以利用这个特性实现跨域:

    <script>
            //下面就输出你在服务端请求的数据
            function dosomething(data){
                console.log(data);
            }
        </script>
        //src 就是你想要请求的地址,cb是请求时带的参数,这是必须要加的,因为上面的函数名也是这个
        <script src="http://localhost:8080/ChickensSys/backDate?cb=dosomething"></script>

    服务端要做相应的配合,这边是用javaweb来调试:在doGet函数里面添加这些代码:

            response.setContentType("text/html");
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            String cbString = request.getParameter("cb");
            PrintWriter out = response.getWriter();
            out.println(cbString + "("this is jsonP ")");
            out.flush();
            out.close();

    仔细看:out.println(cbString + "("this is jsonP ")");

    我们把参数结果带入进去,可以发现输出的是cb("this is jsonP");相当于是调用这个函数,没错,结果就是这样。

    你会看到页面的控制台打印了this isjsonP。

    结论:我们用src(不会被同源策略拦截)请求别的域名的数据,返回的结果放在已定义好的函数参数里面并且执行这个函数,然后你要对数据做哪些操作就可以在函数里面随便操作。

    三、window.name + iframe跨域获取数据

    这个的原理和jsonP差不多吧,也是利用src,不过这次是利用iframe(可以理解html中一个内嵌页面,也可以包含一个html文件)的src和window.name的特性来跨域, window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。也就是你第一次设置后,不管你的iframe重定向到哪个页面,window.name都不会变。

         <script type="text/javascript"> 
        let iframe = document.createElement('iframe');
             //src你请求的地址,此时会报错,说你跨域了
        iframe.src = 'http://localhost:8080/ChickensSys/backDate';
        document.body.appendChild(iframe);
        iframe.onload = function() {
            //在本地新建空白的proxy.html因为上面报错了,这边赶紧重定向到本地的proxy.html
          iframe.src = 'proxy.html';
    //contentWindow属性是指指定的frame或者iframe所在的window对象。 console.log(iframe.contentWindow.name) }; </script>

    服务端需要相应的配合:

    out.println("<script>window.name = "this is CORS</script>");

    预期结果跟我们想的一样,一开始报错,我们重定向到本地后就没报错,输出结果也是没错的,因为服务端输出的是一个脚本,window.name=" ";还记得上面讲过window.name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化)。但是为什么会一直调用onload函数呢,因为在onload函数中又被重定向所以又一次调用,跟递归差不多意思。既然可以拿到数据,那我们下面来改进下,让它不报错,并只拿到一次数据。

        <script>
        let iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        var state = 0;
        iframe.onload = function() {
            //重定向完,可以取window.name的数据了,这边可以对数据进行处理
          if(state === 1) {
              var data = iframe.contentWindow.name;
              console.log(data);
              //移除这个节点,其实上面display:none已经对dom无影响了,这个加了保险
              document.body.removeChild(iframe);
              //当下面的iframe.src执行到时,也就是第一次onload,迅速重定向到本地
          } else if(state === 0) {
              state = 1;
              iframe.src = 'proxy.html';
          }
        };
        iframe.src = 'http://localhost:8080/ChickensSys/backDate';
        document.body.appendChild(iframe);
        </script>

    运行结果:

    只有一次请求。

    上面只是讲下原理,我们可以对上面做个封装,封装成一个函数,方便以后用:

        <script>
        //url是请求的地址,handle是处理数据的函数
        function getDataWithIframe(url, handle){
        let iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        var state = 0;
        iframe.onload = function() {
            //重定向完,可以取window.name的数据了,这边可以对数据进行处理
          if(state === 1) {
              handle(iframe.contentWindow.name);
              //移除这个节点,其实上面display:none已经对dom无影响了,这个加了保险
              document.body.removeChild(iframe);
              //当下面的iframe.src执行到时,也就是第一次onload,迅速重定向到本地
          } else if(state === 0) {
              state = 1;
              iframe.src = 'proxy.html';
          }
        };
        iframe.src = url;
        document.body.appendChild(iframe);
        }
        let url = 'http://localhost:8080/ChickensSys/backDate';
        getDataWithIframe(url, function(data){
            console.log('这是请求来的数据:' + data);
        })
        </script>

    总结:看了好多跨域,大部分都是通过src来跨域的,但好像通过src的都只能是get请求,比如刚说的jsonP和iframe+window.name的方式都是通过get来请求数据,而且都是需要要后端进行相应的配合,比如jsonP需要加个cb()来执行函数,iframe需要<script>window.name=" "</script>来执行赋值语句,第一种设置后端的header的方式倒是可以支持post请求,真是又简单又好用。。。

  • 相关阅读:
    作业16
    递归函数
    三元表达式与生成式
    迭代器与生成器
    作业15
    装饰器
    作业14
    string的入门与进阶
    修理牧场(优先队列)
    旅游规划
  • 原文地址:https://www.cnblogs.com/doudoublog/p/8652213.html
Copyright © 2011-2022 走看看