【问题标题】:PUT request for image upload not working in django restPUT 图像上传请求在 django rest 中不起作用
【发布时间】:2015-11-08 03:01:55
【问题描述】:

我正在尝试在 django rest 中使用 multipart/form-dataPUT 请求和 Pillow 中上传图像:

class ABC(APIView):
    parser_classes = (MultiPartParser,)
    def put(self, request):
        a = Image()
        a.image_url = request.data["image"]
        a.save()

class Image(models.Model):
      image_url = models.ImageField(upload_to='static/bills', blank=True)

我提出了一个 PUT 请求和一个多部分/表单数据的请求。我最终得到 400 的响应代码和消息:

{
  "detail": "Multipart form parse error - Invalid boundary in multipart: None"
}

不知何故,这刚刚坏了。当我第一次写它时,它工作得很好。从那时起,我为 CORS 请求添加了一些设置配置,例如:

CORS_ORIGIN_ALLOW_ALL = True

CORS_ALLOW_HEADERS = (
    'x-requested-with',
    'content-type',
    'accept',
    'origin',
    'authorization',
    'x-csrftoken',
    'token',
    'x-device-id',
    'x-device-type',
    'x-push-id',
    'dataserviceversion',
    'maxdataserviceversion'
)
CORS_ALLOW_METHODS = (
        'GET',
        'POST',
        'PUT',
        'PATCH',
        'DELETE',
        'OPTIONS'
    )

有什么想法吗?

OPTIONS 请求响应:

Access-Control-Allow-Headers → x-requested-with, content-type, accept, origin, authorization, x-csrftoken, token, x-device-id, x-device-type, x-push-id, dataserviceversion, maxdataserviceversion
    Access-Control-Allow-Methods → GET, POST, PUT, PATCH, DELETE, OPTIONS
    Access-Control-Allow-Origin → *
    Access-Control-Max-Age → 86400
    Allow → GET, POST, DELETE, HEAD, OPTIONS
    Content-Type → application/json
    Date → Fri, 21 Aug 2015 06:23:28 GMT
    Server → WSGIServer/0.1 Python/2.7.6
    Vary → Accept
    X-Frame-Options → SAMEORIGIN

【问题讨论】:

  • 你能把浏览器请求添加到嗅探器中吗?
  • 没有嗅探器。我正在使用邮递员提出此请求。
  • 你能发送OPTIONS 请求到同一个 URL 并检查响应是什么吗?对于一个有效的 CORS 服务,响应应该是一个空的 200 OK 响应,带有 Access-Control-Allow-Methods, Access-Control-Allow-Origin 等标头。
  • 所以来自邮递员的请求标头+表单数据
  • 在找了很多解决方案后,我发现从请求中删除content-type 标头可以解决这个问题。

标签: python django rest pillow


【解决方案1】:

您通常希望同时使用 FormParser 和 MultiPartParser 以完全支持 HTML 表单数据。

【讨论】:

    【解决方案2】:

    您的错误是告诉您请求的multipart/form-data 内容的边界无效 - 特别是None。根据设计,这会返回一个400(“错误请求”)响应代码。引发错误here in the django code

    使用boundary 等于None 进入该代码分支意味着您的请求的content-type 标头中未指定boundary 选项。

    content-type 中使用multipart/form-data 时必须指定boundary,如RFC2046 中指定(由RFC2388 引用) - 特别是第5.1.1 节

    多部分实体的 Content-Type 字段需要一个参数, “边界”。

    您说它以前有效,因此您应该检查用于发出请求的代码 - 一定有一些地方发生了变化,这意味着 boundary 未在 content-type 中指定。

    NB 我认为请求是代码生成的,如<form method="put"> is invalid HTML,因此由浏览器生成的请求假定 HTML 将是 GET 而不是PUT

    【讨论】:

    • 你能分享一下我应该用于这种请求的 curl 请求吗?我对它不太熟悉,对 api 的怀疑只是让我对 curl 请求感到困惑。
    • curl -v -XPUT -H "Content-Type: multipart/form-data; boundary=----------------------------4ebf00fbcf09" --data-binary @test.jpg http://<your_test_url> 之类的东西应该可以工作,boundary= 后面的字符串是任意的,但不应该出现在后面的数据中。我假设您的图像数据位于名为 "test.jpg" 的文件中,但您同样可以将原始数据放在那里。
    • 我不熟悉邮递员,因此无法真正评论如何通过该工具生成请求。如果上述curl 有效,我可以将其复制到答案中以使其完整。
    • 嗯 - 不确定 CURL 命令是否真的有效。 man page 似乎表明 1) 你应该使用 -F 而不是 --data-binary 来获取内容类型 multipart/form-data 2) 这些将被编译成 POST 请求。我不确定-X PUT 是否会覆盖它,但我怀疑不会(现在还没有一个可以轻松测试的环境)。使用 PUT 而不是 POST 似乎有点不寻常 - 你这样做有什么原因吗?
    • 嗨@VarunJain 想知道你是否有这个工作/这个答案是否对你有帮助。我不希望你的赏金白白浪费——如果你还在苦苦挣扎,也许我可以帮你调试更多...... :)
    【解决方案3】:

    从标头中删除内容类型可以解决此问题。

    【讨论】:

    • 如果您使用的是 POSTMAN,有一个部分可以查看不同语言的请求代码。这是一个线索。
    • 也为我工作!谢谢,但有一个问题:你知道它为什么起作用吗?
    • 刚刚发生在我身上。如果您为正文选择“表单数据”,邮递员将自动添加带有边界的 Content-Type 标头。但是如果你指定自己的无边界 Content-Type 标头,那么 Postman 不会覆盖你给它的标头,或者可能标头加倍,服务器只读取遇到的第一个 Content-Type 标头。
    • 如何从标题中删除内容类型?
    • 天哪,你救了我!谢谢
    猜你喜欢
    • 2018-12-28
    • 2012-03-20
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 2017-10-30
    相关资源
    最近更新 更多