本文使用JAX-WS2.2編譯webservice,並使用HttpUrlConnection的POST方式對wsdl發送soap報文進行請求返回數據,
對錯誤Server returned HTTP response code: 500 的解決方法進行簡單分析。
問題描述:
由於課程需要博主需要自己寫一個webservice並且通過soap進行請求,
於是使用JAX-WS編譯了下面java代碼生成webservice服務
生成webservice的java代碼:
- @WebService()
- public class HelloWorld {
- @WebMethod
- public String sayHelloWorldFrom(String from) {
- System.out.println("getMessage.");
- String result = "Hello, world, from " + from;
- System.out.println(result);
- return result;
- }
- public static void main(String[] argv) {
- System.out.println("Service is running...");
- Object implementor = new HelloWorld ();
- String address = "http://localhost:9000/HelloWorld";
- Endpoint.publish(address, implementor);
- }
- }
查看webservice

在網上查到的一個方法就是通過HttpUrlConnection進行請求,這邊貼一下代碼,應該很多人都有查到類似的方法
HttpUrlConnection請求實現代碼:
- public static void main(String[] args) throws Exception
- {
- String urlString = "http://localhost:9000/HelloWorld?wsdl";//自定義的wsdl服務
- URL url = new URL(urlString);
- HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();//打開連接
- String xmlFile = "soap_xml\\soap.xml";//要發送的soap格式文件
- File fileToSend = new File(xmlFile);
- byte[] buf = new byte[(int) fileToSend.length()];// 用於存放文件數據的數組
- new FileInputStream(xmlFile).read(buf);
- //Content-Length長度會自動進行計算
- httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
- httpConn.setRequestMethod("POST");
- httpConn.setDoOutput(true);
- httpConn.setDoInput(true);
- OutputStream out = httpConn.getOutputStream();
- out.write(buf);
- out.close();
- InputStreamReader is = new InputStreamReader(httpConn.getInputStream());
- BufferedReader in = new BufferedReader(is);
- String inputLine;
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream("result.xml")));// 將結果存放的位置
- while ((inputLine = in.readLine()) != null)
- {
- System.out.println(inputLine);
- bw.write(inputLine);
- bw.newLine();
- }
- bw.close();
- in.close();
- httpConn.disconnect();
- }
soap.xml代碼如下:
- <?xml version="1.0" encoding="utf-8"?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
- <soap:Body>
- <sayHelloWorldFrom>
- <arg0>
- 撐撐
- </arg0>
- </sayHelloWorldFrom>
- </soap:Body>
- </soap:Envelope>
這段代碼是網上找的,並沒有錯誤,但是一運行就懵逼了,報了下面的錯誤
明明直接在瀏覽器查看wsdl接口是可以訪問頁面,但是返回500錯誤
錯誤代碼:
- Exception in thread "main" java.io.IOException: Server returned HTTP response code: 500 for URL: http://localhost:9000/HelloWorld?wsdl
- at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1839)
- at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1440)
- at soap.HelloSoap.main(HelloSoap.java:38)
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
- at java.lang.reflect.Method.invoke(Method.java:497)
- at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
錯誤語句指向
- InputStreamReader is = new InputStreamReader(httpConn.getInputStream());
而網上其他大部分文章都沒有給解決方法,或者給了其他的解決方法,我就在這邊分享一下這個問題的詳細解決方法。
解決流程(干貨
首先應該確認具體的錯誤,通過下面的語句可以了解InputStream的錯誤詳情。
- InputStream is = httpConn.getErrorStream(); //通過getErrorStream了解錯誤的詳情,因為錯誤詳情也以XML格式返回,因此也可以用JDOM來獲取。
這個語句其實也是從請求的服務方取回的錯誤信息,實質也是xml內容,用上面的BufferReader那一連串的語句解析出具體內容,然后輸出查看,具體代碼如下:
- InputStream is = httpConn.getErrorStream(); //通過getErrorStream了解錯誤的詳情,因為錯誤詳情也以XML格式返回,因此也可以用JDOM來獲取。
- InputStreamReader isr = new InputStreamReader(is,"utf-8");
- BufferedReader in = new BufferedReader(isr);
- String inputLine;
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream("result.xml")));// 將結果存放的位置
- while ((inputLine = in.readLine()) != null)
- {
- System.out.println(inputLine);
- bw.write(inputLine);
- bw.newLine();
- bw.close();
- }
- in.close();
錯誤詳情輸出如下:
- <?xml version='1.0' encoding='UTF-8'?>
- <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
- <S:Body>
- <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
- <faultcode>
- S:Client
- </faultcode>
- <faultstring>
- 找不到{}sayHelloWorldFrom的分派方法
- </faultstring>
- </S:Fault>
- </S:Body>
- </S:Envelope>
在這邊就要注意了!這個xml文件是第一個要點!
分析一下這段xml代碼,可以看到有一個faultcode和faultstring,這就是解決這個問題的第一個突破口
靈光一閃百度了一下SOAP Fault(百科連接:http://baike.baidu.com/link?url=vehb23KNtl58uv2cwVDk8LYzDTUC4MHW9kmpaALl9qht9VXp8ASufe0QlpUrEELEApdKx80AMPzMsfCbUJtWiK)


這樣就一目了然了,錯誤代碼中faultcode所含的是Client,說明傳遞的消息有誤,服務端是沒有問題的。
於是從要發送的soap中查找錯誤。
這時候發現faultstring “{}找不到xxx的分派方法” 中有一個大括號,想不明白那個是什么,剛好查看了一下web服務的頁面,就是最上面那張圖片,發現服務名和端口名那邊也有大括號{http://example/},然后也想起來之前看的其他xml代碼中,要發送的方法的那個節點中有寫命名空間(xmlns),就是網上那個getWeatherByCityName的那個例子,大家應該都有看過,我就不再這邊費口舌了。
要是有仔細看我發送的soap.xml的代碼,就可以看到sayHelloWorldFrom那個節點沒有寫命名空間,實在是查了這么多代碼網上都沒人提到,也沒有查到關於soap報文的編寫規范,還以為那邊可以不用寫,於是刪掉了。
問題就出在這,我重新試了一下,先把命名空間隨便寫了個網址,再次運行后依然報錯,但是大括號中就有了命名空間指向的網址了,於是把web服務里的大括號里的地址,即{http://example/}寫上去,總算是請求成功並成功返回數據!
修改后的soap.xml(就是添加了命名空間)
- <?xml version="1.0" encoding="utf-8"?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
- <soap:Body>
- <m:sayHelloWorldFrom xmlns:m="http://example/">
- <arg0>
- 撐撐
- </arg0>
- </m:sayHelloWorldFrom>
- </soap:Body>
- </soap:Envelope>
大括號里的地址其實就是wsdl中denfinition里定義的targetNameSpace,具體解釋我貼個鏈接吧大家自己看吧,反正知道問題出在這邊總算是解決了。
WebService 之 WSDL文件 講解 http://blog.itpub.net/20200170/viewspace-740276/
其實出了bug第一反應確實應該是找Error信息,這樣才好針對性的進行處理,如果本文的方法還沒辦法幫你解決的話,那還是建議大家靠前面查看錯誤詳情的方法去進行bug的查找~
主要內容到這邊結束啦,希望能幫到大家~
附錄
- package soap;
- import java.io.*;
- import java.net.HttpURLConnection;
- import java.net.URL;
- /**
- * Created by cc on 2016/10/21.
- */
- public class HelloSoap {
- public static void main(String[] args) throws Exception
- {
- String urlString = "http://localhost:9000/HelloWorld?wsdl";//wsdl文檔的地址
- URL url = new URL(urlString);
- HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();//打開連接
- //String soapActionString = "http://localhost:9000/HelloWorld/sayHelloWorldFrom";//Soap 1.1中使用
- String xmlFile = "soap_xml\\soap.xml";//要發送的soap格式文件
- File fileToSend = new File(xmlFile);
- byte[] buf = new byte[(int) fileToSend.length()];// 用於存放文件數據的數組
- new FileInputStream(xmlFile).read(buf);
- //Content-Length長度會自動進行計算
- httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
- //httpConn.setRequestProperty("soapActionString",soapActionString);//Soap1.1使用 其實完全可以不需要
- httpConn.setRequestMethod("POST");
- httpConn.setDoOutput(true);
- httpConn.setDoInput(true);
- OutputStream out = httpConn.getOutputStream();
- out.write(buf);
- out.close();
- if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK)
- {
- InputStreamReader is = new InputStreamReader(httpConn.getInputStream());
- BufferedReader in = new BufferedReader(is);
- String inputLine;
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream("result.xml")));// 將結果存放的位置
- while ((inputLine = in.readLine()) != null)
- {
- System.out.println(inputLine);
- bw.write(inputLine);
- bw.newLine();
- }
- bw.close();
- in.close();
- }
- else{
- //如果服務器返回的HTTP狀態不是HTTP_OK,則表示發生了錯誤,此時可以通過如下方法了解錯誤原因。
- InputStream is = httpConn.getErrorStream(); //通過getErrorStream了解錯誤的詳情,因為錯誤詳情也以XML格式返回,因此也可以用JDOM來獲取。
- InputStreamReader isr = new InputStreamReader(is,"utf-8");
- BufferedReader in = new BufferedReader(isr);
- String inputLine;
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream("result.xml")));// 將結果存放的位置
- while ((inputLine = in.readLine()) != null)
- {
- System.out.println(inputLine);
- bw.write(inputLine);
- bw.newLine();
- bw.close();
- }
- in.close();
- }
- httpConn.disconnect();
- }
- }
