1. 程式人生 > >跨域的幾種常見的解決方式

跨域的幾種常見的解決方式

今天給大家分享一下,修真院官網JSS-5任務中可能會使用到的知識點:

1.背景介紹

1.1什麼是跨域?

跨域是指一個域下的文件或指令碼試圖去請求另一個域下的資源,這裡跨域是廣義的。


廣義的跨域:
1.) 資源跳轉: A連結、重定向、表單提交
2.) 資源嵌入: link script img frame等dom標籤,還有樣式中background:url()、@font-face()等檔案外鏈
3.) 指令碼請求: js發起的ajax請求、dom和js物件的跨域操作等


在前端部分其實我們通常所說的跨域是狹義的,是由瀏覽器同源策略限制的一類請求場景。

1.2那麼是什麼同源策略呢?

同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協議+域名+埠"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。


同源策略限制以下幾種行為: 1.) Cookie、LocalStorage 和 IndexDB 無法讀取 2.) DOM 和 Js物件無法獲得 3.) AJAX 請求不能傳送

1.3常見的跨域場景


2.知識剖析

2.1 常見的跨域方式

JSONP


在使用XMLHTTPRequest物件傳送HTTP請求時,會遇到同源策略問題,域不同請求會被瀏覽器攔截。這時就可以選擇繞過,或者說是不使用XMLHTTPRequest物件進行傳送跨域HTTP請求。 在平常寫html時會發現比如

<script src="http://www.a.com/script/1.js"></script>
<img src="http://www.b.com/1.jpg">
<link href="http://www.c.com/1.css">              
                      
這種標籤是不會遇到'跨域'問題的,嚴格上來說,這不是跨域,跨域是指在指令碼程式碼中向非同源域傳送HTTP請求,這只是跨站資源請求

那麼我們可以試試看用這種跨站資源請求的方式來實現跨域HTTP請求

                  <!-- HTML表頭部分-->
                        ...
                        <!--  javaScript片段1-->
                        // 如果jsonp 的請求為GET
  if ( ctx.method === 'GET' && ctx.url.split('?')[0] === '/getData') {

    // 獲取jsonp的callback
    let callbackName = ctx.query.callback || 'callback'
    let returnData = {
      success: true,
      data: {
        text: 'this is a jsonp api',
        time: new Date().getTime(),
      }
    }

    // jsonp的script字串
    let jsonpStr = `;${callbackName}(${JSON.stringify(returnData)})`

    // 用text/javascript,讓請求支援跨域獲取
    ctx.type = 'text/javascript'

    // 輸出jsonp字串
    ctx.body = jsonpStr

  } else {

    ctx.body = 'hello jsonp'

  }
})
NGINX的反向代理

nginx支援配置反向代理,通過反向代理實現網站的負載均衡。這部分先寫一個nginx的配置,後續需要深入研究nginx的代理模組和負載均衡模組。 nginx通過proxy_pass_http 配置代理站點,upstream實現負載均衡。


WINDOW.NAME + IFRAME

WINDOW.NAME 傳輸技術的基本原理:

當在瀏覽器中開啟一個頁面,或者在頁面中新增一個iframe時即會建立一個對應的window物件,當頁面載入另一個新的頁面時,window的name屬性是不會變的。這樣就可以利用在頁面動態新增一個iframe然後src載入資料頁面,在資料頁面將需要的資料賦值給window.name。然而此時承載iframe的parent頁面還是不能直接訪問,不在同一域下iframe的name屬性,這時只需要將iframe再載入一個與承載頁面同域的空白頁面,即可對window.name進行資料讀取

name 在瀏覽器環境中是一個全域性/window物件的屬性,且當在 frame 中載入新頁面時,name 的屬性值依舊保持不變。通過在 iframe 中載入一個資源,該目標頁面將設定 frame 的 name 屬性。此 name 屬性值可被獲取到,以訪問 Web 服務傳送的資訊。但 name 屬性僅對相同域名的 frame 可訪問。這意味著為了訪問 name 屬性,當遠端 Web 服務頁面被載入後,必須導航 frame 回到原始域。同源策略依舊防止其他 frame 訪問 name 屬性。一旦 name 屬性獲得,銷燬 frame 。

