跨域请求解决方案

浏览器的同源策略

浏览器有个要求,当前页面和要请求的资源,必须得在同一个源内。
同源就是,同协议,同域名,同端口。
如果不同源,浏览器会阻止这次请求,浏览器阻止的!与ajax和http无关。
这个问题叫跨域。
浏览器认为,只要没有明确允许,就是拒绝!
浏览器不允许的跨域,仅仅是针对ajax。

解决跨域请求

该文章的代码运行在服务器环境下

  1. 前端的解决方案,不用ajax,用jsonp的方式解决
    什么是jsonp?
    利用html标签可以跨域的特点,解决跨域问题
    利用script标签,引入外部资源,实现跨域请求
    第一步:
    jsonp.js
var d = "这是js中的数据";

jsonp.txt

var d = "txt";

jsonp.php

<?php
    // print "var a = 'php';";
    // $data = "'这是php要返回的数据'";
    // "var a = '这是php要返回的数据'";
    // echo "var a = ".$data;
    echo "function fn(){console.log('hello php')}";
?>

jsonp.html

<!-- <script src="data/jsonp.js"></script> -->
<!-- <script src="data/jsonp.txt"></script> -->
<script src="data/jsonp.php"></script>
<script>
    // console.log(d);
    // script标签将引入的资源 返回的数据,作为js代码执行了!
    // console.log(d);
    // script标签将引入的资源 返回的数据,作为js代码执行了!
    // console.log(a);
    // console.log(a);
    // 所以引入的文件返回的值会被js解析
    fn();
</script>

第二步:
jasonp2.html

<script>
	// 在这里定义函数fn
    function fn(res){
        // console.log("html");
        
        console.log(res);
    }
    // 函数在执行时,可以发送参数,实参
    // 函数在定义时,可以接受参数,形参
</script>

jsonp2.php

<?php
    $data = "hello";
	// 在这里执行函数fn,对fn进行传参,注意传入的参数是否字符,下面的代码相当与在js中执行的代码为fn('hello')
    echo "fn('". $data ."')";
?>

第三步:
jsonp3.html

    // 有script标签
    // 设置src属性,要请求的跨域地址
    // 在请求的文件中,还需要一个函数等待被请求到的资源返回的函数执行

    // jsonp("",function(){},data);

    document.onclick = function(){
        let url = "http://127.0.0.1/jsonp/data/jsonp3.php";
        jsonp(url,function(res){
            console.log(res);
        },{
            user:"root",
            pass:678
        });
    }

    // 要发送的数据,实在是太丑了,直接在写字符,不好看
    // "user=admin&pass=123"
    // 处理处理,处理成对象,多好看
    // {user:"admin",pass:123}

    function jsonp(url,cb,data){
        // 处理要发送的数据,处理成这种格式:"user=admin&pass=123"
        data = data || {};
        let str = "";
        for(var key in data){
            str += `${key}=${data[key]}&`;
        }
        let t = new Date().getTime();
        str = str + "__qft="+t;
        // 创建一个script标签
        var script = document.createElement("script");
        // 设置要请求的资源地址,拼接要发送的数据
        // jsonp只能get方式发送数据,因为只有url在连接后台,没有xhr对象
        script.src = url + "?" + str;
        // 将script标签插入页面
        document.body.appendChild(script);
        // 使用window,在局部声明全局函数,准备被后台返回的数据解析后,执行
        window.fn = function(res){
            cb(res);
        }
    }

isonp3.php

<?php
	// 接收数据
    // $_GET[""];
    $u = $_REQUEST["user"];
    $p = $_REQUEST["pass"];

    $data = "hello 这是php接收到的数据,又还给你了:".$u."---".$p;
    
    echo "fn('".$data."')";
?>

第四步:
jsonp.html

    document.onclick = function(){
        let url = "http://127.0.0.1/jsonp/data/jsonp4.php";
        jsonp(url,function(res){
            console.log(res);
        },{
            user:"root",
            pass:678,
            // 根据后台规定的字段名,随便传个函数名过去,让后台返回值后,能被script解析
            cbn:"zxc",
            // 为了实现前端的封装思想,为了适应后台不断变化的地址,将后台要接受的字段名,传给自己的函数
            fieldName:"cbn"
        });
    }
    function jsonp(url,cb,data){
        data = data || {};
        let str = "";
        for(var key in data){
            str += `${key}=${data[key]}&`;
        }
        let t = new Date().getTime();
        str = str + "__qft="+t;
        var script = document.createElement("script");
        script.src = url + "?" + str;
        document.body.appendChild(script);
        
        var b = data.fieldName;
        var a = data[b];
        window[a] = function(res){
            cb(res);
        }
    }

    // 当对象的属性是变量时,要使用[]语法包裹变量

jasonp.php

<?php

    $u = $_REQUEST["user"];
    $p = $_REQUEST["pass"];
    $cbn = $_REQUEST["cbn"];

    $data = "hello 这是php接收到的数据,又还给你了:".$u."---".$p;
    
    echo $cbn."('".$data."')";

?>

根据以上步骤详细了解了如何用jsonp解决跨域请求问题,可以对其进行封装,方便之后的调用
封装的函数如下:

function jsonp(url,success,data){
    data = data || {};
    let str = "";
    for(var key in data){
        str += `${key}=${data[key]}&`;
    }
    let t = new Date().getTime();
    str = str + "__qft="+t;
    var script = document.createElement("script");
    script.src = url + "?" + str;
    document.body.appendChild(script);
    
    window[data[data.fieldName]] = function(res){
        success(res);
    }
}
// 封装置后的调用形式,如:jsonp(url,success,data)
// url:为支持jsonp跨域的请求地址
// success:请求的表示成功之后,执行的回调函数
// data:要发送给后台的数据,对象形式
	// 其中:
		// fieldName属性保存的是后台接收的 要执行的函数名所在的字段名
		// 根据后台接收的字段名,将随便写的函数名传给后台
  1. 后台的解决方案
    CORS,服务器代理
    CORS的原理:在后台设置,允许所有的来源请求,不会被浏览器阻止
    代码如下:
<script src="../ajax.js"></script>
<script>
    document.onclick = function(){
        ajax({
            url:"http://127.0.0.1/CrossDomain/data/data.php",
            success:function(res){
                console.log(res);
            }
        })
    }
</script>
<?php
	// 下面三行代码就是后台的解决方案
    header("Access-Control-Allow-Origin:*");
    header("Access-Control-Request-Methods:GET, POST, PUT, DELETE, OPTIONS");
    header('Access-Control-Allow-Headers:x-requested-with,content-type,test-token,test-sessid');

    echo "允许所有来源访问的资源";
?>
  1. 服务器代理
    当客户端A请求服务器B时,A和B不在同一个源内,如果在本地,搭建一个服务器C,使用服务器C请求服务器B的数据(不允许跨域是浏览器的安全机制,服务器之间的数据交互没有浏览器),将服务器B的数据,拿到服务器C中,服务器C和客户端A在同一个源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值