JavaScript 跨域訪問的問題和解決過程

來源:互聯網
上載者:User

分享一下最近用jQuery跨域請求的經曆, 

希望能給大家一些關於這個方案的概念和資料。

該部分包括用戶端和伺服器端,(如果伺服器不在自己手上,那麼還是考慮通過自己的伺服器轉寄請求吧)
 

 

1.原本的代碼很簡單。。如果是同網域名稱什麼問題都沒有 (有興趣的朋友可以嘗試在自己的伺服器上運行以下代碼)

           $.ajax({
url: "http://www.google.com/", //不同網域名稱,而且google 沒有允許第三方提交所以會出錯
cache: false,
//data: params,
dataType: 'json',
success: function (data) {
console.log(data);
},
error: function (e) {
alert(e.statusText);
}
})

嗯,我的預設瀏覽器是Chrome, 上去一跑。。。當然不能用。。。什麼都還沒做呢,就想做跨域訪問這麼危險的事情

下面是Chrome給出的錯誤提示 

  

2.在伺服器端做點手腳,

                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); // 可以設定為詳細的地址

3. 好了現在Chrome中的Get已經可以運行了,依葫蘆畫瓢開發了Post方法。。。。發現Post不能用。。。。- -# 真是不順利啊

在Fiddler中發現用戶端提交的是OPTIONS的請求。。。。恩。。。。。那就加一段邏輯處理OPTIONS

                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); // 可以設定為詳細的地址

if (HttpContext.Current.Request.HttpMethod == "OPTIONS") // 加點邏輯
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept,X-Requested-With");
HttpContext.Current.Response.End();
}
 

實際運行中有兩次請求 第一次是OPTIONS 第二次才是POST

 

4.還有問題。。。。忽然發現在IE8和IE9中無法運行,而在其他的瀏覽器中都正常(opera未測試,google說這個瀏覽器也有問題。不過這東西比較小眾)

使用Fiddler發現 這個動作根本沒有被提交到伺服器端。。。。

經常Google以後發現。。。。IE8以上的版本跨域提交需要使用XDomainRequest 對象。。。。(IE 為什麼每次你都這麼另類!,jQuery你為什麼不相容ie8和ie9的跨域提交功能。。加點代碼很麻煩麼!!!)

 var xdr = new XDomainRequest();
xdr.onload = function (e) {
var data = $.parseJSON(xdr.responseText);
if (data == null || typeof (data) == 'undefined') {
data = $.parseJSON(data.firstChild.textContent);
}
//success
};
xdr.onerror = function (e) {
//error
}

xdr.open("GET", url);
xdr.send();

關於 XDomainRequest 請在這裡查看詳細,http://msdn.microsoft.com/en-us/library/cc288060(VS.85).aspx

 

5.恩 get功能在ie中也可以了。。。不錯不錯, POST還不行。。。莫非又是IE的問題?? 這。。怎麼每個功能都這麼多問題?

奇怪的是Fiddler中顯示IE8 中POST請求確實發出去了啊。。。怎麼回事??

把問題分解來看,吧fiddler擷取的http request raw資料拿出來 單獨提交試試。。。也不行?! 伺服器返回415。。。 看來好像不是ie的問題。(這次冤枉了它了)

仔細排查,發現缺少Content-Type(Content-Type其實不是必須的,參考RFC)

這坑爹的WCF 3.5啊, 不傳Content Type就給我報415異常  (WCF 4.0已經解決這個問題,3.5解決起來很麻煩,我一怒之下用了普通的ashx來處理)

.....嗯。。。少什麼我加什麼。。。 what?!!! XDomainRequest 不能隨便設定header,    

var xdr=new XDomainRequest ();
xdr.contentType="application/json"; //異常。。。。。。。
xdr.contentType = "text/plain"; //這是唯一可以設定的值。。。。MS。。。我要json不要這個。。。。

好吧javascript這邊設定失敗了。。只能去伺服器動手腳。。。想死的心都有了。。。。做點功能怎麼這麼麻煩。。。

到此為止,總算告一個段落了。。。

 

附錄1

用來解決跨域問題的,伺服器端代碼

    public class Global : System.Web.HttpApplication
{
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (HttpContext.Current != null && HttpContext.Current.Response != null)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); // take care

if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept,X-Requested-With");
HttpContext.Current.Response.End();
}
}
}

}

伺服器也可以通過放置crossdomain.xml在根目錄下指定該邏輯,參考http://www.weibo.com/crossdomain.xml 

 

附錄2 用來解決用戶端問題的參考代碼(代碼比較潦草,不過重要的是邏輯)

View Code

function cloverGet(url, params, isRenderLoading, callback) {
if ($.browser.msie && parseInt($.browser.version, 10) >= 8 && window.XDomainRequest) {
var xdr = new XDomainRequest();

xdr.onload = function (e) {
var data = $.parseJSON(xdr.responseText);
if (data == null || typeof (data) == 'undefined') {
data = $.parseJSON(data.firstChild.textContent);
}
//需要手動處理json資料
};
xdr.onerror = function (e) {

}
xdr.open("GET", url);
xdr.send();
}
else {
$.ajax({
url: url,
cache: false,
data: params,
dataType: 'json',
success: function (data) {

},
error: function (e) {

},
complete: function (e) {

},
beforeSend: function (xhr) {

}
});



}
}
function cloverPost(url, params, callback) {

if ($.browser.msie && parseInt($.browser.version, 10) >= 8 && window.XDomainRequest) {
var xdr = new XDomainRequest();
xdr.contentType = "text/plain";
xdr.onload = function () {
var data = $.parseJSON(xdr.responseText);
if (data == null || typeof (data) == 'undefined') {
data = $.parseJSON(data.firstChild.textContent);
}
//需要手動格式化
};
xdr.onerror = function (e) {

}
xdr.open("POST", url);
xdr.send(params); //這裡的資料是 a=1&b=2這樣的

}
else {
$.ajax({
type: "POST",
url: url,
data: params,
// dataType: "json", //有的時候jsonp也是一個選擇
crossDomain: true,
success: function (data) {

},
error: function (e) {

},
complete: function (e) {

},
beforeSend: function (xhr) {

}
});
}
}

 

 

  • get和post都行了。。。還有檔案上傳呢。。。這樣的POST是不能傳檔案的。。 (考慮用第三方方案或者不要直接提交)
  • 善用工具 例如Fiddler 還有javascript/HTML調試工具 (我個人覺得Chrome和FF的調試器比較好用)似乎不少人還習慣用alert調試。。。。
  •  IE和safari 跨域iframe有問題, 記得設定header,例如: Response.Headers["p3p"] = "CP=IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT";
  • 有興趣的朋友可以瞭解一下XSS和CSRF,這可是網站的一大安全問題
  • 分解問題是排查問題的一個很好的辦法
  • 更多的時候,使用同網域名稱的Proxy 伺服器是很好的解決方案 (也是唯一的解決方案,如果瀏覽器直接調用第三方有許可權問題的話)

 

本人水平有限,如果有所遺漏和謬誤,請各位朋友指正,希望一起討論學習和進步

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.