Google App Engine:使用高级路由正确配置静态站点
Google App Engine: Correctly configuring a static site with advanced routing
我花了几个可耻的时间试图解决这个问题,但无济于事...
问题:
我正在开发一个静态网站,该网站 100% 通过 Grunt 和 Assemble 进行了预处理(如果您熟悉 Jekyll,它本质上是相同的概念)。它还有一个简单的静态博客组件,其中包含各种名称的类别目录。因此,我需要 app.yaml 中的包罗万象来适当地路由它们。
但是,我也希望有一个自定义错误页面来代替标准的 GAE 页面状态。
app.yaml两个场景你好像无法单独完成统计,因为你只能使用一次catch-all target。
这是我目前的逻辑app.yaml
- url: (.*)/
static_files: dist/index.html
upload: dist/index.html
expiration: "15m"
- url: /(.*)
static_files: dist//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//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
祝你好运!
我不认为你可以让你的第一个解决方案像那样工作,因为正如你所说它将匹配所有模式并且错误处理程序永远不会匹配。
并且除非您计划在每次要添加新博客 post 时部署您的应用程序,否则我不认为拥有静态处理程序是一个可行的解决方案,因为您无法直接在您的网站上上传内容静态应用程序文件夹。
但是您可以将内容上传到 GCS(例如)并从 WSGIApplication 检索它。
然后这个 WSGIApplication 可以有一个自定义错误处理程序:
def handle_404(request, response, exception):
response.write("my custom error 404")
app.error_handlers[404] = handle_404
如果未找到模板,您只需引发 404 并调用此处理程序。
正如@Anthuin 的回答所指出的,您不能写入(也不能修改)磁盘上的那些index.html
文件(也不能动态创建新文件),所以它尝试从磁盘 read 它们毫无意义——GAE 应用程序可用的 "disk" 是只读的(并且在仅可用于静态服务的部分和应用程序代码本身可读的部分)。
相反,除非 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
文件(现在是数据存储实体)?我不知道,因为只要它们 是 文件,您的应用就不可能写入或修改它们。不管怎么说,既然都在data store里了,写起来也变得很简单了:
def write_indx(path, body):
ent = Indx(body=body, id=path)
ent.put()
请注意,没有真正的 "modify" -- 可能 "modify" 一些 index.html
的 "body",你实际上会阅读上一个,做一个新建body
字符串,并用上面的write_indx
.
改写实体
潜在问题包括:正文超过 1 MB;以及超过 500 个字符的键(路径)。正如@Anhuin 建议的那样,可以通过使用 Google Cloud Storage 而不是 GAE 数据存储轻松解决前者问题;后者可能是一个问题,因为即使是 GCS 对象名称也有限制(不同于 GCS 对象长度)——具体来说,一旦名称转换为 utf-8,则为 1024 字节。这些问题中的任何一个对您来说可能是个问题吗?如果是这样,请告诉我们!
我花了几个可耻的时间试图解决这个问题,但无济于事...
问题:
我正在开发一个静态网站,该网站 100% 通过 Grunt 和 Assemble 进行了预处理(如果您熟悉 Jekyll,它本质上是相同的概念)。它还有一个简单的静态博客组件,其中包含各种名称的类别目录。因此,我需要 app.yaml 中的包罗万象来适当地路由它们。
但是,我也希望有一个自定义错误页面来代替标准的 GAE 页面状态。
app.yaml两个场景你好像无法单独完成统计,因为你只能使用一次catch-all target。
这是我目前的逻辑app.yaml
- url: (.*)/
static_files: dist/index.html
upload: dist/index.html
expiration: "15m"
- url: /(.*)
static_files: dist//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//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
祝你好运!
我不认为你可以让你的第一个解决方案像那样工作,因为正如你所说它将匹配所有模式并且错误处理程序永远不会匹配。
并且除非您计划在每次要添加新博客 post 时部署您的应用程序,否则我不认为拥有静态处理程序是一个可行的解决方案,因为您无法直接在您的网站上上传内容静态应用程序文件夹。
但是您可以将内容上传到 GCS(例如)并从 WSGIApplication 检索它。
然后这个 WSGIApplication 可以有一个自定义错误处理程序:
def handle_404(request, response, exception):
response.write("my custom error 404")
app.error_handlers[404] = handle_404
如果未找到模板,您只需引发 404 并调用此处理程序。
正如@Anthuin 的回答所指出的,您不能写入(也不能修改)磁盘上的那些index.html
文件(也不能动态创建新文件),所以它尝试从磁盘 read 它们毫无意义——GAE 应用程序可用的 "disk" 是只读的(并且在仅可用于静态服务的部分和应用程序代码本身可读的部分)。
相反,除非 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
文件(现在是数据存储实体)?我不知道,因为只要它们 是 文件,您的应用就不可能写入或修改它们。不管怎么说,既然都在data store里了,写起来也变得很简单了:
def write_indx(path, body):
ent = Indx(body=body, id=path)
ent.put()
请注意,没有真正的 "modify" -- 可能 "modify" 一些 index.html
的 "body",你实际上会阅读上一个,做一个新建body
字符串,并用上面的write_indx
.
潜在问题包括:正文超过 1 MB;以及超过 500 个字符的键(路径)。正如@Anhuin 建议的那样,可以通过使用 Google Cloud Storage 而不是 GAE 数据存储轻松解决前者问题;后者可能是一个问题,因为即使是 GCS 对象名称也有限制(不同于 GCS 对象长度)——具体来说,一旦名称转换为 utf-8,则为 1024 字节。这些问题中的任何一个对您来说可能是个问题吗?如果是这样,请告诉我们!