无法从 rails API return 二进制数据

Unable to return binary data from rails API

我使用 rails 中的 binary 数据类型将 base64url_encoded 字符串存储到 postgres 数据库中。这是迁移

def change
  add_column :gmail_attachments, :base64_data, :binary
end

我正在存储的数据是来自 gmail API 的 base64 url 编码字符串。当我试图在 postgres 中将数据存储为 string 数据类型时,我得到了

ArgumentError (string contains null byte)

所以,我使用了二进制数据类型,它成功地存储到数据库中。现在,当我尝试

render status: 200, json: gmail_attachment_record

我收到以下错误

Encoding::UndefinedConversionError ("\xFF" from ASCII-8BIT to UTF-8):

如何消除此错误和 return 存储的数据?我是否将其存储在错误的数据类型中? rails ActiveRecord 数据类型中实现此目的的最佳选择是什么?

当您保存带有 :binary 列的模型时,Rails 将为您完成所有工作,确保正确设置编码以确保正确保存数据。

我认为您遇到了编码错误,因为 to_json 方法(通过 render 隐式调用)正试图通过 JSON.encode 将您的二进制字符串转换为 UTF-8。这就是您收到 UndefinedConversionError 的原因。 (ASCII-8BIT 是 ruby 中的一种特殊编码,本质上表示 BINARY。)


要进入工作状态,我认为您需要:

  • 将您的数据保存到二进制列中,就像您在上面所做的那样 - 考虑将其命名为 data。 (更好的是,使用 ActiveStorage 并将其保存到其他地方的文件中。)我建议您首先将数据从 base64 转换为原始二进制表示形式:
# Not sure what the api exactly looks like, but you get the idea
require('base64')

base64_data = Gmail.get_attachment(...)

gmail_attachment.data = Base64.decode64(base64_data) # now our data field is just the raw bytes.
gmail_attachment.save
  • 然后您需要将其序列化回 base64,以便通过 to_json 传输。你可以通过这样的 as_json 方法来做到这一点:
# models/gmail_attachment.rb
require('base64')

class GmailAttachment < ApplicationRecord

  def base64_data
    Base64.encode64(self.data)
  end
end

# controllers/your_controller.rb
render json: gmail_attachment_record.as_json(except: [:data], methods: [:base64_data])

很确定这会让您朝着正确的方向前进!