Using Android to Post XML files

2020-08-09 06:30发布

问题:

EDIT :

I am trying to send an xml file as a post request in Android.

The server accepts text/xml. I tried creating a MultipartEntity, which has a content type of multipart/form-data.

 HttpClient httpClient = new DefaultHttpClient();

    /* New Post Request */
    HttpPost postRequest = new HttpPost(url);

    byte[] data = IOUtils.toByteArray(payload);

    /* Body of the Request */
     InputStreamBody isb = new InputStreamBody(new ByteArrayInputStream(data), "uploadedFile");
    MultipartEntity multipartContent = new MultipartEntity();
    multipartContent.addPart("uploadedFile", isb);

    /* Set the Body of the Request */
    postRequest.setEntity(multipartContent);

    /* Set Authorization Header */
    postRequest.setHeader("Authorization", authHeader);
    HttpResponse response = httpClient.execute(postRequest);
    InputStream content = response.getEntity().getContent();
    return content;

However I get an error saying the content type cannot be consumed.

The server refused this request because the request entity is in a format not supported by the requested resource for the requested method (Cannot consume content type).

How do I change the content type of the request?

Edit:

回答1:

Long story short - use another constructor for your InputStreamBody that lets you specify the mime type you wish to use. If you don't, the parts in your multipart request will not have a Content-Type specified (see below for details). Consequently, the server does not know what type the file is, and in your case might be refusing to accept it (mine accepted them anyway, but I assume this is driven by config). If this still doesn't work, you might have a server-side issue.

Note: Changing the Content-Type of the request itself to anything but multipart/form-data; boundary=someBoundary renders the request invalid; the server will not correctly parse the multipart parts.

Long story long - here's my findings.

Given the following code:

byte[] data = "<someXml />".getBytes();
multipartContent.addPart("uploadedFile", new InputStreamBody(new ByteArrayInputStream(data), "text/xml", "somefile.xml"));
multipartContent.addPart("otherPart", new StringBody("bar", "text/plain", Charset.forName("UTF-8")));
multipartContent.addPart("foo", new FileBody(new File("c:\\foo.txt"), "text/plain"));

The HttpClient posts the following payload (captured w/ Wireshark):

POST /upload.php HTTP/1.1
Transfer-Encoding: chunked
Content-Type: multipart/form-data; boundary=SeXc6P2_uEGZz9jJG95v2FnK5a8ozU8KfbFYw3
Host: thehost.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1-alpha2 (java 1.5)

--SeXc6P2_uEGZz9jJG95v2FnK5a8ozU8KfbFYw3
Content-Disposition: form-data; name="uploadedFile"; filename="someXml.xml"
Content-Type: text/xml
Content-Transfer-Encoding: binary

<someXml />
--SeXc6P2_uEGZz9jJG95v2FnK5a8ozU8KfbFYw3
Content-Disposition: form-data; name="otherPart"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

yo
--SeXc6P2_uEGZz9jJG95v2FnK5a8ozU8KfbFYw3
Content-Disposition: form-data; name="foo"; filename="foo.txt"
Content-Type: text/plain
Content-Transfer-Encoding: binary

Contents of foo.txt

--SeXc6P2_uEGZz9jJG95v2FnK5a8ozU8KfbFYw3--

On the server, the following PHP script:

<?php
print_r($_FILES);
print_r($_REQUEST);

spitted out the following:

Array
(
    [uploadedFile] => Array
        (
            [name] => someXml.xml
            [type] => text/xml
            [tmp_name] => /tmp/php_uploads/phphONLo3
            [error] => 0
            [size] => 11
        )

    [foo] => Array
        (
            [name] => foo.txt
            [type] => text/plain
            [tmp_name] => /tmp/php_uploads/php58DEpA
            [error] => 0
            [size] => 21
        )

)
Array
(
    [otherPart] => yo
)


回答2:

you can go this way for uploading to server

        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(url);
        InputStreamEntity reqEntity = new InputStreamEntity(new FileInputStream(filePath), -1);
        reqEntity.setContentType("binary/octet-stream");
        reqEntity.setChunked(true); // Send in multiple parts if needed
        httppost.setEntity(reqEntity);
        HttpResponse response = httpclient.execute(httppost);


回答3:

I have done something similar to access webservices. The soap request was an XML request. See the code below:

package abc.def.ghi;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
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.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;


public class WebServiceRequestHandler {

    public static final int CONNECTION_TIMEOUT=10000;
    public static final int SOCKET_TIMEOUT=15000;

    public String callPostWebService(String url,  String soapAction,   String envelope) throws Exception {
        final DefaultHttpClient httpClient=new DefaultHttpClient();
        HttpParams params = httpClient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
        HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT);

        HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), true);

        // POST
        HttpPost httppost = new HttpPost(url);
        // add headers. set content type as XML
        httppost.setHeader("soapaction", soapAction);
        httppost.setHeader("Content-Type", "text/xml; charset=utf-8");

        String responseString=null;
        try {
            // the entity holds the request
            HttpEntity entity = new StringEntity(envelope);
            httppost.setEntity(entity);

            ResponseHandler<String> rh=new ResponseHandler<String>() {
                // invoked on response
                public String handleResponse(HttpResponse response)
                throws ClientProtocolException, IOException {
                    HttpEntity entity = response.getEntity();

                    StringBuffer out = new StringBuffer();
                                    // read the response as byte array
                    byte[] b = EntityUtils.toByteArray(entity);
                    // write the response byte array to a string buffer
                    out.append(new String(b, 0, b.length));        
                    return out.toString();
                }
            };
            responseString=httpClient.execute(httppost, rh); 
        } 
        catch (UnsupportedEncodingException uee) {
            throw new Exception(uee);

        }catch (ClientProtocolException cpe){

            throw new Exception(cpe);
        }catch (IOException ioe){
            throw new Exception(ioe);

        }finally{
            // close the connection
            httpClient.getConnectionManager().shutdown();
        }
        return responseString;
    }

}


回答4:

Using your code, the following should work:

response.setContentType("Your MIME type");


回答5:

Regardless of API, content type is negotiated via a header with the 'Content-Type' key:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

You cannot control what the service expects. It's a part of their contract. You're probably sending 'text/plain' and they're expecting something in the realm of 'multipart/form-data' (think html form data).