一.什麼是同源政策?
同源政策是指在Web浏覽器中,允許某個網頁腳本通路另一個網頁的資料,但前提是這兩個網頁必須有相同的URI、主機名和端口号,一旦兩個網站滿足上述條件,這兩個網站就被認定為具有相同來源。此政策可防止某個網頁上的惡意腳本通過該頁面的文檔對象模型通路另一網頁上的敏感資料。同源政策對Web應用程式具有特殊意義,因為Web應用程式廣泛依賴于HTTP cookie來維持使用者會話,是以必須将不相關網站嚴格分隔,以防止丢失資料洩露。值得注意的是同源政策僅适用于腳本,這意味着某網站可以通過相應的HTML标簽通路不同來源網站上的圖像、CSS和動态加載腳本等資源。而跨站請求僞造就是利用同源政策不适用于HTML标簽的缺陷——***
舉個例子:

總結就是:同一協定,同一域名,同一端口号
正如上面所說,因為浏覽器同源政策的限制,非同源下的請求,都會産生跨域的問題,jsonp則是解決這一問題的簡便方法之一。
二.如何突破同源政策限制?
在上面關于同源政策的描述中有一句話:同源政策僅适用于腳本
這意味着我們可以将通路的連結放在HTML中,這樣就可以繞過同源政策的幹擾,實作跨域。
- 比如我們可以将跨域的請求放在script标簽中
<!-- 将非同源伺服器端的請求位址寫在script标簽的src屬性中 -->
<script src="http://localhost:3001/better?callback=fn2"></script>
- 是以我們可以動态建立script标簽來使用json方法擷取資料
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);
}
}
- 基于以上可以封裝一個簡單的jsonp方法
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)
},
})
三.使用jsonp第三方庫完成封裝
以下是NPM中jsonp第三方庫的關鍵函數jsonp介紹:
- 下載下傳第三方jsonp庫
npm install jsonp -S
- 封裝jsonp方法
// 導入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) : ''
}