0

我花了几个可耻的时间试图解决这个问题无济于事......

问题:

我有一个我正在开发的静态网站,它是通过 Grunt & Assemble 100% 预处理的(如果你熟悉 Jekyll,它本质上是相同的概念)。它还有一个简单的静态博客组件,其中包含各种名称的类别目录。因此,我需要 app.yaml 中的全部内容来适当地路由它们。

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

您似乎无法单独在 app.yaml 中完成这两种情况的计算,因为您只能使用一次 catch-all 目标。

这是我当前 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

因为它只呈现没有匹配 url 模式的路径......

想法:

我的下一个想法是,我可以通过外部 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

祝你好运!

4

2 回答 2

0

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

除非您计划在每次要添加新博客文章时部署您的应用程序,否则我不认为拥有静态处理程序是一个可行的解决方案,因为您无法直接在静态应用程序文件夹中上传内容。

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

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

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

app.error_handlers[404] = handle_404

如果找不到模板,您只需引发 404 并且此处理程序将被调用。

于 2015-04-01T14:28:34.130 回答
0

正如@Anthuin 的回答所指出的那样,您不能在磁盘上写入(或修改)这些index.html文件(也不能动态创建新文件),因此尝试从磁盘读取它们毫无意义——GAE 应用程序可用的“磁盘”是只读的(并且分为仅可用于静态服务的部分和应用程序代码本身可读的部分)。

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

from google.appengine.ext import ndb

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

假设路径不超过 500 个字符且正文不超过 1 兆字节。然后,您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 Cloud Storage 而不是 GAE 数据存储轻松解决;后者可能是一个问题,因为即使 GCS 对象名称也有限制(与 GCS 对象长度不同)——具体来说,一旦名称转换为 utf-8,就有 1024 个字节。这些问题中的任何一个都可能成为您的问题吗?如果是这样,请告诉我们!

于 2015-04-01T17:16:16.447 回答