使用 Ruby on Rails 5 API 处理文件上传

发布日期:2026-06-25 05:58:04   来源 : 杭州电子商务研究院    浏览量 :21
杭州电子商务研究院 发布日期:2026-06-25 05:58:04  
21

介绍

在大多数情况下,将由字符串组成的基本 JSON 数据发送到 API(应用程序编程接口)是一项简单而直接的任务。但是,如果发送由多种格式的二进制数据组成的文件怎么办?这样的数据需要采用略有不同的方法将文件发送到 API。

在本指南中,我们将通过使用paperclipcarrierwave 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'
    

JBuilder用于为应用程序的响应创建 JSON 结构。在 MVC 术语中,JSON 响应将成为应用程序的视图层(又称 UI 层或表示层)。因此,所有 Jbuilder 生成的响应都必须放在 app/views/(特定控制器操作的视图) 中。

rack-cors可以实现跨域资源共享(CORS)。简单来说,rack-cors 可以让基于浏览器的应用(AngularJS、React)和移动端的应用从 API 中请求信息。在应用配置文件中添加 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
    

每种方法的具体内容如下:

  1. has_attached_file 是添加文件附件的主要方法。第一个参数是用于文件附件的模型的属性(在本例中为:picture,正如我们从数据库迁移中了解到的那样)。styles:是一个可选参数,它将根据文件大小将上传的文件分发到不同的文件夹中。在这个例子中,中等大小的照片将是 300x300 像素及以上,并将放入 /images/medium 目录。default_url 也是一个可选参数,用于指定如果模型中的对象没有附加图像则返回的默认图像的路径。你可以把默认图像放在 app/assets/images/(medium 或 thumb)/ 中。如果你上传的文件不同于图像,你可以省略可选参数。

  2. validates_attachment 可以验证文件的内容类型存在性大小。您可以<font style="vertical-al

以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据