simple HttpURLConnection POST fichier multipart/form-data à partir de l'android de google blobstore

j'ai très peu d'idée de comment fonctionne html.Ce que je veux faire est exactement similaire à la suivante mais sur android

<body>
    <form action="<%= some_url %>" method="post" enctype="multipart/form-data">
        <input type="file" name="myFile">
        <input type="submit" value="Submit">
    </form>
</body>

j'ai essayé le code suivant -

private static void postToUrl(String url_to_upload_on,
        String file_name_with_ext, byte[] byteArray) {

    String attachmentName = "file";
    String attachmentFileName = file_name_with_ext;
    String crlf = "rn";
    String twoHyphens = "--";
    String boundary =  "*****";

    try{

    URL url = new URL(url_to_upload_on);
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setDoOutput(true);
    connection.setRequestMethod("POST");

    connection.setRequestProperty(
        "Content-Type", "multipart/form-data;boundary=" + boundary);
    DataOutputStream request = new DataOutputStream(
            connection.getOutputStream()); 
    request.writeBytes(twoHyphens + boundary + crlf);
    request.writeBytes("Content-Disposition: form-data; name="" +
        attachmentName + "";filename="" + 
        attachmentFileName + """ + crlf);
    request.writeBytes(crlf);
    request.write(byteArray);
    request.writeBytes(crlf);
    request.writeBytes(twoHyphens + boundary + 
        twoHyphens + crlf);
    request.flush();
    request.close();

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


}

cela ne me donne pas d'erreurs directes mais quand j'obtiens erreur-stream en utilisant -

 Log.w(TAG, "connection.getErrorStream() = " +      connection.getErrorStream());

je reçois ce-

12-14 18:25:54.911: W/uploadToBlobStore(30558): httpUrlConnection.getErrorStream() = com.android.okhttp.internal.http.HttpTransport$FixedLengthInputStream@426dd5a8

, sans succès.

PS - je suis en train de télécharger un fichier sur google blobstore

PS - Je ne peux pas utiliser les bibliothèques http Apache ou sa classe multipart comme android dit son déprécié

EDITION 1

maintenant j'utilise le code suivant mais il ne fonctionne que pour les fichiers de moins de 2,3 Mb -

private static void postToUrl3(String url_to_upload_on,
        String file_name_with_ext, byte[] byteArray, String mimeType) {

    CloseableHttpClient httpClient = null;

    try {

        httpClient = HttpClientBuilder.create().build();

        HttpPost postRequest = new HttpPost(url_to_upload_on);


        MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
        reqEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);            
        ByteArrayBody bab = new ByteArrayBody(byteArray, file_name_with_ext);           
        reqEntity.addPart("file", bab);         
        postRequest.setEntity(reqEntity.build());


        httpClient.execute(postRequest);// takes time

    } catch (Exception e) {
        Log.w("uploadToBlobStore", "postToUrl Exception e = " + e);
        e.printStackTrace();
    } finally {
        if (httpClient != null) {
            Log.w("uploadToBlobStore", "connection.closing ");
            try {
                httpClient.close();
            } catch (IOException e) {
                Log.w("uploadToBlobStore", "connection.closing errot e = "
                        + e);
                e.printStackTrace();
            }
        }
    }
}

comment faire pour qu'il fonctionne avec des fichiers plus grands?

PS - i Je l'envoie à blobstore et j'ai mis le maxUploadSizeBytes et MaxUploadSizeBytesPerBlob à 30MB.Je ne suis pas en mesure de comprendre le problème avec la taille parce que la documentation de google blobstore dit -

Google App Engine inclut le service Blobstore, qui permet aux applications de servir des objets de données limités seulement par la quantité de données qui peuvent être téléchargées ou téléchargées sur une seule connexion HTTP.

alors peut-il être un problème avec connexion http? et si oui, comment puis-je configurer.

34
demandé sur Flying Monkey 2015-12-14 23:57:57

5 réponses

j'utilise HttpURLConnection pour réaliser ceci.

créer une classe multipart custom::

public class MultipartUtility {
    private final String boundary;
    private static final String LINE_FEED = "\r\n";
    private HttpURLConnection httpConn;
    private String charset;
    private OutputStream outputStream;
    private PrintWriter writer;

    /**
     * This constructor initializes a new HTTP POST request with content type
     * is set to multipart/form-data
     *
     * @param requestURL
     * @param charset
     * @throws IOException
     */
    public MultipartUtility(String requestURL, String charset)
            throws IOException {
        this.charset = charset;

        // creates a unique boundary based on time stamp
        boundary = "===" + System.currentTimeMillis() + "===";
        URL url = new URL(requestURL);
        httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setUseCaches(false);
        httpConn.setDoOutput(true);    // indicates POST method
        httpConn.setDoInput(true);
        httpConn.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=" + boundary);
        outputStream = httpConn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
                true);
    }

    /**
     * Adds a form field to the request
     *
     * @param name  field name
     * @param value field value
     */
    public void addFormField(String name, String value) {
        writer.append("--" + boundary).append(LINE_FEED);
        writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
                .append(LINE_FEED);
        writer.append("Content-Type: text/plain; charset=" + charset).append(
                LINE_FEED);
        writer.append(LINE_FEED);
        writer.append(value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a upload file section to the request
     *
     * @param fieldName  name attribute in <input type="file" name="..." />
     * @param uploadFile a File to be uploaded
     * @throws IOException
     */
    public void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();
        writer.append("--" + boundary).append(LINE_FEED);
        writer.append(
                "Content-Disposition: form-data; name=\"" + fieldName
                        + "\"; filename=\"" + fileName + "\"")
                .append(LINE_FEED);
        writer.append(
                "Content-Type: "
                        + URLConnection.guessContentTypeFromName(fileName))
                .append(LINE_FEED);
        writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
        writer.append(LINE_FEED);
        writer.flush();

        FileInputStream inputStream = new FileInputStream(uploadFile);
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.flush();
        inputStream.close();
        writer.append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a header field to the request.
     *
     * @param name  - name of the header field
     * @param value - value of the header field
     */
    public void addHeaderField(String name, String value) {
        writer.append(name + ": " + value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Completes the request and receives response from the server.
     *
     * @return a list of Strings as response in case the server returned
     * status OK, otherwise an exception is thrown.
     * @throws IOException
     */
    public List<String> finish() throws IOException {
        List<String> response = new ArrayList<String>();
        writer.append(LINE_FEED).flush();
        writer.append("--" + boundary + "--").append(LINE_FEED);
        writer.close();

        // checks server's status code first
        int status = httpConn.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    httpConn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                response.add(line);
            }
            reader.close();
            httpConn.disconnect();
        } else {
            throw new IOException("Server returned non-OK status: " + status);
        }
        return response;
    }
}

Utiliser (async) ::

    MultipartUtility multipart = new MultipartUtility(requestURL, charset);

    // In your case you are not adding form data so ignore this
                /*This is to add parameter values */
                for (int i = 0; i < myFormDataArray.size(); i++) {
                    multipart.addFormField(myFormDataArray.get(i).getParamName(),
                            myFormDataArray.get(i).getParamValue());
                }


//add your file here.
                /*This is to add file content*/
                for (int i = 0; i < myFileArray.size(); i++) {
                    multipart.addFilePart(myFileArray.getParamName(),
                            new File(myFileArray.getFileName()));
                }

                List<String> response = multipart.finish();
                Debug.e(TAG, "SERVER REPLIED:");
                for (String line : response) {
                    Debug.e(TAG, "Upload Files Response:::" + line);
// get your server response here.
                    responseString = line;
                }
58
répondu KDeogharkar 2015-12-23 06:21:41

utiliser okhttp et l'utilisation de l'extrait de code suivant (extrait de recettes )

ajustez les valeurs d'en-tête en fonction des attentes de votre serveur.

private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

private final OkHttpClient client = new OkHttpClient();

public void run() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
    RequestBody requestBody = new MultipartBuilder()
    .type(MultipartBuilder.FORM)
    .addPart(
        Headers.of("Content-Disposition", "form-data; name=\"title\""),
        RequestBody.create(null, "Square Logo"))
    .addPart(
        Headers.of("Content-Disposition", "form-data; name=\"image\""),
        RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
    .build();

Request request = new Request.Builder()
    .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
    .url("https://api.imgur.com/3/image")
    .post(requestBody)
    .build();

Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

System.out.println(response.body().string());
}
9
répondu eriuzo 2015-12-17 00:52:58

comme alternative vous pouvez utiliser Retrofit .

, Vous pouvez spécifier un appel comme ceci:

@Multipart
@POST("/user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

alors créer comme ceci:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .build();
GitHubService service = retrofit.create(GitHubService.class);

et enfin l'exécuter comme ceci:

service.updateUser(Photo, description).enqueue() --> asynchrone

service.updateUser(Photo, description).execute() --> synchrone

voir la documentation ici

6
répondu Lars Celie 2016-08-23 17:01:34

j'ai été en mesure de télécharger un fichier en utilisant multipart entity, vérifier le code que j'ai posté dans la réponse ici: URLConnection retourne toujours 400 : Mauvaise demande quand j'essaie de télécharger un .fichier wav Tique vert si ça marche!!! acclamations!

1
répondu Josh 2017-05-23 12:34:37

Volley est une bonne bibliothèque http pour multipart données. La classe AndroidMultiPartEntity est pour l'auditeur de progrès.

    public class AndroidMultiPartEntity extends MultipartEntity

    {

    private final ProgressListener listener;

    public AndroidMultiPartEntity(final ProgressListener listener) {
    super();
    this.listener = listener;
    }

    public AndroidMultiPartEntity(final HttpMultipartMode mode, final ProgressListener listener) {
    super(mode);
    this.listener = listener;
    }

    public AndroidMultiPartEntity(HttpMultipartMode mode, final String boundary,
    final Charset charset, final ProgressListener listener) {
    super(mode, boundary, charset);
    this.listener = listener;
    }

    @Override
    public void writeTo(final OutputStream outstream) throws IOException {
    super.writeTo(new CountingOutputStream(outstream, this.listener));
    }

    public static interface ProgressListener {
    void transferred(long num);
    }

    public static class CountingOutputStream extends FilterOutputStream {

    private final ProgressListener listener;
    private long transferred;

    public CountingOutputStream(final OutputStream out,
                                final ProgressListener listener) {
        super(out);
        this.listener = listener;
        this.transferred = 0;
    }

    public void write(byte[] b, int off, int len) throws IOException {
        out.write(b, off, len);
        this.transferred += len;
        this.listener.transferred(this.transferred);
    }

    public void write(int b) throws IOException {
        out.write(b);
        this.transferred++;
        this.listener.transferred(this.transferred);
    }
    }
    }

    Call the Async task like this
    new UploadFileToServer().execute();


    The Call method:
    private class UploadFileToServer extends AsyncTask<Void, Integer, String> {
    @Override
    protected void onPreExecute() {

        super.onPreExecute();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {

    }

    @Override
    protected String doInBackground(Void... params) {

        return uploadFile();

    }

    private String uploadFile() {

        String responseString = null;

        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(Config.Seeker_Image_Upload);

        try {
            AndroidMultiPartEntity entity = new AndroidMultiPartEntity(new AndroidMultiPartEntity.ProgressListener() {

                @Override
                public void transferred(long num) {
                    publishProgress((int) ((num / (float) totalSize) * 100));
                }
            });

            File sourceFile = new File(Path);

            // Adding file data to http body
            entity.addPart("logo", new FileBody(sourceFile));

            // Extra parameters if you want to pass to server
            //entity.addPart("website", new StringBody("www.androidhive.info"));

            // String emailaddress = UserActivity.emailaddress;

            /*preferences = SeekerProfile.this.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
            email_address = preferences.getString("EMAILADDRESS", "");*/
            entity.addPart("EMAILADDRESS", new StringBody(email_address));
            entity.addPart("OPER", new StringBody(Operation_recruiter_logo_upload));

            totalSize = entity.getContentLength();
            httppost.setEntity(entity);

            // Making server call
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity r_entity = response.getEntity();

            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                // Server response
                responseString = EntityUtils.toString(r_entity);
            } else {
                responseString = "Error occurred! Http Status Code: " + statusCode;
            }

        } catch (ClientProtocolException e) {
            responseString = e.toString();
        } catch (IOException e) {
            responseString = e.toString();
        }

        return responseString;

        }

        @Override
        protected void onPostExecute(String result) {
        //Log.e(TAG, "Response from server: " + result);
        enter code here
        }

    }
0
répondu Ram 2016-10-26 07:14:24