【问题标题】:How is the checksum calculated in the blobs table for rails ActiveStoragerails ActiveStorage的blob表中的校验和是如何计算的
【发布时间】:2018-11-12 10:24:25
【问题描述】:

有人知道在 Rails 5.2+ 上使用 ActiveStorage 时如何计算 active_storage_blobs 中的校验和字段吗?

对于奖励积分,有谁知道我如何让它使用与 md5 CLI 命令中的校验和匹配的 md5 校验和?

【问题讨论】:

    标签: ruby-on-rails rails-activestorage


    【解决方案1】:

    这是 blob 数据的 base64 编码 MD5 摘要。恐怕 Active Storage 不支持像 md5(1) 发出的十六进制校验和。对不起!

    【讨论】:

      【解决方案2】:

      源代码在这里:https://github.com/rails/rails/blob/master/activestorage/app/models/active_storage/blob.rb#L234

      def compute_checksum_in_chunks(io)
        Digest::MD5.new.tap do |checksum|
          while chunk = io.read(5.megabytes)
            checksum << chunk
          end
      
          io.rewind
        end.base64digest
      end
      

      在我的项目中,我需要使用这个校验和值来判断用户是否上传了重复文件,我使用下面的代码与上面的方法得到相同的值:

      md5 = Digest::MD5.file(params[:file].tempfile.path).base64digest
      puts "========= md5: #{md5}"
      

      输出:

      ========= md5: F/9Inmc4zdQqpeSS2ZZGug==
      

      数据库数据:

      pry(main)> ActiveStorage::Blob.find_by(checksum: 'F/9Inmc4zdQqpeSS2ZZGug==')
        ActiveStorage::Blob Load (2.7ms)  SELECT  "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."checksum" = $1 LIMIT $2  [["checksum", "F/9Inmc4zdQqpeSS2ZZGug=="], ["LIMIT", 1]]
      => #<ActiveStorage::Blob:0x00007f9a16729a90
      id: 1,
      key: "gpN2NSgfimVP8VwzHwQXs1cB",
      filename: "15 Celebrate.mp3",
      content_type: "audio/mpeg",
      metadata: {"identified"=>true, "analyzed"=>true},
      byte_size: 9204528,
      checksum: "F/9Inmc4zdQqpeSS2ZZGug==",
      created_at: Thu, 29 Nov 2018 01:38:15 UTC +00:00>
      

      【讨论】:

      • 您是如何实施重复检查的?我正在考虑通过使用校验和并使用已上传文件的 blob_id 来查看它是否重复。也许我需要开始一个新话题。
      【解决方案3】:

      让我们分解一下

      我知道我参加聚会有点晚了,但这更适合那些在寻找答案时遇到这个问题的人。所以这里是..

      背景:

      Rails 在 5.2 版中引入了大量新功能,其中之一是 ActiveStorage。官方最终版本于 2018 年 4 月 9 日发布。

      免责声明:

      为了清楚起见,以下信息与开箱即用的 vanilla 主动存储有关。这也没有考虑到一些围绕某个场景的疯狂代码fu。

      话虽如此,校验和的计算方式因您的 Active Storage 设置而异。使用普通的开箱即用 Rails Active Storage,有 2 种“类型”(没有更好的术语)配置。

      1. 代理上传
      2. 直接上传

      代理上传

      文件上传流程: [Client] → [RoR App] → [Storage Service]

      通讯。流程:可能会有所不同,但在大多数情况下,它应该类似于文件上传流程。

      上面 SparkBao 的回答中指出的是“代理上传”。这意味着您将文件上传到您的 RoR 应用程序并执行某种处理,然后再将文件发送到您配置的存储服务(AWS、Azure、Google、BackBlaze 等)。即使您将存储服务设置为“localdisk”,该逻辑在技术上仍然适用,即使您的 RoR 应用程序是存储端点。

      代理上传”方法并不适合在 Heroku 等服务上部署在云中的 RoR 应用程序。 Heroku 有 30 秒的硬性限制来完成您的交易并将响应发送回您的客户(最终用户)。因此,如果您的文件相当大,则需要考虑文件上传所需的时间,然后考虑计算校验和所需的时间。如果您遇到无法在 30 秒内完成请求并做出响应的情况,您将需要使用“直接上传”方法。

      代理上传答案:

      正如 Spark.Bao 所指出的,Ruby 类 Digest::MD5 用于方法 compute_checksum_in_chunks(io)


      直接上传

      文件上传流程: [客户端] → [存储服务]

      通讯。流程: [Client] → [RoR App] → [Client] → [Storage Service] → [Client] → [RoR App] → [Client]

      维护和开发 Rails 的好朋友已经为我们完成了所有繁重的工作。我不会详细介绍如何设置直接上传,但这里有一个关于如何设置的链接 »Rails EdgeGuide - Direct Uploads

      代理上传答案:

      现在说了这么多,通过开箱即用的“直接上传”设置,文件校验和是通过利用 SparkMD5 (JavaScript) 来计算的。

      下面是来自Rails Active Storage Source Code- (activestorage.js)的sn-p

        var fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
        var FileChecksum = function() {
          createClass(FileChecksum, null, [ {
            key: "create",
            value: function create(file, callback) {
              var instance = new FileChecksum(file);
              instance.create(callback);
            }
          } ]);
          function FileChecksum(file) {
            classCallCheck(this, FileChecksum);
            this.file = file;
            this.chunkSize = 2097152;
            this.chunkCount = Math.ceil(this.file.size / this.chunkSize);
            this.chunkIndex = 0;
          }
          createClass(FileChecksum, [ {
            key: "create",
            value: function create(callback) {
              var _this = this;
              this.callback = callback;
              this.md5Buffer = new sparkMd5.ArrayBuffer();
              this.fileReader = new FileReader();
              this.fileReader.addEventListener("load", function(event) {
                return _this.fileReaderDidLoad(event);
              });
              this.fileReader.addEventListener("error", function(event) {
                return _this.fileReaderDidError(event);
              });
              this.readNextChunk();
            }
          },

      结论

      如果有什么我错过的,我会提前道歉。我尽量做到彻底。

      所以总结一下以下应该足以作为可接受的答案:

      • 代理上传配置: ruby​​ 类Digest::MD5

      • 直接上传配置: JavaScript 哈希库SparkMD5

      【讨论】:

      • compute_checksum_in_chunks 中使用了哪些 blob 数据?如果我想计算与 ActiveStorage 计算的文件校验和相匹配的新校验和(不使用 DirectUpload),我需要提供什么?
      【解决方案4】:

      对于您的额外问题(可能也是主要问题):

      您可以将校验和从 base64 转换为十六进制(如 md5(1) 命令支持)并返回。

      Converting a hexadecimal digest to base64 in Ruby:

      def hex_to_base64(hexdigest)
        Base64.strict_encode64([hex_string].pack("H*"))
      end
      

      从base64到十六进制:

      def base64_to_hex(base64_string)
        Base64.decode64(base64_string).each_byte.map { |b| "%02x" % b.to_i }.join
      end
      

      【讨论】:

        猜你喜欢
        • 2016-04-02
        • 1970-01-01
        • 2022-06-21
        • 2021-06-10
        • 1970-01-01
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 2016-10-08
        相关资源
        最近更新 更多