在最頂層,name 屬性是不安全的,對於所有後續頁面,設定在 name 屬性中的任何資訊都是可獲得的。然而 windowName 模組總是在一個 iframe 中載入資源,並且一旦獲取到資料,或者當你在最頂層瀏覽了一個新頁面,這個 iframe 將被銷燬,所以其他頁面永遠訪問不到 window.name 屬性

<script type="text/javascript"> 
iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0;
iframe.onload = function() {
if(state === 1) {
var data = JSON.parse(iframe.contentWindow.name);
console.log(data);
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
} else if(state === 0) {
state = 1;
iframe.contentWindow.location = 'http://localhost:81/cross-domain/proxy.html';//指向自己根目錄下的空檔案
}
};
iframe.src = 'http://localhost:8080/data.php';//要請求的不同源資料
document.body.appendChild(iframe);
</script>

也可以node.js或者其他服務端設定cors表頭來授權跨域

3.常見問題

4.解決方案

5.編碼實戰

6.拓展思考

6.1正向代理



正向代理類似一個跳板機,代理訪問外部資源。




 我是一個使用者,我訪問不了某網站,但是我能訪問一個代理伺服器,這個代理伺服器呢,他能訪問那個我不能訪問的網站,於是我先連上代理伺服器,告訴他我需要那個無法訪問網站的內容,代理伺服器去取回來,然後返回給我。從網站的角度,只在代理伺服器來取內容的時候有一次記錄,有時候並不知道是使用者的請求,也隱藏了使用者的資料,這取決於代理告不告訴網站。

  客戶端必須設定正向代理伺服器,當然前提是要知道正向代理伺服器的IP地址,還有代理程式的埠。

總結來說:正向代理 是一個位於客戶端和原始伺服器(origin server)之間的伺服器,為了從原始伺服器取得內容,客戶端向代理髮送一個請求並指定目標(原始伺服器),然後代理向原始伺服器轉交請求並將獲得的內容返回給客戶端。客戶端必須要進行一些特別的設定才能使用正向代理。   
正向代理的用途:
  (1)訪問原來無法訪問的資源,如google
(2) 可以做快取,加速訪問資源
  (3)對客戶端訪問授權,上網進行認證

  (4)代理可以記錄使用者訪問記錄(上網行為管理),對外隱藏使用者資訊

6.2反向代理


客戶端是無感知代理的存在的,反向代理對外都是透明的,訪問者者並不知道自己訪問的是一個代理。因為客戶端不需要任何配置就可以訪問。
  反向代理(Reverse Proxy)實際執行方式是指以代理伺服器來接受internet上的連線請求,然後將請求轉發給內部網路上的伺服器,並將從伺服器上得到的結果返回給internet上請求連線的客戶端,此時代理伺服器對外就表現為一個伺服器。
反向代理的作用:
(1)保證內網的安全,可以使用反向代理提供WAF功能,阻止web攻擊

大型網站,通常將反向代理作為公網訪問地址,Web伺服器是內網。


(2)負載均衡,通過反向代理伺服器來優化網站的負載


6.3二者的區別


借某乎上一個靈魂畫手的圖片解釋下

7.參考文獻

前端常見跨域解決方案:https://www.cnblogs.com/roam/p/7520433.html 

js中幾種使用的跨域方法詳解:https://www.cnblogs.com/2050/p/3191744.html

8.更多討論

一、哪種跨域常用?

淘寶、百度、網易雲音樂,之類會配置公共的API,會是JSONP

公司內的話會選擇window.name或者nginx反向代理

我們任務中會使用nginx.conf進行反向代理

二、從安全性而言選擇那種跨域方式最好,為什麼?

一般最安全的是WINDOW.NAME,因為iframe會銷燬

三、JSONP的缺點
jsonp有個缺陷就是隻能get

而且會把請求的內容傳送到url中導致安全性極低