Wysyłanie obrazów za pomocą Http Post

130

Chcę wysłać obraz z klienta Android na serwer Django za pomocą Http Post. Obraz jest wybierany z galerii. Obecnie używam par nazw wartości listy do wysyłania niezbędnych danych do serwera i otrzymywania odpowiedzi z Django w formacie JSON. Czy to samo podejście można zastosować w przypadku obrazów (z adresami URL obrazów osadzonych w odpowiedziach JSON)?

Ponadto, która metoda jest lepsza: zdalny dostęp do obrazów bez pobierania ich z serwera lub pobierania i przechowywania ich w tablicy Bitmap i używania ich lokalnie? Obrazy są nieliczne (<10) i małe (50 * 50 zanurzeń).

Każdy samouczek dotyczący rozwiązania tych problemów byłby bardzo mile widziany.

Edycja: Obrazy wybrane z galerii są wysyłane na serwer po przeskalowaniu go do wymaganego rozmiaru.

Pierwotny Pappachan
źródło

Odpowiedzi:

145

Zakładam, że znasz ścieżkę i nazwę pliku obrazu, który chcesz przesłać. Dodaj ten ciąg do NameValuePairużywania imagejako nazwę klucza.

Wysyłanie obrazów można wykonać za pomocą bibliotek HttpComponents . Pobierz najnowszą HttpClient (obecnie 4.0.1 ) Dwójka z pakietem zależności i skopiować apache-mime4j-0.6.jari httpmime-4.0.1.jardo projektu i dodać je do ścieżki budowania Java.

Będziesz musiał dodać następujące importy do swojej klasy.

import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;

Teraz możesz utworzyć, MultipartEntityaby dołączyć obraz do żądania POST. Poniższy kod przedstawia przykład, jak to zrobić:

public void post(String url, List<NameValuePair> nameValuePairs) {
    HttpClient httpClient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();
    HttpPost httpPost = new HttpPost(url);

    try {
        MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

        for(int index=0; index < nameValuePairs.size(); index++) {
            if(nameValuePairs.get(index).getName().equalsIgnoreCase("image")) {
                // If the key equals to "image", we use FileBody to transfer the data
                entity.addPart(nameValuePairs.get(index).getName(), new FileBody(new File (nameValuePairs.get(index).getValue())));
            } else {
                // Normal string data
                entity.addPart(nameValuePairs.get(index).getName(), new StringBody(nameValuePairs.get(index).getValue()));
            }
        }

        httpPost.setEntity(entity);

        HttpResponse response = httpClient.execute(httpPost, localContext);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Mam nadzieję, że pomoże ci to trochę we właściwym kierunku.

Piro
źródło
6
Zdecydowanie poleciłbym to. W ten sposób prawdopodobnie możesz użyć funkcji Django, aby łatwo otrzymać obraz i go przechowywać. Innym sposobem byłoby zakodowanie strumienia bajtów z obrazu do łańcucha zakodowanego w standardzie base64 i zdekodowanie go po stronie serwera. Ale moim zdaniem byłoby to zbyt kłopotliwe i nie jest właściwą drogą.
Piro
6
Hej, czy można to zrobić bez MultipartEntity? NAPRAWDĘ nie chcę importować całego Apache HC tylko dla tych 4 klas. :-(
Neil Traft
6
Po prostu dodaj drugi parametr do FileBodyżądanego typu Mime. Np .:new FileBody(new File (nameValuePairs.get(index).getValue()), "image/jpeg")
Piro
4
Wygląda na to, że wielostronność jest przestarzała?
Nanne,
1
@Piro Też myślałem o edycji twojej odpowiedzi. Encja wieloczęściowa jest amortyzowana wraz z używaną wersją treści ciągu. Powodem, dla którego nie edytuję, jest to, że nie mogłem powiązać wszystkich danych w parametrach nazw, tak jak to zrobiłeś.
Nielegalny argument
15

Wersja 4.3.5 Zaktualizowany kod

  • httpclient-4.3.5.jar
  • httpcore-4.3.2.jar
  • httpmime-4.3.5.jar

Odkąd MultipartEntityzostał wycofany . Zobacz poniższy kod.

String responseBody = "failure";
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

String url = WWPApi.URL_USERS;
Map<String, String> map = new HashMap<String, String>();
map.put("user_id", String.valueOf(userId));
map.put("action", "update");
url = addQueryParams(map, url);

HttpPost post = new HttpPost(url);
post.addHeader("Accept", "application/json");

MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setCharset(MIME.UTF8_CHARSET);

if (career != null)
    builder.addTextBody("career", career, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (gender != null)
    builder.addTextBody("gender", gender, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (username != null)
    builder.addTextBody("username", username, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (email != null)
    builder.addTextBody("email", email, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (password != null)
    builder.addTextBody("password", password, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (country != null)
    builder.addTextBody("country", country, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (file != null)
    builder.addBinaryBody("Filedata", file, ContentType.MULTIPART_FORM_DATA, file.getName());

post.setEntity(builder.build());

try {
    responseBody = EntityUtils.toString(client.execute(post).getEntity(), "UTF-8");
//  System.out.println("Response from Server ==> " + responseBody);

    JSONObject object = new JSONObject(responseBody);
    Boolean success = object.optBoolean("success");
    String message = object.optString("error");

    if (!success) {
        responseBody = message;
    } else {
        responseBody = "success";
    }

} catch (Exception e) {
    e.printStackTrace();
} finally {
    client.getConnectionManager().shutdown();
}
AZ_
źródło
Jakie opakowania słoików są potrzebne?
3
httpclient-4.3.5.jar httpcore-4.3.2.jar httpmime-4.3.5.jar
AZ_
Co zwraca addQueryParams?
San,
11

Do tego celu można użyć biblioteki loopj w prosty sposób:

SyncHttpClient client = new SyncHttpClient();
RequestParams params = new RequestParams();
params.put("text", "some string");
params.put("image", new File(imagePath));

client.post("http://example.com", params, new TextHttpResponseHandler() {
  @Override
  public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
    // error handling
  }

  @Override
  public void onSuccess(int statusCode, Header[] headers, String responseString) {
    // success
  }
});

http://loopj.com/

vonox7
źródło
5

Bardzo się męczyłem, próbując zaimplementować wysyłanie obrazu z klienta Android do serwletu przy użyciu httpclient-4.3.5.jar, httpcore-4.3.2.jar, httpmime-4.3.5.jar. Zawsze otrzymywałem błąd wykonania. Dowiedziałem się, że w zasadzie nie można używać tych słoików z Androidem, ponieważ Google używa starszej wersji HttpClient na Androida. Wyjaśnienie znajduje się tutaj http://hc.apache.org/httpcomponents-client-4.3.x/android-port.html . Musisz pobrać jar httpclientandroidlib-1.2.1 z biblioteki http-klienta systemu Android . Następnie zmień import z or.apache.http.client na ch.boye.httpclientandroidlib. Mam nadzieję że to pomoże.

David C.
źródło
-13

Zwykle robię to w wątku obsługującym odpowiedź json:

try {
  Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(imageUrl).getContent());
} catch (MalformedURLException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

Jeśli chcesz dokonać transformacji obrazu, będziesz chciał utworzyć Drawable zamiast Bitmap.

Dylan McClung
źródło
3
Pytanie brzmi, jak opublikować obraz, a nie jak go zdobyć.
dwbrito