Ruby 用户输入特殊字符保存到数据库后提示 invalid byte sequence in UTF-8

Ddl1st · 2015年08月19日 · 最后由 tonykeng 回复于 2015年08月28日 · 2948 次阅读

ruby 2.2.1 rails 4.2.1.rc4 mysql 5.5

用户在输入特殊字符保存到数据库之后,通过页面访问报错 invalid byte sequence in UTF-8

通过日志可以看到,用户输入的特殊字符被转码了 \xED\xA0\xBD, 而且值也存到数据库了。但是在显示出来的时候就报错. User-Agent "Mozilla/5.0 (Linux; U; Android 4.1.2; zh-cn; Coolpad 5891Q Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"

正好前几天也遇到了,重现过程大概这样:

irb(main):043:0> city  = "Montréal"
=> "Montréal"
irb(main):045:0> city.encode! 'iso8859-1'
=> "Montr\xE9al"
irb(main):047:0> puts city
Montral
=> nil
irb(main):048:0> city.force_encoding 'utf-8'
=> "Montr\xE9al"
irb(main):049:0> city.valid_encoding?
=> false

其实就是对方给你了一个非 utf-8 字符,你把它当成了 utf-8 处理,不兼容的时候当然报错了。

另,对于 invalid 字符,会被 Rails(具体哪部分记不得了) 转成\xED\xA0\xBD

@hooopo 我看到有的方案是用middleware来解决,不知道有什么好的解决方案没

应该不需要 middleware,可能只是配置的问题,比如 config/database.yml 里面的encoding,mysql 里表的编码等。如果从浏览器到数据库的编码都是utf-8,任何地方都不需要转码。

#3 楼 @yanhao 问题是在存到数据库之前就已经被转码了,数据库是utf8mb4的。

#3 楼 @yanhao 你的意思是数据库可以自动进行字符转码吗?

#5 楼 @Ddl1st 数据库不做转码,给它什么它就保存什么。先检查一下表单 POST 的字符串是不是 utf-8 吧。一般表单的源码是这样的:

<form class="..." id="..." action="..." accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="&#x2713;" />
... ...

#6 楼 @yanhao API 服务... 网站是没问题的。

当我把浏览器的编码改成iso8859-1 或者其他的时候,日志中的参数才会显示是经过转码的值

#6 楼 @yanhao 最终应该通过服务端来处理吧,不能因为用户输入的内容编码不正确而导致程序出现这种错误?

#9 楼 @Ddl1st 我觉得应该是修正 HTML 中的错误,不然,从服务器端很难准确判断浏览器提交的字符串到底是什么编码。

#10 楼 @yanhao 但是这个问题是存在的,因为别人输入一个这样的字符而导致网站都 500

暂时还是决定先用 String#scrub 过滤下

database.yml -> collation: utf8mb4_unicode_ci

需要 登录 后方可回复, 如果你还没有账号请 注册新账号