瀏覽器的同源策略與跨域處理

1、  同源策略

若是兩個頁面的協議,端口(若是有指定)和域名都相同,則兩個頁面具備相同的javascript

下表給出了相對http://store.company.com/dir/page.html同源檢測的示例:html

同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。前端

容許跨源訪問的一些例子:java

  • <script src="..."></script> 標籤嵌入跨域腳本。語法錯誤信息只能在同源腳本中捕捉到。
  • <link rel="stylesheet" href="..."> 標籤嵌入CSS。因爲CSS的鬆散的語法規則,CSS的跨域須要一個設置正確的Content-Type 消息頭。不一樣瀏覽器有不一樣的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。
  • <img>嵌入圖片。支持的圖片格式包括PNG,JPEG,GIF,BMP,SVG,...
  • <video> 和 <audio>嵌入多媒體資源。
  • <object><embed> 和 <applet> 的插件。
  • @font-face 引入的字體。一些瀏覽器容許跨域字體( cross-origin fonts),一些須要同源字體(same-origin fonts)。
  • <frame> 和 <iframe> 載入的任何資源。站點可使用X-Frame-Options消息頭來阻止這種形式的跨域交互。

 使用 CORS 容許跨源訪問。jquery

 

跨源腳本API的訪問git

Javascript的APIs中,如 iframe.contentWindowwindow.parentwindow.open 和 window.opener 容許文檔間直接相互引用。當兩個文檔的源不一樣時,這些引用方式將對 Window 和 Location對象的訪問添加限制。github

可使用window.postMessage做不一樣源文檔之間的交流。web

 

跨源數據存儲訪問ajax

存儲在瀏覽器中的數據,如localStorageIndexedDB,以源進行分割。每一個源都擁有本身單獨的存儲空間,一個源中的Javascript腳本不能對屬於其它源的數據進行讀寫操做。chrome

 

2、幾種跨域解決方案

 一、JSONP

Jsonp(JSON with Padding) 是 json 的一種"使用模式",可讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。

Jsonp 的實現原理是利用 <script> 標籤能夠獲取不一樣源資源的特色,來達到跨域訪問某個資源的目的。假如 <script> 元素內部的代碼沒有位於某個函數中,那麼這些代碼會在頁面被加載時被當即執行。

應用實例:

服務端代碼使用jFinal框架

 1 package com.controller;
 2 
 3 import com.mazu.core.Controller;
 4 
 5 public class JsonPController extends Controller{
 6 
 7     public void getUserInfo(){
 8     
 9         String userId = getPara("userId");
10         String callBackFunc = getPara("callback");
11         if(userId!=null&&userId.equals("123")){
12             String userJson = "{\"userName\":\"Admin\",\"age\":26}";
13             callBackFunc += "('success',"+userJson+")";//拼接爲callback(a,b)的形式返回給前端 14             renderJson(callBackFunc);
15         }else{
16             renderJson(callBackFunc+"('error')");
17         }
18     }
19 }

客戶端代碼

 1 <script>
 2 function callbackFunc(status,data){
 3     if(status=="success"){
 4         console.log(data.userName+":"+data.age);
 5     }else{
 6         console.log(status);
 7     }
 8 }
 9 </script>
10 <script type="text/javascript" src="http://localhost/TestJSONP/jsonp/getUserInfo?userId=123&callback=callbackFunc"></script>

chrome中執行結果

因爲是本地測試,使用的是端口不一樣的兩個項目,能夠看到服務端響應後,返回給前端一個字符串callback(status,data),前端<script>接收到這段代碼後當即執行,成功實現了跨域資源的訪問。

在jQuery中如何經過JSONP來跨域獲取數據

第一種方法是在ajax函數中設置dataType爲'jsonp': 

$.ajax({
    dataType: 'jsonp',
    url: 'http://localhost/TestJSONP/jsonp/getUserInfo?userId=123',
    success: function(data){
       console.log(data);//success
    }
});

上面的方式只能返回一個參數,多參數時將沒法獲得第二個及以後的參數。

 

能夠在傳遞過程當中自定義函數名,使用jsonpCallback參數

jsonp:表示傳遞的參數,默認爲callback,咱們也能夠自定義

