如何使用 Retrofit 发送多部分/表单数据? [英] How to send multipart/form-data with Retrofit?

查看:38
本文介绍了如何使用 Retrofit 发送多部分/表单数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从 Android 客户端向 REST 服务器发送文章.这是来自服务器的 Python 模型:

I want to send an Article from and Android client to a REST server. Here is the Python model from the server:

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

以下接口描述了之前的实现:

The following interface describes the former implementation:

@POST("/api/v1/articles/")
public Observable<CreateArticleResponse> createArticle(
        @Body Article article
);

现在我想发送带有文章数据的图像.照片 不是 Android 客户端上的 文章 模型的一部分.

Now I want to send an image with the Article data. The photo is not part of the Article model on the Android client.

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

API 已准备好并通过 cURL 成功测试.

The API is prepared and successfully tested with 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"

当我从 Android 客户端通过 createArticle() 发送数据时,我收到一个 HTTP 400 状态,说明 字段是必需/缺失.

When I send data through createArticle() from the Android client I receive an HTTP 400 status stating that the fields are required/missing.

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 接收的:

This is what is received as request.data on the server side:

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

如何将Article 对象转换为多部分符合数据类型?我读到 Retrofit 可能允许使用 转换器为此.据我了解 文档.

How can convert the Article object in a multipart conform data type? I read that Retrofit might allow to use Converters for this. It should be something that implements a retrofit.mime.TypedOutput as far as I understood for the documentation.

多部分使用 RestAdapter 的转换器,或者它们可以实现 TypedOutput 来处理它们自己的序列化.

Multipart parts use the RestAdapter's converter or they can implement TypedOutput to handle their own serialization.

相关

  • HTML 4.01 规范 - 表单提交 - multipart/form-数据
  • 改造注解类型部分文档
  • 使用 Retrofit 以 JSON 格式上传多部分图像数据?
  • REST - HTTP Post Multipart with JSON
  • 改造分段上传图片失败
  • 改造问题 #178:创建使用改造发送文件的手册
  • 改造问题 #531:通过 POST/Multipart 上传文件时出现问题
  • 改造问题 #658:使用 Multipart 时无法发送带有图像的字符串参数
  • 改造问题 #662:在单个请求中改造表单编码和多部分
  • 推荐答案

    根据您的 curl 请求,您正在尝试像这样创建 smth:

    According to your curl request you are trying to create smth like this:

    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!>
    
    MUUÕ+4qUUU¯°WUUU¿×ß¿þ Naa…k¿    IEND®B`‚
    ------------------------------23473c7acabb--
    

    使用改造适配器可以通过以下方式创建此请求:

    With retrofit adapter this request can be created in a next way:

    @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 作为 multipart param,默认情况下由 Converter 转换为 json.而您的服务器需要纯字符串.使用 curl,您发送的是 cURL,而不是 {"author":"cURL"}.

    The key difference here is that you used POJO Article article as multipart param, which by default is converted by Converter into json. And your server expects plain string instead. With curl you are sending cURL, not {"author":"cURL"}.

    这篇关于如何使用 Retrofit 发送多部分/表单数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