一個iOS程序員眼中的跨域問題

最近公司的iOS開發任務比較少,因此本身最近開始了Web開發的任務,在用H5作了不少頁面,所作的東西和以前客戶端界面如出一轍,只是作好h5搬到微信上。本人開發環境:html開發ide一會用HBulder一下子用Sublime。javascript

php

了模擬真實的環境,因此HBulder新建了WebApp,跑起來能夠針個人大玫瑰金上運行看效果(iphone6s plus玫瑰金)。我很傻的覺得手機上運行沒錯就沒問題了,不會存在傳說中的<b>跨域問題</b>,沒想到週五下午要合併代碼到Dev分支,才發現合併進去頁面報錯。html

只能怪本身"too young too naive",回頭一想,原來App請求接口相似於C/S不存在跨域問題。而網頁這種方式只要協議、域名、端口、有一個不一致就會致使跨域,因爲本身所作的頁面有40多,因此改起來煩的要死,問同事除了將數據放進url後來造成相似http://xxx/com?s=xx&q=yy這種形式有木有其餘辦法?最後找出一種快速修改的方法,見下面代碼html5

修改前java

$.ajax({
type: "post",
url: early_children_url ,
data:urlJson,
success: function(data) {
console.log(storageData);
swal({
//省略...

修改後ajax

var neonataldetail = '{' +
'"babyinfoid":"' + earlyBabyInfoId + '",' +
'"days":"' + day + '",' +
'"feedingtimes":"' + feedingtimes + '",' +
'"feedingway":"' + feedingway + '",' +
'"stoolfrequency":"' + stoolfrequency + '",' +
'"urinate":"' + urinate + '",' +
'"yellowish":"' + yellowish + '",' +
'"weight":"' + weight + '"' +
'}';

var dataJson = {
"type": early_children_perinatal_type,
"neonataldetail": JSON.parse(neonataldetail)
};
var urlJson = JSON.stringify(dataJson);
$.ajax({
dataType: "jsonp",
type: "post",
url: early_children_url + "?s=" + urlJson,
success: function(data) {
console.log(storageData);
swal({
title: "提交成功",
text: "",
showCancelButton: false,
closeOnConfirm: false,
showLoaderOnConfirm: true
}, function(data) {
window.location.href = "early-children.html";
});
},
error: function() {
swal("上傳失敗,請檢查網絡後重試");
}
});

 

最後查了相關的資料發現跨域問題大致有3種解決方案:(1)、代理;(2)、JSONP(支持get請求);(3)、XHR2;(4)、CORS跨域資源共享;(5)、經過修改document.domain來解決iframe跨域問題;(6)、window.name進行跨域;(7)、HTML5的window.postMessage方法json

 

具體說明:基於瀏覽器的安全考慮,因爲同源策略的限制,不一樣域名、不一樣端口、不一樣協議的對象不能互相調用。(其實瀏覽器成功發送請求並拿回了數據 只是瀏覽器的同源策略 禁止了獲取 )跨域

 

代理:經過統一域名下的Web服務器建立一個代理。瀏覽器

舉例說明:www.hangzhou.com的a.html須要調用www.shanghai.com下的b.php服務,顯然這違反了同源策略,因此就須要經過代碼這個方法去解決問題。具體怎麼作?能夠在www.hangzhou.com下能夠寫個exchange.php。將去請求www.shanghai.com下的服務,以後將結果返回給a.html。這樣訪問www.hangzhou.com/exchange.php的效果等於訪問www.shanghai.com的服務安全

 

JSONP:JSON with padding。是JSON的一種使用方式,適用於主流瀏覽器的跨域訪問問題。JSONP由2部分組成:回調函數和數據

//www.hangzhou.com

<script type="text/javascript">

   function getArg(data){

      //處理數據

   }

</script>

<script type="text/javascript" src="http://www.shanghai.com/showUser.php?callback=getArg."></script>


js文件載入成功後會執行咱們在url參數中指定的函數,因此JSONP是須要服務端進行配合的。

//www.shanghai.com

<?php

     $callback = $_GET['callback'];//獲得回調函數名

     $data = array('a','b','c');//要返回的數據

     echo $callback.'('.json_encode($data).')';//輸出

?>

XHR2:HTML5提供的XMLHttpRequest Level2已經實現了跨域訪問以及其餘的一些新功能。但不適配全部瀏覽,好比IE10如下的版本均不支持。

此外還須要在服務端修改

header('Access-Controller-Allow-Origin:*');

header('Access-Controller-Allow-Methods:POST、GET');

window.onload = function () {

   var xhr = new XMLHttpRequest();

   //判斷瀏覽器是否支持XHR2

   if (xhr.withCredentials === undefined) return false;



   xhr.open("get", "http://www.baidu.com");

   xhr.onreadystatechange = function () {

  if (xhr.readyState !== 4) return;//忽略未完成的調用

    if (xhr.status === 200) {

       console.log(xhr.responseText);

    }

  }

  xhr.send(null);

}

 

CORS跨域資源共享:Cross-Origin Resource Sharing定義了進行訪問跨域資源時瀏覽器如何與服務器通訊。

<script type="">

   var xhr = new XMLHTTPRequest();

   xhr.open("get","/showUser.php");

   xhr.send();

</script>

若是使用CORS

<script type="">

   var xhr = new XMLHTTPRequest();

   xhr.open("get","http://hangzhou.com/showUser.php");

   xhr.send();

</script>

 

代碼與以前的代碼差異就是使用了絕對路徑。服務端對於CORS的支持在於Access-Control-Allow-Origin來進行的。若是瀏覽器檢測到相應的設置,就能夠容許Ajax進行跨域的訪問。

 

CORS和JSONP對比

一、JSONP只能夠實現get請求,CORS能夠全部類型的HTTP請求

二、CORS開發者可使用普通的XMLHTTPRequest請求和獲取數據

三、JSONP支持較老的瀏覽器,而老版本的瀏覽器不支持CORS

 

 

 

經過修改document.domain來跨域

瀏覽器的同源策略限制之一就是不能經過Ajax去請求不一樣源的文檔,限制之二就是瀏覽器中不一樣域的框架之間是不能進行js交互。

不一樣框架之間能夠獲取window對象,可是window對象的屬性和方法不可獲取到。

http://www.hangzhou.com/a.html的一個frame的src是http://www.xihu.hangzhou.com/b.html這時候document.domain就能夠上場了,

不過須要注意,document.domain的設定有限制,必須設置成自身或比自身更高一級的父域,且主域必須相同。

<iframe id = "iframe" src="http://xihu.hangzhou.com/b.html" onload="showUser()"></iframe>

<script type="text/javascript">

document.domain = 'hangzhou.com';//設置成主域

function showUser(){

alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 對象

}

</script>

在頁面http://xihu.hangzhou.com/b.html也須要設置

<script type="text/javascript">

document.domain = 'hangzhou.com';//在iframe載入這個頁面也設置document.domain,使之與主頁面的document.domain相同

</script>

 

經過window.name來跨域

window對象有個name屬性,該屬性有個特徵:即在一個窗口(window)的生命週期內,窗口載入的全部的頁面都是共享一個window.name的,每一個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的全部頁面中的

 

HTML5的window.postMessage方法跨域

window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可使用它來向其它的window對象發送消息,不管這個window對象是屬於同源或不一樣源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支持window.postMessage方法。

 

傳送門:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policyhttp://www.ruanyifeng.com/blog/2016/04/cors.html

相關文章
相關標籤/搜索