Rails 3 – 如何处理PG错误不完整的多字节字符

在Rails 3.2应用程序(Ruby 1.9.2)中,我收到以下错误

在mobile_users#update中发生PGError:

不完整的多字节字符

这些是Postgres错误我在开发和测试模式下测试时遇到类似的SQLIte错误

导致此错误的参数是(故意省略auth令牌)

* Parameters: {"mobile_user"=>{"quiz_id"=>"1", "auth"=>"xxx", "name"=>"Joaqu\xEDn"}, "action"=>"update", "controller"=>"mobile_users", "id"=>"1", "format"=>"mobile"} 

这是作为JSON HTTP Put请求进行的,处理此问题的更新操作如下所示

  # PUT /mobile_users/1 # PUT /mobile_users/1.xml def update @mobile_user = current_mobile_user @mobile_user.attributes = params[:mobile_user] respond_to do |format| if @mobile_user.save format.html { redirect_to(@mobile_user, :notice => 'Mobile user was successfully updated.') } format.json { head :ok } format.mobile { head :ok } format.xml { head :ok } else format.html { render :action => "edit" } format.json { render :json => @mobile_user.errors, :status => :unprocessable_entity } format.mobile { render :json => @mobile_user.errors, :status => :unprocessable_entity } format.xml { render :xml => @mobile_user.errors, :status => :unprocessable_entity } end end end 

违规字符串在上面的参数中是“Joaqu \ xEDn”,这是完全有效的。 问题是我需要处理任何语言的所有字符集。

我假设我需要使用iconv库,但为了做到这一点,我需要检测从转换为UTF8的字符集,我不知道如何做到这一点。

我也在UTF-8中获取"name"=>"p\xEDa "无效字节序列

这个:

 "Joaqu\xEDn" 

"Joaquín"的ISO-8859-1编码版本,因此它不是有效的UTF-8,您的数据库是正确的抱怨。 如果可能,请修复您的移动客户端以在JSON中使用UTF-8; 如果你不能这样做那么你可以用这个修复编码:

 params[:mobile_user][:name].force_encoding('iso-8859-1').encode!('utf-8') 

在服务器上。 在服务器上修复它的问题是你必须猜测传入的编码是什么,你的猜测可能不正确。 没有办法可靠地猜测特定字符串的编码,有rchardet,但它不适用于最新版本的Ruby,它似乎已被放弃; 您可能能够修复此gem以使用现代Ruby。 还有一些其他的猜测库,但它们似乎都被抛弃了。

根据定义 ,JSON文本始终默认为Unicode和UTF-8编码:

 3. Encoding JSON text SHALL be encoded in Unicode. The default encoding is UTF-8. 

任何向您发送不是UTF-8的JSON的客户端都会被IMO破坏,因为几乎所有客户都会认为JSON将是UTF-8。 当然,可能有某个编码标题在某处指定ISO 8859-1,或者标题可能是UTF-8,即使它是ISO 8859-1。

我在解析文件时遇到了与用户生成的数据相同的问题并以这种方式解决了它:

 require 'iconv' .... line = Iconv.conv('UTF-8//IGNORE', 'UTF-8', line) #now variable line has valid utf-8 data 

您可以尝试覆盖’name’setter,以便它删除非utf8字符:

 def name=(name) write_attribute(:name, Iconv.conv('UTF-8//IGNORE', 'UTF-8', name)) end