关于javascript跨域及JSONP的道理与运用

一、同源战略

同源战略,它是由Netscape提出的一个有名的安全战略,如今一切的可支撑javascript的浏览器都邑运用这个战略。

为何须要同源战略,这里举个例子:

假定如今没有同源战略,会发作什么事变呢?人人晓得,JavaScript能够做很多东西,比方:读取/修正网页中某个值。恩,你如今打开了浏览器,在一 个tab窗口中打开了银行网站,在别的一个tab窗口中打开了一个歹意网站,而谁人歹意网站挂了一个的特地修正银行信息的JavaScript,当你接见 这个歹意网站而且实行它JavaScript时,你的银行页面就会被这个JavaScript修正,效果会异常严峻!而同源战略就为了防备这类事变发作.

比方说,浏览器的两个tab页中离别打开了http://www.baidu.com/index.X19Xhtml和http: //www.google.com/index.html,个中,JavaScript1和JavaScript3是属于百度的剧本,而 JavaScript2是属于谷歌的剧本,当浏览器的tab1要运转一个剧本时,便会举行同源搜检,只要和www.baidu.com同源的剧本才被执 行,所谓同源,就是指域名、协定、端口雷同。所以,tab1只能实行JavaScript1和JavaScript3剧本,而JavaScript2不能 实行,从而防备其他网页对本网页的不法改动。

二、什么是JSONP?

JSONP(JSON with Padding)是一个非官方的协定,它许可在服务器端集成Script tags返回至客户端,经由过程javascript callback的情势完成跨域接见(这仅仅是JSONP简朴的完成情势)。

三、为何运用JSONP?

由于 JSON 只是一种含有简朴括号构造的纯文本,因而很多通道都能够交流 JSON 音讯。由于同源战略的限定,们不能在与外部服务器举行通讯的时刻运用 XMLHttpRequest。而JSONP是一种能够绕过同源战略的要领,即经由过程运用 JSON 与 < script> 标记相结合的要领,从服务端直接返回可实行的JavaScript函数挪用或许JavaScript对象。

实在 jsonp 是个很简朴的一个东西。主假如应用了 <script/>标签对javascript文档的动态剖析来完成。(实在也能够用eval函数)。

<script type="text/javascript">
    function jsonpCallback(result) {
        alert(result.msg);
    }
</script>
<script type="text/javascript" src="http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback"></script>

个中 jsonCallback 是客户端注册的,猎取跨域服务器上的json数据后,回调的函数。

http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback

这个 url 是跨域服务器取 json 数据的接口,参数为回调函数的名字,返回的花样为:

jsonpCallback({ msg:'this  is  json  data'})

Jsonp道理:

首先在客户端注册一个callback, 然后把callback的名字传给服务器。此时,服务器先天生 json 数据。然后以 javascript 语法的体式格局,天生一个function , function 名字就是通报上来的参数 jsonp.

末了将 json 数据直接以入参的体式格局,安排到 function 中,如许就天生了一段 js 语法的文档,返回给客户端。

客户端浏览器,剖析script标签,并实行返回的javascript文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态实行回调函数) .

实在说白了,就是客户端定义一个函数(如a),要求地点后服务器端返回的效果是挪用a函数,须要的数据都放在了a函数的参数内里。

demo:

应为它用到的只是一切 HTML 元素中一个简朴的 script 元素。看到这是否是以为更加奇怪了?没紧要,继承看下去就会厕所(塞)顿开的,嘿嘿~来看个例子吧:
demo.html:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Demo</title>
</head>
<body>
<script type="text/javascript">
    function say(words) {
       alert(words);
    }
</script>
<script type="text/javascript" src="demo.js"></script>
</body>
</html>

demo.js:

say("Hello, everyone!");

