文章目錄
- 同源政策
- 跨域問題
-
- JSONP
- CORS
同源政策
Ajax請求限制:
Ajax 隻能向自己的伺服器發送請求。同源政策是浏覽器的一個安全功能,不同源的用戶端腳本在沒有明确授權的情況下,不能讀寫對方資源。
- 比如現在有一個A網站、有一個B網站,A網站中的 HTML 檔案隻能向A網站伺服器中發送 Ajax 請求,B網站中的 HTML 檔案隻能向 B 網站中發送 Ajax 請求,但是 A 網站是不能向 B 網站發送 Ajax請求的,同理,B 網站也不能向 A 網站發送 Ajax請求。
同源:
如果兩個頁面擁有相同的協定、域名和端口,那麼這兩個頁面就屬于同一個源,其中隻要有一個不相同,就是不同源。
http://www.example.com/dir/page.html
- http://www.example.com/dir2/other.html:同源
- http://example.com/dir/other.html:不同源(域名不同)
- http://v2.www.example.com/dir/other.html:不同源(域名不同)
- http://www.example.com:81/dir/other.html:不同源(端口不同)
- https://www.example.com/dir/page.html:不同源(協定不同)
同源政策的目的:
- 同源政策是為了保證使用者資訊的安全,防止惡意的網站竊取資料。最初的同源政策是指 A 網站在用戶端設定的 Cookie,B網站是不能通路的。
- 随着網際網路的發展,同源政策也越來越嚴格,在不同源的情況下,其中有一項規定就是無法向非同源位址發送Ajax 請求,如果請求,浏覽器就會報錯。
不受同源政策限制:
- 頁面中的連結,重定向以及表單送出是不會受到同源政策限制的
- 跨域資源的引入是可以的。但是js不能讀寫加載的内容。如嵌入到頁面中的
,<script src="..."></script>
,<img>
,<link>
等<iframe>
跨域問題
跨域:隻要協定、域名、端口号有一個不同就是跨域
跨域的原因:
跨域問題 來源于 JavaScript的同源政策,即隻有 協定+主機名+端口号(如存在)相同,則允許互相通路。為了防止某域名下的接口被其他域名下的網頁非法調用,是浏覽器對JavaScript施加的安全限制。也就是說JavaScript隻能通路和操作自己域下的資源,不能通路和操作其他域下的資源。跨域問題是針對 JS 和 Ajax 的, html 本身沒有跨域問題,比如a标簽、script标簽、甚至form标簽(可以直接跨域發送資料并接收資料) 等
解決跨域問題:
- JSONP:利用script标簽可跨域的特點,在跨域腳本中可以直接回調目前腳本的函數。
- CORS:伺服器設定HTTP響應頭中Access-Control-Allow-Origin值,解除跨域限制。
- 注意:這兩個跨域方案都存在一個緻命的缺陷,嚴重依賴後端的協助。
- 反向代理(Reverse Proxy):前端獨立就能解決的跨域方案:
指以 代理伺服器 來接受internet上的連接配接請求,然後将請求轉發給内部網絡上的伺服器,并将從伺服器上得到的結果傳回給internet上請求連接配接的用戶端,此時代理伺服器對外就表現為一個反向代理伺服器。
JSONP
使用 JSONP 解決
jsonp 是 JSON with padding(填充式 JSON 或參數式 JSON)的簡寫,它 不屬于 Ajax 請求,但它可以 模拟 Ajax 請求
JSONP 由兩部分組成:回調函數和資料
- 回調函數是當響應到來時應該在頁面中調用的函數。回調函數的名字一般是在請求中指定的。
- 資料就是傳入回調函數中的 JSON 資料。
解決方法:
簡單了解:在伺服器端将json資料作為函數參數,填充到函數當中,在用戶端中調用函數進而對資料進行處理
JSONP實作跨域請求的原理簡單的說,就是動态建立
<script>
标簽,然後利用
<script>
的 src 不受同源政策限制來跨域擷取資料。
JSONP的優缺點:
優點:
- 不像XMLHttpRequest對象實作的Ajax請求那樣受到同源政策的限制
- 相容性更好,在更加古老的浏覽器中都可以運作,不需要XMLHttpRequest或ActiveX的支援
- 并且在請求完畢後可以通過調用callback的方式回傳結果
缺點:
- 隻支援GET請求而不支援POST等其它類型的HTTP請求
- 隻支援跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JavaScript調用的問題
JSONP代碼優化:
- 用戶端需要将函數名稱傳遞到伺服器端
- 将 script 請求的發送變成動态請求
- 封裝 jsonp 函數,友善請求發送
- 伺服器端代碼優化之res.jsonp 方法
JSONP函數封裝:
function jsonp (options) {
// 動态建立script标簽
var script = document.createElement('script');
// 拼接字元串的變量
var params = '';
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// myJsonp0124741
var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
// 将它變成全局函數
window[fnName] = options.success;
// 為script标簽添加src屬性
script.src = options.url + '?callback=' + fnName + params;
// 将script标簽追加到頁面中
document.body.appendChild(script);
// 為script标簽添加onload事件
script.onload = function () {
document.body.removeChild(script);
}
}
使用:
// 擷取按鈕
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
// 為按鈕添加點選事件
btn1.onclick = function () {
jsonp({
// 請求位址
url: 'http://localhost:3001/better',
data: {
name: 'lisi',
age: 30
},
success: function (data) {
console.log(123)
console.log(data)
}
})
}
btn2.onclick = function () {
jsonp({
// 請求位址
url: 'http://localhost:3001/better',
success: function (data) {
console.log(456789)
console.log(data)
}
})
}
CORS
使用CORS解決
CORS:全稱為 Cross-origin resource sharing,即跨域資源共享,它允許浏覽器向跨域伺服器發送 Ajax 請求,克服了 Ajax 隻能同源使用的限制。
//設定伺服器的響應頭資訊,實作跨域
res.setHeader("Access-Control-Allow-Origin", "*"); /* 星号表示所有的域都可以接受, */
Express架構中跨域的實作:
- 安裝跨域子產品:文法:
npm install cors
- 在app.js檔案中引入cors子產品:
var cors = require('cors')
- 使用跨域子產品(在app.js檔案中) :
app.use(cors());