本文使用JAX-WS2.2编译webservice,并使用HttpUrlConnection的POST方式对wsdl发送soap报文进行请求返回数据,

对错误Server returned HTTP response code: 500 的解决方法进行简单分析。

问题描述:

由于课程需要博主需要自己写一个webservice并且通过soap进行请求,

于是使用JAX-WS编译了下面java代码生成webservice服务

生成webservice的java代码:

[java] view plain copy
  • @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请求实现代码:

    [java] view plain copy
  • 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代码如下:

    [html] view plain copy
  • <? xml version= "1.0" encoding= "utf-8" ?>
  • < soap:Envelope xmlns:soap= "http://schemas.xmlsoap.org/soap/envelope/" >
  • < soap:Body >
  • < sayHelloWorldFrom >
  • </ arg0 >
  • </ sayHelloWorldFrom >
  • </ soap:Body >
  • </ soap:Envelope >
  • 这段代码是网上找的,并没有错误,但是一运行就懵逼了,报了下面的错误

    明明直接在浏览器查看wsdl接口是可以访问页面,但是返回500错误

    错误代码:

    [java] view plain copy
  • 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)
  • 错误语句指向

    [java] view plain copy
  • 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(就是添加了命名空间)

    [html] view plain copy
  • <? 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 >
  • </ m:sayHelloWorldFrom >
  • </ soap:Body >
  • </ soap:Envelope >

  • 大括号里的地址其实就是wsdl中denfinition里定义的targetNameSpace,具体解释我贴个链接吧大家自己看吧,反正知道问题出在这边总算是解决了。

    WebService 之 WSDL文件 讲解 http://blog.itpub.net/20200170/viewspace-740276/

    其实出了bug第一反应确实应该是找Error信息,这样才好针对性的进行处理,如果本文的方法还没办法帮你解决的话,那还是建议大家靠前面查看错误详情的方法去进行bug的查找~

    主要内容到这边结束啦,希望能帮到大家~

    发送httpUrlConnection的java代码
    [java] view plain copy
  • 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();
  •