跨域存取設定
一、什麼是跨域?
跨域是指一個網域下的文件或腳本試圖去請求另一個網域下的資源。廣義的跨域包括:
- 資源跳轉:A連結、重新導向、表單提交
- 資源嵌入:
<link>、<script>、<img>、<video>等DOM標籤以及樣式表中的background:url( )、@font-face( )等檔案外鏈 - 腳本請求:Ajax請求、DOM和JavaScript物件的跨域操作等
而我們通常所說的跨域是狹義的,是由瀏覽器同源策略限制的一類請求場景。**同源策略**(Same-origin policy)是瀏覽器最核心也最基本的一個安全策略,它限制了從同一個來源載入的文件或腳本如何與另一個來源的資源進行互動。它能幫助阻隔惡意文件,減少可能被攻擊的媒介。所謂同源是指協定、網域名稱、連接埠三者相同,當一個請求URL的協定、網域名稱、連接埠三者中任意一個與當前頁面URL不同即為跨域。同源策略的限制如下:
- 無法讀取非同源網頁的Cookie、LocalStorage和IndexDB
- 無法獲得非同源網頁的DOM和JS物件
- 無法向非同源位址發送Ajax請求
二、跨域解決方案
常見的跨域解決方案有:
- 透過jsonp跨域
- 跨域資源共享(CORS)
- Nginx代理跨域
- postMessage跨域
- WebSocket協定跨域
- ...
開發者應結合實際情況選擇最適合的方案,下面將對與保利威視訊播放服務相關的跨域問題解決方案進行介紹。
1、透過jsonp跨域
<script>、<img>等一些獲取資源的HTML標籤是沒有跨域限制的,基於此原理,網頁可透過新增一個<script>,向伺服器請求 JSON 資料,伺服器收到請求後將資料放在一個指定名字的回呼函數的參數位置傳回來。
JSONP 是伺服器與客戶端跨來源通訊的常用方法。最大特點就是簡單適用,相容性好(相容低版本IE),缺點是只支援GET請求。
原生實作:
<script src="http://www.domain2.com:8080/login?user=admin&callback=handleCallback"></script>
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function handleCallback(res){
// 处理获得的数据
console.log(res);
}
</script>
伺服器端回傳資料如下:
handleCallback({"status":true,"user":"admin"})
jQuery Ajax:
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
Vue.js:
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
2、跨域資源共享(CORS)
跨域資源共享(Cross-Origin Resource Sharing)是W3C標準,目前所有瀏覽器都支援該功能(IE8/9需要使用XDomainRequest物件來支援CORS),CORS也已經成為主流的跨域解決方案。詳見HTTP存取控制CORS的詳解。
- 普通跨域請求:只需伺服器端設定Access-Control-Allow-Origin即可,前端無需設定
- 帶cookie跨域請求:前後端都需要進行設定
前端設定:
1.) 原生Ajax
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
2.) jQuery Ajax
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
data: {},
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
});
3.) vue-resource
Vue.http.options.credentials = true
4.) axios
axios.defaults.withCredentials = true
伺服器端設定:
伺服器端對於CORS的支援,主要是透過設定Access-Control-Allow-Origin來進行的。如果瀏覽器偵測到相應的設定,就可以允許Ajax進行跨域的存取。
1.) Java後台
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
2.) PHP後台
<?php
header("Access-Control-Allow-Origin:*");
3、Flash播放器的跨域配置
Flash播放器在請求授權播放和跑馬燈介面時,需要配置允許跨域請求。配置方式為:新增crossdomain.xml檔案到播放網域的根目錄下。
crossdomain.xml檔案內容:
<?xml version="1.0" encoding="UTF-8"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
</cross-domain-policy>
