web-dev-qa-db-fra.com

Http POST en Java (avec téléchargement de fichier)

Ce que je veux faire, c'est soumettre un formulaire Web à partir d'une application Java. Le formulaire que je dois remplir se trouve ici: http://cando-dna-origami.org/

Lorsque le formulaire est soumis, le serveur envoie un courrier électronique de confirmation à l'adresse électronique indiquée, que je ne vérifie pour l'instant que manuellement. J'ai essayé de remplir le formulaire manuellement et les courriels ont été envoyés correctement. (Il convient également de noter que lorsque le formulaire est mal rempli, la page est simplement actualisée et ne donne aucun retour).

Je n'avais jamais utilisé http auparavant, mais j'ai jeté un coup d'œil autour de moi pour trouver le code suivant, censé envoyer une demande POST au serveur:

    String data = "name=M+V&affiliation=Company&email="
            + URLEncoder.encode("[email protected]", "UTF-8")
            + "&axialRise=0.34&helixDiameter=2.25&axialStiffness=1100&bendingStiffness=230" +
            "&torsionalStiffness=460&nickStiffness=0.01&resolution=course&jsonUpload="
            + URLEncoder.encode("C:/Users/Marjie/Downloads/twisted_DNA_bundles/monotwist.L1.v1.json",
            "UTF-8") + "&type=square";

    URL page = new URL("http://cando-dna-origami.org/");
    HttpURLConnection con = (HttpURLConnection) page.openConnection();

    con.setDoOutput(true);
    con.setRequestMethod("POST");
    con.connect();

    OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
    out.write(data);
    out.flush();

    System.out.println(con.getResponseCode());
    System.out.println(con.getResponseMessage());

    out.close();
    con.disconnect();

Cependant, quand il fonctionne, il ne semble rien faire - c'est-à-dire que je ne reçois aucun courrier électronique, bien que le programme affiche "200 OK" dans System.out, ce qui semble indiquer que quelque chose a été reçu du serveur. Bien que je ne sois pas sûr de ce que cela signifie exactement. Je pense que le problème vient peut-être du téléchargement de fichier, car je ne savais pas si ce type de données nécessitait un format différent.

Est-ce une manière correcte d’envoyer une demande POST en utilisant Java? Dois-je faire quelque chose de différent pour le téléchargement de fichier? Merci!


Après avoir lu le message d'Adam, j'ai utilisé Apache HttpClient et écrit le code suivant:

    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("type", "square"));
    //... add more parameters

    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);

    HttpPost post = new HttpPost("http://cando-dna-origami.org/");
    post.setEntity(entity);

    HttpResponse response = new DefaultHttpClient().execute(post);
    post = new HttpPost("http://cando-dna-origami.org/");

    post.setEntity(new FileEntity(new File("C:/Users/Marjie/Downloads/twisted_DNA_bundles/monotwist.L1.v1.json"), "text/plain; charset=\"UTF-8\""));
    HttpResponse responseTwo = new DefaultHttpClient().execute(post);

Cependant, cela ne semble toujours pas fonctionner; Encore une fois, je ne savais pas comment le fichier téléchargé s'insérait dans le formulaire. J'ai donc essayé d'envoyer deux demandes POST distinctes, une avec le formulaire et l'autre avec les données. Je cherche toujours un moyen de les combiner en une seule demande; Quelqu'un sait-il quelque chose à ce sujet?

15
Reyan

Vous feriez probablement mieux d'utiliser quelque chose comme Apache HttpClient , avec lequel vous pouvez créer une requête POST par programme.

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://.../whatever");

List <NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("param1", "value1"));
params.add(new BasicNameValuePair("param2", "value2"));
...

httpost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

HttpResponse response = httpclient.execute(httppost);

Si vous devez télécharger un fichier avec votre formulaire, vous devrez utiliser une variable MultipartEntity à la place:

MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("someParam", "someValue");
reqEntity.addPart("someFile", new FileBody("/some/file"));
....

httpost.setEntity(reqEntity);

Quelques exemples de programmes sont disponibles sur leur site . "Connexion basée sur un formulaire" et "Entité de requête codée en plusieurs parties" sont de bons exemples.

Il peut également être intéressant de tester vos connexions et d'examiner les données réseau sous-jacentes pour voir ce qui se passe. Quelque chose comme Firebug vous permettra de voir exactement ce qui se passe dans votre navigateur et vous pouvez activer la journalisation HttpClient pour voir toutes les données échangées dans votre programme. Alternativement, vous pouvez utiliser quelque chose comme Wireshark ou Fiddler pour surveiller le trafic de votre réseau en temps réel. Cela peut vous donner une meilleure idée de ce que fait exactement votre navigateur par rapport à ce que fait votre programme.

17
Adam Batkin

Vous devez utiliser définitivement apaches HTTPClient pour ce travail! Cela rend la vie beaucoup plus facile. Voici un exemple comment télécharger un fichier avec Apaches HttpClient. 

byte[] data = outStream.toByteArray()
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://localhost:8080/YourResource");

ByteArrayBody byteArrayBody = new ByteArrayBody(data, "application/json", "some.json");
MultipartEntity multipartEntity = new MultipartEntity();
multipartEntity.addPart("upload", byteArrayBody);
httpPost.setEntity( multipartEntity );

HttpResponse response = client.execute(httpPost);
Reader reader = new InputStreamReader(response.getEntity().getContent());

