参数标识为字符串而不是文件

param identified as a string rather than a file

在我的视图文件 submit.html.erb 中,我决定直接使用 <form> 标签,而不是 rails 中包含的表单助手。这是视图文件:

<form action = "/winter" method="post">
<input type="file" name="doc">
<p> Upload your question. </p>
<input type = "submit">
 <input name="authenticity_token" type="hidden" 
      value="....">
</form>

提交此表单会在 /winters 上使用参数

调用 post 请求
{"doc"=>"1.docx", "authenticity_token"=>"...."}

虽然我希望 doc 参数是我上传的文件 1.docx,但 doc 参数仍然是文件 1.docx 的字符串 original_filename ].

我的 routes.rb 文件有代码

post "/winter" => "paper#submit"

而在 paper_controller 的提交方法中是代码:

File.write("Papers/rain.docx", params[:doc].read)
redirect_to "/paper"

相应地,当我提交上述表格时,我进入 /winters url 并得到错误

undefined method 'read' for "1.docx":String

那么为什么 doc 参数设置为文件名而不是文件本身呢?这与文档相反,我想:[http://guides.rubyonrails.org/form_helpers.html#what-gets-uploaded]

还有一点,可能与此相关,是在文档的第一段中说:

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.

那么,是不是说 params[:doc] 有时可能是一个文件实例,有时可能是一个字符串?如何处理这种随机行为?

还有一件事,如果我尝试 get 请求而不是 put 请求会怎么样? get 必须将参数放在 url 之后作为查询字符串,对吗?那么 params[:doc] 应该总是一个字符串吗?我尝试使用 get,并被发送到 url

http://localhost:3000/winter?doc=1.docx

(当时我没有使用 authenticity token 参数的隐藏输入)。 当然,同样

undefined method 'read' for "1.docx":String

发生错误。

您必须使用 multipart/formdata encoding 才能进行文件传输。对于任何 Web 框架都是如此。

我建议您只使用表单助手,因为它会添加正确的真实性标记:

<%= form_tag("/winter", multipart: true) do %>
  <%= file_field_tag 'doc' %>
  # ...
<% end %>

And, one more thing, what if I tried get request instead of put request? get has to put the params right after the url, as a query string, right? So should then params[:doc] be always a string? I tried using get, and was sent to the url

您不能在 GET 请求中上传文件。它们必须包含在使用 multipart/formdata 编码的 POST/PATCH/PUT 请求的请求正文中。

文件是二进制的 - 用于在 GET 请求中传递数据的查询字符串只是一个包含表单数据 key/value 对的字符串。因此,要在 GET 请求中传递文件,您需要对其进行 base64 编码,这会使文件大小增加约 30%。许多浏览器也像某些 Web 服务器一样限制 URI 的长度以防止 DOS 攻击,这使它成为一个非常糟糕的主意。