在Google AppEngine (python)中存储配置的好地方是什么?

14 投票
3 回答
4098 浏览
提问于 2025-04-16 04:30

我正在制作一个Google AppEngine的应用程序,但我在想,应该把一些敏感的配置信息,比如账号密码,存放在哪里比较好。

我是在考虑是不是应该创建一个大的表格来存放这些配置信息,还是有其他更好的存储方式呢?

3 个回答

4

如果你要处理敏感数据,千万不要把它放在源代码里,因为这些代码会被上传到版本控制系统。这样的话,可能会有不该看到这些数据的人(无论是公司内部还是外部)找到它。而且,你的开发环境和生产环境的配置值通常是不同的。如果这些值都放在代码里,你就得在开发和生产中运行不同的代码,这样会很麻烦,也是不好的做法。

在我的项目中,我会把配置数据放在数据存储中,使用这个类:

from google.appengine.ext import ndb

class Settings(ndb.Model):
  name = ndb.StringProperty()
  value = ndb.StringProperty()

  @staticmethod
  def get(name):
    NOT_SET_VALUE = "NOT SET"
    retval = Settings.query(Settings.name == name).get()
    if not retval:
      retval = Settings()
      retval.name = name
      retval.value = NOT_SET_VALUE
      retval.put()
    if retval.value == NOT_SET_VALUE:
      raise Exception(('Setting %s not found in the database. A placeholder ' +
        'record has been created. Go to the Developers Console for your app ' +
        'in App Engine, look up the Settings record with name=%s and enter ' +
        'its value in that record\'s value field.') % (name, name))
    return retval.value

你的应用程序可以这样获取一个值:

AMAZON_KEY = Settings.get('AMAZON_KEY')

如果数据存储中有这个键对应的值,你就能拿到它。如果没有,系统会创建一个占位记录,并抛出一个异常。这个异常会提醒你去开发者控制台更新这个占位记录。

我发现这样做可以省去设置配置值时的猜测。如果你不确定该设置什么配置值,只需运行代码,它会告诉你!

10

把它们存放在一个模块里。你可以简单点,比如创建一个叫 config.py 的模块,里面写一些配置,比如:

AMAZON_KEY = 'XXXX'

然后你可以这样使用:

import config
service = my_amazon_service(config.AMAZON_KEY)

或者你可以做一个稍微复杂一点的配置对象,这样可以为你的应用设置合理的默认值,还可以使用命名空间来管理配置键等等。

18

如果你可以把这些设置直接写进你的代码里,那就可以这样做。不过,如果你想要让这些设置可以动态调整,使用数据存储是更好的选择。你可以把设置缓存到本地内存里,这样就不用每次请求都去获取设置了。下面是一个帮助类的示例:

class Configuration(db.Model):
  _INSTANCE = None

  @classmethod
  def get_instance(cls):
    if not cls._INSTANCE:
      cls._INSTANCE = cls.get_or_insert('config')
    return cls._INSTANCE

你只需要根据自己的需要,继承这个类,添加你需要的配置值(或者直接修改这个类)。因为加载的代码在请求之间是会保留的,所以每个应用实例只需要获取一次设置。不过,如果你希望能够动态更新配置,可能需要设置一个超时时间。

如果你想要缓存一些东西一段时间,最简单的方法就是在获取数据时记录下时间戳:

class Configuration(db.Model):
  CACHE_TIME = datetime.timedelta(minutes=5)

  _INSTANCE = None
  _INSTANCE_AGE = None

  @classmethod
  def get_instance(cls):
    now = datetime.datetime.now()
    if not cls._INSTANCE or cls._INSTANCE_AGE + cls.CACHE_TIME < now:
      cls._INSTANCE = cls.get_or_insert('config')
      cls._INSTANCE_AGE = now
    return cls._INSTANCE

撰写回答