Ruby:使用google-api-ruby-client SDK将文件上传到Google驱动器失败并显示Timeout :: Error

时间:2012-11-28 10:36:48

标签: ruby-on-rails ruby file-upload google-drive-api google-api-ruby-client

我在我的Rails应用程序中使用google-api-ruby-client与Google Drive进行交互。所有基本功能,如列出文件夹中的文件,获取,移动,复制和删除文件,创建新文件夹等都可以正常工作。

但是,使用Timeout :: Error

上传新文件总是失败

我收到要从我的网站上传的常规文件上传文件(multipart / form-data),这就是我将其上传到Google云端硬盘的方式

result = nil
new_file_obj = google_drive.files.insert.request_schema.new({
  'title' => file_name,
  'mimeType' => file_mime_type,
  'parents' => [{'id' => current_folder_id}]
})

file_content = Google::APIClient::UploadIO.new(new_file.tempfile, file_mime_type, file_name)

result = google_client.execute(
    api_method: google_drive.files.insert,
    body_object: new_file_obj,
    media: file_content,
    parameters: {
      'uploadType' => 'multipart',
      'alt' => 'json'
    }
  )

此处new_file是客户端上传的文件。 new_file.tempfile提供Tempfile类型的对象。

execute方法永远不会返回,最终我得到一个Timeout :: Error异常。这是相关的堆栈跟踪:

/lib/ruby/1.9.1/net/protocol.rb:140:in `rescue in rbuf_fill'
/lib/ruby/1.9.1/net/protocol.rb:134:in `rbuf_fill'
/lib/ruby/1.9.1/net/protocol.rb:116:in `readuntil'
/lib/ruby/1.9.1/net/protocol.rb:126:in `readline'
/lib/ruby/1.9.1/net/http.rb:2211:in `read_status_line'
/lib/ruby/1.9.1/net/http.rb:2200:in `read_new'
/lib/ruby/1.9.1/net/http.rb:1183:in `transport_request'
/lib/ruby/1.9.1/net/http.rb:1169:in `request'
/lib/ruby/1.9.1/net/http.rb:1162:in `block in request'
/lib/ruby/1.9.1/net/http.rb:627:in `start'
/lib/ruby/1.9.1/net/http.rb:1160:in `request'
/lib/ruby/gems/1.9.1/gems/faraday-0.8.4/lib/faraday/adapter/net_http.rb:74:in `perform_request'
/lib/ruby/gems/1.9.1/gems/faraday-0.8.4/lib/faraday/adapter/net_http.rb:37:in `call'
/lib/ruby/gems/1.9.1/gems/faraday-0.8.4/lib/faraday/request/url_encoded.rb:14:in `call'
/lib/ruby/gems/1.9.1/gems/google-api-client-0.5.0/lib/google/api_client/request.rb:154:in `send'
/lib/ruby/gems/1.9.1/gems/google-api-client-0.5.0/lib/google/api_client.rb:546:in `execute'

我按照此处的示例编写了此代码:https://developers.google.com/drive/examples/ruby#saving_new_files我在这里缺少什么?

我要上传的文件是一个小png图像。该文件正好适用于我的Web应用程序,因为如果我将其写入磁盘,我可以查看该文件。由于我可以从drive.google.com上传文件,因此Google服务器肯定没有关闭。这也意味着我的网络足够好了。

那究竟是什么导致了超时?

提到同一异常的解决方案是增加read_timeout(http://stackoverflow.com/questions/10011387/rescue-in-rbuf-fill-timeouterror-timeouterror)。那是我应该做的吗?如果是这样,我如何使用google-api-ruby-client sdk?

进行此操作

4 个答案:

答案 0 :(得分:1)

从一些快速实验中,可能只是因为tempfile没有被重新读取。我修改了quickstart示例以从tempfile中读取并能够重现错误。例如:

tmp = Tempfile.new('foo')
tmp.write("hello world")

media = Google::APIClient::UploadIO.new(tmp, 'text/plain', 'foo.txt')
file = drive.files.insert.request_schema.new({
  'title' => 'My document',
  'description' => 'A test document',
  'mimeType' => 'text/plain'
})
result = client.execute(
  :api_method => drive.files.insert,
  :body_object => file,
  :media => media,
  :parameters => {
    'uploadType' => 'multipart',
    'alt' => 'json'})

这将在挂起约30秒左右后产生相同的堆栈跟踪。但是,添加一个重绕调用以重置tempfile使其工作正常

tmp = Tempfile.new('foo')
tmp.write("hello world")
tmp.rewind # Reset for reading...

尝试一下,看看它是否能解决您的问题。

答案 1 :(得分:0)

查看https://github.com/google/google-api-ruby-client/blob/master/lib/google/api_client.rb#L532-560

您可以将法拉第连接传递给execute方法。像

这样的东西
conn = Faraday.default_connection
conn.options[:timeout] = 500 

result = google_client.execute(
api_method: google_drive.files.insert,
body_object: new_file_obj,
media: file_content,
parameters: {
  'uploadType' => 'multipart',
  'alt' => 'json'
 },
connection: conn
)

这会增加Net:HTTP超时。

答案 2 :(得分:0)

显然,Google 关于使用 Ruby 将文件上传到文件夹的文档尚未记录。它的实现方式如下。

class DriveUpload
    def self.process
            drive_service = Google::Apis::DriveV3::DriveService.new

            drive_service.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
            json_key_io: File.open('client_secret.json'),
            scope: Google::Apis::DriveV3::AUTH_DRIVE)
            meta_data = Google::Apis::DriveV3::File.new(name:'README_ONDRIVE.md',parents:["1gUxa7_9kbaBX_iofwUYKU_3BFXbBu6Ip"])

            file = drive_service.create_file(meta_data, upload_source: 'README.md',content_type: 'text/plain')

    end
end

请注意,parent 是指 Drive 内的文件夹(您与服务帐户共享的文件夹)

答案 3 :(得分:-1)

这个答案是对的。

}上传文件需要。{/ p>

今天我按照@Steve Bazyl的建议尝试了没有drive.install的上传,它刚刚工作(即使没有drive.install调用)。

看起来这个问题很短暂,因为环境中的其他因素都没有改变。

<击> 原来问题是权限不足。以前这些是我要求用户许可的范围:

tmp_file.rewind

Google驱动器要求应用程序为https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/drive ,以便代表用户上传文件。并且,对于应用installed,还应该要求对以下范围的许可:installed

来源:

  1. How do I add/create/insert files to Google Drive through the API?(您无需在Chrome商店中列出您的应用,如上所述。只需要获取drive.install权限即可。请务必重新验证/重新授权所有用户获得新的令牌)

  2. https://developers.google.com/drive/scopes#google_drive_scopes

  3. 然而https://www.googleapis.com/auth/drive.install仍然有些异常。当他们看到提供的令牌中的权限不足时,Google服务器可能没有回复错误消息。

    P.S:如果有人解释Timeout::Error,它将被接受为正确答案。