Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


¿Cómo enviar multipart / form-data con Retrofit?

Quiero enviar un artículo desde y un cliente Android a un servidor REST. Aquí está el modelo Python del servidor:

class Article(models.Model): author = models.CharField(max_length=256, blank=False) photo = models.ImageField() 

La siguiente interfaz describe la implementación anterior:

  • Cargar imagen de compresión en un servidor mediante retroadaptación
  • ¿Cómo realizar una solicitud DELETE sin tipo de devolución o devolución de llamada?
  • Android: notifyDataSetChanged (); no funciona
  • Controles de dependencia estrictos de Android en SDK 17
  • Retrofit-IllegalArgumentException: url inesperada
  • Tipo de contenido de Retrofit de Android como aplicación / x-www-form-urlencoded
  •  @POST("/api/v1/articles/") public Observable<CreateArticleResponse> createArticle( @Body Article article ); 

    Ahora quiero enviar una imagen con los datos del artículo . La photo no forma parte del modelo de artículo en el cliente de Android .

     @Multipart @POST("/api/v1/articles/") public Observable<CreateArticleResponse> createArticle( @Part("article") Article article, @Part("photo") TypedFile photo ); 

    El API se prepara y se prueba con éxito con cURL .

     $ curl -vX POST http://localhost:8000/api/v1/articles/ \ -H "Content-Type: multipart/form-data" \ -H "Accept:application/json" \ -F "author=cURL" \ -F "photo=@/home/user/Desktop/article-photo.png" 

    Cuando envío datos a través de createArticle() desde el cliente de Android recibo un estado de HTTP 400 indicando que los campos son obligatorios / faltantes .

     D <--- HTTP 400 http://192.168.1.1/articles/ (2670ms) D Date: Mon, 20 Apr 2015 12:00:00 GMT D Server: WSGIServer/0.1 Python/2.7.8 D Vary: Accept, Cookie D X-Frame-Options: SAMEORIGIN D Content-Type: application/json D Allow: GET, POST, HEAD, OPTIONS D OkHttp-Selected-Protocol: http/1.0 D OkHttp-Sent-Millis: 1429545450469 D OkHttp-Received-Millis: 1429545453120 D {"author":["This field is required."],"photo":["No file was submitted."]} D <--- END HTTP (166-byte body) E 400 BAD REQUEST 

    Esto es lo que se recibe como request.data en el lado del servidor:

     ipdb> print request.data <QueryDict: {u'article': [u'{"author":"me"}'], \ u'photo': [<TemporaryUploadedFile: IMG_1759215522.jpg \ (multipart/form-data)>]}> 

    ¿Cómo puede convertir el objeto Artículo en un tipo de datos conformes multipart? He leído que Retrofit podría permitir el uso de convertidores para esto. Debe ser algo que implemente un retrofit.mime.TypedOutput por lo que entendí para la documentación .

    Las partes multipart utilizan el convertidor de RestAdapter o pueden implementar TypedOutput para manejar su propia serialización.

    Relacionado

    • HTML 4.01 Specification – Presentación de formularios – multipart / form-data
    • Retrofit Annotation Type Documentación de la pieza
    • Subir datos de imagen de varias partes en JSON con Retrofit?
    • REST – HTTP Post Multipart con JSON
    • Error de actualización de la imagen de subida múltiple
    • Edición # 178: Crear manual para enviar archivos con retrofit
    • Problema de actualización # 531: Problema al subir el archivo a través de POST / Multipart
    • Problema de actualización # 658: No es posible enviar parámetros de cadena con la imagen al usar Multipart
    • Edición de actualización # 662: Formulario de Retrofit Codificado y Multipart en solicitud única

  • Manejo de inicio de sesión y recuerda conmigo con AccountManager
  • Node.js npm en Android
  • OnFling en un ListView, Obtener el swiped Información del ítem
  • ¿Hay una buena herramienta para hacer diseño de diseño de Android?
  • Cómo implementar la compra en la aplicación en mi aplicación Android?
  • ¿Es el proveedor de contenido una implementación del patrón del repositorio?
  • 2 Solutions collect form web for “¿Cómo enviar multipart / form-data con Retrofit?”

    De acuerdo con su solicitud de curl usted está tratando de crear smth como este:

     POST http://localhost:8000/api/v1/articles/ HTTP/1.1 User-Agent: curl/7.30.0 Host: localhost Connection: Keep-Alive Accept: application/json Content-Length: 183431 Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------23473c7acabb ------------------------------23473c7acabb Content-Disposition: form-data; name="author" cURL ------------------------------23473c7acabb Content-Disposition: form-data; name="photo"; filename="article-photo.png" Content-Type: application/octet-stream ‰PNG <!RAW BYTES HERE!> M\UUÕ+4qUUU¯°WUUU¿×ß¿þ Naa…k¿ IEND®B`‚ ------------------------------23473c7acabb-- 

    Con el adaptador de adaptación, esta solicitud se puede crear de una manera siguiente:

     @Multipart @POST("/api/v1/articles/") Observable<Response> uploadFile(@Part("author") TypedString authorString, @Part("photo") TypedFile photoFile); 

    Uso:

     TypedString author = new TypedString("cURL"); File photoFile = new File("/home/user/Desktop/article-photo.png"); TypedFile photoTypedFile = new TypedFile("image/*", photoFile); retrofitAdapter.uploadFile(author, photoTypedFile) .subscribe(<...>); 

    Que crea una salida similar:

     POST http://localhost:8000/api/v1/articles/ HTTP/1.1 Content-Type: multipart/form-data; boundary=32230279-83af-4480-abfc-88a880b21b19 Content-Length: 709 Host: localhost Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/2.3.0 --32230279-83af-4480-abfc-88a880b21b19 Content-Disposition: form-data; name="author" Content-Type: text/plain; charset=UTF-8 Content-Length: 4 Content-Transfer-Encoding: binary cUrl --32230279-83af-4480-abfc-88a880b21b19 Content-Disposition: form-data; name="photo"; filename="article-photo.png" Content-Type: image/* Content-Length: 254 Content-Transfer-Encoding: binary <!RAW BYTES HERE!> --32230279-83af-4480-abfc-88a880b21b19-- 

    La diferencia clave aquí es que usaste el Article article POJO como multipart param, que por defecto es convertido por el Converter en json. Y su servidor espera la cadena llana en su lugar. Con curl estás enviando cURL , no {"author":"cURL"} .

    El servidor espera una cadena de "autor" pero está intentando pasarle un objeto "artículo". Pasar "String autor" en lugar de "Artículo artículo".

    Además, creo que el "no archivo enviado" error es un arenque rojo, porque el archivo está claramente presente en su "request.data".

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.