同源策略及jsonp实现跨域

1、浏览器的同源策略

同源策略/**SOP(Same origin policy)**是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

http://www.example.com/detail.html
https://www.example.com/detail.html 协议不同
http://api.example.com/detail.html 域名不同
http://www.example.com:8080/detail.html 端口不同

2、跨域解决方案

  • jsonp
  • document.domain + iframe 跨域
    此方案仅限主域相同,子域不同的跨域应用场景。
  • nginx 代理跨域
  • nodejs 中间件代理跨域
  • 后端在头部信息里面设置安全域名

3、jsonp实现跨域的原理

function foo(data){
  console.log(data);
}

var script = document.createElement("script");
script.src = 'http://localhost:8080/hello.php?callback=foo&username=zhangsan&password=123';
var head = document.getElementsByTagName("head")[0];
head.appendChild(script);
  • jsonp从本质上讲,是通过动态创建script标签,然后通过src属性发送跨域请求,服务器端响应数据格式为【函数调用】。

4、利用jQuery实现跨域

主要属性设置:

  • dataType
    必须为jsonp
  • jsonp
    jsonp属性用于设置自定义参数名,即callback=abc中的callback,后端会根据jsonp属性的值获取方法名,jquery默认是callback
  • jsonpCallback
    用于自定义回调函数名,即callback=abc中的abc
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jQuery中jsonp的使用</title>
    <script src="./jquery-1.12.4.js"></script>
    <script type="text/javascript">

        $(function (){
            $("#btn").click(function (){
                $.ajax({
                    type: 'get',
                    url: 'http://localhost:8080/jsonp.php',
                    dataType: 'jsonp',
                    jsonp: 'cb', //jsonp属性用于自定义参数名,即callback=abc中的callback,后端会根据jsonp属性的值获取方法名,jquery默认是callback
                    jsonpCallback: 'abc', //jsonpCallback属性用于自定义回调函数名,即callback=abc中的abc
                    success: function (data){
                        console.log(data);
                    },
                    error: function (){
                        console.log("error");
                    }
                });
            });
        })

    </script>
</head>
<body>
<input type="button" value="点击" id="btn" />
</body>
</html>

后端:

<?php

	$cb = $_GET['cb'];
	$arr = array("username"=>"张三", "password"=>"123");
    echo $cb.'('.json_encode($arr).')';

?>

5、模仿jQuery实现跨域


function ajax(obj){
    var defaults = {
      type: 'get',
      async: true,
      url: '#',
      dataType: 'text',
      jsonp: 'callback',
      data: {},
      success: function (data){
          console.log(data);
      }
    };

    for (var objKey in obj) {
        defaults[objKey] = obj[objKey];
    }

    if (defaults.dataType == 'jsonp'){
        ajax4Jsonp(defaults);
    } else {
        ajax4Json(defaults);
    }

}

function ajax4Jsonp(defaults){
    //  回调函数名称
    //  jQuery中的默认函数名为:expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
    var version = "1.12.4";
    var callbackName = "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ) + "_" + (new Date().getTime());
    //  如果传递了回调函数名称
    if (defaults.jsonpCallback){
        callbackName = defaults.jsonpCallback;
    }

    //  定义回调函数,由服务器响应内容来调用,向window中添加方法
    window[callbackName] = function (data){
        //  调用success方法
        defaults.success(data);
    };

    //  入参的处理
    var param = '';
    for (var attr in defaults.data){
        param += '&' + attr + "=" + defaults.data[attr];
    }

    //  动态创建script标签
    var script = document.createElement("script");
    script.src = defaults.url + "?" + defaults.jsonp + "=" + callbackName + param;
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(script);
}

function ajax4Json(defaults){
    //  创建XMLHttpRequest对象
    var xhr = null;
    if (window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }

    //  处理get请求参数
    var param = null;
    if (defaults.type == "get"){
        for (var deKey in defaults.data) {
            param += "&" + deKey + "=" + defaults.data[deKey];
        }
        defaults.url += "?" + param;
    }

    // 准备发送
    xhr.open(defaults.type, defaults.url, defaults.async);

    //  处理post请求参数
    if (defaults.type == "post"){
        param = defaults.data;
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    }

    //  执行发送
    if (param){
        xhr.send(param);
    } else {
        xhr.send(null);
    }

    //  处理异步和同步
    if (!defaults.async) {
        //  如果是同步
        if (defaults.dataType == "json"){
            return JSON.parse(xhr.responseText);
        } else {
            return xhr.responseText;
        }
    }

    //  如果是异步
    xhr.onreadystatechange = function (){
        if (xhr.readyState == 400){
            if (xhr.status == 200){
                var response = xhr.responseText;
                if (defaults.dataType == "json"){
                    defaults.success(JSON.parse(response));
                } else {
                    defaults.success(response);
                }
            }
        }
    };
}

测试:

        // ajax({
        //     type:'get',
        //     // url:'http://localhost:8080/jsonp.php',
        //     dataType:'json',
        //     success:function(data){
        //         console.log(data.username,data.password);
        //     }
        // });

        ajax({
            type:'get',
            url:'http://localhost:8080/jsonp.php',
            dataType:'jsonp',
            data:{username:'zhangsan',password:'123'},
            jsonp:'cb',
            jsonpCallback:'abc',
            success:function(data){
                console.log(data.username,data.password);
            }
        });
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值