一個回傳 500 Internal Server Error的故事

最近在寫一個要將系統事件藉由簡訊平台發送到手機簡訊的軟體,我想說這玩意以前我就寫過應該不會太難,以前都用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」的訊息時,彈出了一個訊息:

2009-10-18_155352 

        於是呢,我查了一下,問題出在  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

     皇天不負苦心人,終於出現了正確的回應:

2009-10-18_162550

        這個故事告訴我們,不要以為別人寫的API都是正常的!不是,應該是當呼叫別人所寫的API時,可能會需要在Exception上面多下點功夫,要多瞭解各類不同Exception的內容(此時心中響起:為什麼我用Every8D的API就不用搞成這樣..為什麼我用Every8D的API就不用搞成這樣..為什麼我用Every8D的API就不用搞成這樣..為什麼..<聲音漸小,落幕>)。