如何修复使用Java调用SOAP Web服务时不可读的XML响应?

How to fix unreadable XML response when calling a SOAP web service with Java?

提问人:Ahmad Yazdi 提问时间:5/21/2023 更新时间:5/21/2023 访问量:128

问:

调用 SOAP Web 服务

我有一个 soap web 服务要调用,这是我的代码:

private List<Guaranty> getGuarantyList(String nationalId, String centerBankCode) throws IOException{
        
        try {
            fixHttpsHandler();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }

        // Code to make a webservice HTTP request
        String responseString = "";
        String outputString = "";
        String wsEndPoint = "http://192.168.5.202/services/out.asmx";
        URL url = new URL(wsEndPoint);
        URLConnection connection = url.openConnection();
        HttpURLConnection httpConn = (HttpURLConnection) connection;
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        String xmlInput = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:pos=\"http://postbank.ir/\">\r\n" + 
                "   <soapenv:Header>\r\n" + 
                "      <pos:PostbankAuth>\r\n" + 
                "         <!--Optional:-->\r\n" + 
                "         <pos:UserName>ebank</pos:UserName>\r\n" + 
                "         <!--Optional:-->\r\n" + 
                "         <pos:Password>qwer@123</pos:Password>\r\n" + 
                "      </pos:PostbankAuth>\r\n" + 
                "   </soapenv:Header>\r\n" + 
                "   <soapenv:Body>\r\n" + 
                "      <pos:getGuaranty>\r\n" + 
                "         <!--Optional:-->\r\n" + 
                "         <pos:nationalCode>" + nationalId + "</pos:nationalCode>\r\n" + 
                "         <!--Optional:-->\r\n" + 
                "         <pos:centerBankCode>" + centerBankCode + "</pos:centerBankCode>\r\n" + 
                "         <!--Optional:-->\r\n" + 
                "         <pos:length>10</pos:length>\r\n" + 
                "         <pos:offset>0</pos:offset>\r\n" + 
                "      </pos:getGuaranty>\r\n" + 
                "   </soapenv:Body>\r\n" + 
                "</soapenv:Envelope>";
        byte[] buffer = new byte[xmlInput.length()];
        buffer = xmlInput.getBytes();
        bout.write(buffer);
        byte[] b = bout.toByteArray();
        String SOAPAction = "http://postbank.ir/getGuaranty";
        httpConn.setRequestProperty("Accept-Encoding", "gzip,deflate");
        httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
        httpConn.setRequestProperty("SOAPAction", SOAPAction);
        httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
        httpConn.setRequestProperty("Host", "192.168.5.202");
        httpConn.setRequestProperty("Connection", "Keep-Alive");
        httpConn.setRequestProperty("User-Agent", "Apache-HttpClient/4.5.5 (Java/16.0.1)");
        httpConn.setRequestMethod("POST");
        httpConn.setDoOutput(true);
        httpConn.setDoInput(true);
        OutputStream out = httpConn.getOutputStream();
        // Write the content of the request to the outputstream of the HTTP
        // Connection.
        out.write(b);
        out.close();
        // Ready with sending the request.
        // Read the response.

        InputStreamReader isr = new InputStreamReader(httpConn.getInputStream(), Charset.forName("UTF-8"));

        BufferedReader in = new BufferedReader(isr);
        // Write the SOAP message response to a String.
        while ((responseString = in.readLine()) != null) {
            outputString = outputString + responseString;
        }
            
        String formattedSOAPResponse = formatXML(outputString);
        return formattedSOAPResponse ;
        
    }

但我得到这个作为响应,而不是一个可读的 XML:

