【问题标题】:unable to add image binary into multipart/form-data无法将图像二进制文件添加到 multipart/form-data
【发布时间】:2018-06-23 16:05:59
【问题描述】:

我收到一个错误:预期的 str 实例,当我尝试将图像二进制文件添加到 multipart/form-data 时发现字节。

问题是我试图将二进制格式的 imageData 附加到字符串中。有没有办法将二进制图像添加到多部分/表单数据?

我束手无策,希望能得到一些帮助。

imageData = request.FILES['filePath'].read()


content_type, request_body = encode_multipart_formdata([('include_target_data', targetMetaDataRet),
                                                     ('max_num_results', str(maxNoResultRet))],
                                                     [('image', imagePath, imageData)])

def encode_multipart_formdata(fields, files):

    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
    CRLF = '\r\n'
    lines = []
    for (key, value) in fields:
        lines.append('--' + BOUNDARY)
        lines.append('Content-Disposition: form-data; name="%s"' % key)
        lines.append('')
        lines.append(value)
    for (key, filename, value) in files:
        lines.append('--' + BOUNDARY)
        lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        lines.append('Content-Type: %s' % get_content_type(filename))
        lines.append('')
        lines.append(value)
    lines.append('--' + BOUNDARY + '--')
    lines.append('')
    body = CRLF.join(lines)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body

追溯:

  35.            response = get_response(request)

  128.           response = self.process_exception_by_middleware(e, request)

  126.           response = wrapped_callback(request, *callback_args, **callback_kwargs)

  166.           [('image', imagePath, imageData)])

  232.           body = CRLF.join(lines)

Exception Type: TypeError at /identify_shrine
Exception Value: sequence item 12: expected str instance, bytes found

根据@coltoneakins 请求,我将请求正文修改为字节,但我似乎收到了错误的请求错误,知道为什么吗?

代码:

content_type = 'multipart/form-data; boundary=----------ThIs_Is_tHe_bouNdaRY_$'
request_body = '----------ThIs_Is_tHe_bouNdaRY_$' +  '\n'+'Content-Disposition: form-data; name="include_target_data"' + '\n' + '\n' + 'top'+ '\n' + '----------ThIs_Is_tHe_bouNdaRY_$' +'\n' + 'Content-Disposition: form-data; name="max_num_results"' + '\n' + '\n' + '1' + '\n' + '----------ThIs_Is_tHe_bouNdaRY_$' +'\n' + 'Content-Disposition: form-data; name="image"; filename="img_2.jpg"' + '\n' + 'Content-Type: image/jpeg' + '\n' + '\n'
request_body1 = request_body.encode('utf-8')
request_body2 = imageData
request_body3 = ('\n' + '\n' + '----------ThIs_Is_tHe_bouNdaRY_$').encode('utf-8')
request_body4 = request_body1 + request_body2 + request_body3

content_type_bare = 'multipart/form-data'

# Sign the request and get the Authorization header
# use client key
auth_header = authorization_header_for_request(CLIENT_ACCESS_KEY, CLIENT_SECRET_KEY, HTTP_METHOD, request_body4,
                                               content_type_bare,
                                               date, path)

request_headers = {
    'Accept': 'application/json',
    'Authorization': auth_header,
    'Content-Type': content_type,
    'Date': date
}
try:
    # Make the request over HTTPS on port 443
    connection = http.client.HTTPSConnection(CLOUD_RECO_API_ENDPOINT, 443)
    connection.request(HTTP_METHOD, path, request_body4, request_headers)

    response = connection.getresponse()
    response_body = response.read()
    reason = response.reason
    status = response.status

finally:
    connection.close()

【问题讨论】:

  • 你能发布错误回溯(带有违规行)吗?
  • @SamuelDion-Girardeau 感谢您的回复,添加了回溯 :-)
  • 注意:你可以通过使用 requests 库来完成这项任务,这将使你的生活变得更加轻松,它将为你进行多部分编码。否则,您可以使用 email.mime 包(标准库的一部分)来编码 multipart/formdata 输出。

标签: python python-3.x multipartform-data


【解决方案1】:

您的代码中存在类型问题。你得到一个 TypeError expected str instance, bytes found 因为你试图 join() 一个包含 str 类型和 类型的列表Python 中的>bytes 类型。

查看代码中的这些行:

    for (key, filename, value) in files:
    lines.append('--' + BOUNDARY)
    lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
    lines.append('Content-Type: %s' % get_content_type(filename))
    lines.append('')
    lines.append(value) # <---------- THIS IS BYTES, EVERYTHING ELSE IS STR
lines.append('--' + BOUNDARY + '--')
lines.append('')
body = CRLF.join(lines) # <---------- AHHH RED FLAG!!!

CRLFstr 类型。但是,value(添加到您的 lines 列表中)是 bytes。这意味着您最终会得到包含 strbytes 类型的 lines。当您通过 mulitpart/form-data 请求发送图像时,请求的整个主体都是字节。因此,您只需要对 bytes 类型使用 join()。

这就是你正在做的:

body = CRLF.join(lines)

这是真的:

'\r\n, i am a str'.join(['i am also str', b'I am not a str, I am bytes']) # <-- NO

这是你需要做的:

b'I am bytes'.join([b'I am also bytes', b'Me too!'])

此外,请注意,Requests 库为您提供了发送文件的机制。请参阅files parameter in the Requests documentation 或此 StackOverflow 答案:

https://stackoverflow.com/a/12385661/9347694

因此,您可能不需要在这里重新发明轮子。请求将对文件进行多部分编码并为您构造请求。

【讨论】:

  • 如果我将整个请求正文转换为字节,请求标头和接受、授权、日期是否也需要以字节为单位?
  • 您好,我对代码进行了更改,需要您的帮助,谢谢!
  • 好问题。最简洁的答案是不。例如,Requests 库不这样做。此外,如果您在 Firefox 等网络浏览器中使用“网络”面板,您可以看到当您上传文件到喜欢图像共享站点时请求是如何形成的。处理它们时,标头不是二进制数据。但是,身体是。如果您想详细了解其工作原理,请阅读 UTF-8 字符编码和二进制。
  • 嗨,我愚蠢地创建了请求标头字节,我对文本进行了更改,但我仍然收到错误的请求错误,知道吗?
  • 见:w3.org/Protocols/rfc1341/7_2_Multipart.html。另外,我不认为你用 CRLF 结束你的行——'\n' 与 '\r\n' 不同。为了更好地解决问题,我们应该查看您的代码正在形成的请求正文。然后,将其与多部分/表单请求正文的正确格式进行比较。另见:stackoverflow.com/a/19712083/9347694
猜你喜欢
  • 2018-07-11
  • 1970-01-01
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 2019-09-01
  • 2019-01-06
  • 1970-01-01
  • 2019-07-05
相关资源
最近更新 更多