• 跨域通信/跨域上传浅析


    web项目跨域问题主要包括跨域通信和跨域上传,下面对这两方面分别做一个分析,具体项目中用哪个方案要看项目具体需求。

    跨域通信

    • jsonp
    • hash
    • server proxy
    • window.name
    • cors
    • postmessage
    • redirect

    jsonp

    原理:发起一个GET请求,回调函数带到请求参数中,把数据发送过去

    坏处:服务器需要支持jsoncallback参数

    好处:业界比较通用的方案,包括打点等操作都可以用类似技术

    浏览器支持:chrome/firefox/safari/opera/ie6+

    client:

    //jquery
    $(function(){
        $.ajax({
            url: 'http://bbb.com:8888/crossdomain/jsonp.php',
            dataType: 'jsonp',
            jsonp : 'callback', //指定callback参数名
            data: {name: 'ysj'} //数据
        }).done(function(result){
            alert(result) // {code:200}
        })
    })
    //实际请求:http://bbb.com:8888/crossdomain/jsonp.php?callback=jQuery111108173922670539469_1410615060808&name=ysj&_=1410615060809  
    
    //native js
    var temp = document.createElement('script');
    temp.src = 'http://bbb.com:8888/crossdomain/jsonp.php'
          + '?callback=jsonpCallback&name=ysj'; //设置callback参数
    document.body.appendChild(temp)
    temp.parentNode.removeChild(temp);
    
    function jsonpCallback(result) {
        alert(result) // {code:200}
    }

    server:

    $callback = $_GET['callback'];
    echo $callback . "({code:200})";

    hash

    原理:父页面把参数设置设置到子iframe的hash,子iframe监听hash变化,把响应的数据设置到父页面的hash

    坏处:需服务器对应支持,目前hash比较常用于路由,用于通信不太合适

    好处:无

    浏览器支持:chrome/firefox/safari/opera/ie6+

    代码略

    server proxy:

    原理:a域请求b域,在a域设置一个proxy服务器脚本页面,接受a的参数,在通过发起一个http请求拿b域的内容,再返回给a域

    坏处:在a域服务器需要增加一个proxy页面

    好处:比较通用的方案

    浏览器支持:chrome/firefox/safari/opera/ie6+

    代码略

    window.name

    原理:a域请求b域的页面,b加载完后设置响应数据到window.name,再重定向到a的一个页面,此时window.name并没有改变

    坏处:b域需重定向到a域的一个处理页面

    好处:无

    浏览器支持:chrome/firefox/safari/opera/ie6+

    代码略

    cors(跨域资源共享):

    原理:服务器设置可访问性Access-Control-Allow-Origin: *,浏览器ajax取数据

    坏处:需要服务器特殊处理

    好处:有比较好的未来

    浏览器支持:chrome/firefox/safari/opera/ie10+

    代码略

    postmessage:

    原理:利用html5的postmessage api跨域穿数据

    坏处:兼容性

    好处:有比较好的未来

    浏览器支持:chrome/firefox/safari/opera/ie10+

    代码在下面跨域上传中演示

    redirect:

    原理:a域iframe请求b域,把url带上,b域把response带上,返回到a域的handler页面

    坏处:有安全隐患

    好处:简单又浏览器支持良好的方案

    浏览器支持:chrome/firefox/safari/opera/ie6+

    代码在下面跨域上传中演示

    跨域上传

    • cors
    • redirect
    • postmessage

    cors

    原理:利用XMLHttpRequest2+FormData,服务器设置Access-Control-Allow-Origin: *,跨域资源访问这个特性,加上html5的FormData可以发送文件的特性。

    坏处:需要服务器设置支持跨域访问 Access-Control-Allow-Origin: *

    好处:又比较好的未来

    浏览器支持:chrome/firefox/safari/opera/ie10+

    client:

    document.forms[0].onsubmit = function() {
        var xhr = new XMLHttpRequest();
        var data = new FormData(document.forms[0]);
        xhr.open('POST' , this.action)
        xhr.onload = function(){
            console.log(xhr.responseText)
        }
    
        xhr.send(data)
        return false
    }

    server:

    header("Access-Control-Allow-Origin: *");
    echo "{code:200}";

    redirect

    原理:a域表单提交到b域,a的表单target指向a域的一个iframe,b域重定向到a域的结果页面,把数据带上。需要浏览器发送一个redirect参数,服务器检查到有这个参数,则重定向到结果页面,把内容带到参数上面

    坏处:服务器和客户端特殊参数redirect处理

    好处:支持所有浏览器

    浏览器支持:chrome/firefox/safari/opera/ie6+

    client:

    <form method="post" action="http://bbb.bbb.com:8888/crossdomain/redirect.php" target="_iframe">
    <input type="hidden" name="redirect" id="redirect"> 
    <input type="file" name="Filedata">
    <button type="submit">submit</button>
    </form>
    <iframe id="_iframe" name="_iframe"></iframe>
    
    document.forms[0].onsubmit = function() {
        document.getElementById('redirect').value = window.location.href.replace(//[^/]*$/,'/result.html?%s'); //设置redirect参数值
    
        var iframe = document.getElementById('_iframe')
        iframe.onload = function(){
            console.log(iframe.contentDocument 
                ? iframe.contentDocument.body.innerHTML 
                : iframe.document.body.innerHTML) // {code:200}
        }
    }

    redirect页面

    document.body.innerText=document.body.textContent=decodeURIComponent(window.location.search.slice(1)); //把参数中的数据写入文档

    server:

    $redirect = isset($_REQUEST['redirect']) ?
                stripslashes($_REQUEST['redirect']) : null;
    $json = '{code:200}';
    
    //有redirect参数,则重定向。需要注意的是服务器需要设置一个白名单,符合的才给予重定向,否则有安全问题
    if ($redirect) {
        //页面重定向,把返回数据替换掉redirect url中的%s
        header('Location: '.sprintf($redirect, rawurlencode($json))); 
    }

    postmessage

    原理:a域准备好参数通过postmessage发送到b域的postMessageAPI页面,这个页面把数据用XHR+FormData的方式提交a域请求的url,postMessageAPI再把返回的数据postmesage到a域的页面

    坏处:b端服务器需准备一个postmessageAPI页面

    好处:有比较好的未来

    浏览器支持:chrome/firefox/safari/opera/ie10+

    client:

    <form method="post">
    <input type="file" name="Filedata" id="file">
    <button type="submit">submit</button>
    </form>
    <iframe src="http://bbb.com:8888/crossdomain/postMessage.html"></iframe>
    
    $('form').submit(function(){
        var iframe = $('iframe')[0];
        //向iframe的postmessate api发送消息
        iframe.contentWindow.postMessage({
            url : 'http://bbb.com:8888/crossdomain/postMessage.php',
            dataType:'json',
            data : {
                file : $('input[type=file]')[0].files[0] //把文件数据传过去
            },
            contentType:false,
            processData:false
    
        }, iframe.src)
    
        return false;
    })
    
    //拿到postmessageAPI返回过来的消息
    $(window).on('message', function(e){
        var e = e.originalEvent;
        alert(e.data) // {code:200}
    })
    

      

    postmesage.html/postmessagetAPI页面

    //等待接受消息
    $(window).on('message', function(e){
        var e = e.originalEvent;
        var options = e.data;
        var truedata = options.data;
        var formdata = new FormData()
        for(var prop in truedata) {
            formdata.append(prop,truedata[prop]);
        }   
        options.data = formdata;
        //向postmessage.php发送ajax请求,都在b域,不跨域
        $.ajax(options).always(function(result){
            //把响应数据再postmessage到请求的页面
            e.source.postMessage(result.responseText, e.origin)
        })
    })
    

      

    server: postMessaget.php

    echo "{code:200}";
    

    跨子域通用方案

    原理:a域aaa.aaa.com,b域bbb.aaa.com。客户端和服务器返回都设置document.domain = 'aaa.com'

    坏处:有安全隐患

    好处:比较方便

    浏览器支持:chrome/firefox/safari/opera/ie7+

    server:

    //可以设置为客户端传来的domain参数,但需要白名单
    <echo> "<script>document.domain='aaa.com'</script>";
    <echo> "{code:200}";
    

    此方案有个需要注意的地方:ie下面对长度小于5个字符的短域名不能设置domain,例如www.uc.cn

    相关代码:https://github.com/aoto/cross-domain

  • 相关阅读:
    源码剖析Django REST framework的请求生命周期
    Django REST framework中的版本控制
    Django REST framework反向生成url
    Django的ModelForm
    SQL Server 2008 R2导出数据脚本的方法
    未在本地计算机上注册 Microsoft.Jet.OLEDB.4.0 提供程序
    Webservice发布出现 测试窗体只能用于来自本地计算机的请求
    StreamWriter和StremReader简单的用法
    (转)PHP下编码转换函数mb_convert_encoding与iconv的使用说明
    (转)PHP中构造函数和析构函数解析
  • 原文地址:https://www.cnblogs.com/aotoYu/p/4027430.html
Copyright © 2020-2023  润新知