Rails文件上传file_field报错Encoding::UndefinedConversionError

简介:

服务器用的是ubuntu12 64bit,环境是ruby1.9.3+rails3+mysql,测试是在windows2003上。


上传一个【.gitconfig】文件,没有问题,上传【新浪微博数据挖掘.pdf】报错,上传【back.jpg】报错。
下面是两段信息,是从【log/production.log】中粘贴出来的。上面一段你是没有问题的日志,下面一段是报错之后的日志。

 

 
  1. Started POST "/posts" for 106.3.102.43 at 2012-10-29 21:16:26 +0800 
  2. Processing by PostsController#create as HTML 
  3.   Parameters: {"utf8"=>"", "authenticity_token"=>"QG8aU6/VW5ZMagzyGhjdbm7fSzr4MB5CKdJeGBIeOa4=", "post"=>{"category_id"=>"1", "title"=>"666666666666", "url"=>"6666666", "picture"=>#<ActionDispatch::Http::UploadedFile:0x000000032fb838 @original_filename=".gitconfig", @content_type="application/octet-stream", @headers="Content-Disposition: form-data; name=\"post[picture]\"; filename=\".gitconfig\"\r\nContent-Type: application/octet-stream\r\n", @tempfile=#<File:/tmp/RackMultipart20121029-2609-1lrmc9o>>, "content"=>"6666", "tags_attributes"=>{"0"=>{"title"=>""}}}, "commit"=>"Create Post"} 
  4. Redirected to http://42.121.5.68/posts 
  5. Completed 302 Found in 36ms (ActiveRecord: 30.1ms) 




 

 
  1. Started POST "/posts" for 123.114.36.100 at 2012-10-30 08:58:13 +0800 
  2. Processing by PostsController#create as HTML 
  3.   Parameters: {"utf8"=>"", "authenticity_token"=>"rRnhcDWYDn+OntxxC2LmIEHpSpjWI5glrs6JlprG1Ho=", "post"=>{"category_id"=>"1", "title"=>"博客尝试最新法宝", "url"=>"post7", "picture"=>#<ActionDispatch::Http::UploadedFile:0x000000030df9a0 @original_filename="新浪微博数据挖掘方案.pdf", @content_type="binary/octet-stream", @headers="Content-Disposition: form-data; name=\"post[picture]\"; filename=\"\xE6\x96\xB0\xE6\xB5\xAA\xE5\xBE\xAE\xE5\x8D\x9A\xE6\x95\xB0\xE6\x8D\xAE\xE6\x8C\x96\xE6\x8E\x98\xE6\x96\xB9\xE6\xA1\x88.pdf\"\r\nContent-Type: binary/octet-stream\r\n", @tempfile=#<File:/tmp/RackMultipart20121030-16129-15agvlb>>, "content"=>"博客尝>试最新法宝", "tags_attributes"=>{"0"=>{"title"=>"博客尝试最新法宝"}}}, "commit"=>"Create Post"} 
  4. Completed 500 Internal Server Error in 45ms 
  5.  
  6. Encoding::UndefinedConversionError ("\xE2" from ASCII-8BIT to UTF-8): 
  7.   app/controllers/posts_controller.rb:60:in `write' 
  8.   app/controllers/posts_controller.rb:60:in `block (2 levels) in create' 
  9.   app/controllers/posts_controller.rb:59:in `open' 
  10.   app/controllers/posts_controller.rb:59:in `block in create' 
  11.   app/controllers/posts_controller.rb:56:in `create' 



比较之后,发现两段的picture部分的@content_type不一样,成功的是@content_type="application/octet-stream",失败的是@content_type="binary/octet-stream"。

尝试上传一个txt文件,成功了,@content_type部分是@content_type="text/plain"。

确定是这个部分的原因,也就是编码,所以报错编码错误,未定义编码转换。

上传部分的代码如下

 

 
  1. uploaded_io = params[:post][:picture] 
  2.         if uploaded_io != nil and uploaded_io.content_type.match('image') 
  3.  
  4.           File.open(Rails.root.join('public','uploads',uploaded_io.original_filename),'w') do |f| 
  5.  
  6.             f.write(uploaded_io.read) 
  7.           end 
  8.  
  9.         else 
  10. end 

经过一番查找,找到了深层的原因,原来是二进制文件的缘故,ruby在读取和保存的时候会自动处理二进制文件,不需要特殊的方式。

可是在windows中,二进制和文本文件是不同的,在二进制mode下,结束行不能被转义为一个单独的换行,而是被保存为一个回车和一个换行。所以如果读取的是二进制文件,需要在open的时候要指明读取的是二进制文件wb。b就是二进制的意思。

图片默认按照二进制文件处理,所以就中招了。其实也只需要把w改成wb就可以了。

 

下面就没有这个问题了。

 
  1. uploaded_io = params[:post][:picture] 
  2.         if uploaded_io != nil and uploaded_io.content_type.match('image') 
  3.  
  4.           File.open(Rails.root.join('public','uploads',uploaded_io.original_filename),'wb') do |f| 
  5.  
  6.             f.write(uploaded_io.read) 
  7.           end 
  8.  
  9.         else 
  10. end

 

 

 
  1. <div class="field"> 
  2.   <%= f.label :picture %><br/> 
  3.   <%= f.file_field :picture %> 
  4. </div> 



从安全角度来讲,文件上传要严格控制路径,权限,以及上传的类型。
 

  • 路径,就是文件在服务器的保存路径,最好是单独路径,不要放在根目录,规划好文件夹,还要做好重命名,因为上传的人不知道服务器上面是不是存在同名的文件,这就涉及文件实际的名称和用户需要看到的文件名的映射。

 

  • 权限,就是上传路径给用户的权限,最好不要有执行权限,只有读写权限就可以了。有必要的话,需要划分用户文件夹来区分权限。保留一个公共文件夹。等等,根据情况而定。

 

  • 上传的类型,上传文件肯定和一个场景相关,一个场景可能只需要一类文件,比如文档场景,图片场景。最好在不同的场景控制不同的文件类型。执行文件要严格控制。


 




本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/1042740,如需转载请自行联系原作者

目录
相关文章
|
7月前
|
Web App开发 前端开发 JavaScript
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
384 0
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
|
3月前
|
XML 数据格式 Python
python 解析xml遇到xml.etree.ElementTree.ParseError: not well-formed (invalid token): |4-8
python 解析xml遇到xml.etree.ElementTree.ParseError: not well-formed (invalid token): |4-8
|
7月前
|
Java Spring
DWR上传文件提示File uploads not supported
确保你的DWR配置和代码都正确地支持文件上传,以解决"DWR上传文件提示File uploads not supported" 错误。
40 0
|
XML 数据安全/隐私保护 数据格式
Minio出现Non-XML response from server. Response code: 400, Content-Type: text/xml; ch的解决
Minio出现Non-XML response from server. Response code: 400, Content-Type: text/xml; ch的解决
3721 0
|
Web App开发 XML 算法
file_put_contents利用技巧(php://filter协议)
file_put_contents利用技巧(php://filter协议)
379 0
|
缓存 前端开发 NoSQL
Laravel项目部署后,出现 file_put_contents ()
问题: 部署博客,服务器经常500 排查:查看laravel日志: file_put_contents () ,failed to open stream: No such file or directory;
431 0
Laravel项目部署后,出现 file_put_contents ()
PHPExcel在高版本PHP7中,Writer-&gt;save出现ERR_INVALID_RESPONSE错误的解决方法
PHPExcel在高版本PHP7中,Writer-&gt;save出现ERR_INVALID_RESPONSE错误的解决方法
263 0
|
缓存 Java 应用服务中间件
SpringBoot文件上传异常之提示The temporary upload location xxx is not valid
SpringBoot搭建的应用,一直工作得好好的,突然发现上传文件失败,提示org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.6239989728636105816.19530/work/Tomcat/localhost/ROOT] is not valid目录非法
779 0
SpringBoot文件上传异常之提示The temporary upload location xxx is not valid
|
JSON PHP 数据格式
PHP curl报错"Problem (2) in the Chunked-Encoded data"解决方案
PHP curl报错"Problem (2) in the Chunked-Encoded data"解决方案
311 0
|
JavaScript
解决ecshop出现Warning: file_put_contents
解决ecshop出现Warning: file_put_contents
274 0