常用的-前端跨域的解決

_王驍凱發表於2019-10-17

跨域(非同源策略請求)

-同源策略請求 是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到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,再請求一個帶參網址實現跨域通訊。

伺服器拆分
  1. web伺服器:靜態資源 
  2. data伺服器:業務邏輯和資料分析 
  3. 圖片伺服器

常用的-前端跨域的解決

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哈哈哈'}複製程式碼

JSONP缺點:JSONP只能處理GET請求

二、 跨域資源共享(CORS)

- 客戶端(傳送ajax/fetch請求)

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);}複製程式碼

- 伺服器端設定相關的頭資訊(需要處理options試探性請求)

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>複製程式碼

六,七,八,九...................................................................睡醒了寫


相關文章