2014年6月10日

C# Web Service遇到IE8 cross domain post問題的解決方式

近幾年太習慣用Web Service來拆解程式功能做系統架構,弄到有點Web Service上癮了。

自己最常使用的開發工具是C# with .NET framework,其中的asmx是根據soap協定來做的Web Service。而在我用asmx建立了一堆service之後,又希望可以讓前端網頁能簡單呼叫這些service,於是就做了一個簡單的soap post function。

下列是這個function內部分程式碼的節錄(其實只是一個標準的javascript client post範例):

var xmlhttp;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open('POST', service_uri, true);
xmlhttp.setRequestHeader('Content-Type', 'text/xml; charset=utf8');

但是這段code遇到IE8就死了,完全不會動,因為IE8有一個全世界獨有的設計:因安全性考量,XMLHttpRequest只能接受相對位址(只允許對同domain發request)。

不過cross domain的需求仍然存在,所以IE8還是留了一條後路:使用XDomainRequest。於是上面那段程式碼最後修改成了下面的樣子:

var isIE8 = window.XDomainRequest ? true : false;
var xmlhttp;

if (isIE8) {
xmlhttp = new XDomainRequest();
var protocal = service_uri.split('/')[0];
xmlhttp.open('POST', service_uri.replace(protocal, location.protocol));
} else {
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open('POST', service_uri, true);
xmlhttp.setRequestHeader('Content-Type', 'application/soap+xml; charset=utf-8');
}

在IE8的處理區段中,除了改用XDomainRequest之外,還有兩個不一樣的點:1.來源網站的protocal要跟service一樣,XDomainRequest似乎不能接受http向https,或是https向http的請求(個人實驗得出結論,不是十分肯定);2.XDomainRequst無法自訂request header,所以不能自訂Content-Type。

不能自訂header,無法設定Content-Type,XDomainRequest自以為安全認為所有的cross domain post都是text/plain,而asmx又只接受xml,沒有在header裡放個Content-Type的request根本就不被接受啊!

在經過無數的google result洗禮後,最後終算讓我找到自己覺得很爛的解決方式,這回要來修改Server端的程式了。

做法是在request被傳到asmx之前,檢查看看header裡有沒有帶Content-Type,如果沒有的話,就幫它加上去。只要在Global.asax上加入下列程式碼就好了:

protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.RequestType == "POST" && !Request.Headers.AllKeys.Contains("Content-Type"))
{
Request.ContentType = "application/soap+xml; charset=UTF-8";
}
}

最後,花了大概五個小時的處理,總算讓我的程式能順利在IE8上運行了,我想如果早點認輸改用JQuery,可能十分鐘就處理掉了吧。

但我實在不是很能理解,為什麼我得在2014年花這麼多時間去處理一個只剩2%市佔2009年瀏覽器版本才會發生的問題啊!


read more...

2012年7月17日

三十歲感言

這是一篇遲到快一年的文章,不過我會儘量用當時的心境寫下來。

--

我又跨過了一個關卡。

這個年紀好像應該要完成一些什麼事,看看身邊的朋友們,有的在事業上獲得了一些成就,有的結了婚有幸福的生活。

除了逹成在30歲前買下房子,然後過著被債追著跑的日子,我看不出來我有什麼值得提出來說的成就,所以老是自嘲,或是自怨,我是個一事無成的人。


read more...

2011年12月19日

懶人便當<一> 烤排骨

話說每天準備便當,在有時間的時候還滿好玩的,每天都要發明奇怪的菜色,然後隔天吃到灰頭土臉上吐下瀉的,但是有時候真的會很懶得花一兩個小時在廚房弄東弄西,但是不煮就會沒得吃,於是就會想一些偷懶的做菜方法,反正美觀不是我的強項,不如就來寫寫懶人食譜吧。

基本上把握的要訣就是減少顧火的時間,跟減少使用的廚具,事後收拾清洗的時候比較省時省力。


read more...

2011年11月6日

日光時間惹的禍

大概是高中的時候,有人警告因為電腦計算年份的位數只有兩位的關係,所以在西元2000年的時候,許多電腦系統會大亂,可能造成不亞於世界末日的後果,也就是俗稱的「千禧蟲」。

