收起左侧

[前端] JSONP - 从理论到实践

6
回复
[复制链接]
avatar
  • TA的每日心情
    qdsmile奋斗
    12 小时前
  • 签到天数: 2663 天

    [LV.Master]伴吧终老

    460

    主题

    1056

    帖子

    3万

    积分
    发表于 2017-8-7 14:27:09 | 显示全部楼层 |阅读模式
    JSONP - 从理论到实践
    同源策略
    ajax之所以需要“跨域”,罪魁祸首就是浏览器的同源策略。即,一个页面的ajax只能获取这个页面相同源或者相同域的数据。
    如何叫“同源”或者“同域”呢?——协议、域名、端口号都必须相同。例如:
    • http://google.com 和 https://google.com 不同,因为协议不同;
    • http://localhost:8080 和 http://localhost:1000 不同,因为端口不同;
    • http://localhost:8080 和 https://google.com 不同,协议、域名、端口号都不同,根本不是一家的。

        根据同源策略,我自己做的一个网页 http://localhost:8080/test.html 就无法通过ajax直接获取 http://google.com 的数据。
        例如,我用ajax去访问一个不同域的页面,错误结果是这样的:
        JSONP-从理论到实践_
        大家想想,这样其实也有道理。如果没有同源策略,你我都可以随便通过ajax直接获取其他网站的信息,这还不乱套了。。。我自己做一个搜索界面,搜索时直接用ajax从百度获取数据,那不成了小偷了。。。
        但是跨域访问是少不了的,mail.163.com 的网页可能需要从 news.163.com 域下获取新闻信息,那怎么办?——开始咱们的跨域之旅。(当然用iframe也可以实现)

    从“盗链”说起
        互联网的许多网站之间图片相互盗链,A网站网页的img.src直接链接到B网站的图片地址,这是常有的事儿。说到“盗链”,大家第一想到的可能是如何去防止盗链,今儿咱不管那个。

        你再想想“盗链”“同源策略”这两个词之间有什么关系?——对,矛盾!既然都“同源策略”了,怎么还能“盗链”呢?
        世间万物都有矛盾,有矛盾了照样可以和谐共处,并不一定非要你死我活。

        重点:<img>src(获取图片)<link>href(获取css)<script>src(获取javascript)这三个都不符合同源策略,它们可以跨域获取数据。因此,你可以直接从一些cdn上获取jQuery,并且你网站上的图片也随时可能被别人盗用,所有最好加上水印!

        而我们今天的主角——jsonp——就是因为<script>的src不符合同源策略而来的。

    JSONP
        例如,域名 a.com 下有一个 a.com/test.html 网页,域名 b.com 下有一个 b.com/data.html 网页和 b.com/alert.js 文件。

    引导第一步:简单引用js
        编写 b.com/alert.js 如下:
    1. alert(123);
    复制代码
       对 a.com/test.html 编写如下代码:
    1. <script type='text/javascript' src='http://b.com/alert.js'/>
    复制代码
       运行 a.com/test.html,结果很明显,就是弹出123

    引导第二步:引用js返回数据
        将 b.com/alert.js 修改为:
    1. myFn(100);
    复制代码
       将 a.com/test.html 修改为:
    1. <script>
    2.     function myFn ( data ) {
    3.         alert( data + 'px' );
    4.     }
    5. </script>
    6. <script type='text/javascript' src='http://b.com/alert.js'/>
    复制代码

        运行 a.com/test.html,结果是弹出100px,这个应该也没有什么疑问。

    引导第三步:已经跨域成功!
        第二步中,如果data——即100——是我要跨域在b.com下获取的一个数据,那么咱们这不就是已经实现跨域请求了吗!!!

        把这个过程再清晰的捋一遍:
    • <script>src不符合同源策略;
    • 我通过给<script>src赋值一个跨域的文件的网址(可能不是一个js文件),这个文件返回的字符串,浏览器会当作javascript来解析;
    • 而这段javascript中,就可以包含着我所需要的跨域服务器端的数据;
    • 最后,我在本页面定义一个myFn函数用来展示数据,而这段javascript中就可以直接调用myFn函数;

    引导第四步:引用html格式
        <script>src不一定仅仅指向javascript文件,可以指向任何地址。例如:
        将 a.com/test.html 修改为:
    1. <script>
    2.     function myFn ( data ) {
    3.         alert( data + 'px' );
    4.     }
    5. </script>
    6. <script type='text/javascript' src='http://b.com/data.html'/>
    复制代码

        将 b.com/data.html 编写为:(注意,data.html中就写以下一行代码,多了不写)
    1. myFn(100);
    复制代码
       运行 a.com/test.html ,结果依然是100px,其中,100就是我们要跨域请求的数据。

    引导第五步:动态数据
        如果要请求的数据是动态的,那就要在动态页面中编写。那么我们就让 a.com/test.html 去调用一个动态的aspx页面:
    1. <script>
    2.     function myFn ( data ) {
    3.         alert( data + 'px' );
    4.     }
    5. </script>
    6. <script type='text/javascript' src='http://b.com/data.aspx?callback=myFn'/>
    复制代码

        大家注意,我们在 src 地址中增加了?callback=myFn,意思是把显示数据的函数也动态传过去了,而第二步、第四步都是静态的写在被调用的文件中的。至于callback参数后台如何接收,如何使用,请接着看:
        在 b.com 下增加一个 b.com/data.aspx 页面,后台代码如下:
    1.     protected void Page_Load(object sender, EventArgs e)
    2.     {
    3.         if (this.IsPostBack == false)
    4.         {
    5.             string callback = "";
    6.             if (Request["callback"] != null)
    7.             {
    8.                 callback = Request["callback"];

    9.                 //服务器端要返回的数据
    10.                 string data = "1024";

    11.                 Response.Write(callback + "(" + data + ")");
    12.             }
    13.         }
    14.     }
    复制代码

        代码很简单,获取callback参数,然后组成一个函数的形式返回。如果b.com/data.aspx?callback=myFn调用的话,那么返回的就是myFn(1024)
        返回的数据变成动态的了(“1024”),前端页面用于显示数据的函数也编程了动态的了(“callback=myFn”),但是归根结底,形式还是一样的。

    引导第六步:调用封装
        a.com/test.html 中,仅仅有一个<script>静静的躺在那里,执行一次之后,就没有作用了。
        而实际情况是,a.com/test.html 中,可能随着用户的操作发生若干次的调用。怎么办?——动态增加呗。
    1. function addScriptTag(src) {
    2.     var script = document.createElement("script");
    3.     script.setAttribute("type", "text/javascript");
    4.     script.src = src;
    5.     document.body.appendChild(script);
    6. }

    7. function myFn (data) {
    8.     alert(data + 'px');  
    9. }

    10. //需要调用时:
    11. //addScriptTag('b.com/data.aspx?callback=myFn');
    复制代码

    总结
        以上层层描述的就是JSONP,你不必去记住它的定义,看明白了上述文字,就全能理解。
        重点在于:同源策略 + <script>src不属于同源策略 + 通过<script>的src指向的文件返回服务器端数据。
        ok,就这些!




    学习心情好,签到少不了。
    avatar
  • TA的每日心情
    qdsmile开心
    2017-12-16 09:04
  • 签到天数: 2 天

    [LV.1]小吧新人

    1

    主题

    10

    帖子

    30

    积分

    发表于 2017-12-15 22:59:03 | 显示全部楼层
    不错
    avatar
  • TA的每日心情
    qdsmile开心
    2017-12-16 09:04
  • 签到天数: 2 天

    [LV.1]小吧新人

    1

    主题

    10

    帖子

    30

    积分

    发表于 2017-12-15 23:00:18 | 显示全部楼层
    zan
    avatar
  • TA的每日心情
    qdsmile开心
    2019-5-9 00:23
  • 签到天数: 5 天

    [LV.2]小吧熟人

    0

    主题

    5

    帖子

    106

    积分

    发表于 2018-5-25 23:44:28 | 显示全部楼层
    很好
    avatar
  • TA的每日心情
    qdsmile郁闷
    2019-6-18 17:07
  • 签到天数: 4 天

    [LV.2]小吧熟人

    0

    主题

    17

    帖子

    245

    积分

    发表于 2018-7-22 12:34:13 | 显示全部楼层
    挺好  
    avatar
  • TA的每日心情
    qdsmile奋斗
    2018-10-31 08:58
  • 签到天数: 5 天

    [LV.2]小吧熟人

    0

    主题

    0

    帖子

    91

    积分

    发表于 2018-10-15 10:18:39 | 显示全部楼层
    清晰,条理清楚,非常好
    avatar
  • TA的每日心情
    qdsmile难过
    2020-2-16 02:51
  • 签到天数: 2 天

    [LV.1]小吧新人

    0

    主题

    0

    帖子

    30

    积分

    发表于 2019-3-10 14:00:39 | 显示全部楼层
    很受益
    您需要登录后才可以回帖 登录 | 立即注册 QQ登录

    本版积分规则