跨域(非同源策略請求)
-同源策略請求 是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協議+域名+埠"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源
ajax / fetch複製程式碼
跨域傳輸(跨域是指一個域下的文件或指令碼試圖去請求另一個域下的資源)
以下下三者一樣就是同源,只要有一項不一樣就是跨域
協議&域名&埠號
http://127.0.0.1:3000/index.html
http://127.0.0.1:4000/list.html//http:協議 127.0.0.1:域名 3000:埠號複製程式碼
一、 通過jsonp跨域
通常為了減輕web伺服器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的伺服器上,在html頁面中再通過相應的標籤從不同域名下載入靜態資源,而被瀏覽器允許,基於此原理,我們可以通過動態建立script,再請求一個帶參網址實現跨域通訊。
- web伺服器:靜態資源
- data伺服器:業務邏輯和資料分析
- 圖片伺服器
1.json.js
$.ajax({ url: 'http://127.0.0.1:8001/list', method: 'get', dataType: 'jsonp', //=>執行的是JSONP的請求 success: res => { console.log(res); }});複製程式碼
2.serverJSON.js
let express = require('express'), app = express();app.listen(8001, _ => { console.log('OK!');});app.get('/list', (req, res) => { let { callback = Function.prototype } = req.query; let data = { code: 0, message: 'JSONP哈哈哈' }; res.send(`${callback}(${JSON.stringify(data)})`);});複製程式碼
Console控制檯顯示
{code:0,message:'JSONP哈哈哈'}複製程式碼
二、 跨域資源共享(CORS)
axios.defaults.baseURL = 'http://127.0.0.1:8888';axios.defaults.withCredentials = true;//?重點axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';axios.defaults.transformRequest = function (data) { if (!data) return data; let result = ``; for (let attr in data) { if (!data.hasOwnProperty(attr)) break; result += `&${attr}=${data[attr]}`; } return result.substring(1);};axios.interceptors.response.use(function onFulfilled(response) { return response.data;}, function onRejected(reason) { return Promise.reject(reason);});axios.defaults.validateStatus = function (status) { return /^(2|3)\d{2}$/.test(status);}複製程式碼
app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "http://localhost:8000"); //=>*(就不能在允許攜帶cookie了) 具體地址
//侷限性 二者選其一 因為CORS的這個缺陷 出現了?http proxy =>webpack webpack-dev-server res.header("Access-Control-Allow-Credentials", true); res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS"); if (req.method === 'OPTIONS') { res.send('OK!'); return; } next();});複製程式碼
三、 http proxy =>webpack webpack-dev-server
proxy相當於node給你模擬了一個ngnix服務請求,伺服器請求伺服器不存在跨域。proxy請求回來資料,從而解決跨域
-在webpack.config.js檔案中:
devServer: {
port: 3000,
progress: true,
contentBase: './build',
proxy: {
'/': { //‘/’ 在請求時不用設定字首
target: 'http://127.0.0.1:3001',
changeOrigin: true //改變源 (當我們設定為true時 devserver會幫我們起一個服務,
//來做中層的代理"與node中介軟體代理類似"]) } } }複製程式碼
四、ngnix反向代理(前端不需要做什麼工作)
server { listen 80; server_name www.baidu.com; location / { proxy_pass www.baidu.cn; //反向代理 proxy_cookie_demo www.baidu.cn www.baidu.com; add_header Access-Control-Allow-Origin www.baidu.cn; add_header Access-Control-Allow-Credentials true; }}複製程式碼
五、postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是為數不多可以跨域操作的window屬性之一,它可用於解決以下方面的問題:
a.) 頁面和其開啟的新視窗的資料傳遞
b.) 多視窗之間訊息傳遞
c.) 頁面與巢狀的iframe訊息傳遞
d.) 上面三個場景的跨域資料傳遞
用法:postMessage(data,origin)方法接受兩個引數
data: html5規範支援任意基本型別或可複製的物件,但部分瀏覽器只支援字串,所以傳參時最好用JSON.stringify()序列化。
origin: 協議+主機+埠號,也可以設定為"*",表示可以傳遞給任意視窗,如果要指定和當前視窗同源的話設定為"/"
-server1.js
let express = require('express'), app = express();app.listen(1001, _ => { console.log('OK!');});app.use(express.static('./'));複製程式碼
-server2.js
let express = require('express'), app = express();app.listen(1002, _ => { console.log('OK!');});app.use(express.static('./'));複製程式碼
- A1.html
<body> <iframe id="iframe"
src="http://127.0.0.1:1002/MESSAGE/B.html"
frameborder="0"
style="display: none;">
</iframe> <script> iframe.onload = function () { iframe.contentWindow.postMessage('哈哈哈哈', 'http://127.0.0.1:1002/'); } //=>監聽B傳遞的資訊 window.onmessage = function (ev) { console.log(ev.data); } </script></body>複製程式碼
- B1.html
<body> <script> //=>監聽A傳送過來的資訊 window.onmessage = function (ev) { // console.log(ev.data); //=>ev.source:A ev.source.postMessage(ev.data + '@@@', '*'); } </script></body>複製程式碼