西元2000年的時候,我還是個大學新鮮人,所以拯救世界這個重責大任,壓根不會落在我肩上;後來在IT界打滾的時候,碰上了民國100年,有些日期在記錄的時候是用6位數的文字欄位來放,這時候就要調整成7位數,好在我早就習慣用西元年來處理日期,所以也不用特別去處理這個問題,八位數的欄位要再過8000年才會不夠放,我想這個期間長到我可以不用去擔心。


read more...

2011年10月10日

陽台上的小花園 - 系列二

好不容易渡過一個可怕的夏天,我的花花草草總算恢復了一點生氣,但是在酷熱天氣以及病蟲害的摧殘之下,還是不幸陣亡了一些弟兄。

聖誕紅的狀況超級好,接下來要進入冬天,紅葉應該會慢慢出現吧。


read more...

2011年8月10日

一個程式呼叫的架構概念

這是我之前花了幾個月的時間做的一個小專案,其中的一個機制,算是專案中我花最多時間去思考的部分。

這個專案要做的是一個選單系統,大概就像是Windows的開始功能表打開的那個感覺,裡面會有多層目錄,也會有很多可執行的程式項目,只是這個選單要用來掛載各個自行開發的系統,所以要能方便維護選單內容,並能支援系統的各種權限及執行設定。


read more...

2011年7月1日

讓我們先來定義它吧

最近接到了一個需求,是要把一個我本來就已經提供的功能,升級為可批次處理。

批次處理這個很好懂啊,就一次輸入一堆資料,然後對每一筆資料做一模一樣的事情,完全就是程式設計的基本功啊(??)。

接到這個需求,當然要先想一下怎麼做再來動手,我準備在畫面上放一個挑選資料的區塊,分割成左右兩邊,左邊是可以挑選的,右邊是已經挑選的,這個介面很常見並不算複雜,然後加上一個輸入變更原因的文字方塊;不過在我把整個程式的架構設計得差不多的時候,客戶突然問我,可不可以讓每個項目有不同的變更原因。

當然礙於我得對我的工作內容保密,所以整個程式的內容不能講得太明白,這樣子可能不太好懂,所以用以下這個我虛擬的程式來說明吧。

某校的教務系統裡提供一個程式,可以讓老師「批次當人」,程式畫面大概像下面這張圖一樣。

操作的方法是先查詢系級的學生名單,名單會出現在左下的區塊,然後把要當掉的人選出來當掉,被當掉的人名字就會移到右下的區塊,最後選擇當人原因後儲存。

但是有老師反應如果他手上四種原因當掉的學生都有,那他就要操作四次,這樣很麻煩,所以在這些老師的建議下,程式改成下面這個樣子。

操作方法是查詢後,選擇要當的學生跟當掉的原因,然後按下當掉,學生的名字跟原因就會出現在右邊的區塊,把所有的學生跟當掉原因都選好後,再儲存結果。

第二種方法給人比較快速簡單省事的錯覺,但是其實按鍵的次數並不會比較少,其實以哪一種方法來操作意思都差不多,而且介面也不會差到哪裡去。

但是如果我們給每次批次加上一個批號,意思就大不相同了,讓我們用表單來說明。

第一種方法,是每一批次都是同樣原因,這裡批次被定義為相同原因被當掉的學生要放在同一批。

第二種方法,這裡的批次就只是同一次當人作業下犠牲的學生為同一批。

用另外一個例子在說明,今天有一批新兵結訓要下部隊,有專車要載這些人去部隊,新兵雖然都從同一個營區出發,但會分發到不同的地方去,這時候專車的開法有兩種,第一是每台專車都只載前往同一個目的地的新兵,第二是每台專車沿途停靠各目的地陸續放人下車,當然兩種方法各有好壞,只能視當時的狀況來決定要用何種方法。

至於我碰到的這個狀況,我覺得批次這東西多少是有意義的,如果把不同原因的東西放在同一批不會很奇怪嗎?但是客戶認定的批次就只是把本來要分好幾次完成的作業一次完成,只是一個省事的方便做法。因為認知的不同,這個要求在我眼中看起來就像是在表單上自行擴充欄位一樣亂來。

所以我說,讓我們先來定義批次這件事吧,我認為批次是這樣,你覺得批次是那樣,兩種我都能幫你們做,那種方法比較好,我想請你們自己評估之後再告訴我吧。

結果因為要實現第二種方法,需要比較長的開發時間(當然成本也會高一些),所以決定採用我的原設計(也是客戶需求最原始的模樣),當然節省營運成本也是一種專業,不過我的資訊專業還是為了此事躲到角落去哭了。


read more...