[JAVA] Multipart request response by HttpURLConnection (and Apache Commons)

A certain server receives a request in multipart and returns a response in multipart, so a memo of the implementation corresponding to it

environment

Implementation

Class preparation

Create a class that implements UploadContext of commons-fileupload to handle multi-part response (although Upload is strange to receive response). Also, define the InputStream that receives the response for the method implementation of UploadContext as a member. Since the response checks whether the response is multipart or header this time, HttpURLConnection is also a member. Also, implement the UploadContext method required to process the multipart.

Class definition


public class MultipartRequestResponse implements UploadContext {

    private InputStream is;
    private HttpURLConnection connection;

    //At a minimum, implement the contents of getInputStream
    @Override
    public InputStream getInputStream() throws IOException {
        return is;
    }

    //Implement if necessary for response header check
    @Override
    public String getContentType() {
        return connection.getHeaderField("Content-Type");
    }

    //Other methods that require Override are only implemented for the time being, so they are omitted.
    //・ ・ ・
}

request

Preparation

Create a part delimiter (boundary)

Since the boundary is used repeatedly, it is easier to create it as a class variable first. Since this is a test, it is fixed, but I think that it is better to make it possible to issue at random, considering the boundary specifications and investigation when something happens.

Define the boundary with a class variable


private static final String BOUNDARY = "--boundary";
Request settings

Prepare the URL of the request destination and the request header. Request headers are set according to the server specifications.

URL url = new URL("https://hogehoge");

connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
connection.setRequestProperty("host", url.getHost());
//If there are other necessary settings

Send request

Set the multipart in the request body

Get the OutputStream from the instance of HttpURLConnection and write the body.

The body must also write line breaks and boundaries according to the multipart specifications. By the way, the line break must be CRLF (I sent it once with LF and it didn't handle the multipart well).

Define the line feed code with a class variable


private static final String CRLF = "\r\n";

Send request


//Start communication with the server
OutputStream os = connection.getOutputStream();

StringBuilder multipartBody = new StringBuilder();
multipartBody.append(CRLF);
//part(JSON)
multipartBody.append(BOUNDARY).append(CRLF);
multipartBody.append("Content-Disposition: form-data; name=\"parameter1\"").append(CRLF);
multipartBody.append("Content-Type: application/json; charset=utf-8").append(CRLF);
multipartBody.append("Content-Transfer-Encoding: 8bit").append(CRLF);
multipartBody.append(CRLF);
multipartBody.append("{\"hoge\": \"fuga\"}" + CRLF);
//End part
multipartBody.append(BOUNDARY).append("--");

//Write body to OutputStream
os.write(multipartBody.toString().getBytes());
//Send body to server
os.close();

Calling HttpURLConnection # getOutputStream () will start communication with the server and send the header. Calling OutputStream # close () sends the written request body to the server. It seems that if you call OutputStream # flush () for each part, you can skip the body to the server each time, but it was not sent. I would like to verify this area separately and write an article again.

response

It is a process when the server side returns the response in multiple parts, but I feel that it may not be possible if I do my best to parse the InputStream of the response, but I will process it with the help of apache commons.

//Receive response
is = connection.getInputStream();

//Check if the response is multipart
// getContentType()The return value of is checked
if (!FileUpload.isMultipartContent((RequestContext) this)) {
    //What to do if the response is not multipart
}

//Converts the contents of InputStream to Iterator
FileUpload upload = new FileUpload();
FileItemIterator fit = upload.getItemIterator(this);

//Loop for each part of the response body
while (fit.hasNext()) {
    FileItemStream fis = fit.next();
    //Get field name of part
    String field = fis.getFieldName();
    //Get InputStream of part
    InputStream isPart = fis.openStream();

    //After that, it is OK if you process the contents of the part
    //・ ・ ・
}

If you receive a response with FileItemIterator, you can rotate it in a loop and process the parts one by one.

I will clean up the sample code and publish it on github later.

Recommended Posts

Multipart request response by HttpURLConnection (and Apache Commons)
Output request and response log in Spring Boot
Apache and tomcat
Search by POST request with Azure Search + Java Apache HttpClient