Как отправить multipart / form-data с дооснащением?
Я хочу отправить статьи и Android клиент на сервер REST. Вот это Python модель с сервера:
class Article(models.Model):
author = models.CharField(max_length=256, blank=False)
photo = models.ImageField()
следующий интерфейс описывает предыдущую реализацию:
@POST("/api/v1/articles/")
public Observable<CreateArticleResponse> createArticle(
@Body Article article
);
теперь я хочу отправить изображение с статьи данные. The photo
не является частью статьи модель Android клиент.
@Multipart
@POST("/api/v1/articles/")
public Observable<CreateArticleResponse> createArticle(
@Part("article") Article article,
@Part("photo") TypedFile photo
);
API подготовлен и успешно протестирован с помощью скручиваемость.
$ 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"
когда я посылаю данные через createArticle()
С Android клиент я получаю HTTP 400
статус, указывающий, что поля обязательны / отсутствуют.
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
это то, что принято как request.data
на стороне сервера:
ipdb> print request.data
<QueryDict: {u'article': [u'{"author":"me"}'],
u'photo': [<TemporaryUploadedFile: IMG_1759215522.jpg
(multipart/form-data)>]}>
как преобразовать статьи "объект" составного соответствовать тип данных? Я читал это модернизация может разрешить использовать конверторы для этого. Это должно быть что-то, что реализует a retrofit.mime.TypedOutput
насколько я понял для документация.
составные части используйте
RestAdapter
конвертер или они могут реализоватьTypedOutput
для обработки собственной сериализации.
по теме
- спецификация HTML 4.01 - форма submission-multipart/form-data
- дооснащение тип аннотации часть документации
- загрузить данные многостраничного изображения в JSON с помощью Retrofit?
- REST-HTTP Post Multipart с JSON
- Retrofit Multipart загрузить изображение не удалось
- Retrofit issue #178: создать руководство по отправке файлов с retrofit
- Ретрофит проблема №531: проблема загрузки файла через POST / Multipart
- проблема дооснащения #658: не удается отправить параметры строки с изображением при использовании Multipart
- Retrofit issue #662: Retrofit Form Encoded and Multipart in single request
2 ответов
согласно вашему запросу curl вы пытаетесь создать smth следующим образом:
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--
с адаптером дооснащения этот запрос может быть создан следующим образом:
@Multipart
@POST("/api/v1/articles/")
Observable<Response> uploadFile(@Part("author") TypedString authorString,
@Part("photo") TypedFile photoFile);
использование:
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(<...>);
, который создает подобный выход:
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--
ключевое отличие здесь в том, что вы использовали POJO Article article
как составной param, который по умолчанию преобразуется Converter
в json. И вместо этого ваш сервер ожидает простой строки. С curl вы отправляете cURL
, а не {"author":"cURL"}
.
сервер ожидает строку" автор", но вы пытаетесь передать ей объект "статья". Передайте его "string author" вместо " Article article."
кроме того, я думаю, что ошибка "нет представленного файла" является отвлекающим маневром, потому что файл явно присутствует в вашем "запросе.данные."