【问题标题】:Google App Engine: Correctly configuring a static site with advanced routingGoogle App Engine:使用高级路由正确配置静态站点
【发布时间】:2015-06-06 05:09:32
【问题描述】:

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

问题:

我正在开发一个静态网站,它是通过 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

祝你好运!

【问题讨论】:

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


    【解决方案1】:

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

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

    from google.appengine.ext import ndb
    
    class Indx(ndb.Model):
        body = ndb.TextProperty()
    

    假设路径不超过 500 个字符,正文不超过 1 MB。然后,您的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 个字节。这些问题中的任何一个都可能成为您的问题吗?如果有,请告诉我们!

    【讨论】:

    • 所以,是的,澄清一下,我在这里没有使用传统意义上的 GAE,只是将其视为一堆预处理静态文件的网络托管(通过 Grunt 等在本地组装,然后推到托管)。我会试一试并报告 - 谢谢
    • 不幸的是,我无法让它工作。部署/页面刷新后,我只收到默认服务器错误,并且应用引擎日志没有显示异常。这是我的代码,我错过了什么吗? app.yaml : pastebin.com/ftVFc23r --- main.py : pastebin.com/haEN6vrn
    • 另外,如果我在某些方面不清楚,这个应用程序的核心只是一个静态站点,只会在每次部署时更新。它将有各种小的动态部分,但它们是外部组件。
    • 好吧,我的 ^ 用户错误(该死的缩进错误!)。所以通过它运行它似乎仍然没有按预期工作(页面加载但它只是拍摄到错误模板)。我将其追溯到 ent 拉取值为 none。有什么想法吗?
    • @dustintheweb,您在哪里/何时编写 Indx 实体?检查控制台以查看您的数据存储区中的实际内容——当然,如果您从未在其中放置任何内容,它将是空的(然后key.get 将始终返回None)。
    【解决方案2】:

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

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

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

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

    def handle_404(request, response, exception):
       response.write("my custom error 404")
    
    app.error_handlers[404] = handle_404
    

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

    【讨论】:

    • 这绝对可以生成自定义错误/模板,但是如果我更改 app.yaml 的全部内容以加载 python 脚本,那么我将需要想出一种方法python来模仿它为我做的事情并将其置于某种条件下。这就是我在上面的第二个例子中被难住的地方:/
    • 您想在哪里存储您的博客文章?那是我不明白的部分,你为什么需要这个通用的静态处理程序?
    • 这是一个静态站点(想想 jekyll 或 assemble),所以它们只是单独的 index.html 文件 - 每个路径一对一匹配。所以 /blog 引用 /blog/index.html,/blog/foo/bar/this-is-a-post 引用 /blog/foo/bar/this-is-a-post/index.html -- 等等
    猜你喜欢
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 2021-05-23
    • 2016-05-15
    • 2016-06-06
    • 2012-11-15
    • 2015-01-01
    相关资源
    最近更新 更多