跨域(非同源策略請求),是由瀏覽器的安全機制引發的。
三者都同樣就是同源,只要有一個不一樣就是跨域css
一、沒有專門的前端,由後端一塊兒作。
二、先後端分開,部署的時候部署在同一個服務器,這樣就不存在跨域問題。可是,開發的時候先後端是分開的,仍是會存在跨域,怎麼辦呢?有的公司要求前端也用idea進行開發,也就是前端代碼外面包一層java或其它後端代碼,運行的時候也要運行後端服務,這樣的作法給前端開發加大了難度。html
部署到web服務器上:同源策略前端
127.0.0.1:1234 http://api.qq.com/
http://127.0.0.1:1234/index.html
http://api.qq.com/getData
三、先後端徹底分離,分開開發,分開部署web服務器,data服務器,圖片服務器。 第三方開源的數據接口也會引發跨域(這樣的狀況很是多)。java
<script src="https://cdn.bootcss.com/jquery/3.4.1/core.js"></script> // 這個就是由於script標籤沒有跨域限制,因此才能成功請求加載。
JSONP核心原理圖:
react中子組件想要修改父組件中的狀態,也是傳遞一個回調函數給父組件,這個思想和JSONP的思想是一致的。react
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"> </head> <body> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="./1.jsonp.js"></script> </body> </html>
$.ajax({ url: 'http://127.0.0.1:8001/list', method: 'get', dataType: 'jsonp', //=>執行的是JSONP的請求,這是jquery封裝的ajax的功能 success: res => { console.log(res); } });
let express = require('express'), app = express(); app.listen(8001, _ => { // 監聽8001端口 console.log('OK!'); }); app.get('/list', (req, res) => { let { callback = Function.prototype // callback若是沒有,默認爲空的函數 } = req.query; let data = { code: 0, message: '返回jsonp請求的結果' }; res.send(`${callback}(${JSON.stringify(data)})`); //=>後端須要處理好這樣的數據格式 });
客戶端正常發送請求,服務端設置相關的頭信息。jquery
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"); // http://localhost:8000是容許跨域請求的地址,若是容許不少地址跨域請求,設置爲"*" //=>*(就不能在容許攜帶cookie了) 具體地址 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
實現跨域請求http proxy =>webpack webpack-dev-server
修改webpack.config.js
webpack
let path = require('path'); let HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'production', entry: './src/index.js', output: { filename: 'bundle.min.js', path: path.resolve(__dirname, 'build') }, devServer: { port: 3000, progress: true, contentBase: './build', proxy: { // => 以'/'開始的請求,就把請求路徑轉到 target '/': { target: 'http://127.0.0.1:3001', changeOrigin: true // => 容許跨域 } } }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html' }) ] };
post message
實現跨域處理https://developer.mozilla.org...ios
A頁面git
<iframe src="http://www.github.com/B.html"></iframe> <script> let iframe = document.querySelector('iframe'); iframe.onload = function () { iframe.contentWindow.postMessage('github', 'http://www.github.com/'); } window.onmessage = function (ev) { console.log(ev.data); } </script>
B頁面github
window.onmessage = function (ev) { console.log(ev.data); ev.source.postMessage(ev.data+'@@', ev.origin); }
ngnix
反向代理 =>不須要前端作什麼www.github.cn -> www.github.com
#proxy服務器 server { listen 80; server_name www.github.com; location / { proxy_pass www.github.cn; #反向代理 proxy_cookie_demo www.github.cn www.github.com; add_header Access-Control-Allow-Origin www.github.cn; add_header Access-Control-Allow-Credentials true; } }
iframe
的跨域解決方案:window.name / document.domin / location.hash
頁面A
let proxy = function(url, callback) { let count = 0; let iframe = document.createElement('iframe'); iframe.src = url; iframe.onload = function() { if(count===0){ iframe.contentWindow.location = 'http://www.github.cn/proxy.html'; count++; return; } callback(iframe.contentWindow.name); }; document.body.appendChild(iframe); }; //請求跨域B頁面數據 proxy('http://www.github.cn/B.html', function(data){ alert(data); });
B頁面
window.name = 'github';
proxy.html是空頁面
A和C同源
A和B非同源
頁面A
<iframe id="iframe" src="http://127.0.0.1:1002/B.html" style="display:none;"></iframe> <script> let iframe = document.getElementById('iframe'); //=>向B.html傳hash值 iframe.onload=function(){ iframe.src = 'http://127.0.0.1:1002/B.html#msg=github'; } //=>開放給同域C.html的回調方法 function func(res) { alert(res); } </script>
頁面B
<iframe id="iframe" src="http://127.0.0.1:1001/C.html" style="display:none;"></iframe> <script> let iframe = document.getElementById('iframe'); //=>監聽A傳來的HASH值改變,再傳給C.html window.onhashchange = function () { iframe.src = "http://127.0.0.1:1001/C.html"+ location.hash; } </script>
頁面C
<script> //=>監聽B傳來的HASH值 window.onhashchange = function () { //=>再經過操做同域A的js回調,將結果傳回 window.parent.parent.func(location.hash); }; </script>
只能實現:同一個主域,不一樣子域之間的操做
v.qq.com
sports.qq.com
父頁面A http://www.github.cn/A.html
<iframe src="http://school.github.cn/B.html"></iframe> <script> document.domain = 'github.cn'; var user = 'admin'; </script>
子頁面B http://school.github.cn/B.html
<script> document.domain = 'github.cn'; alert(window.parent.user); </script>
前端處理
<script src="./socket.io.js"></script> <script> let socket = io('http://127.0.0.1:3001/'); //=>鏈接成功處理 socket.on('connect', function() { //=>監聽服務端消息 socket.on('message', function(msg) { console.log('data from server:' + msg); }); //=>監聽服務端關閉 socket.on('disconnect', function() { console.log('server socket has closed!'); }); }); //=>發送消息給服務器端 socket.send("github"); </script>
服務器端處理
//=>監聽socket鏈接:server是服務器建立的服務 socket.listen(server).on('connection', function(client) { //=>接收信息 client.on('message', function(msg) { //=>msg客戶端傳遞的信息 //... client.send(msg+'@@'); }); //=>斷開處理 client.on('disconnect', function() { console.log('client socket has closed!'); }); });