Как использовать okhttp для загрузки файла?

Я использую okhttp для моего httpclient. Я думаю, что это хороший api, но документ не так подробно.

как использовать его для создания почтового запроса http с загрузкой файла?

public Multipart createMultiPart(File file){
    Part part = (Part) new Part.Builder().contentType("").body(new File("1.png")).build();
    //how to  set part name?
    Multipart m = new Multipart.Builder().addPart(part).build();
    return m;
}
public String postWithFiles(String url,Multipart m) throws  IOException{
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    m.writeBodyTo(out)
    ;
    Request.Body body =  Request.Body.create(MediaType.parse("application/x-www-form-urlencoded"),
            out.toByteArray());

    Request req = new Request.Builder().url(url).post(body).build();
    return client.newCall(req).execute().body().string();

}

мой вопрос:

  • как установить имя части? в форме файл должен иметь имя file1.
  • как добавить другие поля в форму?

Ответ 1

Примечание: этот ответ для охтп 1.х/2.х. Для 3.x см. Этот другой ответ.

Класс Multipart из mimecraft инкапсулирует все тело HTTP и может обрабатывать обычные поля следующим образом:

Multipart m = new Multipart.Builder()
        .type(Multipart.Type.FORM)
        .addPart(new Part.Builder()
                .body("value")
                .contentDisposition("form-data; name=\"non_file_field\"")
                .build())
        .addPart(new Part.Builder()
                .contentType("text/csv")
                .body(aFile)
                .contentDisposition("form-data; name=\"file_field\"; filename=\"file1\"")
                .build())
        .build();

Взгляните на примеры кодирования multipart/form-data, чтобы понять, как вам нужно создавать детали.

Когда у вас есть объект Multipart, все, что осталось сделать, это указать правильный заголовок Content-Type и передать байты тела в запрос.

Поскольку вы, похоже, работаете с v2.0 API OkHttp, с которым у меня нет опыта, это всего лишь код предположения:

// You'll probably need to change the MediaType to use the Content-Type
// from the multipart object
Request.Body body =  Request.Body.create(
        MediaType.parse(m.getHeaders().get("Content-Type")),
        out.toByteArray());

Для OkHttp 1.5.4 вот урезанный код, который я использую, который адаптирован из примера фрагмента:

OkHttpClient client = new OkHttpClient();
OutputStream out = null;
try {
    URL url = new URL("http://www.example.com");
    HttpURLConnection connection = client.open(url);
    for (Map.Entry<String, String> entry : multipart.getHeaders().entrySet()) {
        connection.addRequestProperty(entry.getKey(), entry.getValue());
    }
    connection.setRequestMethod("POST");
    // Write the request.
    out = connection.getOutputStream();
    multipart.writeBodyTo(out);
    out.close();

    // Read the response.
    if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
        throw new IOException("Unexpected HTTP response: "
                + connection.getResponseCode() + " " + connection.getResponseMessage());
    }
} finally {
    // Clean up.
    try {
        if (out != null) out.close();
    } catch (Exception e) {
    }
}

Ответ 2

Вот базовая функция, которая использует okhttp для загрузки файла и некоторого произвольного поля (буквально имитирует регулярную отправку HTML-формы)

Измените тип MIME, чтобы он соответствовал вашему файлу (здесь я предполагаю .csv) или сделайте его параметром функции, если вы собираетесь загружать файлы разных типов.

  public static Boolean uploadFile(String serverURL, File file) {
    try {

        RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(),
                        RequestBody.create(MediaType.parse("text/csv"), file))
                .addFormDataPart("some-field", "some-value")
                .build();

        Request request = new Request.Builder()
                .url(serverURL)
                .post(requestBody)
                .build();

        client.newCall(request).enqueue(new Callback() {

            @Override
            public void onFailure(final Call call, final IOException e) {
                // Handle the error
            }

            @Override
            public void onResponse(final Call call, final Response response) throws IOException {
                if (!response.isSuccessful()) {
                    // Handle the error
                }
                // Upload successful
            }
        });

        return true;
    } catch (Exception ex) {
        // Handle the error
    }
    return false;
}

Примечание: поскольку это асинхронный вызов, логический тип возврата не указывает на успешную загрузку, а только на то, что запрос был отправлен в очередь okhttp.

Ответ 3

Вот ответ, который работает с OkHttp 3.2.0:

public void upload(String url, File file) throws IOException {
    OkHttpClient client = new OkHttpClient();
    RequestBody formBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", file.getName(),
            RequestBody.create(MediaType.parse("text/plain"), file))
        .addFormDataPart("other_field", "other_field_value")
        .build();
    Request request = new Request.Builder().url(url).post(formBody).build();
    Response response = client.newCall(request).execute();
}

Ответ 4

OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(180, TimeUnit.SECONDS).readTimeout(180, TimeUnit.SECONDS).build();
    RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
            .addFormDataPart("File", path.getName(),RequestBody.create(MediaType.parse("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),path))
            .addFormDataPart("username", username) 
            .addFormDataPart("password", password)
            .build();
    Request request = new Request.Builder().url(url).post(body).build();
    Response response = client.newCall(request).execute();
    result = response.body().string();

Выше кода отправит имя пользователя, пароль в качестве параметра post, и файл будет загружен под именем "Файл".

Сервер PHP получит файлы

    if (isset($_FILES["File"]) &&
        isset($_POST['username']) &&
        isset($_POST['password'])) {
        //All Values found
    }else{
        echo 'please send the required data';
    }

Ответ 5

Я создал класс cool helper для OkHttp3. это здесь

public class OkHttp3Helper {

    public static final String TAG;
    private static final okhttp3.OkHttpClient client;

    static {
        TAG = OkHttp3Helper.class.getSimpleName();
        client = new okhttp3.OkHttpClient.Builder()
                .readTimeout(7, TimeUnit.MINUTES)
                .writeTimeout(7, TimeUnit.MINUTES)
                .build();
    }

    private Context context;

    public OkHttp3Helper(Context context) {
        this.context = context;
    }

    /**
     * <strong>Uses:</strong><br/>
     * <p>
     * {@code
     * ArrayMap<String, String> formField = new ArrayMap<>();}
     * <br/>
     * {@code formField.put("key1", "value1");}<br/>
     * {@code formField.put("key2", "value2");}<br/>
     * {@code formField.put("key3", "value3");}<br/>
     * <br/>
     * {@code String response = helper.postToServer("http://www.example.com/", formField);}<br/>
     * </p>
     *
     * @param url       String
     * @param formField android.support.v4.util.ArrayMap
     * @return response from server in String format
     * @throws Exception
     */
    @NonNull
    public String postToServer(@NonNull String url, @Nullable ArrayMap<String, String> formField)
            throws Exception {
        okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
        if (formField != null) {
            okhttp3.FormBody.Builder formBodyBuilder = new okhttp3.FormBody.Builder();
            for (Map.Entry<String, String> entry : formField.entrySet()) {
                formBodyBuilder.add(entry.getKey(), entry.getValue());
            }
            requestBuilder.post(formBodyBuilder.build());
        }
        okhttp3.Request request = requestBuilder.build();
        okhttp3.Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException(response.message());
        }
        return response.body().string();
    }

    /**
     * <strong>Uses:</strong><br/>
     * <p>
     * {@code
     * ArrayMap<String, String> formField = new ArrayMap<>();}
     * <br/>
     * {@code formField.put("key1", "value1");}<br/>
     * {@code formField.put("key2", "value2");}<br/>
     * {@code formField.put("key3", "value3");}<br/>
     * <br/>
     * {@code
     * ArrayMap<String, File> filePart = new ArrayMap<>();}
     * <br/>
     * {@code filePart.put("key1", new File("pathname"));}<br/>
     * {@code filePart.put("key2", new File("pathname"));}<br/>
     * {@code filePart.put("key3", new File("pathname"));}<br/>
     * <br/>
     * {@code String response = helper.postToServer("http://www.example.com/", formField, filePart);}<br/>
     * </p>
     *
     * @param url       String
     * @param formField android.support.v4.util.ArrayMap
     * @param filePart  android.support.v4.util.ArrayMap
     * @return response from server in String format
     * @throws Exception
     */
    @NonNull
    public String postMultiPartToServer(@NonNull String url,
                                        @Nullable ArrayMap<String, String> formField,
                                        @Nullable ArrayMap<String, File> filePart)
            throws Exception {
        okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
        if (formField != null || filePart != null) {
            okhttp3.MultipartBody.Builder multipartBodyBuilder = new okhttp3.MultipartBody.Builder();
            multipartBodyBuilder.setType(okhttp3.MultipartBody.FORM);
            if (formField != null) {
                for (Map.Entry<String, String> entry : formField.entrySet()) {
                    multipartBodyBuilder.addFormDataPart(entry.getKey(), entry.getValue());
                }
            }
            if (filePart != null) {
                for (Map.Entry<String, File> entry : filePart.entrySet()) {
                    File file = entry.getValue();
                    multipartBodyBuilder.addFormDataPart(
                            entry.getKey(),
                            file.getName(),
                            okhttp3.RequestBody.create(getMediaType(file.toURI()), file)
                    );
                }
            }
            requestBuilder.post(multipartBodyBuilder.build());
        }
        okhttp3.Request request = requestBuilder.build();
        okhttp3.Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException(response.message());
        }
        return response.body().string();
    }

    private okhttp3.MediaType getMediaType(URI uri1) {
        Uri uri = Uri.parse(uri1.toString());
        String mimeType;
        if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            ContentResolver cr = context.getContentResolver();
            mimeType = cr.getType(uri);
        } else {
            String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
                    .toString());
            mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                    fileExtension.toLowerCase());
        }
        return okhttp3.MediaType.parse(mimeType);
    }
}

Ответ 6

Идеальный код для загрузки любых файлов на диск Google вместе с метаданными файлов легко.

    String url = String.format("https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart");

    //String url = String.format("https://www.googleapis.com/upload/drive/v2/files?uploadType=resumable");
    boolean status;
    String metaDataFile = "{\"title\":\"" + step.getFile_name() + "\"," +
            "\"description\":\"" + step.getDescription() + "\"," +
            "\"parents\":[{\"id\":\"" + step.getFolderId() + "\"}]," +
            "\"capabilities\":{\"canEdit\":\"" + false + "\", \"canDownload\":\" "+ false +" \" }, " +
            "\"type\":\"" + step.getFile_access() + "\"" +
            "}";

    //get the encoded byte data for decode
    byte[] file = Base64.decodeBase64(step.getFile_data());

    //attaching metadata to our request object
    RequestBody requestBodyMetaData = RequestBody.create(MediaType.parse("application/json"), metaDataFile);

    //passing both meta data and file content for uploading
    RequestBody requestBodyMultipart = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("metadata", null, requestBodyMetaData)
            .addFormDataPart("file", null, RequestBody.create(MediaType.parse("application/octet-stream"), file))
            .build();
    Request request = new Request.Builder()
            .url(url)
            .addHeader("Authorization", String.format("Bearer %s", step.getAccess_token()))
            .post(requestBodyMultipart)
            .build();

    OkHttpClient okHttpClient = new OkHttpClient();

    try {
        // Get response after rest call.
        Response response = okHttpClient.newCall(request).execute();
        status = response.code() == 200 ? true : false;
        map.put(step.getOutput_variable(), response.code());