运转 demo.html 文件后,是否是看到写着“Hello, everyone!”的正告框了?你能够会以为这个例子很简朴,没什么了不得的,甚至会在想:这和 JSONP 有关联吗?那末,我能够很一定的通知你:有关联!而且,这个例子实际上就是 JSONP 的原型!你或许会想到,JSONP 不是接见长途数据的吗?对,试想一下,假如 demo.js 文件在别的域的服务器上呢?效果会不会出现问题?我也能够很担任的通知你:不会!你能够将上面例子中的 demo.js 更改成:http://demo.hpyer.cn/php/jsonp.php?callback=say 再试一下。
如今,智慧的你应当已邃晓 JSONP 究竟是怎么回事了,那末,再来解释一下本节开首第一句话吧。看过 demo.js 文件的内容,应当晓得,其只是对一个函数(一般称之为:回调函数)的挪用,而须要交互的数据则经由过程参数情势举行返回。所以经由过程 JSONP 接见的服务器须要供应一个能够设置回调函数名的接口,就像 http://demo.hpyer.cn/php/jsonp.php?callback=say 中的 callback,所以,综上所述 JSONP 是须要服务器端的支撑的。附上 jsonp.php 的源码:

<?php
$type = isset($_GET['type']) ? $_GET['type'] : '';
$callback = isset($_GET['callback']) ? $_GET['callback'] : '';
$json = '';
if ($type == 'json') {
   $json = '{
   "Image": {
   "Width": 800,
   "Height": 600,
   "Title": "View from 15th Floor",
   "Thumbnail": {
   "Url": "http://www.example.com/image/481989943",
   "Height": 125,
   "Width": "100"
   },
   "IDs": [116, 943, 234, 38793]
   }
   }';
} else {
   $json = '"Hello, everyone!"';
}
if (!empty($callback)) {
   $json = $callback . '(' . $json . ')';
}
echo $json;

jquery 中的运用:
自 1.2 版本起,jQuery 加入了对 JSONP 的支撑。我们能够很轻易的应用 $.getJSON() 要领(或许别的基于 $.ajax() 的要领),来跨域加载 JSON 数据。来个例子吧:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Demo</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
function do_jsonp() {
   $.getJSON("http://demo.hpyer.cn/php/jsonp.php?type=json&callback=?",
   function(data) {
   $('#result').val('data.Image.IDs: ' + data.Image.IDs);
   });
}
</script>
</head>
<body>
<a href="javascript:do_jsonp();">Click me</a><br />
<textarea id="result" cols="50" rows="5"></textarea>
</body>
</html>

你能够注重到上面的例子中,url 被写成了 http://demo.hpyer.cn/php/jsonp.php?type=json&callback=?,须要申明的是,这个问号会被 jQuery 自动替换为回调函数的函数名(假如是一个匿名函数,jQuery 会自动天生一个带时候戳的函数名)。

看我在项目中的一个例子:

//定义Ajax函数
function ajaxFun() {
    var timeStamp = Math.floor(new Date().getTime() / 1000);
    var url = "http://apiso.alidemo.3gpp.cn/httpserver/cp/yisou/ali_feedback_interface.php?callback=jsonpCallback&feedbacktype=add&type=" + feedbackNumber + "&book=" + me.mixedInfo.title + "&author=" + me.mixedInfo.author + "&chapter=" + me.mixedInfo.cname + "&chapterid=" + me.mixedInfo.cid + "&questiondesc=" + text + "&platform=1&t=" + timeStamp + "&sn=" + md5("d30fcd1a9f1900fa049b4766e0a275e1" + timeStamp);
    var scriptObj = document.createElement("script");
    scriptObj.src = url;
    scriptObj.id = "jsonpScript";
    document.body.appendChild(scriptObj);
    //jsonp回调函数,jsonpCallback必需为全局函数,由于jsonp返回的是在全局环境中实行函数的语句,即jsonpCallback(data)
    window.jsonpCallback = function(data) {
        switch (data.code) {
            case "1":
                novel.readerPrompt('提交胜利,行将返回……', 1, function() {
                    window.history.go(-1);
                });
                break;
            case "0":
                novel.readerPrompt('提交失利。', 2);
                break;
            case "900":
                novel.readerPrompt('提交失利,考证失利。', 2);
                break;
        }
        //胜利后删除scriptObj,背面的setTimeout就不会实行了
        if (document.getElementById("jsonpScript")) {
            document.body.removeChild(scriptObj);
        }
    }
    //设置超时,超时的话直接显现提交胜利
    setTimeout(function() {
        if (document.getElementById("jsonpScript")) {
            document.body.removeChild(scriptObj);
            novel.readerPrompt('提交胜利,行将返回……', 1, function() {
                window.history.go(-1);
            });
        }
    }, 2000);
}
ajaxFun();

via WEB前端开辟

    原文作者:江小湖Laker
    原文地址: https://segmentfault.com/a/1190000002438126
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