• 实现跨域访问的方法总结


    解决跨域问题的常用方法

    跨域, 是指调用方和被调用方的协议域名端口,不完全相同(即不同源),跨域的访问或调用会被浏览器禁止,因而跨域是浏览器端特有的,服务端无跨域问题。

    服务端代理

    服务端代理,又称为请求转发/反向代理

    原理:

    A站的页面跨域访问B站的服务端接口,A站请求自己的后端接口,A站的后端接口负责转发请求到B站,并将B站的响应返回给A站页面。

    适用场景:

    调用第三方服务接口

    优点:
    比较通用,可解决大多数跨域问题

    **缺点: **
    需要后端支持(提供转发接口),增加本站服务器负担,无法维持session状态

    示例

    系统A(A.com)对外提供一个邮件发送接口,可接收GET或POST方式传递参数(如email, subject, body等)数据。当系统b(b.com)需要使用到这个接口的功能时,并提供比较好的用户体验时,采取了通过ajax将用户填入的信息传递数据给这个接口,来实现发送邮件的目的。

    系统b的页面请求自身的后端接口proxy.php

    $.post(
        'http://b.com/proxy.php',
        {
            email:"impng@impng.com",
            subject:"ajax跨域之代理",
            body:"这里是邮件内容"
        },
        function(data){
            if(data == 1) alert('发送成功!');
        }
    );
    

    proxy.php转发请求到系统A

    $post = $_POST;
    $data = array(
                'email'     => $post['email'],
                'subject'   => $post['subject'],
                'body'      => $post['body'],
            );
    
    $url = 'http://A.com/ISendMail.php?';   // 系统A的发送邮件接口
    $url .= http_build_query($data);
    
    $res = file_get_contents($url);
    echo $res;
    

    JSONP

    原理:
    由于引用外部资源不受同源策略限制,如 <img> <link> <script>, 所以可通过动态插入<script>标签, 访问跨域的服务接口,只要跨域接口把数据组装成函数调用的形式,前端页面就可以获取到数据.

    优点:
    完全由前端控制,不需要后端支持,兼容性好。

    缺点:
    只能get方式(因为本质是加载js)

    示例:

    <!doctype html>
    
    <html>
    <head>
        <script>
        function loadContent() {
            var s = document.createElement('SCRIPT');
            s.src = 'http://www.anotherdomain.com/TestCrossJS.aspx?f=setDivContent'; //指定回调
            document.body.appendChild(s);
        }
    
        function setDivContent(v) {
            var dv = document.getElementById("dv");
            dv.innerHTML = v;
        }
        </script>
    </head>
    
    <body>
        <div id="dv"></div>
        <input value="Click Me">
    </body>
    
    </html>
    
    // 其中的www.anotherdomain.com/TestCrossJS.aspx是这样的,
    <script runat="server">
    void Page_Load(object sender, EventArgs e) {
        string f = Request.QueryString["f"];
        Response.Clear();
        Response.ContentType = "application/x-javascript";
        Response.Write(String.Format(@" {0}('{1}'); ", f, DateTime.Now)); //组装函数调用表达式
        Response.End();
    }
    </script>
    

    iframe监听hash

    在页面内嵌或动态生成指向别的网站的IFRAME,然后这2个网页间可以通过改变对方的anchor hash fragment来传输消息。改变一个网页的anchor hash fragment并不会使浏览器重新加载网页,所以一个网页的状态得以保持,而网页本身则可以通过一个计时器(timer)来察觉自己anchor hash的变化(h5 window.onhashchange),从而获取数据并作出响应。

    父页面

    <!doctype html>
    <html>
    
    <head>
        <meta charset="utf8" />
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <title>Test iframe cross domain</title>
        <script>
        var url = "http://localhost:8081/cross_sub.html";
        var oldHash = null;
        var timer = null;
    
        function getHash() {
            var hash = window.location.hash;
            if ((hash.length >= 1) && (hash.charAt(0) == '#')) {
                hash = hash.substring(1); //获得#后的值
            }
    
            return hash;
        }
    
        function sendRequest() {
            var d = document; //简写document
            var t = d.getElementById('request');
            var f = d.getElementById('ifrm');
            f.src = url + "#" + t.value + (new Date().getTime());//修改iframe.src的hash
        }
    
        function setDivHtml(v) {
            var d = document;
            var dv = d.getElementById('response');
            dv.innerHTML = v;
        }
    
        function idle() {
            var newHash = getHash();
    
            if (newHash != oldHash) {
                setDivHtml(newHash);
                oldHash = newHash;
            }
    
            timer = window.setTimeout(idle, 100); // 递归实现循环 定时检查自身hash的变化
        }
    
        window.onload = function (){
            timer = window.setTimeout(idle, 100);
        };
    
        window.name = 'parent';
        </script>
    </head>
        
    <!-- localhost:8080/cross_parent.html -->
    <body>
        <h1>THIS IS THE PARENT PAGE</h1>
        <input type="text" id="request" />
        <input type="submit" value="send" id="send" />
        <div id="response" style="margin: 30px; padding: 30px; border:1px dashed #ccc;">
            
        </div>
        <iframe src="http://localhost:8081/cross_sub.html" frameborder="0" id="ifrm" style="border:5px solid #ddd; padding:20px; 80%; margin:auto; display:block; height:300px; "></iframe>
    
        <script type="text/javascript">
            var sendBtn = document.getElementById('send');
            sendBtn.onclick = sendRequest;
        </script>
    </body>
    
    </html>
    

    子页面

    <!doctype html>
    <html>
    
    <head>
        <meta charset="utf8" />
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <title>Test iframe cross domain</title>
        <script>
        var url = "http://localhost:8080/cross_parent.html";
        var oldHash = null;
        var timer = null;
    
        function getHash() {
            var hash = window.location.hash;
            if ((hash.length >= 1) && (hash.charAt(0) == '#')) {
                hash = hash.substring(1);
            }
    
            return hash;
        }
    
        function sendRequest() {
            var d = document;
            var t = d.getElementById('request');
            var f = parent;
            //alert(f.document); //试着去掉这个注释,你会得到“Access is denied”
            f.location.href = url + "#" + t.value +( new Date().getTime() ); //修改父窗口的hash
        }
    
        function setDivHtml(v) {
            var d = document;
            var dv = d.getElementById('response');
            dv.innerHTML = v;
        }
    
        function idle() {
            var newHash = getHash();
    
            if (newHash != oldHash) {
                setDivHtml(newHash);
                oldHash = newHash;
            }
    
            timer = window.setTimeout(idle, 100);
        }
    
        window.onload = function() {
            timer = window.setTimeout(idle, 100);
        };
        window.name = 'sub';
        </script>
    </head>
    <!-- localhost:8081/cross_sub.html -->
    
    <body>
        <h1>THIS IS THE SUB PAGE</h1>
        <input type="text" id="request" />
        <input type="submit" value="send" id="send" />
        <div id="response" style="margin: 30px; padding: 30px; border:1px dashed #ccc;">
        </div>
    
    
        <script type="text/javascript">
            var sendBtn = document.getElementById('send');
            sendBtn.onclick = sendRequest;
        </script>
    
    </body>
    
    </html>
    

    window.name

    window 对象的name属性是一个很特别的属性,当该window的location变化,然后重新加载,它的name属性可以依然保持不变。那么我们可以在页面 A中用iframe加载其他域的页面B,而页面B中用JavaScript把需要传递的数据赋值给window.name,iframe加载完成之后,页面A修改iframe的地址,将其变成同域的一个地址,然后就可以读出window.name的值了。这个方式非常适合单向的数据请求,而且协议简单、安全。不会像JSONP那样不做限制地执行外部脚本。

    父页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>window.name test</title>
    </head>
    <body>
        <button onclick="toggleIfrmSrc()">切换iframe src</button>
        <iframe  id="ifrm" src="http://localhost:9200/a.html" frameborder="0" style=" 500px; height: 500px;"></iframe>
        <script>
            var $ = function(s ) {
                return document.querySelector(s);
            }
    
            function toggleIfrmSrc() {
                if (!oldUrl) {
                    oldUrl = ifrm.src;
                }
                var isCross = /:9200/.test(ifrm.src);
                var newUrl = isCross ? '/a-same.html' : oldUrl;
                ifrm.src = newUrl;
    
    
                console.log('subwin.name:', subwin.name); // 获取到
            }
    
            var oldUrl = '';
    
            var ifrm = $('#ifrm');
            var subwin = ifrm.contentWindow;
            console.log('subwin.name:', subwin.name); // 跨域,获取不到
    
    
        </script>
    </body>
    </html>
    

    子页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>window.name test </title>
    </head>
    <body>
        <h2>sub page, window.name</h2>
        <script>
        window.name = 'iamA';
    
        var c = 1;
        setInterval(function () {
            window.name += c;
        }, 2000);
        </script>
    </body>
    </html>
    

    document.domain

    仅仅是子域名不同,可改为同域。如:blog.exam.com, exam.com blog.examp.com/hello.html中,可设置 document.domain = 'exam.com';

    window.postMessage

    h5 api

    CROS

    需后端支持

  • 相关阅读:
    类BufferedImage
    Fileltem
    文件上传api——MultipartFile
    热插播 devtools
    生成banner
    maven 配置
    配置java环境变量
    u盘如何恢复存储量
    四则运算
    PM
  • 原文地址:https://www.cnblogs.com/stephenykk/p/8417318.html
Copyright © 2020-2023  润新知