使用 Ruby on Rails 5 API 处理文件上传
介绍
在大多数情况下,将由字符串组成的基本 JSON 数据发送到 API(应用程序编程接口)是一项简单而直接的任务。但是,如果发送由多种格式的二进制数据组成的文件怎么办?这样的数据需要采用略有不同的方法将文件发送到 API。
在本指南中,我们将通过使用paperclip和carrierwave gem 的 Rails 5 API 应用程序研究处理文件上传的两种主要方法,即多部分表单数据和base64 编码。
向 Rails 5 API 发送文件的方法
多部分表单数据
多部分表单自HTML 4以来就已存在。之所以引入它们,是因为标准application/x-www-form-urlencoded表单无法很好地处理大量数据。
根据W3C的规定,multipart/form-data用于“包含文件、非 ASCII 数据和二进制数据”的表单。多部分表单的不同之处在于,它们将数据分成不同的块,代表文件的各种特征(大小、内容类型、名称、内容)以及表单的标准文本和数字数据的特征。
为了使事情更清楚,让我们考虑以下形式:
<form action="http://localhost:3000/api/v1/items"
enctype="multipart/form-data"
method="post">
<p>
What is your name? <input type="text" name="submit-name"><br>
What file are you sending? <input type="files" name="file"><br>
</p>
<input type="submit" value="Send"> <input type="reset">
</form>
如果用户在文本输入中输入“John”,并选择文本文件“file1.txt”,则浏览器将返回以下数据:
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
John
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
表单的每个部分都由边界分隔,边界代表不同的字符串(示例中为 AaB03x)。该部分本身包含带有 Content-Type 的二进制信息。较大的文件可以分解成块并在服务器中组装,从而允许流式传输文件并在连接中断的情况下保持其完整性。
让我们考虑另一个文件。如果用户选择另一个文件“file2.gif”,则浏览器将按如下方式构建各部分:
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
John
--AaB03x
Content-Disposition: form-data; name="file"
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-Disposition: file; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
这里可以看到表单数据中又添加了一部分。这一次,由于文件不是纯文本格式,因此它被分解为二进制,这可以从 Content-Transfer-Encoding 属性推断出来。
Content-Type 属性提供有关文件类型的信息,也称为其媒体 (MIME) 类型。如果未定义 Content-Type 属性且文件不是文本格式,则其格式将默认为 application/octet-stream ,这意味着最终文件将是二进制文件且没有类型。
当向 API 发送数据时,最好在包含文件的每个部分都包含一个 Content-Type,否则就无法验证文件的内容。
Base64 编码
Base64 是最常用的二进制转文本编码格式之一。它使用一种算法将二进制代码分解成几部分并将其转换为 ASCII 字符(文本)。它有广泛的应用 - 除了用于将文件编码为文本以将其发送到 API 之外,它还用于将图像表示为 CSS、HTML 和 SVG 中的内容源。
base64 编码文件的结构非常简单。它由两部分组成 - MIME 类型(类似于多部分 Content-Type 和实际的 base64 编码字符串:
data:image/gif;base64,iVBORw0KGgoAAAANag...//rest of the base64 text
上传时,文件在客户端被编码为 base64,在服务器上被解码。base64 字符串可以轻松附加到 JSON 对象的属性上:
{
"file": {
"name": "file2",
"contents": "data:image/gif;base64, iVBORw0KGgoAAA..."
}
}
API 可以轻松获取参数并将其解码回二进制。这使得 base64 编码的文件上传对于 API 来说非常方便,因为包含文件的消息格式及其传输方式与向 API 发送信息的标准方式没有区别。
Base64 编码与多部分表单数据
Base64 编码的文件可轻松被 JSON 和 XML API 使用,因为它们以文本形式表示,并且可以通过标准 application/json 格式发送。但是,编码会使文件大小增加 33%,从而难以传输较大的文件。编码和解码还会增加服务器和客户端的计算开销。因此,base64 适合发送图像和 100MB 以下的小文件。
另一方面,多部分表单对于 API 来说更“不自然”,因为数据采用不同的格式编码,需要不同的处理方式。但是,由于处理较大文件的性能提升以及流式传输文件的能力,多部分表单数据更适合上传较大的文件(例如视频)。
设置 Rails API 以进行文件上传
让我们应用这些概念。首先,让我们设置一个 Rails 5 API 应用程序并搭建将要使用的模型。
安装和配置 Rails 5 API
要创建 Rails 5 API,您需要安装 Ruby 2.2.4。获得合适的 Ruby 版本后,第一步是通过终端/命令提示符安装最新版本的 Rails:
gem install rails --pre --no-ri --no-rdoc
这将使您能够使用最新版本(当前为 5.0.0.beta3)运行 rails new:
rails _5.0.0.beta3_ new fileuploadapp --api
这将创建一个全新的 Rails 5 应用程序,并且使用生成器中包含的 --api 选项,它将全部设置为用作 API。移动到新项目的目录:
cd fileuploadapp
转到 Gemfile 并取消注释 jbuilder 和 rack-cors 。
# Gemfile.rb
gem 'jbuilder', '~> 2.0'
gem 'rack-cors'
#config/application.rb
module Fileuploadapp
class Application < Rails::Application
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
config.api_only = true
end
end
此配置将授予对 API 的完全访问权限(* 表示接受所有内容)。这对于本指南来说不是问题,因为我们只使用本地服务器。
安装宝石:
bundle install
安装 gem 之后,模型将会用 Jbuilder 生成的视图进行搭建,并准备被客户端应用程序使用。
rails g scaffold Item name:string description:string
我们将构建一个名为 Item 的模型,该模型的名称和描述都是字符串。请注意,目前还没有关于文件的信息 - 文件信息将在稍后阶段包含在模型的架构中。现在,我们已准备好继续将模型迁移到数据库中:
rails db:migrate
这将在数据库中为新模型创建一个表。请注意,在 Rails 5 中,您可以使用 rails 而不是 rake 来执行迁移命令。
要继续本指南,您必须选择要用于实现文件上传的 gem 。如果您想同时执行这两项操作,我建议您使用git等版本控制,这样实现就不会发生冲突。
使用 Paperclip 上传文件
要开始使用 Paperclip,首先将 gem 添加到你的 Gemfile 中:
#Gemfile.rb
gem "paperclip", "~> 5.0.0.beta1"
并安装它:
bundle install
上传单个文件
首先,生成一个将附件添加到数据库的迁移。** 您必须在模型中为附件输入与在生成器中相同的名称(在本例中为图片)。**
rails g paperclip item picture
完成后,不要忘记迁移数据库:
rails db:migrate
其次,在模型文件中添加以下几行:
#app/models/item.rb
class Item < ApplicationRecord
has_attached_file :picture, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :picture, presence: true
do_not_validate_attachment_file_type :picture
end
每种方法的具体内容如下:
has_attached_file 是添加文件附件的主要方法。第一个参数是用于文件附件的模型的属性(在本例中为:picture,正如我们从数据库迁移中了解到的那样)。styles:是一个可选参数,它将根据文件大小将上传的文件分发到不同的文件夹中。在这个例子中,中等大小的照片将是 300x300 像素及以上,并将放入 /images/medium 目录。default_url 也是一个可选参数,用于指定如果模型中的对象没有附加图像则返回的默认图像的路径。你可以把默认图像放在 app/assets/images/(medium 或 thumb)/ 中。如果你上传的文件不同于图像,你可以省略可选参数。
validates_attachment 可以验证文件的内容类型、存在性和大小。您可以<font style="vertical-al
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~