jsonpCallback:表示傳遞的參數值,也就是回調的函數名稱,這是自定義的名稱

 1 <script src="http://apps.bdimg.com/libs/jquery/1.8.3/jquery.js"></script>
 2 <script>
 3 function callbackFunc(status,data){
 4     if(status=="success"){
 5        // console.log(data.userName+":"+data.age);
 6         console.log("callback:"+data);
 7     }else{
 8         console.log("callback:"+status);
 9     }
10 }
11 $.ajax({
12     type:"get",
13     url: 'http://localhost/TestJSONP/jsonp/getUserInfo?userId=123',
14     dataType: 'jsonp',
15     jsonp:'callback',
16     jsonpCallback:'callbackFunc',
17     success: function(data){
18        console.log("ajax:"+data);
19     }
20 });
21 
22 </script>

執行結果:

能夠看到返回結果中,仍然獲取不到第二個參數值。仔細debug了一下後臺,返回的字符串也是正確的。

因而我改了下後臺的返回值和回調函數的參數,獲得了正確的測試結果。

 因而可知,使用jQuery作JSONP跨域調用時,與ajax的success回調函數同樣,服務端須要將傳的內容封裝在一個返回值中。

爲何使用jsonpCallback簡單的綁定回調函數就能實現回調函數調用了呢?

仔細跟蹤chrome中的執行過程,發現Jquery首先將回調函數賦值給一個內部函數,在服務端響應成功後,執行這個內部函數,而後銷燬,起到一個臨時代理的做用。

jQuery 的 $.ajax 只支持get方式獲取跨域數據,而且它不支持出錯時的回調。

jQuery-JSONP是一個支持 JSONP 調用的 jQuery 插件,使用它是由於它支持出錯時的 ajax 回調。 

 1 <script src="jquery-3.2.1.js"></script>
 2 <script src="jquery-jsonp.js"></script>
 3 <script>
 4     $.jsonp({
 5         url: 'http://localhost/TestJSONP/jsonp/getUserInfo',
 6         data: { userId: 123 },
 7         callbackParameter: "callback",
 8         success: function (data, textStatus, xOptions) {
 9             console.log(data);
10         },
11         error: function (xOptions, textStatus) {
12         }
13     });
14 </script>

第1個須要注意的地方是 callbackParameter,若是沒有專門的 callback 函數,必定要寫上 "callback";
第2個須要注意的地方是在 success 回調函數中,xOptions包含傳給服務器的參數,如xOptions.data={userId:123}。

 

二、CORS

CORS全稱是「跨域資源共享」(Cross-origin resource sharing),它是一種經過設置HTTP頭信息來獲取跨源服務器上的特定資源,主要是設置Access-Control-Allow-Origin字段的值。

服務端代碼:

 1 public void getUserInfo(){
 2     
 3         String userId = getPara("userId");
 4         String userJson = "";
 5         if(userId!=null&&userId.equals("123")){
 6             System.out.println("userId:"+userId);
 7             userJson = "{\"userName\":\"Admin\",\"age\":26}";
 8         }
 9         //getResponse().setHeader("Access-Control-Allow-Origin", "*");
10         renderJson(userJson);
11         
12     }

客戶端代碼:

1   $.ajax({
2       type:"get",
3       url: 'http://localhost/TestJSONP/jsonp/getUserInfo?userId=123',
4       dataType: 'json',
5       success: function(data){
6           console.log("ajax:"+data);
7       }
8   })

當服務端迴應頭信息中沒有包含Access-Control-Allow-Origin字段時,瀏覽器報錯以下:

設置Access-Control-Allow-Origin爲*,表示接受任意域名的請求,在實際開發中爲了安全起見通常設爲特定域名。

與JSONP的比較

CORS與JSONP的使用目的相同,可是比JSONP更強大。

JSONP只支持GET請求,CORS支持全部類型的HTTP請求。JSONP的優點在於支持老式瀏覽器,以及能夠向不支持CORS的網站請求數據。

 

三、window.postMessage

HTML5跨文檔消息傳輸Cross Document Messaging。下一代瀏覽器都將支持這個功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。

用postMessage支持基於web的實時消息傳遞。

window.postMessage() 方法被調用時,會在全部頁面腳本執行完畢以後(e.g., 在該方法以後設置的事件、以前設置的timeout 事件,etc.)向目標窗口派發一個  MessageEvent 消息。

MessageEvent消息有四個屬性須要注意:

  • message 屬性表示該message 的類型; 
  • data 屬性爲 window.postMessage 的第一個參數;
  • origin 屬性表示調用window.postMessage() 方法時調用頁面的當前狀態; 
  • source 屬性記錄調用 window.postMessage() 方法的窗口信息。

 語法:

otherWindow.postMessage(message, targetOrigin, [transfer]);

 

 

 

 

 

 

 

 

參考:

相關文章
相關標籤/搜索