使用 requests 发送带有 base64 编码附件的 HTTP PUT 请求

5
我正在使用 requests 进行 HTTP PUT 请求,但是由于某种原因它上传的是原始 ASCII 而不是事先进行 base64 编码的文件。
files = {'file': ('mydata.csv', open('mydata.csv', 'rb'))}  
...  
try:
    logging.info("Upload URL: " + insert_upload_url)
    headers = {'Content-type': 'multipart/form-data'}
    upload_res = requests.put(insert_upload_url, files=files,
                              data={'insertUpload': data}, headers=headers)
    logging.info("Status: " + str(upload_res.status_code))
    if upload_res.status_code != requests.codes.ok:
        logging.info("Reason: " + upload_res.reason)
    else:
        logging.info("Response: " + upload_res.text)
except Exception as e:
    logging.info("Error: " + e.message)

当我转储原始HTTP请求时,我发现数据没有被编码为application/octet-stream,也不是base64编码:
PUT /apibatchmember/services/rest/batchmemberservice/G9X7CsNn3HisxFdwAu4W76mBewUkQcKD_limGK1MDZ-eW3-olsn8HW0l5oePvEU_ZwHaPbEz2_c1YonjauDs7Jhk9DGvGNSTLMbgSSY9TGVuk00I_-tKPw8mjoXzC63YsFzBIYIeYXHKf34dYxmmhz4iSeDw/batchmember/insertUpload HTTP/1.1
Host: api.example.com
Content-Length: 5062
Content-type: multipart/form-data
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/1.2.3 CPython/2.7.5 Darwin/12.5.0

--5f934d42eabb4d7abe8bdef2cea94b6b
Content-Disposition: form-data; name="insertUpload"

<?xml version="1.0" encoding="UTF-8"?>
<insertUpload>
    <criteria>LOWER(EMAIL)</criteria>
    <fileName>email.csv</fileName>
    <separator>,</separator>
    <fileEncoding>UTF-8</fileEncoding>
    <skipFirstLine>false</skipFirstLine>
    <dateFormat>mm/dd/YYYY</dateFormat>
    <mapping>
        <column>
            <colNum>0</colNum>
            <fieldName>CUSTNUM</colNum>
        <column>
        <column>
            <colNum>1</colNum>
            <fieldName>FIRSTNAME</colNum>
        <column>
        <column>
            <colNum>2</colNum>
            <fieldName>LASTNAME</colNum>
        <column>
        <column>
            <colNum>3</colNum>
            <fieldName>EMAIL</colNum>
        <column>
    </mapping>
</insertUpload>
--5f934d42eabb4d7abe8bdef2cea94b6b
Content-Disposition: form-data; name="file"; filename="email.csv"
Content-Type: text/csv

\xef\xbb\xbf1045,Janice,Waddell,blah@example.com
1156,Scott,Sheldon,blah@example.com
1267,Adrianus,Lengkeek,blah@example.com
1295,EDWIN,ODIFE,blah@example.com
1345,Albert,Stephenson,blah@example.com
...

--5f934d42eabb4d7abe8bdef2cea94b6b--

我该如何将text/csv编码成base64的流呢?

谢谢!

更新

现在我使用以下代码可以得到正确的附件头了:

with open('/Users/mark.richman/email.csv', 'rb') as fd:
     b64data = base64.b64encode(fd.read())

files = {'file': ('email.csv', b64data, 'application/octet-stream')}

然而,我仍然不明白文件附件头中的Content-Transfer-Encoding: base64是什么意思。有任何想法吗?
更新2
我不得不这样修改标题:files = {'file': ('email.csv', b64data, 'application/octet-stream\r\nContent-Transfer-Encoding: base64')}
我在HTTP转储中看到了标题,但我仍然收到HTTP 415 Unsupported Media Type
更新3
看起来requests需要API更新以支持我在这里尝试的操作。多部分的第一部分(XML数据)需要设置Content-Type: text/xml,而API目前不支持此操作。讨论在此处

1
感谢您的第二次更新 - 解决了我的问题,因为它为我添加了标题,现在我的集成可以正常工作了。虽然不是最理想的,但已经能够正常运行了! - matt.chatterley
1个回答

3

您需要做的是

import base64


response = requests.put(url, data={'insertUpload': base64.b64encode(data)}, files=files, ...)

您没有定义 data,如果您试图使用文件对象,则无法正常工作。

如果data是字符串,则可以正常工作。


我最初误解了您的问题。

因此,如果您不想避免将整个文件加载到内存中(似乎是这样),您可以直接执行以下操作:

with open('mydata.csv', 'rb') as fd:
     b64data = base64.b64encode(fd.read())

files = {'file': ('mydata.csv', b64data, 'application/octet-stream')}
requests.put(...)  # everything here is the same as what you did

另一方面,如果您希望对数据进行编码而无需将其完全加载到内存中,则目前没有现成的方法。要正确地对整个内容进行base64编码,首先需要文件中的所有内容。例如,请考虑以下内容:

print(base64.b64encode('line\n'))
# => bGluZQo=
print(base64.b64encode('line\nline\n'))
# => bGluZQpsaW5lCg==

它们是相关的,但它们不能简单地进行连接。你可以尝试将问题范围缩小到仅使用类似文件的对象,这个对象可以在运行时对文本进行base64编码。

祝你好运!


我不需要对“data”进行编码,我需要对附加的csv文件进行编码。 - Mark Richman
1
啊,抱歉,我没有往下滚动你的请求内容。据我所知,无法在读取CSV文件时对其进行base64编码。您可以提前对其进行编码,然后使用上面使用的文件方法。不过,我会更新我的答案,提供更多可能性。 - Ian Stapleton Cordasco
那个方法可行,但我必须在文件字典中设置MIME类型。然而,我仍然没有在文件附件头中得到“Content-Transfer-Encoding: base64”。有任何想法吗? - Mark Richman
我们目前还不支持发送任意标头,但我们正在这里讨论它。 - Ian Stapleton Cordasco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接