同源策略是指在Web瀏覽器中,容許某個網頁腳本訪問另外一個網頁的數據,但前提是這兩個網頁必須有相同的URI、主機名和端口號,一旦兩個網站知足上述條件,這兩個網站就被認定爲具備相同來源。此策略可防止某個網頁上的惡意腳本經過該頁面的文檔對象模型訪問另外一網頁上的敏感數據。同源策略對Web應用程序具備特殊意義,由於Web應用程序普遍依賴於HTTP cookie來維持用戶會話,因此必須將不相關網站嚴格分隔,以防止丟失數據泄露。值得注意的是同源策略僅適用於腳本,這意味着某網站能夠經過相應的HTML標籤訪問不一樣來源網站上的圖像、CSS和動態加載腳本等資源。而跨站請求僞造就是利用同源策略不適用於HTML標籤的缺陷——維基百科npm
舉個例子:
json
總結就是:同一協議,同一域名,同一端口號
正如上面所說,由於瀏覽器同源政策的限制,非同源下的請求,都會產生跨域的問題,jsonp則是解決這一問題的簡便方法之一。跨域
在上面關於同源策略的描述中有一句話:同源策略僅適用於腳本
這意味着咱們能夠將訪問的連接放在HTML中,這樣就能夠繞過同源策略的干擾,實現跨域。瀏覽器
<!-- 將非同源服務器端的請求地址寫在script標籤的src屬性中 --> <script src="http://localhost:3001/better?callback=fn2"></script>
var btn = document.getElementById('btn'); btn.onclick = function () { // 建立script標籤 var script = document.createElement('script'); // 設置src屬性 script.src = 'http://localhost:3001/better?callback=fn2'; // 將srcipt標籤追加到頁面中 document.body.appendChild(script); // 爲script標籤添加onload事件 script.onload = function () { // 將body中的script標籤刪除掉 document.body.removeChild(script); } }
function jsonp(options) { // 動態建立script標籤 var script = document.createElement('script') // 拼接傳入的數據 var params = '' for (var key in options.data) { params += '&' + key + '=' + options.data[key] } // 建立隨機函數名,防止路徑相同 var fnName = 'myJsonp' + Math.random().toString().replace('.', '') // 讓函數中的success變成全局函數 window[fnName] = options.success // 爲script標籤添加src屬性 script.src = options.url + '?callback=' + fnName + params // 將script標籤追加到頁面中 document.body.appendChild(script) // 爲script標籤添加onload事件 script.onload = function () { // 刪除script標籤 document.body.removeChild(script) } }
jsonp({ // 請求地址 url: 'http://localhost:3001/better', // 請求成功 success: function (data) { console.log('函數調用成功') console.log(data) }, })
如下是NPM中jsonp第三方庫的關鍵函數jsonp介紹:
服務器
npm install jsonp -S
// 導入jsonp模塊 import originJSONP from 'jsonp' // 封裝json函數並導出 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) } }) }) } // 參數處理 function param(data) { let url = '' for (var k in data) { const value = data[k] !== undefined ? data[k] : '' url += `&${k}=${encodeURIComponent(value)}` } return url ? url.substring(1) : '' }