乐者为王

Do one thing, and do it well.

打错multipart引发的血案

浪费几个小时,杀死无数脑细胞,最终发现是单词打错了。不过错有错招,这个问题也让我重新温习了一遍关于form数据编码的知识。

在做上传表单时,一直报告如下错误:

1
undefined method 'original_filename' for "example.csv":String

http://guides.rubyonrails.org/form_helpers.html#what-gets-uploaded 有这样一段文字:

The object in the params hash is an instance of a subclass of IO. Depending on the size of the uploaded file it may in fact be a StringIO or an instance of File backed by a temporary file. In both cases the object will have an original_filename attribute containing the name the file had on the user's computer and a content_type attribute containing the MIME type of the uploaded file.

说明example.csv应该是IO类型的,这里怎么显示是String呢?

表单代码为

1
<%= form_tag import_stocks_path, mutlipart: true do %>

1
<%= form_tag import_stocks_path, method: :post, mutlipart: true do %>

生成后的HTML代码都是:

1
<form action="/stocks/import" method="post" mutlipart="true">

正确的HTML代码应该是:

1
<form action="/stocks/import" method="post" enctype="multipart/form-data">

使用HttpFox工具抓取表单提交信息如下:

1
2
3
4
5
6
POST /stocks/import HTTP/1.1
Host localhost:3000
Referer http://localhost:3000/stocks/import
Connection keep-alive
Content-Type application/x-www-form-urlencoded
Content-Length 112

什么是application/x-www-form-urlencoded?含有file类型字段的表单编码不应该是multipart/form-data吗。

form的enctype属性通常有两种:application/x-www-form-urlencoded和multipart/form-data,默认为前者。当method=get时,浏览器用application/x-www-form-urlencoded编码方式把form数据转换成一个字串(name1=value1&name2=value2...),然后把这个字串附加到url后面,用?分割。当method=post的时候,浏览器把form数据封装到post-body中。如果没有type=file的控件,就用默认的application/x-www-form-urlencoded编码。但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name等信息,并加上分割边界(boundary)。

这时才发现原来是把multipart打错成mutlipart了,真是惨痛的教训啊!

Comments