1.瀏覽器的同源策略及規避方法
目前,所有瀏覽器都實行同源政策。即協議、域名、端口都相同的URI稱為"同源"。不同源的url之間:
a.無法讀取cookie、localstorage、indexDB
b.無法獲取DOM
c.無法發送ajax請求
document.domain規避半同源網頁間不能共享cookie:
cookie是服務器寫入瀏覽器的一段信息。同源網頁之間才能共享cookie。
一級域名相同,二級域名不同的網頁之間允許通過設置document.domain='一級域名'的方式共享cookie。另外服務器在設置cookie的時候,指定cookie所屬的域名為一級域 名,這樣的話不需要做任何操作.
postMesage規避不同源網頁之間不能共享數據:
html5新增的跨文檔通信API為window對象新增了一個方法window.postMesage允許跨窗口通信,無論這兩個窗口是否同源。
postMessage方法有兩個參數,第一個為需要傳遞的數據,第二個為傳送目標窗口地址。通過window.addEventListener('message',function(){})監聽window的message事件 獲取數據。message事件的event對象有三個屬性:event.source =>發送消息的窗口 event.origin=>消息發向的網址 event.data=>消息內容。
window.name規避父子窗口之間不能共享數據:(父窗口打開iframe子窗口)
瀏覽器窗口有window.name屬性。這個屬性的最大特點是,無論是否同源,只要在同一個窗口里,前一個網頁設置了這個屬性,后一個網頁可以讀取它。
這種方法的優點是,window.name容量很大,可以放置非常長的字符串;缺點是必須監聽子窗口window.name屬性的變化,影響網頁性能。
2.ajax請求跨域
同源政策規定,AJAX請求只能發給同源的網址,否則就報錯。
除了架設服務器代理(瀏覽器請求同源服務器,再由后者請求外部服務),有三種方法規避這個限制:
a.jsonp (利用script標簽不受同源策略影響,只支持get方式,一般用jquery的jsonp封裝,接口需在返回值的外面包回調函數)
b.websocket(一種通信協議,不受同源策略影響)
c.cors(CORS是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。是跨源AJAX請求的根本解決方法。)
CORS需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低於IE10。
整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。
瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。
因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。
常見后端解決方案:
PHP后台配置
PHP后台得配置幾乎是所有后台中最為簡單的,遵循如下步驟即可:
-
第一步:配置Php 后台允許跨域
<?php header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
//主要為跨域CORS配置的兩大基本信息,Origin和headers
-
第二步:配置Apache web服務器跨域(httpd.conf中)
原始代碼
<Directory />
AllowOverride none
Require all denied
</Directory>
改為以下代碼
<Directory />
Options FollowSymLinks
AllowOverride none
Order deny,allow
Allow from all
</Directory>
JAVA后台配置
JAVA后台配置只需要遵循如下步驟即可:
-
第一步:獲取依賴jar包下載 cors-filter-1.7.jar, java-property-utils-1.9.jar 這兩個庫文件放到lib目錄下。(放到對應項目的webcontent/WEB-INF/lib/下)
-
第二步:如果項目用了Maven構建的,請添加如下依賴到pom.xml中:(非maven請忽視)
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>[ version ]</version>
</dependency>
其中版本應該是最新的穩定版本,CORS過濾器
-
第三步:添加CORS配置到項目的Web.xml中( App/WEB-INF/web.xml)
<!-- 跨域配置-->
<filter>
<!-- The CORS filter with parameters -->
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<!-- Note: All parameters are options, if omitted the CORS
Filter will fall back to the respective default values.
-->
<init-param>
<param-name>cors.allowGenericHttpRequests</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowSubdomains</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, HEAD, POST, OPTIONS</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<!--這里可以添加一些自己的暴露Headers -->
<param-value>X-Test-1, X-Test-2</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.maxAge</param-name>
<param-value>3600</param-value>
</init-param>
</filter>
<filter-mapping>
<!-- CORS Filter mapping -->
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
請注意,以上配置文件請放到web.xml的前面,作為第一個filter存在(可以有多個filter的)
-
第四步:可能的安全模塊配置錯誤(注意,某些框架中-譬如公司私人框架,有安全模塊的,有時候這些安全模塊配置會影響跨域配置,這時候可以先嘗試關閉它們)
Node.js后台配置(express框架)
Node.js的后台也相對來說比較簡單就可以進行配置。只需用express如下配置:
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
//這段僅僅為了方便返回json而已
res.header("Content-Type", "application/json;");
if(req.method == 'OPTIONS') {
//讓options請求快速返回
res.sendStatus(200);
} else {
next();
}
});
