web-dev-qa-db-fra.com

Envoyer un fichier image en utilisant Java HTTP POST les liaisons

J'essaie d'envoyer une image sur un site Web à l'aide de requêtes Java HTTP POST.

J'utilise le code de base utilisé ici Télécharger des fichiers du client Java vers un serveur HTTP :

Ceci est ma modification:

String urlToConnect = "http://localhost:9000/upload";
File fileToUpload = new File("C:\\Users\\joao\\Pictures\\bla.jpg");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.

URLConnection connection = new URL(urlToConnect).openConnection();
connection.setDoOutput(true); // This sets request method to POST.
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
    writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream()));
    writer.println("--" + boundary);
    writer.println("Content-Disposition: form-data; name=\"picture\"; filename=\"bla.jpg\"");
    writer.println("Content-Type: image/jpeg");
    writer.println();
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileToUpload)));
        for (String line; (line = reader.readLine()) != null;) {
            writer.println(line);
        }
    } finally {
        if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
    }
    writer.println("--" + boundary + "--");
} finally {
    if (writer != null) writer.close();
}

// Connection is lazily executed whenever you request any status.
int responseCode = ((HttpURLConnection) connection).getResponseCode();
System.out.println(responseCode); // Should be 200

Je reçois un code de réponse 200 à la fin, mais l'image est boguée, comme dans les couleurs aléatoires, ce qui me fait penser que c'est une erreur de codage des caractères. J'ai essayé d'utiliser UTF-8 comme dans l'exemple d'origine, mais cela ne fait que créer une image corrompue.

Je suis également sûr à 100% qu'il ne s'agit pas d'un problème lié au serveur, car je peux utiliser des clients restants tels que Advanced Rest Client/Postman et ils peuvent envoyer une image sans problème.

Pouvez-vous m'aider à identifier ce qui ne va pas? Je vous remercie.

15
asdt11
import Java.io.File;
import org.Apache.http.HttpEntity;
import org.Apache.http.HttpResponse;
import org.Apache.http.HttpVersion;
import org.Apache.http.client.HttpClient;
import org.Apache.http.client.methods.HttpPost;
import org.Apache.http.entity.mime.MultipartEntity;
import org.Apache.http.entity.mime.content.ContentBody;
import org.Apache.http.entity.mime.content.FileBody;
import org.Apache.http.impl.client.DefaultHttpClient;
import org.Apache.http.params.CoreProtocolPNames;
import org.Apache.http.util.EntityUtils;


public class PostFile {
  public static void main(String[] args) throws Exception {
    HttpClient httpclient = new DefaultHttpClient();
    httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

    HttpPost httppost = new HttpPost("http://localhost:9000/upload");
    File file = new File("C:\\Users\\joao\\Pictures\\bla.jpg"");

    MultipartEntity mpEntity = new MultipartEntity();
    ContentBody cbFile = new FileBody(file, "image/jpeg");
    mpEntity.addPart("userfile", cbFile);


    httppost.setEntity(mpEntity);
    System.out.println("executing request " + httppost.getRequestLine());
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity resEntity = response.getEntity();

    System.out.println(response.getStatusLine());
    if (resEntity != null) {
      System.out.println(EntityUtils.toString(resEntity));
    }
    if (resEntity != null) {
      resEntity.consumeContent();
    }

    httpclient.getConnectionManager().shutdown();
  }
}

Utilisez HttpClient pour résoudre ce code. Il est toujours préférable d’utiliser des bibliothèques stables autres que la gestion à partir de rien, sauf s’il ya quelque chose à manipuler de manière personnalisée.

18
Kris

Les classes Reader/Writer sont conçues pour gérer les données texte tandis que les images sont binaires. Vous devez interpréter vos fichiers comme binaires:

FileChannel         in  = new FileInputStream(fileToUpload).getChannel();
WritableByteChannel out = Channels.newChannel(connection.getOutputStream());

in.transferTo(0, fileToUpload.size(), out)

Bien sûr, vous devez toujours fermer toutes les ressources ouvertes. 

3
ursa

Essayez ça:

private DefaultHttpClient mHttpClient;
Context context;
public String error = "";

//Contrutor para que metodos possam ser usados fora de uma activity
public HTTPconector(Context context) {
    this.context = context;
}


public HTTPconector() {
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
    mHttpClient = new DefaultHttpClient(params);
}


public void FileClientPost(String txtUrl, File file){
    try
    {
        error = "";
        HttpPost httppost = new HttpPost(txtUrl);
        MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
        multipartEntity.addPart("Image", new FileBody(file));
        httppost.setEntity(multipartEntity);
        mHttpClient.execute(httppost, new PhotoUploadResponseHandler());
    }
    catch (Exception e)
    {
        Log.e(HTTPconector.class.getName(), e.getLocalizedMessage(), e);
        e.getStackTrace();
        error = e.getMessage();
    }
}

//Verifica se a rede esta disponível
public boolean isNetworkAvailable() {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = cm.getActiveNetworkInfo();
    // if no network is available networkInfo will be null
    // otherwise check if we are connected
    if (networkInfo != null && networkInfo.isConnected()) {
        return true;
    }
    return false;
}

public String Get(String txtUrl){
    try {
        URL url = new URL(txtUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setReadTimeout(10000);
        con.setConnectTimeout(15000);
        con.setRequestMethod("GET");
        con.setDoInput(true);
        con.connect();

        return readStream(con.getInputStream());

    }  catch (ProtocolException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    } catch (IOException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    }
}


public String Post(String txtUrl){
    File image;

    try {
        URL url = new URL(txtUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();

        //con.getOutputStream().write( ("name=" + "aa").getBytes());

        return readStream(con.getInputStream());
    } catch (ProtocolException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    } catch (IOException e) {
        e.printStackTrace();
        return "ERRO: "+e.getMessage();
    }
}


//Usado para fazer conexão com a internet
public String conectar(String u){
    String resultServer = "";
    try {
        URL url = new URL(u);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        resultServer = readStream(con.getInputStream());
    } catch (Exception e) {
        e.printStackTrace();
        resultServer = "ERRO: "+ e.getMessage();
    }

    Log.i("HTTPMANAGER: ", resultServer);
    return resultServer;
}

//Lê o resultado da conexão
private String readStream(InputStream in) {
    String serverResult = "";
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        serverResult = reader.toString();
    }   catch (IOException e) {
        e.printStackTrace();
        serverResult = "ERRO: "+ e.getMessage();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
                serverResult = "ERRO: "+ e.getMessage();
            }
        }
    }
    return  serverResult;
}

