最近在寫一個要將系統事件藉由簡訊平台發送到手機簡訊的軟體,我想說這玩意以前我就寫過應該不會太難,以前都用Every8D的平台寫,從來沒出過毛病,不過這一次的需求比較特殊,因為是政府單位(我猜應該是某個XX事務所),人客要求說要使用「全國XX即時訊息發送中心」發送訊息之URL API 平台發送簡訊,一開始看到範例的時候就傻眼了,因為那個範例是Java的,幸好朋友多,半問半猜之下也把測試的程式碼拼湊出來。
最近在寫一個要將系統事件藉由簡訊平台發送到手機簡訊的軟體,我想說這玩意以前我就寫過應該不會太難,以前都用Every8D的平台寫,從來沒出過毛病,不過這一次的需求比較特殊,因為是政府單位(我猜應該是某個XX事務所),人客要求說要使用「全國XX即時訊息發送中心」發送訊息之URL API 平台發送簡訊,一開始看到範例的時候就傻眼了,因為那個範例是Java的,而我對Java的程式碼有極嚴重的閱讀障礙,幸好朋友多,半問半猜之下也把測試的程式碼拼湊出來。大概如下:
Dim myStreamWriter As IO.StreamWriter = Nothing
Dim objCSserverInfo As New CSJVSMS.CSServerInfo
Dim URIstring As String = 那個莫名其妙的api的URI
Dim strPost As String = "userid=John & password=1234" ‘這個其實是假的, 一定login不進去
Dim myHttpWebRequest As Net.HttpWebRequest = CType(Net.WebRequest.Create(URIstring), Net.HttpWebRequest)
myHttpWebRequest.Timeout = 5000
myHttpWebRequest.Method = "POST"
myHttpWebRequest.ContentLength = strPost.Length
myHttpWebRequest.ContentType = "application/x-www-form-urlencoded"
myStreamWriter = New IO.StreamWriter(myHttpWebRequest.GetRequestStream())
myStreamWriter.Write(strPost)
myStreamWriter.Close()
Dim myHttpWebResponse As HttpWebResponse = CType(myHttpWebRequest.GetResponse(), HttpWebResponse)
Dim streamResponse As Stream = myHttpWebResponse.GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
MessageBox.Show(GetResponseData(streamResponse))
streamRead.Close()
streamResponse.Close()
myHttpWebResponse.Close()
正在我沉浸原來我也看的懂JAVA Code (其實是猜猜看,偏又不小心猜對了) 的喜悅中,按下了Button滿心以為它會回傳一個 「Access Denide」的訊息時,彈出了一個訊息:
於是呢,我查了一下,問題出在 Dim myHttpWebResponse As HttpWebResponse = CType(myHttpWebRequest.GetResponse(), HttpWebResponse) 這一行的myHttpWebRequest.GetResponse() 。好啦,就開始把書拿出來東翻西找、東問西問,想說自個兒的程式碼是在哪裡寫錯了,正在抓狂的時候,想說把URI丟進瀏覽器中的網址列看看,放在FireFox中還真的給我出現了「Access Denide」;然而在IE6中卻顯示「無法顯示網頁」,視窗標題則是那個可恨的 HTTP 500。正當我因為這個矛盾而準備要打電話給119請他們派救護車送我去精神病院急診的時候,靈光一閃!拿出了威力強大又不用錢的封包分析工具Packetyzer,一個令世人震驚的封包內容被我看到了,原來它在500錯誤的封包中帶了Access Denied的訊息在後面,此時只能心中暗譙:「這是瞎米爛API,把錯誤訊息藏在另外一個錯誤訊息裡面?」(此API的原作如果看到這篇請原諒我,你知道客戶催單的壓力會讓一個人處於精神分裂的邊緣的。)
然後我就一面在Plurk上訐譙、一面茫然地看著MSDN文件庫中的 WebException 成員 (其實我本來考慮只要Exception就不管它的,可是我猜客戶一定不會接受我的講法,只好乖乖地一直找資料解決 ),在黑暗中出現了一絲光明 (想像一下如果你三天沒錢吃飯突然在地上撿到50塊,正巧旁邊又開著自助餐店的那種喜悅),原來WebException是有 WebException.Response 屬性 的 ( 所以我說要常常查MSDN文件庫的吧! ) ,這種帶在HTTP錯誤標頭後面的訊息就要靠這個來取出它內容的Stream。於是程式碼就變成了這樣:
Try
Dim myStreamWriter As IO.StreamWriter = Nothing
Dim objCSserverInfo As New CSJVSMS.CSServerInfo
Dim URIstring As String = 那個莫名其妙的api的URI
Dim objCSUserData As New CSJVSMS.CSUserData
Dim strPost As String = "userid=John & password=1234"
Dim myHttpWebRequest As Net.HttpWebRequest = CType(Net.WebRequest.Create(URIstring), Net.HttpWebRequest)
myHttpWebRequest.Timeout = 5000
myHttpWebRequest.Method = "POST"
myHttpWebRequest.ContentLength = strPost.Length
myHttpWebRequest.ContentType = "application/x-www-form-urlencoded"
myStreamWriter = New IO.StreamWriter(myHttpWebRequest.GetRequestStream())
myStreamWriter.Write(strPost)
myStreamWriter.Close()
Dim myHttpWebResponse As HttpWebResponse = CType(myHttpWebRequest.GetResponse(), HttpWebResponse)
Dim streamResponse As Stream = myHttpWebResponse.GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
MessageBox.Show(GetResponseData(streamResponse))
streamRead.Close()
streamResponse.Close()
myHttpWebResponse.Close()
Catch Wex As WebException
MessageBox.Show(Wex.Message.ToString)
If CType(Wex.Response, HttpWebResponse).StatusCode = 500 Then
Dim streamResponse As Stream = CType(Wex.Response, HttpWebResponse).GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
MessageBox.Show(GetResponseData(streamResponse))
End If
End Try
皇天不負苦心人,終於出現了正確的回應:
這個故事告訴我們,不要以為別人寫的API都是正常的!不是,應該是當呼叫別人所寫的API時,可能會需要在Exception上面多下點功夫,要多瞭解各類不同Exception的內容(此時心中響起:為什麼我用Every8D的API就不用搞成這樣..為什麼我用Every8D的API就不用搞成這樣..為什麼我用Every8D的API就不用搞成這樣..為什麼..<聲音漸小,落幕>)。