Google App Engine:使用高级路由正确配置静态站点

时间:2015-04-01 13:56:50

标签: python google-app-engine webapp2 google-cloud-platform app.yaml

我花了好几个小时试图解决这个问题无济于事......

问题:

我有一个我正在开发的静态网站,通过Grunt& amp;进行100%预处理。组装(如果您熟悉Jekyll,它基本上是相同的概念)。它还有一个简单的静态Blog组件,它包含各种名称的类别目录。因此,我需要在我的app.yaml中使用catch-all来适当地路由它们。

但是,我还希望有一个自定义错误页面来代替标准GAE页面状态。

似乎你无法单独在app.yaml中完成这两种方案的计算,因为你只能使用一次全能目标。

这是我当前app.yaml中的逻辑

- url: (.*)/
  static_files: dist\1/index.html
  upload: dist/index.html
  expiration: "15m"

- url: /(.*)
  static_files: dist/\1/index.html
  upload: dist/(.*)/index.html
  expiration: "15m"

这非常适合我的用例,因为它将任何路径路由到索引文件(如果它存在于当前目录中)。但是,因为它使用了全能,所以我不能再将其用于以下内容

- url: /(.*)
  static_files: custom_error.html

或依赖

error_handlers:
  - file: custom_error.html

因为它只渲染没有匹配网址模式的路径......

思路:

我的下一个想法是,我可以通过外部Python脚本进行一些高级路由来实现这一目标

- url: /.*
  script: main.app

但在尝试了各种不同的设置之后,我还没有找到实现这一目标的方法。

我所使用的面包屑痕迹的一个例子是

import os
import webapp2
import jinja2

# vars
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader('jinja'), extensions=['jinja2.ext.autoescape'], autoescape=True)

class mainHandler(webapp2.RequestHandler):
    def get(self):
        if (an-index-file-exists-in-this-directory)
            # follow the same static file logic as the app.yaml
            # static_files: dist/\1/index.html
            # upload: dist/(.*)/index.html
        else:
            template = jinja_environment.get_template('404/index.html')
            context =  {
                'page_title': '404',
            }
            self.response.out.write(template.render(context))
            self.error(404)

app = webapp2.WSGIApplication([
    ('/.*', mainHandler)
], debug=False)

我甚至不确定将它放入外部python文件是否有助于解决问题,但这是我对它的尴尬。

当您的追赶模式被用于其他重要目的时,有没有人对如何实现自定义错误页面有任何想法?

更新:已解决

好的我终于搞清楚了,但是因为Stack Overflow认为我不够酷以回答我自己的问题(低点阈值?),我在这里发布了解决方案:

https://gist.github.com/dustintheweb/c5e6e4ee1a64d50d7f87

祝你好运!

2 个答案:

答案 0 :(得分:0)

我认为你不能让你的第一个解决方案像这样工作,因为你说它会匹配每个模式,错误处理程序永远不会匹配。

除非您计划在每次添加新博客帖子时部署应用程序,否则我认为无论如何都不能使用静态处理程序,因为您无法直接在静态应用程序文件夹中上传内容。

但您可以将内容上传到GCS(例如)并从WSGIApplication中检索它。

然后,这个WSGIApplication可以有一个自定义错误处理程序:

def handle_404(request, response, exception):
   response.write("my custom error 404")

app.error_handlers[404] = handle_404

如果找不到模板,你只需要引发404,这个处理程序就会被调用。

答案 1 :(得分:0)

正如@ Anthuin的回答指出的那样,你不能(也不能修改)磁盘上的那些index.html文件(也不能动态创建新的文件),所以试一试没有意义从磁盘读取它们 - GAE应用程序可用的“磁盘”是只读的(并且在仅适用于静态服务的部分和应用程序代码本身可读的部分之间分开)。 / p>

相反,除非index.html文件很大(我不太可能,我怀疑),否则我会将它们保存在您应用的GAE 数据存储区中。一个非常简单的模型:

from google.appengine.ext import ndb

class Indx(ndb.Model):
    body = ndb.TextProperty()

假设路径不超过500个字符且正文达到兆字节。然后,您的MainHandler变得非常简单:

class MainHandler(webapp2.RequestHandler):

    def get(self):
        key = ndb.Key('Indx', self.request.path)
        ent = key.get()
        if ent:
            self.response.write(ent.body)
        else:
            # your existing 404-returning code goes here

此脚本的app.yaml路由/.*以及您的app =代码无需更改。

现在,唯一剩下的就是,您希望如何编写或修改这些index.html文件(现在是数据存储区实体)?我不知道,因为只要他们 成为您的应用程序无法编写或修改它们的文件。无论如何,现在他们在数据存储中,写作也变得非常简单:

def write_indx(path, body):
    ent = Indx(body=body, id=path)
    ent.put()

请注意,没有真正的“修改” - 可能“修改”某些index.html的“正文”,您实际上会读取前一个,创建一个新的body字符串,并使用上述write_indx重写实体。

潜在问题包括:超过1 MB的尸体;和,超过500个字符的键(路径)。正如@Anhuin建议的那样,前者可以通过使用Google云端存储而不是GAE数据存储来轻松解决;后者可能是个问题,因为即使GCS对象名称也有限制(与GCS对象长度不同) - 具体来说,一旦名称转换为utf-8,就会有1024个字节。这些问题中的任何一个都可能成为您的问题吗?如果是这样,请告诉我们!