private class PhotoUploadResponseHandler implements ResponseHandler<Object>
{
    @Override
    public Object handleResponse(HttpResponse response)throws ClientProtocolException, IOException {

        HttpEntity r_entity = response.getEntity();
        String responseString = EntityUtils.toString(r_entity);
        Log.d("UPLOAD", responseString);
        return null;
    }
}

Aujourd'hui, je rencontre le même problème, j'ai écrit un petit serveur nodejs ne prenant en charge que deux itinéraires, télécharger et télécharger des images.

Le client doit être une classe Java qui envoie une charge utile d'images via le standard HTTP POST multipart/form-data au serveur.

Si vous souhaitez savoir pourquoi HTTP POST multipart/form-data , vérifiez la réponse de Ciro Santilli à partir de cet article: Que fait enctype = 'multipart/form-data ' signifier?

Heureusement, j'ai trouvé cet exemple de code Nice et vraiment bon:

_ { https://www.techcoil.com/blog/how-to-upload-a-file-via-a-http-multipart-request-in-Java-without-using-any-external-libraries/

Il montre comment nous pouvons construire la charge utile d'un corps http multipart manuellement sans aucune bibliothèque externe, la seule petite limitation de mon point de vue est qu'il ne gère qu'un corps multipartite avec un seul fichier.


Comme je n'avais aucune page HTML pour renifler la charge utile POST générée, j'ai utilisé python pour le générer et le renifler via wirehark .

Code Python3:

import requests
posturl = 'http://<server>:<port>/<path>'
files = {'image' : open('<file>', 'rb')}
r = requests.post(posturl, files = files)

Remarque: si nous définissons le paramètre files à partir de la requête lib avec un dict, cela génère un contenu mulipart/form-data. http://docs.python-requests.org/en/master/user/advanced/#post-multiple-multipart-encoded-files

Wireshark montre que tout est très clair et je me suis finalement retrouvé avec ceci pour l'envoi de Java:

HttpURLConnection conn =
        (HttpURLConnection) new URL("http://<server>:<port>/<path>")).openConnection();

// some arbitrary text for multitext boundary
// only 7-bit US-ASCII digits max length 70
String boundary_string = "some radom/arbitrary text";

// we want to write out
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary_string);

// now we write out the multipart to the body
OutputStream conn_out = conn.getOutputStream();
BufferedWriter conn_out_writer = new BufferedWriter(new OutputStreamWriter(conn_out));
// write out multitext body based on w3 standard
// https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
conn_out_writer.write("\r\n--" + boundary_string + "\r\n");
conn_out_writer.write("Content-Disposition: form-data; " +
        "name=\"image\"; " +
        "filename=\""+ <File class instance>.getName() +"\"" +
        "\r\n\r\n");
conn_out_writer.flush();

// payload from the file
FileInputStream file_stream = new FileInputStream(<File class instance>);
// write direct to outputstream instance, because we write now bytes and not strings
int read_bytes;
byte[] buffer = new byte[1024];
while((read_bytes = file_stream.read(buffer)) != -1) {
conn_out.write(buffer, 0, read_bytes);
}
conn_out.flush();
// close multipart body
conn_out_writer.write("\r\n--" + boundary_string + "--\r\n");
conn_out_writer.flush();

// close all the streams
conn_out_writer.close();
conn_out.close();
file_stream.close();
// execute and get response code
conn.getResponseCode();

Pour obtenir la réponse du POST, il suffit de lire le flux d'entrée auquel on a accédé via getInputStream (), le code a été inséré dans le lien.

0
whati001