Sinatra,上传表单中的进度条

发布于 2024-09-07 03:00:04 字数 1662 浏览 8 评论 0原文

我正在开发一个 Sinatra 应用程序,其中包含一个上传表单,并有一个进度条指示上传已完成的程度。 ryan dahl 描述的过程如下:

HTTP 上传进度条相当混乱 - 它们通常涉及在服务器上运行的进程,跟踪 HTTP 服务器正在写入的临时文件的大小,然后在客户端每隔几秒进行一次 AJAX 调用上传过程中向服务器询问上传进度。

每次上传都有一个随机的session-id,为了跟踪关联,我在我的应用程序中使用了一个类变量(我知道,这太可怕了——如果你已经有更好的想法,请告诉我)

configure do
  @@assoc = {}
end

我有一个用于上传的 POST 路由,以及一个用于 AJAX 轮询的 GET 路由。 在 POST 路由中,我保存了 session-idTempfile 和总大小的关联。

post '/files' do
  tmp = params[:file][:tempfile]
  # from here on, @@assoc[@sid] should have a value, even in other routes
  @@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] } 
  File.open("#{options.filesdir}/#{filename}", 'w+') do |file|
    file << tmp.read
  end
end 

GET 路由中,我根据 Tempfile 的当前大小计算百分比:

get '/status/:sid' do
  h = @@assoc[params[:sid]]
  unless h.nil?
    percentage = (h[:file].size / h[:size].to_f) * 100 
    "#{percentage}%"
  else
    "0%"
  end 
end

问题是,直到 POST 请求还没有已完成(即,在读取所有 Tempfile 后),h.nil? 返回 true,这实际上没有意义,因为我刚刚在另一条路线中为 @@assoc[@sid] 分配了一个值。

那么,我在这里缺少什么?

编辑:我尝试过

  • set :reload, false
  • set :environment, :product
  • config { @@assoc ||= { } }
  • 我也尝试向它扔一个关系数据库(带有 DataMapper 的 SQLite)

都没有成功。

I'm developing a Sinatra app that consists of an upload form, with a progress bar indicating how much of the upload has completed.
The process, as described by ryan dahl, is the following:

HTTP upload progress bars are rather obfuscated- they typically involve a process running on the server keeping track of the size of the tempfile that the HTTP server is writing to, then on the client side an AJAX call is made every couple seconds to the server during the upload to ask for the progress of the upload.

Every upload has a random session-id, and to keep track of the association i employ a class variable in my app (i know, that's horrible -- if you've got better ideas, please tell me)

configure do
  @@assoc = {}
end

I have a POST route for the upload, and a GET one for the AJAX polling.
Inside the POST route i save the association of session-id, Tempfile, and total size.

post '/files' do
  tmp = params[:file][:tempfile]
  # from here on, @@assoc[@sid] should have a value, even in other routes
  @@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] } 
  File.open("#{options.filesdir}/#{filename}", 'w+') do |file|
    file << tmp.read
  end
end 

In the GET route, i calculate the percentage based on the Tempfile's current size:

get '/status/:sid' do
  h = @@assoc[params[:sid]]
  unless h.nil?
    percentage = (h[:file].size / h[:size].to_f) * 100 
    "#{percentage}%"
  else
    "0%"
  end 
end

The problem is that until the POST request hasn't completed (i.e., after it has read all of the Tempfile) the h.nil? returns true, which doesn't really make sense as I've just assigned @@assoc[@sid] a value in the other route.

So, what am I missing here?

EDIT: I've tried

  • set :reload, false
  • set :environment, :production
  • config { @@assoc ||= {} }
  • I also tried throwing a relational db at it (SQLite with DataMapper)

Neither worked.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡淡的优雅 2024-09-14 03:00:04

我想我明白了问题所在:

tmp = params[:file][:tempfile] 在完全收到文件之前不会返回。

I think i got what the problem is:

tmp = params[:file][:tempfile] doesn't return until the file has been fully received.

不…忘初心 2024-09-14 03:00:04
@@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] }

应该是

@@assoc[params[:sid]] = { :file => tmp, :size => env['CONTENT_LENGTH'] }
@@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] }

should be

@@assoc[params[:sid]] = { :file => tmp, :size => env['CONTENT_LENGTH'] }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文