美文网首页让前端飞JavaScript 进阶营
浏览器非同源跨域之JSONP

浏览器非同源跨域之JSONP

作者: 临安linan | 来源:发表于2019-04-16 01:07 被阅读3次

    本文是在阮一峰老师和方应杭老师的教程上总结写得,相关链接:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

    首先,同源是什么?

    网站url由 协议 + 域名 + 端口 + 路径组成,也可能包含查询参数和锚点


    image.png

    只要两个网址协议域名端口有一个不一样,这两个网址就是非同源


    image.png

    为何会有同源政策

    目的就是保证安全,假如用户访问了网页A,然后又去访问网页B,要是网页B能读取到A的cookie(比如登录信息等......),那互联网就没有安全可言了。

    同源策略对非同源网页作出了限制:

    (1) Cookie、LocalStorage 和 IndexDB 无法读取。
    (2) DOM 无法获得。
    (3) AJAX 请求不能发送。
    

    那面对非同源url,如何实现跨域?

    可以选择JSONP来进行跨域请求。
    先来了解一下JSONP:
    我们知道,script标签是不受跨域限制的。比如用script请求cdn资源,就从来没有受过限制,于是就有脑洞大开的程序员想到,可以动态生成一个script标签做跨域了!
    只要我传一个回调函数给后端,后端给我返回函数的调用,那我这个script标签在html中总会执行的吧,那不就可以了吗?
    来看代码:

    let script = document.createElement('script')
    window[functionName] = function () {
        console.log('要执行的回调函数');
    }
    script.src = 'http://xxx.com?callback=' + functionName
    document.body.appendChild(script) // script必须插入页面中才会执行
    
    // 这里省略了后台代码,只需要知道后台会返回一个functionName(),这个functionName()会被放入script中执行就可以了
    // 这里我们就已经实现了简单的JSONP了。
    

    我们再来完善一下,将传入参数统一规定为callback,callback的值统一为随机数(为了防止重复,毕竟一个服务器可能要处理成千上万个请求)

    let functionName = Math.random()*10000;
    let script = document.createElement('script')
    window[functionName] = function () {
        console.log('要执行的回调函数');
    }
    script.src = 'http://xxx.com?callback=' + functionName
    document.body.appendChild(script)
    

    再来看看,现在我们的JSONP已经写的还行了,但是有一个问题,我每做一次JSONP请求,页面就会被嵌入一个标签,而且全局会出现一个随机数的函数,这些前端肯定不能忍啊,必须干掉! 那我们就在script执行完之后干掉吧,用script.onload

    let functionName = Math.random()*10000;
    let script = document.createElement('script')
    window[functionName] = function () {
        console.log('要执行的回调函数');
    }
    script.src = 'http://xxx.com?callback=' + functionName
    document.body.appendChild(script)
    script.onload = function(e){
        e.currentTarget.remove()   // 干掉嵌入的script标签
        delete window[functionName]   // 删掉定义的回调函数
    }
    

    完美,接下来,我们只要写一写请求失败的情况就可以了

    let functionName = Math.random()*10000;
    let script = document.createElement('script')
    window[functionName] = function () {
        console.log('要执行的回调函数');
    }
    script.src = 'http://xxx.com?callback=' + functionName
    document.body.appendChild(script)
    script.onload = function(e){
        e.currentTarget.remove()   // 干掉嵌入的script标签
        delete window[functionName]   // 删掉定义的回调函数
    }
    script.onerror = function (e) {        
        e.currentTarget.remove()   // 失败了也要删除script标签
        delete window[functionName]  // 失败了也要干掉这个随机函数     
    }
    

    完。

    相关文章

      网友评论

        本文标题:浏览器非同源跨域之JSONP

        本文链接:https://www.haomeiwen.com/subject/gpzywqtx.html