4

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

但是,上传新文件总是因 Timeout::Error 而失败

我从我的网站(多部分/表单数据)收到要作为常规文件上传的文件,这就是我将其上传到 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 上传文件。这也意味着我的网络足够好。

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

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

4

4 回答 4

1

通过一些快速的实验,可能只是临时文件没有被倒带读取。我修改了快速入门示例以从临时文件中读取,并且能够重现该错误。例如:

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 秒左右后产生相同的堆栈跟踪。但是,添加一个调用 rewind 来重置临时文件使它工作得很好

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

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

于 2012-11-30T19:24:28.867 回答
0

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

您可以将法拉第连接传递给执行方法。就像是

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 超时。

于 2013-04-09T14:09:30.897 回答
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

请注意,父级意味着驱动器内的文件夹(您与服务帐户共享的文件夹)

于 2021-01-20T06:12:31.293 回答
-1

这个答案是错误的。上传文件不需要权限drive.install

今天我尝试在没有drive.install@Steve Bazyl 建议的情况下上传,它就可以正常工作(即使没有tmp_file.rewind电话)。

看起来这个问题是短暂的,因为环境中的其他任何东西都没有改变。

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

https://www.googleapis.com/auth/userinfo.email 
https://www.googleapis.com/auth/userinfo.profile 
https://www.googleapis.com/auth/drive

谷歌驱动器要求应用程序installed代表用户上传文件。并且installed还应请求应用程序获得以下范围的权限:https://www.googleapis.com/auth/drive.install

资料来源:

  1. 如何通过 API 向 Google Drive 添加/创建/插入文件?(您不必像那里提到的那样在 chrome 商店中列出您的应用程序。只需请求 drive.install 权限就足够了。请务必重新验证/重新授权所有用户以获取新令牌)

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

然而,这Timeout::Error仍然有些反常。当 Google 服务器在提供的令牌中看到权限不足时,可能也没有响应错误消息。

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

于 2012-11-29T18:09:57.430 回答