web前端都会去了解的技术文

Web 跨域

2015-11-09  本文已影响339人  KeKeMars

为什么需要跨域?

浏览器 同源策略 (域名、协议、端口相同)限制其他网页对本网页进行非法篡改, 只有带有 src 属性的标签才允许跨域(<img> <iframe> <script>)

JSONP

JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。利用<script/>标签对javascript进行动态解析来实现(其实也可以用eval函数),然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。

IE 兼容

P3P 规范让 IE 跨域接受第三方 cookie

header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');

原理

1.首先在客户端注册一个callback, 然后把callback的名字传给服务器。

  1. 此时,服务器先生成 json 数据。
  2. 然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp.
  3. 最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
  4. 客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)

缺点

代码示例

原生实现JSONP跨域
// 客户端
<script>
    // 这是回调方法
    function cb(data){
        alert(data.website);
    }
</script>
<!--这是跨域请求的代码,切记,这段代码要在回调函数之后-->
<script src="http://172.22.22.120/new/ajax_jsonp.php?callback=cb"></script>
<!-- 服务端 -->
<?php
    $cb = htmlspecialchars($_GET['callback']);  // 注意了,这里要做好过滤,防止xss攻击
    echo $cb,'(',json_encode(array('website'=>'hcoding')),')';  // 返回客户端的数据为:cb({"name":"hcoding"})  这是一段js代码
?>
AJax实现JSONP

客户端代码:

<script>
    // 客户端使用getJSON方法请求另一台机子上的脚本
    // 浏览器会生成一个随机的callback参数
    $.getJSON("http://172.22.22.120/new/ajax_jsonp.php?callback=?",function(json){
        alert(json.website);
    });
// $.getJSON简单易用,但就是不能指定回调函数。
</script>
//或者
<script>
    $.ajax({
        type : "GET",
        url : "http://172.22.22.120/new/ajax_jsonp.php",
        dataType : "jsonp",    // 数据格式指定为jsonp
        jsonp: "callback",     // 服务点通过这个键值获取回调方法
        jsonpCallback:"cb",   // 指定回调方法
        success : function(json){

        },
    });   

    // 回调方法
    function cb(data){
        alert(data.website);
    }
</script>

服务端PHP脚本代码:

<?php
    $cb = htmlspecialchars($_GET['callback']);  // 注意了,这里要做好过滤,防止xss攻击
    echo $cb,'(',json_encode(array('website'=>'hcoding')),')';  // 返回客户端的数据,这是一段js代码
?>

CORS (IE8+) 推荐使用

跨源资源共享标准( cross-origin sharing standard ) 使得以下场景可以使用跨站 HTTP 请求:

相关Header

服务端设置Header: (ResponseHeader)

HTTP 请求头(RequestHeader)

注意这些请求头信息都是在请求服务器的时候已经为你设置好的,当开发者使用跨域的XMLHttpRequest的时候,不需要手动的设置这些头信息.

请求方式

安全问题:不要依赖CORS当中的权限制度,应当使用更多其它的措施来保障,比如OAuth2

iframe 隐藏表单,进行POST提交(非现代浏览器)

window.name

有三个页面:

实现起来基本步骤如下:

<script type="text/javascript">
    window.name = 'I was there!';    // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
                                     // 数据格式可以自定义,如json、字符串
</script>
<script type="text/javascript">
    var state = 0, 
    iframe = document.createElement('iframe'),
    loadfn = function() {
        if (state === 1) {
            var data = iframe.contentWindow.name;    // 读取数据
            alert(data);    //弹出'I was there!'
        } else if (state === 0) {
            state = 1;
            iframe.contentWindow.location = "http://a.com/proxy.html";    // 设置的代理文件
        }  
    };
    iframe.src = 'http://b.com/data.html';
    if (iframe.attachEvent) {
        iframe.attachEvent('onload', loadfn);
    } else {
        iframe.onload  = loadfn;
    }
    document.body.appendChild(iframe);
</script>
<script type="text/javascript">
    iframe.contentWindow.document.write('');
    iframe.contentWindow.close();
    document.body.removeChild(iframe);
</script>

总结起来即:iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

HTML5 postMessage(IE8+)

otherWindow.postMessage(message, targetOrigin);

a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样
                                        // 若写成'http://c.com'就不会执行postMessage了
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html中的代码:

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通过origin属性判断消息来源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 弹出"I was there!"
            alert(event.source);  // 对a.com、index.html中window对象的引用
                                  // 但由于同源策略,这里event.source不可以访问window对象
        }
    }, false);
</script>

用nginx/Apache把B网站的数据url反向代理。(数据转发)

参考

上一篇下一篇

猜你喜欢

热点阅读