________ _$ؐ@ _iG#) * eVe]f@ 흼 { { ;N' ?\fd_l J ɞ! ?~|?」 _ _ez MQ-? hw Q / լX^| Ѻ= > 8z T 2/ U + > yۮ_ڽ L “k >W ] r7ח ~ k _7 ٽ { 5_ . M - {kv [) O ヰ | ٲ ~ 7 j ( _Ъj I |;.n ºl __ 7Mv _Uo_ 5 ?~ N |v ] Y __ $πG E ^ ۏ > 1 I~Q, e GG{;{{�;ٻ hg νG -ۚ^ j潹 Km _ ыl 5 _ f _ = 6 _5 k C wv?˻ wp n Rެ __ nz 6 |V ۬]7 g NO _ \ 51 ku _5 ҏѠi E^c( ѿ 7 _X o _O _ ?& _ _ _ o ? o _F_ [_ W [տ 7_ _ _ dzu $ C_ q aB 2} { ӶG _ TD ;?y0 9, B$o oW , g Ͻ o 5 c ~ 3 q ٫ ;{4=43 v _ ?x s_ : _B _ 7 ;4�;; _t^Ֆ { h פ o 1D #R“ _ o 4” _A _t ;+ ?}@ _ uM__o 2_ͫe r v_ } C ^c_BL ^z S~ 9z ^ y3 __ 5 ) + ? 8 _ o K ? _ m鏿 ˜n_ Q _ o 5 _w N?G .q“i _ '} iW ˘ _ꙴZH_I�%&/m�{_J�J��t�_�

这种方式适用于其他 Web 服务,但不适用于此服务。我在 SOAP-UI 中测试了 Web 服务,它工作正常...... 谢谢

Java SOAP UTF-8 XML 解析

评论

0赞 tgdavies 5/21/2023
响应有哪些标头?

答:

4赞 Ben Meehan 5/21/2023 #1

您收到的乱码响应表示响应已使用 gzip 或 deflate 编码进行压缩。若要正确处理此压缩响应,需要先对其进行解码,然后再将其读取为可读的 XML。

import java.io.*;
import java.net.*;

import java.util.zip.GZIPInputStream;

private List<Guaranty> getGuarantyList(String nationalId, String centerBankCode) throws IOException {
    try {
        fixHttpsHandler();
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
    }

    String responseString = "";
    String outputString = "";
    String wsEndPoint = "http://192.168.5.202/services/out.asmx";
    URL url = new URL(wsEndPoint);
    URLConnection connection = url.openConnection();
    HttpURLConnection httpConn = (HttpURLConnection) connection;
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    String xmlInput = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:pos=\"http://postbank.ir/\">\r\n" + 
            ...
            "</soapenv:Envelope>";
    byte[] buffer = new byte[xmlInput.length()];
    buffer = xmlInput.getBytes();
    bout.write(buffer);
    byte[] b = bout.toByteArray();
    String SOAPAction = "http://postbank.ir/getGuaranty";
    httpConn.setRequestProperty("Accept-Encoding", "gzip,deflate");
    httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
    httpConn.setRequestProperty("SOAPAction", SOAPAction);
    httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
    httpConn.setRequestProperty("Host", "192.168.5.202");
    httpConn.setRequestProperty("Connection", "Keep-Alive");
    httpConn.setRequestProperty("User-Agent", "Apache-HttpClient/4.5.5 (Java/16.0.1)");
    httpConn.setRequestMethod("POST");
    httpConn.setDoOutput(true);
    httpConn.setDoInput(true);
    OutputStream out = httpConn.getOutputStream();
    out.write(b);
    out.close();

    InputStream inputStream = httpConn.getInputStream();
    String contentEncoding = httpConn.getContentEncoding();

    if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
        inputStream = new GZIPInputStream(inputStream);
    } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
        inputStream = new InflaterInputStream(inputStream);
    }

    InputStreamReader isr = new InputStreamReader(inputStream, Charset.forName("UTF-8"));

    BufferedReader in = new BufferedReader(isr);
    while ((responseString = in.readLine()) != null) {
        outputString = outputString + responseString;
    }

    String formattedSOAPResponse = formatXML(outputString);
    return formattedSOAPResponse;
}

我添加了逻辑来检查 HTTP 响应的 Content-Encoding 标头。如果它指示 gzip 压缩,则 inputStream 被包装在 GZIPInputStream 中进行解压缩。同样,如果编码为 deflate,则将其包装在 InflaterInputStream 中。

评论

1赞 Ahmad Yazdi 5/21/2023
问题已解决