[JAVA] Réponse à une requête en plusieurs parties par HttpURLConnection (et Apache Commons)

Un certain serveur reçoit une requête en multipart et renvoie une réponse en multipart, donc un mémo de l'implémentation qui lui correspond

environnement

la mise en oeuvre

Préparation de classe

Créez une classe qui implémente le UploadContext de commons-fileupload pour gérer la réponse en plusieurs parties (même si cela semble étrange de recevoir la réponse). Définissez également InputStream qui reçoit la réponse pour l'implémentation de méthode de UploadContext en tant que membre. Puisque la réponse vérifie si la réponse est en plusieurs parties ou l'en-tête cette fois, HttpURLConnection est également un membre. Implémentez également la méthode UploadContext requise pour traiter le multipart.

Définition de classe


public class MultipartRequestResponse implements UploadContext {

    private InputStream is;
    private HttpURLConnection connection;

    //Au minimum, implémentez le contenu de getInputStream
    @Override
    public InputStream getInputStream() throws IOException {
        return is;
    }

    //Implémenter si nécessaire la vérification de l'en-tête de réponse
    @Override
    public String getContentType() {
        return connection.getHeaderField("Content-Type");
    }

    //D'autres méthodes qui nécessitent un remplacement ne sont implémentées que pour le moment, elles sont donc omises.
    //・ ・ ・
}

demande

Préparation

Créer une limite pour la pièce

Étant donné que la limite est utilisée à plusieurs reprises, il est plus facile de la créer d'abord en tant que variable de classe. Puisqu'il s'agit d'un test, il est fixe, mais je pense qu'il vaut mieux permettre d'émettre au hasard compte tenu des spécifications des limites et de l'enquête lorsque quelque chose se passe.

Définissez la limite avec une variable de classe


private static final String BOUNDARY = "--boundary";
Demander des paramètres

Préparez l'URL de destination de la demande et l'en-tête de la demande. L'en-tête de la demande est défini selon les spécifications du serveur.

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());
//S'il y a d'autres paramètres nécessaires

Envoyer une demande

Définir le multipart dans le corps de la demande

Récupérez OutputStream de l'instance HttpURLConnection et écrivez le corps.

Le corps doit également écrire des sauts de ligne et des limites selon les spécifications en plusieurs parties. Au fait, le saut de ligne doit être CRLF (je l'ai envoyé une fois avec LF et je ne pouvais pas bien gérer le multipart).

Définissez le code de saut de ligne avec une variable de classe


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

Envoyer une demande


//Commencer la communication avec le serveur
OutputStream os = connection.getOutputStream();

StringBuilder multipartBody = new StringBuilder();
multipartBody.append(CRLF);
//partie(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);
//Partie finale
multipartBody.append(BOUNDARY).append("--");

//Ecrire le corps dans OutputStream
os.write(multipartBody.toString().getBytes());
//Envoyer le corps au serveur
os.close();

L'appel de HttpURLConnection # getOutputStream () démarrera la communication avec le serveur et enverra l'en-tête. L'appel de OutputStream # close () envoie le corps de la requête écrite au serveur. Il semble que si vous appelez OutputStream # flush () pour chaque partie, vous pouvez envoyer le corps au serveur à chaque fois, mais il n'a pas été envoyé. Je voudrais vérifier cette zone séparément et rédiger à nouveau un article.

réponse

C'est un processus lorsque le côté serveur renvoie la réponse en plusieurs parties, mais je pense que ce ne sera peut-être pas possible si je fais de mon mieux pour analyser le InputStream de la réponse, mais je le traiterai avec l'aide d'apache commons.

//Recevoir une réponse
is = connection.getInputStream();

//Vérifiez si la réponse est en plusieurs parties
// getContentType()La valeur de retour de est vérifiée
if (!FileUpload.isMultipartContent((RequestContext) this)) {
    //Que faire si la réponse n'est pas en plusieurs parties
}

//Convertit le contenu d'InputStream en Iterator
FileUpload upload = new FileUpload();
FileItemIterator fit = upload.getItemIterator(this);

//Boucle pour chaque partie du corps de réponse
while (fit.hasNext()) {
    FileItemStream fis = fit.next();
    //Obtenir le nom du champ de la pièce
    String field = fis.getFieldName();
    //Obtenir InputStream de la pièce
    InputStream isPart = fis.openStream();

    //Après cela, c'est OK si vous traitez le contenu de la pièce
    //・ ・ ・
}

Si vous recevez une réponse avec FileItemIterator, vous pouvez la tourner en boucle et traiter les parties une par une.

Je nettoierai l'exemple de code et le publierai sur github plus tard.

Recommended Posts

Réponse à une requête en plusieurs parties par HttpURLConnection (et Apache Commons)
Sortie des journaux de demande et de réponse avec Spring Boot
Apache et Tomcat
Recherche par requête POST avec Azure Search + Java Apache HttpClient