聊聊jsonp的原理及跨域

跨域是老生常談的問題了也是面試會問到的,本質上就是瀏覽器同源策略javascript

瀏覽器同源策略

所謂同源策略是瀏覽器的一種安全策略,所謂同源是指,域名,協議,端口號徹底相同,可是開發者發現瀏覽器並不會對script標籤的src仍是img標籤的src,link標籤的href限制,因此咱們能夠利用這一特性能夠進行ajax請求,有同窗可能會問到,我怎麼去*證實瀏覽器對這些標籤沒有進行同源限制?php

請看下圖:html

src或href連接的靜態資源,本質上來講也是一個get請求java

接下來咱們利用這個特性來解決ajax開發中遇到的跨域問題jquery

jsonp解決跨域

原理

在jquery開發年代,咱們一般是使用script標籤引入對應的js文件,假設咱們如今有a,b兩個文件,文件內的代碼假設以下:git

a文件:github

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript"> function getData(data){ console.log(data) } </script>
<script type="text/javascript" src="./b.js"></script>
</body>
</html>

複製代碼

b文件:面試

getData({name:"vnues"})
複製代碼

效果圖:ajax

上面的代碼很簡單,我聲明一個全局函數,傳入一個data, b調用者調用getData方法,打印出data,那麼咱們如今把調用者切換下,若是是 服務器調用這個方法,而且傳入一串data數據,這樣就拿到咱們所須要的數據了,實際上jsonp就是這個原理, 客戶端聲明好方法,將方法名傳給後端,後端調用這個getData方法,實際咱們經過script標際加載進來的是一串腳本,就是後端建立的腳原本調用這個方法,因此jsonp的方法也 須要後端的支持,那麼咱們來看看jsonp的實現吧

<script type="text/javascript"> 
    // 獲得我的信息 
    let getUserData = function(data){
        console.log(data)
    }; 
    // 將方法名傳給後端
    let url = "https://www.vnues.com/user.php?code=123&callback=getUserData"
    // 建立script標籤,設置其屬性 
    let script = document.createElement('script'); 
    script.setAttribute('src', url); 
    // 把script標籤加入head,此時調用開始 
    document.getElementsByTagName('head')[0].appendChild(script); 
</script>
複製代碼
// 數據
$data = [
    "name":"vnues",
    "age":"18",
    "like":"coding"
];
// 接收callback函數名稱
$callback = $_GET['callback'];
// 輸出
echo $callback . "(" . json_encode($data) . ")";
複製代碼

拓展

github早已有很是豐富庫支持jsonp方法,好比jsonp包,咱們能夠經過Promise封裝這個jsonpnpm

// npm install jsonp --save
import originJsonp from 'jsonp';
// Promise封裝jsonp
export default function jsonp(url, data, option) {
 url += (url.indexOf('?') < 0 ? '?' : '') + param(data);
 return new Promise((resolve, reject) => {
   originJsonp(url, option, (err, data) => {
     if (!err) {
       resolve(data);
     } else {
       reject(err);
     };
   });
 });
};
// 將參數拼接到Url中
export function param(data) {
 let url = '';
 for (let k in data) {
   let value = data[k] !== undefined ? data[k] : '';
   url += `&${k}=${encodeURIComponent(value)}`;
 };
 return url.substr(1);
};
複製代碼

總結

  • script標籤src連接(地址)不必定是文件也能夠是個api接口,只要返回一串調用腳本就能夠實現jsonp

  • 實際上jsonp只支持get請求,並不支持post請求,因此這也是開發用的少的緣故

相關文章
相關標籤/搜索