JavaScript--跨域

  跨域

    什么是跨域?

      跨域请求就是不同域的网站之间的文件数据之间的传送 ,由于浏览器的同源策略机制(基于安全,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性)Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准; 但用户往往需要从其他域设置或获取数据。

    但是,在Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>);所以 一般利用这个特性来实现‘跨域’

  

  什么是jsonp请求?

    jsonp请求跟ajax请求是不一样的,jsonp请求是可以实现跨域访问,而ajax请求是无法实现跨域访问的。那什么是jsonp?

      JSONP的全称为“JSON with Padding” 可以译为‘json的装饰物’。那为什么会有叫JSONP的东西出现?我们知道现在唯一可以实现跨域的方式只有一种:引用js文件,把服务器端的数据设法装到js文件里,在客户端引用js文件,客户端就可以调用和进一步处理了。 恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP。JSONP协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。问题来了:为什么会有callback函数?

    先抛开JSONP!前面说到<script>标签有跨域能力,只需外部引入js文件就可以实现跨域访问。如:

  

<script type="text/javascript" src="http://localhost:3000/Scripts/jquery-1.4.4.min.js"></script>

    这样就可以访问到端口3000的文件了。根据上面的分析,很容易想到:利用js构造一个script标签,把json的url赋给script的src属性,然后把script标签插到DOM里,让浏览器去获取。实践如下:

function CreateScript(src) {
                $("<script></script>").attr("src", src).appendTo("body")
                }
                添加一个按钮事件来测试一下:

                $("#getJsonByHand").click(function () {
                    CreateScript("http://localhost:2701/home/somejson")
                })

    实际上,浏览器会报错。因为script标签加载完毕后会立即把相应当做js(此时传入的是json文件)执行,很明显,json里面装的只是数据,不是js合法的语句,所以会报错。怎么办呢?回到JSONP里的要点:callback函数    如果把上面的json放到一个callback函数里是最简单的方法类似这样:                                 callback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})  里面的数据就是前端想要的数据。

    由于服务器不知道客户端的回调函数会是什么(什么乱七八糟的名字都有),所以统一协议叫做callback    现在来添加一下回调函数:

    

function jsonpcallback(json) {
        console.log(json)
    }
    改一下参数:
    $("#getJsonpByHand").click(function () {
        CreateScript("http://localhost:2701/home/somejsonp?callback=jsonpcallback")
    })

    服务器返回jsoncallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"}),我们也写了jsonpcallback方法,当然会执行。OK顺利获得了json。没错,到这里就是jsonp的全部。

  

简单来说:利用Script标签的跨域能力和跟服务器约定好返回callback,进行调用得到数据,这就是‘jsonp’。

    来一个具体的实例:仿写百度搜索

      前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp跨域</title>
    <script>
        document.addEventListener('DOMContentLoaded',function(){
            var keyword = document.querySelector('#keyword');
            var suggest = document.querySelector('#suggest');
        //这是百度搜索的api cb指的是callback 
            var searchUrl = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?json=1&cb=getData&wd=';

            var timer; 
            keyword.oninput = function(){
                var _keyword =  keyword.value;
                //清除上一次的搜索关键字
                clearTimeout(timer);
                //减少请求次数
                timer = setTimeout(function(){
            //动态创建script标签
var script = document.createElement('script'); script.src = searchUrl+_keyword; document.head.appendChild(script); }, 500); } window.getData = function(data){ console.log(data); var res = data.g; suggest.innerHTML = res.map(function(item){ return `<option value="${item.q}">${item.q}</option>`; }).join(''); } }) </script> </head> <body> <input type="text" id="keyword" list="suggest"> <datalist id="suggest"> </datalist> </body> </html>

  php代码:

  

<?php
    // header("Content-type:text/html;charset=utf-8");


    // 百度下拉搜索
    $keyword = isset($_GET['key']) ? $_GET['key'] : '';
    $url = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=' . $keyword.'&json=1&cb=getData';

    $res = file_get_contents($url);

    // 解决乱码问题
    $res = mb_convert_encoding( $res, 'UTF-8', 'UTF-8,GBK,GB2312,BIG5');

    $res = str_replace(array('getData(',');'), '', $res);

    echo $res;
    
?>

    可以看出:jsonp请求是单向请求, 而且是在服务器允许的情况下才可以请求数据。 

 再来看看另一种跨域请求的方式:CORS请求

    什么是cors请求?

        CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器发出 XMLHttpRequest请求,从而克服了ajax只能同源使用的限制。 简单来说,就是cors和ajax搭配使用就可以实现跨域请求。

    先来看具体实现:

    js代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>cros跨域</title>
    <script>
        window.onload = function(){
            var xhr = new XMLHttpRequest();

            xhr.open('get','ajax/cors_fotge.php', true);
            xhr.send(null);
        }
    </script>
</head>
<body>
    
</body>
</html>

  php代码:

<?php
    
    header('Access-Control-Allow-Origin:*');
    $res = array(
        'name'=>'jjk',
        'age'=>18
        );

    echo json_encode($res,JSON_UNESCAPED_UNICODE);
?>

  

在chrome中显示:

JavaScript--跨域

        服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。
Header set Access-Control-Allow-Origin *  表示接受任意域名的请求

      为了防止XSS攻击我们的服务器, 我们可以限制域,比如
Access-Control-Allow-Origin: http://blog.csdn.net

      只需在php代码返回数据之前,添加  header('Access-Control-Allow-Origin:*'); 即可。

CORS与JSONP相比,更为先进、方便和可靠。
1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了


  
  未完待续