我正在编写一个脚本来使用 RFC 2388 中定义的 multipart/form-data 内容类型上传包括文件在内的内容。 .从长远来看,我试图提供一个简单的 Python 脚本来执行 uploads of binary packages for github ,这涉及将类似表单的数据发送到 Amazon S3。
This question已经问过如何做到这一点,但到目前为止还没有一个可以接受的答案,the more useful目前有两个答案指向 these recipes依次手动构建整个消息。我有点担心这种方法,尤其是在字符集和二进制内容方面。
还有this question , 及其 currently highest-scoring answer建议 MultipartPostHandler模块。但这与我提到的食谱没有太大区别,因此我的担忧也适用于此。
RFC 2388 Section 4.3明确指出内容应为 7 位,除非另有声明,因此 Content-Transfer-Encoding header可能需要。这是否意味着我必须对二进制文件内容进行 Base64 编码?或者 Content-Transfer-Encoding: 8bit 是否足以用于任意文件?或者应该读作 Content-Transfer-Encoding: binary?
一般的标题字段,特别是 filename 标题字段,默认情况下仅为 ASCII。我希望我的方法也能够传递非 ASCII 文件名。我知道对于我当前为 github 上传内容的应用程序,我可能不需要它,因为文件名在单独的字段中给出。但我希望我的代码可以重用,所以我宁愿以一种一致的方式对文件名参数进行编码。 RFC 2388 Section 4.4建议在 RFC 2231 中引入的格式,例如filename*=utf-8''t%C3%A4st.txt.
由于 multipart/form-data 本质上是一种 MIME 类型,我认为应该可以使用 email package从标准 python 库来撰写我的帖子。特别是对非 ASCII header 字段的相当复杂的处理是我想委托(delegate)的事情。
所以我写了下面的代码:
#!/usr/bin/python3.2
import email.charset
import email.generator
import email.header
import email.mime.application
import email.mime.multipart
import email.mime.text
import io
import sys
class FormData(email.mime.multipart.MIMEMultipart):
def __init__(self):
email.mime.multipart.MIMEMultipart.__init__(self, 'form-data')
def setText(self, name, value):
part = email.mime.text.MIMEText(value, _charset='utf-8')
part.add_header('Content-Disposition', 'form-data', name=name)
self.attach(part)
return part
def setFile(self, name, value, filename, mimetype=None):
part = email.mime.application.MIMEApplication(value)
part.add_header('Content-Disposition', 'form-data',
name=name, filename=filename)
if mimetype is not None:
part.set_type(mimetype)
self.attach(part)
return part
def http_body(self):
b = io.BytesIO()
gen = email.generator.BytesGenerator(b, False, 0)
gen.flatten(self, False, '\r\n')
b.write(b'\r\n')
b = b.getvalue()
pos = b.find(b'\r\n\r\n')
assert pos >= 0
return b[pos + 4:]
fd = FormData()
fd.setText('foo', 'bar')
fd.setText('täst', 'Täst')
fd.setFile('file', b'abcdef'*50, 'Täst.txt')
sys.stdout.buffer.write(fd.http_body())
结果是这样的:
--===============6469538197104697019==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: form-data; name="foo"
YmFy
--===============6469538197104697019==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: form-data; name*=utf-8''t%C3%A4st
VMOkc3Q=
--===============6469538197104697019==
Content-Type: application/octet-stream
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: form-data; name="file"; filename*=utf-8''T%C3%A4st.txt
YWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJj
ZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVm
YWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJj
ZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVm
YWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJjZGVmYWJj
ZGVmYWJjZGVmYWJjZGVm
--===============6469538197104697019==--
它似乎确实可以很好地处理 header 。二进制文件内容将得到 base64 编码,这可能是可以避免的,但应该工作得很好。让我担心的是中间的文本字段。它们也是 base64 编码的。我认为根据标准,这应该工作得很好,但我宁愿在那里有纯文本,以防某些愚蠢的框架必须在中间级别处理数据并且不知道 Base64 编码数据。
Content-Transfer-Encoding 写成 8bit 还是 binary?email.header package单独格式化 header 值?email.utils.encode_rfc2231 这样做。)这些问题密切相关,可以概括为“您将如何实现”。在许多情况下,回答一个问题要么回答另一个问题,要么使另一个问题过时。因此,我希望您同意将所有这些都发布在一个帖子中是合适的。
最佳答案
这是一个占位符答案,描述了我在等待对我的一些问题的权威输入时所做的事情。如果证明这种方法在至少一个设计决策中是错误的或不合适的,我将很乐意接受不同的答案。
Here是我现在根据自己的喜好来完成这项工作的代码。 我做出了以下决定:
Can I use 8 bit data for my text fields and still conform to the specification?
我决定这样做。至少对于这个应用程序,它确实有效。
Can I get the email package to serialize my text fields as 8 bit data without extra encoding?
我找不到办法,所以我正在做我自己的序列化,就像所有 other recipes我看到了。
Can I avoid base64 encoding for binary file content as well?
简单地以二进制形式发送文件内容似乎效果很好,至少在我的单个应用程序中是这样。
If I can avoid it, should I write the Content-Transfer-Encoding as 8bit or as binary?
作为RFC 2045 Section 2.8指出,8bit 数据受 CRLF 对之间 998 个八位字节的行长度限制,我认为 binary 更通用,因此这里的描述更合适。
If I had to serialize the body myself, how could I use the email.header package on its own to just format header values?
正如我的问题中已经编辑的那样,email.utils.encode_rfc2231对此非常有用。我首先尝试使用 ascii 编码,但在双引号字符串中禁止使用非 ascii 数据或 ascii 字符的情况下使用该方法。
Is there some implementation that already did all I'm trying to do?
据我所知不是。邀请其他实现采用来自 my code 的想法, 不过。
编辑:
感谢this comment我现在知道对 header 使用 RFC 2231 并未得到普遍接受:HTML 5 的当前草案 forbids its use .也有人看过cause problems in the wild .但是由于 POST header 并不总是对应于特定的 HTML 文档(例如考虑 Web API),我不确定在这方面我是否会信任该草案。也许正确的做法是同时提供编码和未编码的名称,即 RFC 5987 Section 4.2建议。但该 RFC 用于 HTTP header ,而 multipart/form-data header 在技术上是 HTTP 主体。因此,该 RFC 不适用,而且我不知道有任何 RFC 会明确允许(甚至鼓励)对 multipart/form-data 同时使用这两种形式。
关于python - 正确格式化多部分/表单数据主体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13514713/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build
question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参
我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西: