在Google AppEngine (python)中存储配置的好地方是什么?
我正在制作一个Google AppEngine的应用程序,但我在想,应该把一些敏感的配置信息,比如账号密码,存放在哪里比较好。
我是在考虑是不是应该创建一个大的表格来存放这些配置信息,还是有其他更好的存储方式呢?
3 个回答
如果你要处理敏感数据,千万不要把它放在源代码里,因为这些代码会被上传到版本控制系统。这样的话,可能会有不该看到这些数据的人(无论是公司内部还是外部)找到它。而且,你的开发环境和生产环境的配置值通常是不同的。如果这些值都放在代码里,你就得在开发和生产中运行不同的代码,这样会很麻烦,也是不好的做法。
在我的项目中,我会把配置数据放在数据存储中,使用这个类:
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')
如果数据存储中有这个键对应的值,你就能拿到它。如果没有,系统会创建一个占位记录,并抛出一个异常。这个异常会提醒你去开发者控制台更新这个占位记录。
我发现这样做可以省去设置配置值时的猜测。如果你不确定该设置什么配置值,只需运行代码,它会告诉你!
把它们存放在一个模块里。你可以简单点,比如创建一个叫 config.py
的模块,里面写一些配置,比如:
AMAZON_KEY = 'XXXX'
然后你可以这样使用:
import config
service = my_amazon_service(config.AMAZON_KEY)
或者你可以做一个稍微复杂一点的配置对象,这样可以为你的应用设置合理的默认值,还可以使用命名空间来管理配置键等等。
如果你可以把这些设置直接写进你的代码里,那就可以这样做。不过,如果你想要让这些设置可以动态调整,使用数据存储是更好的选择。你可以把设置缓存到本地内存里,这样就不用每次请求都去获取设置了。下面是一个帮助类的示例:
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