我无法在“dev_appserver.py”上创建Google Cloud Storage文件。

2 投票
1 回答
2823 浏览
提问于 2025-04-18 12:21

我遇到了一个错误,如下所示。

INFO     ~ module.py:639] default: "HEAD /_ah/gcs/app_default_bucket/multibytes.txt HTTP/1.1" 404 -
ERROR    ~ gcs.py:99] Expect status [200] from Google Storage. But got status 404.
Path: '/app_default_bucket/multibytes.txt'.
Request headers: None.
Response headers: {'date': 'Mon, 07 Jul 2014 12:59:44 GMT', 'server': 'Development/2.0', 'connection': 'close'}.
Body: ''.
Extra info: None.
Traceback (most recent call last):
  File "/gcs.py", line 97, in status
        stat = gcs.stat("/%s/%s" % (b,nm))
  File "/cloudstorage/cloudstorage_api.py", line 142, in stat
        body=content)
  File "/cloudstorage/errors.py", line 132, in check_status
        raise NotFoundError(msg)
NotFoundError: Expect status [200] from Google Storage. But got status 404.
Path: '/app_default_bucket/multibytes.txt'.
Request headers: None.
Response headers: {'date': 'Mon, 07 Jul 2014 12:59:44 GMT', 'server': 'Development/2.0', 'connection': 'close'}.
Body: ''.
Extra info: None.

这是我自定义的 GCS 客户端类的一个例子。

# encoding: utf-8

import cloudstorage as gcs

class mycustomgcsclient:

  #...

  def create(self,name,data,**options):
    options['retry_params'] = gcs.RetryParams(backoff_factor=1.1)

    if not options.get('content_type'):
      options['content_type'] = 'octet-stream'

    if isintance(name,unicode):
      name = name.encode('utf-8')

    path = '/mybucketname/%s' % name
    try:
      with gcs.open(path,'w',**options) as f:
        f.write(data)
      return True
    except Exception as e:
      logging.exception(e)

    return False

if __name__=='__main__':
  data = 'some data ...¥n'

  filename = 'somedir/%s' % u'sample.txt'
  mycustomgcsclient().create(filename,data) # no error occured.

  filename = 'somedir/%s' % u'あいうえお.txt'
  mycustomgcsclient().create(filename,data) # error occured in this line.

当我只使用多字节文件名时,我遇到了上面的错误。

而使用 ASCII 文件名时,我没有遇到任何错误。

我使用的是一个名为 "GCS Client Library (Python)" 的库,可以在这个链接找到:https://developers.google.com/appengine/docs/python/googlecloudstorageclient/download

我的 dev_appserver.py 版本是 Development SDK 1.9.6,运行在 MacOS X 上(具体版本忘记了)。

有没有什么解决方案?

1 个回答

3

我觉得你可能需要在把名字编码成utf8之后,调用一下 urllib.quote()

这里有一个修改过的GCS Python示例版本(http://appengine-gcs-client.googlecode.com/svn/trunk/python/demo/main.py),它可以正确处理多字节的文件名:

# Copyright 2012 Google Inc. All Rights Reserved.
# encoding: utf-8

"""A modified version of the sample app that uses GCS client to operate on
   bucket and file.
"""

import logging
import os
import cloudstorage as gcs
import webapp2
import urllib

from google.appengine.api import app_identity

my_default_retry_params = gcs.RetryParams(initial_delay=0.2,
                                          max_delay=5.0,
                                          backoff_factor=2,
                                          max_retry_period=15)
gcs.set_default_retry_params(my_default_retry_params)


class MainPage(webapp2.RequestHandler):
  """Main page for GCS demo application."""

  def get(self):
    bucket_name = os.environ.get('BUCKET_NAME',
                                 app_identity.get_default_gcs_bucket_name())

    self.response.headers['Content-Type'] = 'text/plain'
    self.response.write('Demo GCS Application running from Version: '
                        + os.environ['CURRENT_VERSION_ID'] + '\n')
    self.response.write('Using bucket name: ' + bucket_name + '\n\n')

    bucket = '/' + bucket_name
    filename = bucket + '/' + urllib.quote(u'あいうえお.txt'.encode('utf8'))
    self.tmp_filenames_to_clean_up = []

    try:
      self.create_file(filename)
      self.response.write('\n\n')

      self.read_file(filename)
      self.response.write('\n\n')

    except Exception, e:
      logging.exception(e)
      self.delete_files()
      self.response.write('\n\nThere was an error running the demo! '
                          'Please check the logs for more details.\n')

    else:
      self.delete_files()
      self.response.write('\n\nThe demo ran successfully!\n')

  def create_file(self, filename):
    """Create a file.

    The retry_params specified in the open call will override the default
    retry params for this particular file handle.

    Args:
      filename: filename.
    """
    self.response.write('Creating file %s\n' %
                        urllib.unquote(filename).decode('utf-8'))

    write_retry_params = gcs.RetryParams(backoff_factor=1.1)
    gcs_file = gcs.open(filename,
                        'w',
                        content_type='text/plain',
                        options={'x-goog-meta-foo': 'foo',
                                 'x-goog-meta-bar': 'bar'},
                        retry_params=write_retry_params)
    gcs_file.write('some data ...¥n\n')
    gcs_file.close()
    self.tmp_filenames_to_clean_up.append(filename)


  def read_file(self, filename):
    self.response.write('File Content:\n')

    gcs_file = gcs.open(filename)
    self.response.write(gcs_file.readline())
    gcs_file.close()

  def delete_files(self):
    self.response.write('Deleting files...\n')
    for filename in self.tmp_filenames_to_clean_up:
      self.response.write('Deleting file %s\n' %
                          urllib.unquote(filename).decode('utf-8'))
      try:
        gcs.delete(filename)
      except gcs.NotFoundError:
        pass

app = webapp2.WSGIApplication([('/', MainPage)],
                              debug=True)

撰写回答