Faites-moi savoir si vous avez d'autres questions. 

2
Robert Reiz

J'écris actuellement un petit serveur Web et j'ai testé votre client de requête. Mon serveur reçoit la requête suivante:

User-Agent: Java/1.6.0_20 
Host: localhost:1700 
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 
Connection: keep-alive 
Content-type: application/x-www-form-urlencoded 
Content-Length: 287 
name=M+V&affiliation=Company&email=m.v%40gmail.com&axialRise=0.34&helixDiameter=2.25&axialStiffness=1100&bendingStiffness=230&torsionalStiffness=460&nickStiffness=0.01&resolution=course&jsonUpload=C%3A%2FUsers%2FMarjie%2FDownloads%2Ftwisted_DNA_bundles%2Fmonotwist.L1.v1.json&type=square

Vous devez vérifier le format des données POST que vous envoyez, elles ne sont probablement pas traitées par le serveur, contrairement à ce que vous attendez.

1
Alex

Comme la plupart des codes de requête Java POST suggérés par Java HTTP ne sont pas opérationnels, j'ai décidé de vous donner mon code entièrement opérationnel que vous trouverez certainement utile pour créer des POST demande à l'avenir.

Cette demande POST est de type multipart afin de permettre l'envoi/le téléchargement d'un fichier sur le serveur. 

La demande en plusieurs parties consiste en un en-tête principal et une chaîne de séparation appelée borne pour indiquer chaque partie de l'autre (ce séparateur apparaît dans le flux avec la chaîne "-" (deux tirets) devant elle, a son propre petit en-tête pour dire son type et quelques méta-données.

Ma tâche consistait à créer un fichier PDF à l'aide de certains services en ligne, mais tous les exemples multi-parties POST ne faisaient pas l'affaire ...

J'avais besoin d'emballer un document HTML avec ses images, JS et CSS dans un fichier Zip/TAR, de le télécharger sur un service de conversion en ligne html2pdf et de récupérer le résultat sous forme de document PDF. réponse (flux) du service.

Le service actuel sur lequel j’ai vérifié l’utilisation du code suivant est: Htmlpdfapi.com mais je suis sûr qu’avec des ajustements mineurs, vous pourrez l’utiliser avec n’importe quel autre service.

La appel de méthode (pour ce service) ressemble à quelque chose comme: [class instance name].sendPOSTRequest("http://htmlpdfapi.com/api/v1/pdf", "Token 6hr4-AmqZDrFVjAcJGykjYyXfwG1wER4", "/home/user/project/srv/files/example.Zip", "result.pdf");

Voici mon code qui a été vérifié et fonctionne à 100%:

public void sendPOSTRequest(String url, String authData, String attachmentFilePath, String outputFilePathName)
{
    String charset = "UTF-8";
    File binaryFile = new File(attachmentFilePath);
    String boundary = "------------------------" + Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
    String CRLF = "\r\n"; // Line separator required by multipart/form-data.
    int    responseCode = 0;

    try 
    {
        //Set POST general headers along with the boundary string (the seperator string of each part)
        URLConnection connection = new URL(url).openConnection();
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        connection.addRequestProperty("User-Agent", "CheckpaySrv/1.0.0");
        connection.addRequestProperty("Accept", "*/*");
        connection.addRequestProperty("Authentication", authData);

        OutputStream output = connection.getOutputStream();
        PrintWriter writer  = new PrintWriter(new OutputStreamWriter(output, charset), true);

        // Send binary file - part
        // Part header
        writer.append("--" + boundary).append(CRLF);
        writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
        writer.append("Content-Type: application/octet-stream").append(CRLF);// + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
        writer.append(CRLF).flush();

        // File data
        Files.copy(binaryFile.toPath(), output);
        output.flush(); 

        // End of multipart/form-data.
        writer.append(CRLF).append("--" + boundary + "--").flush();

        responseCode = ((HttpURLConnection) connection).getResponseCode();


        if(responseCode !=200) //We operate only on HTTP code 200
            return;

        InputStream Instream = ((HttpURLConnection) connection).getInputStream();

        // Write PDF file 
        BufferedInputStream BISin = new BufferedInputStream(Instream);
        FileOutputStream FOSfile  = new FileOutputStream(outputFilePathName);
        BufferedOutputStream out  = new BufferedOutputStream(FOSfile);

        int i;
        while ((i = BISin.read()) != -1) {
            out.write(i);
        }

        // Cleanup
        out.flush();
        out.close();


    }
    catch(Exception e)
    {
        e.printStackTrace();
    }

}
1
JamesC

Voici un exemple de travail utilisant Apache httpclient. De plus, n'oubliez pas d'ajouter ces dépendances:

    <dependency>
        <groupId>org.Apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.4.1</version>
    </dependency>


    <dependency>
        <groupId>org.Apache.httpcomponents</groupId>
        <artifactId>httpmime</artifactId>
        <version>4.4.1</version>
    </dependency>

Le code: HttpClient httpclient = HttpClientBuilder.create (). Build (); 

HttpPost httppost = new HttpPost(DataSources.TORRENT_UPLOAD_URL);

MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addPart("a_field_name", new FileBody(torrentFile));

HttpEntity entity = builder.build();

httppost.setEntity(entity);

HttpResponse response = httpclient.execute(httppost);
0
thouliha