1. 程式人生 > 其它 >跨域解決方法——jsonp原理

跨域解決方法——jsonp原理

技術標籤:web前端javascriptjsonp

跨域解決方法——jsonp原理

  • 一個域名地址的組成:
    在這裡插入圖片描述
  • 當協議、子域名、主域名、埠號任意一個不相同時,都算作不同域,不同域之間相互請求資源,就算做“跨域”。由於瀏覽器同源策略的限制,非同源下的請求,都會產生跨域問題。
  • 使用jquery的jsonp可以發起跨域請求,下面來探究下他的原理及使用。

首先看下如何使用script src=""來完成一個跨域請求:

普通的ajax請求是會發生跨域問題的,但是img的src,a的href,script的src卻可以發起任意網址的請求並接收到響應,於是我們首先利用script的src來完成一個跨域請求。

客戶端:

<script>
    function show(weather){
        document.write(weather)
    }
    //show('返回的資料');
</script>
<!--用請求引數將函式名傳遞給伺服器。-->
<script src="http://localhost:3000?callback=show"></script>

伺服器端:

const http = require("http");
const url = require("url");
http.createServer(
    (req,res)=>{
        var Url = url.parse(req.url,true);
        //接收客戶端傳過來的名為callback的引數中儲存的函式名
        var callback = Url.query.callback;
        var weather="北京 晴";
        //將函式名動態拼接到要返回的函式呼叫語句中。
        res.write(`${callback}("${weather}")`);//實際想要在客戶端執行的函式呼叫語句。
        res.end();
    }
).listen(3000);

script只能識別js語句,一旦接收到js語句就立即執行。於是在伺服器端拼接一條函式呼叫的js語句,並且提前在客戶端定義一個函式,當客戶端接收到伺服器返回的js語句後就會立即執行。
為了使函式名在客戶端可修改,於是用請求引數將函式名從客戶端傳遞給伺服器。

動態建立script元素

script是在頁面中寫死的,只能在頁面載入過程中執行一次,如果想每次單擊按鈕,隨時傳送請求,可以每次單擊按鈕時動態建立script元素。

<body>
<button>傳送請求</button>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"
>
</script> <script> function show(weather){ alert(weather); $("body>script:last").remove();//刪除建立的那個script元素 } //show('返回的資料'); $("button").click(function(){ var script = document.createElement('script'); script.src="http://localhost:3000?callback=show"; document.body.appendChild(script); }) </script> </body>

jQuery對jsonp方式跨域進行了終極簡化

1.服務端程式碼不變,js程式碼如下:
最簡單的方式,只需配置一個dataType:‘jsonp’,就可以發起一個跨域請求。
jsonp指定伺服器返回的資料型別為jsonp格式,可以看發起的請求路徑,自動帶了一個callback=xxx,xxx是jquery隨機生成的一個回撥函式名稱。//callback: jQuery34105977893922582984_1578207815633
_: 1578207815634

這裡的success就跟上面的show一樣,如果有success函式則預設success()作為回撥函式。

<body>
<button>傳送請求</button>
<script src="jquery.js"></script>
<script>
    $("button").click(function(){
        $.ajax({
            url: "http://localhost:3000",
            type: "GET",
            dataType: "jsonp",  //其實也是動態建立script,藉助script傳送跨域請求,必須有服務端的支援,
            success: function(weather) {
                alert(weather);
            }
        })
    })
</script>
</body>

2.再看下如何指定特定的回撥函式:
jsonpCallback: “show”,
看請求引數 callback: show_: 1578208620937,請求時帶的引數是:callback=show;呼叫回撥函式的時候,先呼叫了指定的show,然後再呼叫了success。所以,success是返回成功後必定會呼叫的函式,就看你怎麼寫了。

<script>
    function show(weather) {
        alert("show"+weather);
    }
    $("button").click(function(){
        $.ajax({
            url: "http://localhost:3000",
            type: "GET",
            dataType: "jsonp", 
            jsonpCallback: "show",   //指定特定的回撥函式
            success: function(weather) {
                alert(weather);
            }
        })
    })

</script>

3.再看看如何改變callback這個名稱:
jsonp: “func”,
看請求資訊:func: show_: 1578208954673

<script>
    function show(weather) {
        alert("show"+weather);
    }
    $("button").click(function(){
        $.ajax({
            url: "http://localhost:3000",
            type: "GET",
            dataType: "jsonp",
            jsonp: "func",               //改變callback這個名稱
            jsonpCallback: "show",
            success: function(weather) {
                alert(weather);
            }
        })
    })

</script>

指定callback這個名稱後,後臺也需要跟著更改。

http.createServer(
    //每當有客戶端發來請求時,自動呼叫一下回調函式。
    (req,res)=>{
        var Url = url.parse(req.url,true);
        //接收客戶端傳過來的名為callback的引數中儲存的函式名
        var callback = Url.query.func;
        var weather="北京 晴";
        //將函式名動態拼接到要返回的函式呼叫語句中。
        res.write(`${callback}("${weather}")`);//實際想要在客戶端執行的函式呼叫語句。
        res.end();
    }
).listen(3000);

總結

jsonp的實現方式其實也是動態建立script,藉助script傳送跨域請求,jquery中ajax的jsonp對這個複雜的過程進行了封裝,並且需要服務端的支援,所以可想而知,jsonp是不支援POST方式的。
jsonp的原理:
動態建立script標籤,並且自動給script的src屬性加入了callback引數,藉助script來發送跨域請求,請求結束後script會被自動刪除。並且必須有伺服器端配合接收callback儲存的函式名,服務端將要返回的資料填充到函式呼叫語句裡返回,客戶端收到js語句執行。