如何使用Python请求库和unicode文件名进行多部分上载?

如何使用Python请求库和unicode文件名进行多部分上载?,python,unicode,utf-8,python-requests,Python,Unicode,Utf 8,Python Requests,我正在尝试使用其RESTAPI将文件上载到JIRA。上传是作为多部分文章完成的。只要文件名是ASCII,代码就可以正常工作。如果它们包含任何非ASCII字符,JIRA将给出500错误 我试图通过在POST操作中对文件名进行编码来纠正这一点,文件上载成功,但JIRA显示了编码文件名的ASCII版本,而不是将文件名解码为原始UTF-8 下面是一段Python代码: files = {'file': (urllib2.quote(zd_attachment['file_name'].encode('u

我正在尝试使用其RESTAPI将文件上载到JIRA。上传是作为多部分文章完成的。只要文件名是ASCII,代码就可以正常工作。如果它们包含任何非ASCII字符,JIRA将给出500错误

我试图通过在POST操作中对文件名进行编码来纠正这一点,文件上载成功,但JIRA显示了编码文件名的ASCII版本,而不是将文件名解码为原始UTF-8

下面是一段Python代码:

files = {'file': (urllib2.quote(zd_attachment['file_name'].encode('utf8')), open('/tmp/%s' % zd_attachment['file_name'], 'rb'), zd_attachment['content_type'])}
mp_header = {'X-Atlassian-Token': 'nocheck'}
r = requests.post("%s/rest/api/2/issue/%s/attachments" % (jira_url, issue_id), headers=mp_header, files=files, auth=jira_auth)
我是否使用了错误的方法对文件名进行编码?为了正确处理Unicode文件名,我是否遗漏了其他内容

我是否使用了错误的方法对文件名进行编码

坏消息是,实际上没有任何广泛接受的方法将非ASCII和其他麻烦字符(如引号)编码到文件名中。
内容配置;文件名
参数在网络上是一个非常不可靠的东西

请求
/
urllib3
努力做好自己。如果文件名包含非ASCII字符,它将尝试使用RFC 2231为MIME提出的疯狂的
filename*=
头参数方案(源代码:
urlib3.fields.format\u header\u param
)对其进行编码

对于HTTP文件下载响应(per)中的
内容处置
头,这实际上是正确的做法,一些浏览器现在甚至支持这一点,但表单提交不在本节中

服务器端没有任何东西支持这种形式的编码,因此我怀疑JIRA可能看到一个文件上载字段没有
文件名
(因为它只有
文件名*
),并将其玩具扔出婴儿车

HTML5已经接管了
多重/表单数据
媒体类型的定义,现在不再支持这种编码方案:

用户代理不得使用RFC 2388建议的RFC 2231编码

相反:

生成的多部分/表单数据资源中包含的文件名(作为文件字段的一部分)必须使用上面选择的字符编码

因此,您应该为文件名传递一个Unicode字符串,
urllib3
应该将其编码为表单其余部分使用的相同编码(例如UTF-8)。您不能这样做是一个应该针对
urllib3
报告的bug。目前,您可能不得不满足于仅使用ASCII文件名

旁白:不幸的是,我们离拯救还很远。除了传统浏览器及其任意编码之外,HTML5还通过允许浏览器应用额外的任意不可恢复的损坏来保持生活的美好和混乱:

如有必要,精确名称可以近似(例如,可以从文件名中删除换行符,将引号更改为“%22”,并且可以用其他字符替换选定字符编码中无法表达的字符)


Urllib3对非ASCII文件名(,)使用了错误的编码方法。解决方法是在发送请求之前创建自己的请求或实现请求并更改请求体。关于这一点,我有一些例子。

这个问题现在应该得到解决。从v1.25.3开始,urllib3使用HTML5编码非ASCII文件名()

我最近尝试过使用requests库通过restapi将附件上传到Jira,文件名不再有问题

可以通过这种方式指定请求的
文件
参数(确保不对文件名进行URL编码):


我想您不需要使用
urllib2.quote()
。当然,
请求
将使用所需的任何编码,并且您不需要在多部分mime头中使用URL编码。您是否尝试过
(zd_附件['file_name'].encode('utf8')、open('/tmp/%s'%zd_附件['file_name']、'rb')、zd_附件['content_type'])
,我对Jira正确处理文件名没有多大信心。Jira似乎确实正确地支持内容处置头,因为如果我更改文件代码,将文件名硬连接到“fred.png”,这就是Jira使用的文件名。我比较了代码上传的网络流量与浏览器上传的网络流量。编码略有不同(例如空格是+而不是%20),但我现在问Atlassian这是否是JIRA问题。是的,它支持
filename=
参数。它(或它使用的任何
multipart/form data
解析库)不支持
filename*=
参数(星号,因为RFC 2231参数编码)。如果将非ASCII文件名输入到
请求中
,则会得到一个RFC 2231编码的参数,而HTML5 sez则不应该出现这种情况。所以这是
urllib3
的错误,而不是JIRA的错误<代码>+
%20
不要进入其中,URL编码不用于文件名参数。离题:我有两个关于你博客的快速问题。1.删除了吗?2.您是否计划在近期内切换到HTTPS?你的文章很棒,顺便说一句,谢谢!我更新了日期。我不知道这破坏了任何现有的链接。我确实想提供HTTPS,但我必须确定要使用哪个托管/CDN解决方案。我明白了。URL更改是不幸的。我希望你能找到一个在文章更新时不会导致404的解决方案
files = {'file': (zd_attachment['file_name'], open('/tmp/%s' % zd_attachment['file_name'], 'rb'), zd_attachment['content_type'])}