在Google App Engine之外,使用webapp2提供样式表

4

我已成功使用webapp2/jinja2和Paste服务器部署了一个应用程序,但是在提供静态样式表方面遇到了问题。

我通过这个方法成功访问了静态文件,并实现了一个StaticFileHandler,该处理程序是通过一些Google的技巧找到的:

import os
import mimetypes
import webapp2
import logging

class StaticFileHandler(webapp2.RequestHandler):
    def get(self, path):
        abs_path = os.path.abspath(os.path.join(self.app.config.get('webapp2_static.static_file_path', 'static'), path))
        if os.path.isdir(abs_path) or abs_path.find(os.getcwd()) != 0:
            self.response.set_status(403)
            return
        try:
            f = open(abs_path, 'r')
            self.response.headers.add_header('Content-Type', mimetypes.guess_type(abs_path)[0])
            self.response.out.write(f.read())
            f.close()
        except:
            self.response.set_status(404)

我的主要应用程序路由如下:

app = webapp2.WSGIApplication([('/', HelloWorld),
                               (r'/display', DisplayHandler),
                               (r'/static/(.+)', StaticFileHandler)
                              ], debug=True)

我的CSS文件存放在应用根目录下的一个文件夹中:/static/css/main.css。
我可以通过直接URL访问该文件,甚至将其链接为样式表,但是样式不会应用。有什么想法吗?是否还有其他提供样式表服务的方法?是否有一种类似于GAE的app.yaml实现方式?
3个回答

0
self.response.headers.add_header('Content-Type', mimetypes.guess_type(abs_path)[0])
self.response.headers['Content-Type'] = mimetypes.guess_type(abs_path)[0]

0

我没有使用 GAE,而是在自己的服务器上运行 webapp2,并使用 paste 进行提供服务。 - Mnemon
嗯...看起来它们被作为“Content-Type:text/html; charset=utf-8, text/css”提供。 - Mnemon
1
好的,我想我解决了这个问题。上面的 StaticFileHandler 添加了一个“Content-Type”标题,但 Paste 服务器似乎自动将 text/html 分配给所有页面。因此上面是 content type。将处理程序更改为将“content-type”标题更改为 mimetypes.guess_type 而不是添加到默认标题。 - Mnemon

0

向@Mnemon致敬,感谢您解决了我的问题。我想给您点赞,但我不能这样做。您让我相信,如果不是唯一的webapp2方式而没有GAE,那么至少这是一种可行的方法。

此外,我可以贡献您的解决方案现在可以通过"pip install webapp2_static"进行安装,来自pipi---一个似乎使用他真实姓名的作者...您肯定知道。我发现有用的其他webapp2文档可以在这里找到。

我正在使用paste在Linux桌面开发服务器上实现您的代码,您也使用了它:

def main():
    from paste import httpserver
    httpserver.serve(app, host='127.0.0.1', port='8080')

但是,根据您上面的代码(似乎与webapp2_static.py文件完全相同),我发现将我的CSS文件放在名为应用程序根目录中的static文件夹中并不像您所说的那样有效。

例如,我有/home/user/proj/public_html/app/app.py,其中py文件包含您的代码以及我的超简单网站的其他“视图”。 (我不知道如何真正粘贴,因此可能现在public_html只是作为参考放在那里,以便我在上传东西到生产服务器时不会感到困惑。)

因此,如果我将css样式表放入名为/static的文件夹中,则如果我将/static作为/app或/public_html的子目录之一放入,则发现两个位置都无法工作; 我必须将其作为/proj的子目录。

我没有预料到这一点,但对我来说,解决方法是更改app.configure.get(...,'static')调用中的默认“static”为“public_html / app / static”。 然后它可以在/app内部使用/static文件夹。

同样地,将 pipi 代码中的默认“static”替换为'./app/static/'也无用;我发现我需要使用'./public_html/app/static'(或者可能仅是'/public_html/app/static'或者public_html/app/static...我忘了...其中一个是有效的)。

我测试了你计算abs_path的方法,并在下面的代码中进行了改进,在我的一个应用程序py文件中,我在顶部放置了以下内容,抛弃了你的方法,选择了更加 Django 风格的方法:

STATIC_DIR = os.sep + 'tostatic' + os.path.abspath(os.path.dirname(__file__)) + os.sep + 'static'

然后在我想要添加CSS的页面上,例如我的主页,我放置了一个非常易读的代码:

<link href="{{STATIC_DIR}}/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">

对于生成我的主页的“视图”,我有以下代码(env是一个jinja2环境对象,它需要一个模板加载器作为参数):

class Home(webapp2.RequestHandler):
    def get(self):
        template = env.get_template('index.html')
        template_values = {'STATIC_DIR': STATIC_DIR }
        self.response.write(template.render(template_values))

最后,URL路由如下:

app = webapp2.WSGIApplication(
[
(r'/', Home),
(r'/tostatic/(.+)', StaticView),
], debug=True)

静态文件服务的视图现在是:

class StaticView(webapp2.RequestHandler):
    def get(self, path):
        path = os.sep + path
        try:
            f = open(path, 'r')
            self.response.headers.add_header('Content-Type', mimetypes.guess_type(path)[0])
            self.response.out.write(f.read())
            f.close()
        except Exception, e:
            print 'Problem in StaticView:', e
            self.response.set_status(404)

最后一点,我对您的方法所遇到的问题是,像我这样的入门者和其他人一样,与URL与文件系统的传统关联的离开有关。在您的方法中,“static”既是一个子目录,也是URL前面斜杠之间的字符串,告诉解释器要运行哪个视图(即webapp2.RequestHandler子类)。您将/static从其余的URL中提取出来,稍后再硬编码回去。当决定在标记中放入href时,HTML页面编码器必须记住这种重复性。使用{{STATIC_DIR}}模板变量方法,就清楚了该怎么做。而且重新定义静态文件的位置很容易 - 只需要更改STATIC_DIR声明即可。
我发现self.response.set_status(404)在Firebug中显示,但在Firefox中没有显示。显然,使用webapp2必须提供并提供自己的HTTP状态代码页面。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接