Trying to build a correct SOAP Request

前端 未结 4 582
滥情空心
滥情空心 2020-12-10 04:16

I have been struggling for hours trying to build the correct SOAP request using ksoap2 for Android with no luck. The ideal request looks like this:



        
相关标签:
4条回答
  • 2020-12-10 04:21

    I think you need another way to create the header, it looks like jax-ws, so i'll go with a jax ws implementation i did a couple of months ago.

    First you need a HeaderHandler class , wich creates the soap header element, it should look like this:


        import javax.xml.namespace.QName;
        import javax.xml.soap.SOAPElement;
        import javax.xml.soap.SOAPEnvelope;
        import javax.xml.soap.SOAPHeader;
        import javax.xml.ws.handler.MessageContext;
        import javax.xml.ws.handler.soap.SOAPHandler;
        import javax.xml.ws.handler.soap.SOAPMessageContext;
    
    
        public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {
    
            public boolean handleMessage(SOAPMessageContext smc) {
                Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
                String AUTH_TK = "http://www.avectra.com/2005/";
                String PREFIX="";//no prefix
                String PREFIX_XMLNS="xmlns";
                String value =  "123456";
                if (outboundProperty.booleanValue()) {
                    try {
                        SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
                        SOAPHeader header = envelope.addHeader();
                        //<AuthorizationToken xmlns="http://www.avectra.com/2005/">
                        SOAPElement authorizationToken = header.addChildElement("AuthorizationToken", PREFIX_XMLNS, AUTH_TK);
                        //<Token>value</Token>
                        SOAPElement usernameToken =
                            authorizationToken.addChildElement("Token", PREFIX);
                            usernameToken.addTextNode(value);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return outboundProperty;
            }
    
    
            public Set<QName> getHeaders() {
                return null;
            }
    
            public void close(MessageContext arg0) {
    
            }
    
            public boolean handleFault(SOAPMessageContext arg0) {
                return false;
            }
        }
    

    After that you create a HeaderHandlerResolver to handle the header creation and insert it in a handler chain:


        import java.util.ArrayList;
        import java.util.List;
        import javax.xml.ws.handler.Handler;
        import javax.xml.ws.handler.HandlerResolver;
        import javax.xml.ws.handler.PortInfo;
    
        public class HeaderHandlerResolver implements HandlerResolver {
    
        @SuppressWarnings("unchecked")
        public List<Handler> getHandlerChain(PortInfo portInfo) {
              List<Handler> handlerChain = new ArrayList<Handler>();
              HeaderHandler hh = new HeaderHandler();
              handlerChain.add(hh);
              return handlerChain;
           }
        }
    

    After that, you add in the Client:


            try{
                //new service instance (your service should be extending javax.xml.ws.Service;)
                YourServiceProxy service = new YourServiceProxy();
                //calls the header handler resolver ;)
                service.setHandlerResolver(new HeaderHandlerResolver());
                //get the service
                YourService port = (YourService)service.getYourService();
                //call the service 
                port.yourMethod()   
            } catch (Exception e) {
                e.printStackTrace();
            }
    

    By the way, i didn't tested this particular header, i modified a previous header handler i had, so it may be not accurate, but i think it's pretty close, i really hope it helps you, try it out and tell us how it comes, i'll try to help you if it still doesn't works.

    0 讨论(0)
  • 2020-12-10 04:26

    set

     envelope.implicitTypes = true;
    

    and DO NOT set

     envelope.setAddAdornments(false)
    

    this worked for me.

    0 讨论(0)
  • 2020-12-10 04:29

    When using KSOAP This worked for me

    SoapObject request = new SoapObject(WEBSERVICE_NAMESPACE, methodName);
        if(null != parameterMap && !parameterMap.isEmpty()){
            for(Entry<String, String> entry: parameterMap.entrySet()){
                request.addProperty(entry.getKey(), entry.getValue());
            }
        }
        // Declare the version of the SOAP request
    
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.implicitTypes = true;
        envelope.dotNet = true;
        envelope.setOutputSoapObject(request);
    
    
        HttpTransportSE androidHttpTransport = new HttpTransportSE(ApplicationConstants.WEBSERVICE_WSDL_URL);
    
        // this is the actual part that will call the webservice
        try {
    
            androidHttpTransport.debug = true;
            androidHttpTransport.call(soapActionUrl, envelope);
            String ss = androidHttpTransport.responseDump;
    
            // Get the SoapResult from the envelope body.
    
            Log.d(TAG, "request: " + androidHttpTransport.requestDump);
            Log.d(TAG, "response: "+    androidHttpTransport.responseDump);
    
    
            SoapObject result = (SoapObject) envelope.getResponse();
    
            Log.d("soap response", "" + result);            
        } catch (IOException e) {
            Log.e(TAG, "IOException", e);
        } 
    

    NOTE:

    androidHttpTransport.debug = true;
    

    resolved the issue in my case. Banged my head but could not reason with why setting debug true helped resolve the issue.

    Why do you need to use ksoap? Simply have the static party of your SOAP request as a String, append the values to the static part and you can finally have the complete SOAP request. Finally use HTTP methods to send your post request.

    No additional JARs

    Also ksoap has issues like OOM for large responses, etc.

    KSOAP OOM issue

    You can use the following code

    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.HashMap;
    import java.util.Map.Entry;
    
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.params.BasicHttpParams;
    import org.apache.http.params.HttpConnectionParams;
    import org.apache.http.params.HttpParams;
    import org.apache.http.protocol.HTTP;
    import org.apache.http.util.EntityUtils;
    
    import android.util.Log;
    
    public final class SOAPRequest{
    
    private static final String TAG = "SOAPRequest";
    private static final String TAG_SOAP_HEADER_START = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Header>";
    private static final String TAG_AUTHORIZATION_START = "<AuthorizationToken xmlns=\"http://www.avectra.com/2005/\">";
    private static final String TAG_TOKEN_START = "<TOKEN>";
    private static final String TAG_TOKEN_END = "</TOKEN>";
    private static final String TAG_AUTORIZATION_END = "</AuthorizationToken>";
    private static final String TAG_SOAPHEADER_END = "</soap:Header>"; 
    private static final String TAG_SOAP_BODY_START = "<soap:Body>";
    private static final String TAG_PARAM_NAME_START = "<Name>";
    private static final String TAG_PARAM_NAME_END = "</Name>";
    private static final String TAG_PARAM_VALUE_START = "<Value>";
    private static final String TAG_PARAM_VALUE_END = "</Value>";
    private static final String TAG_METHOD_START = "<methodName>";
    private static final String TAG_METHOD_END = "</methodName>";
    private static final String TAG_SERVICE_START = "<serviceName>";
    private static final String TAG_SERVICE_END = "</serviceName>";
    private static final String TAG_PARAMS_START = "<parameters><Parameter>";
    private static final String TAG_EXE_METHOD_START = "<ExecuteMethod xmlns=\"http://www.avectra.com/2005/\">";
    private static final String TAG_SOAP_REQ_END = "</Parameter></parameters></ExecuteMethod></soap:Body></soap:Envelope>";
    
    /**
     * Constructor intentionally made private 
     */
    private SOAPRequest() {
    
    }
    /**
     * Builds a SOAP request with the specified value
     * @param token Value of token
     * @param serviceName Value of servicename
     * @param methodName Value of methodName
     * @param paramsMap Collection of parameters as set of name value pair which needs to be sent
     * @return the complete soap request
     */
    public static String buildRequest(String token, String serviceName, String methodName, HashMap<String, String> paramsMap){
        StringBuilder requestBuilder = new StringBuilder(TAG_SOAP_HEADER_START);
        requestBuilder.append(TAG_AUTHORIZATION_START);
        requestBuilder.append(TAG_TOKEN_START);
        requestBuilder.append(token);
        requestBuilder.append(TAG_TOKEN_END);
        requestBuilder.append(TAG_AUTORIZATION_END);
        requestBuilder.append(TAG_SOAPHEADER_END);
        requestBuilder.append(TAG_SOAP_BODY_START);
        requestBuilder.append(TAG_EXE_METHOD_START);
        requestBuilder.append(TAG_SERVICE_START);
        requestBuilder.append(serviceName);
        requestBuilder.append(TAG_SERVICE_END);
        requestBuilder.append(TAG_METHOD_START);
        requestBuilder.append(methodName);
        requestBuilder.append(TAG_METHOD_END);
        requestBuilder.append(TAG_PARAMS_START);
        for(Entry<String, String> param :paramsMap.entrySet()){
            requestBuilder.append(TAG_PARAM_NAME_START);
            requestBuilder.append(param.getKey());
            requestBuilder.append(TAG_PARAM_NAME_END);
            requestBuilder.append(TAG_PARAM_VALUE_START);
            requestBuilder.append(param.getValue());
            requestBuilder.append(TAG_PARAM_VALUE_END);
        }
        requestBuilder.append(TAG_SOAP_REQ_END);
        return requestBuilder.toString();
    }
    
    /**
     * Connection timeout set for the HttpClient
     */
    private static final int CONNECTION_TIMEOUT= 6000;
    /**
     * Socket timeout set for the HttpClient
     */
    private static final int SOCKET_TIMEOUT = 10000; 
    
    /**
     * @return httpClient An instance of {@link DefaultHttpClient}
     */
    private static DefaultHttpClient getHttpClient() {
        HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is established.
        // The default value is zero, that means the timeout is not used.
        HttpConnectionParams.setConnectionTimeout(httpParameters,CONNECTION_TIMEOUT);
        // Set the default socket timeout (SO_TIMEOUT)
        // in milliseconds which is the timeout for waiting for data.
        HttpConnectionParams.setSoTimeout(httpParameters, SOCKET_TIMEOUT);
    
        return new DefaultHttpClient(httpParameters);
    }
    
    /**
     * Sends a SOAP request to the specified service endpoint. 
     * 
     * @param serviceEndpoint The service endpoint which will be hit
     * @param soapRequest The SOAP request
     * @return The string representing the response for the specified SOAP request. 
     */
    public static String send(String serviceEndpoint, String soapRequest){
        HttpPost httppost = new HttpPost(serviceEndpoint);          
        StringEntity se = null;
        try {
            se = new StringEntity(soapRequest,HTTP.UTF_8);
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG,"send", e);
            return null;
        }
    
        se.setContentType("text/xml");  
        httppost.setHeader("Content-Type","application/soap+xml;charset=UTF-8");
        httppost.setEntity(se);  
        String result = null;
        HttpClient httpclient = getHttpClient();
        try {
            HttpResponse httpResponse = httpclient.execute(httppost);
            HttpEntity responseEntity = httpResponse.getEntity();
            if(null!= responseEntity){
                //if you have a huge chunk of data read it using a buffer
                result =EntityUtils.toString(responseEntity);
            }
        } catch (ClientProtocolException e) {
            Log.e(TAG,"send", e);
        } catch (IOException e) {
            Log.e(TAG,"send", e);
        } catch (Exception e){
            Log.e(TAG,"send", e);
        }
    
        return result;
    }
    
    }
    
    0 讨论(0)
  • 2020-12-10 04:29

    Have you checked whether the types generated by kSOAP for parameters (i.e. i:type="n1:parameters") and Parameter (i.e. i:type="n1:Parameter") nodes are correct (they are defined in the wsdl)?

    Try setting

    envelope.implicitTypes = true;
    

    And also play with

    envelope.setAddAdornments(false);
    

    to force kSOAP not to include the type attribute and name spaces.

    0 讨论(0)
提交回复
热议问题