Google App Engine 静态文件服务与应用冲突
我有一个单页面应用(SPA),它运行在Google App Engine(GAE)上。GAE主要做三件事:
- 提供index.html文件
- 提供静态文件(比如JS、CSS等)
- 提供动态文件(比如图片、文本等,通过REST接口)
我使用以下的app.yaml配置。
handlers:
- url: /app
static_dir: app
- url: /.*
script: main.app
我的理解是,这个配置应该能匹配到所有请求到/app文件夹的内容,从而提供我的静态文件。所有的REST服务和主index页面应该会被/.*捕获,然后由main.py处理。
但是,我遇到了以下情况:
- 如果我去掉/app处理器,我可以成功提供index.html(通过Jinja模板)和REST服务(比如localhost/subjects/)。但是,我看不到静态文件(这也是预期的结果)。
- 如果我添加/app处理器,index.html文件无法提供,并且出现“内部服务器错误” IOError(errno.EACCES, '文件不可访问', filename)。但是,当我请求一个静态文件,比如“localhost/app/app.js”,这个请求是成功的。
我是不是漏掉了什么?我不明白为什么这两者会冲突。
谢谢!
备注:使用Google App Engine 1.8.9,Python 2.7,本地开发
编辑:
这是我用来提供页面的Python代码
path = os.path.join(os.path.dirname(__file__), 'app')
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(path))
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html'
template_values = {}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
我的目录结构如下:
/
main.py
app.yaml及其他文件
app
index.html
app.js
模块A
moduleA.tpl.html
moduleA.js
编辑2:
我把index.html移动到了根目录(/),然后使用了以下的Python代码:
path = os.path.dirname(__file__)
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(path))
有趣的是,index.html同时映射到Jinja模板和静态目录文件时出现了问题。我想知道最佳实践是什么。我使用Jinja的一个原因是:在index.html文件中添加(GAE生成的)登录/登出链接。除此之外,使用它没有其他理由。
3 个回答
Jinja 模板(或者 Django、Mako 等)并不需要放在一个可以公开访问的文件夹里。它们总是通过应用程序中的一个处理器来调用,并在提供给用户之前在应用程序内部进行编译。
通常我们会把这些模板放在一个叫做 /templates 的文件夹里。这个文件夹在 app.yaml 文件中并没有被提到,它只是用来在内部提供模板的。你可以在 GitHub 上找一些基础的应用程序(搜索 'gae boilerplate')。这个链接是一个很简单的例子,使用了 Jinja,可能对你来说是个不错的参考 https://github.com/SoulAuctioneer/notvanillae
好的,这可能解释了第二种情况,你是怎么访问index.html的呢?如果你在处理程序中加上/app,然后你的请求网址是/app/index.html,这样就会从静态文件夹中提供这个文件。
在你的情况中,似乎你的网址没有包含/app,因此它就会走到第二个处理规则,也就是main.app。
不过,因为你把html文件放在了/app里面,appengine会把它当作静态文件来处理。如果你想通过jinja模板来提供这个文件,就不应该把它放在静态文件夹里。
在默认情况下,Python无法访问在App Engine中标记为静态的文件或文件夹。你可以在你的处理程序映射中添加application_readable: true
来解决这个问题,让Python可以访问这些文件。
另一种解决办法是把index.html
文件移出静态文件夹,因为它实际上并不是一个静态文件,而是一个Python用的jinja模板。
application_readable
这是一个可选项。默认情况下,标记为静态文件的文件会被当作静态数据上传,只能提供给最终用户,应用程序无法读取这些文件。如果将这个选项设置为true,这些文件也会被当作代码数据上传,这样你的应用程序就可以读取它们。两种上传都会计入你的代码和静态数据存储资源配额。