【问题标题】:Serve static files based on dynamic URLs with Flask+Nginx?使用 Flask+Nginx 提供基于动态 URL 的静态文件?
【发布时间】:2013-11-16 03:13:15
【问题描述】:

在 Flask 中,如果您将文件放在名为 static/ 的目录中,则任何形式为 http://localhost/static/foo.jpg 的 URL 都将从 static/foo.jpg 提供该文件。

这也可以通过 nginx 配置来完成:

    location /static {
        alias    /var/www/mywebsite/static;
    }

但是,我想做动态 URL 重写。

如果有人请求 URL http://localhost/username/foo.jpg,我想告诉 nginx 从任意 URL 获取静态文件,例如,/var/www/assets/11235/1bcd5.jpg。我希望用户看到一个漂亮的 url,并且我希望该位置对用户是透明的。

有没有简单的方法来做到这一点?理想情况下,我可以做一些事情让 nginx 为文件提供服务。但是,如果 Flask 需要为它提供服务,那也没关系(我的项目还没有用户!)

我在这里错过了什么?

【问题讨论】:

    标签: url-rewriting nginx rewrite flask


    【解决方案1】:

    如果文件可以使用“漂亮”URL中直接引用的名称存储,那么您可以在nginx中进行简单的重写。

    但是,您似乎希望将 URL 路径信息映射到磁盘上的其他表示形式,如 username -> 11235foo.jpg -> 1bcd5.jpg。如果提供的内容应该受到身份验证或会话的保护,那么您可能应该将映射和重写保留在您的 Flask 应用程序中,因为 Flask 提供了这样做的方法。

    如果内容可以被视为公共内容并且只需要完成映射,那么可以将 nginx 配置为获取查询字符串参数,在数据存储中查找它们,然后重写 URL。

    这是一个 example from agentzh,最初发布在 nginx 邮件列表中:

    假设你的 seo uri 是 /baz,真正的 uri 是 /foo/bar。我有 我的本地 mysql“测试”数据库中的下表:

    create table my_url_map(id serial, url text, seo_url);
    insert into my_url_map(url, seo_url)values('/foo/bar', '/baz');
    

    我以这种方式构建我的 nginx 0.8.41:

    ./configure \
    --add-module=/path/to/ngx_devel_kit \
    --add-module=/path/to/set-misc-nginx-module \
    --add-module=/path/to/ngx_http_auth_request_module-0.2 \
    --add-module=/path/to/echo-nginx-module \
    --add-module=/path/to/lua-nginx-module \
    --add-module=/path/to/drizzle-nginx-module \
    --add-module=/path/to/rds-json-nginx-module
    

    另外,我的系统中安装了 lua 5.1.4 和 lua-yajl 库。

    这是我的 nginx.conf 中的核心部分:

    upstream backend {
        drizzle_server 127.0.0.1:3306 dbname=test
        password=some_pass user=monty protocol=mysql;
        drizzle_keepalive max=300 mode=single overflow=ignore;
    }
    
    lua_package_cpath '/path/to/your/lua/yajl/library/?.so';
    
    server {
        ...
    
        location /conv-mysql {
            internal;
            set_quote_sql_str $seo_uri $query_string; # to prevent sql injection
            drizzle_query "select url from my_url_map where seo_url=$seo_uri";
            drizzle_pass backend;
            rds_json on;
        }
    
        location /conv-uid {
            internal;
            content_by_lua_file 'html/foo.lua';
        }
    
        location /jump {
            internal;
            rewrite ^ $query_string? redirect;
        }
    
        # your SEO uri
        location /baz {
            set $my_uri $uri;
            auth_request /conv-uid;
    
            echo_exec /jump $my_uri;
        }
    }
    

    foo.lua 的内容,必不可少的粘合剂:

    local yajl = require('yajl')
    local seo_uri = ngx.var.my_uri
    local res = ngx.location.capture('/conv-mysql?' .. seo_uri)
    if (res.status ~= ngx.HTTP_OK) then
    ngx.throw_error(res.status)
    end
    res = yajl.to_value(res.body)
    if (not res or not res[1] or not res[1].url) then
    ngx.throw_error(ngx.HTTP_INTERNAL_SERVER_ERROR)
    end
    ngx.var.my_uri = res[1].url;
    

    那我们从客户端访问/baz:

    $ curl -i localhost:1984/baz
    HTTP/1.1 302 Moved Temporarily
    Server: nginx/0.8.41 (without pool)
    Date: Tue, 24 Aug 2010 03:28:42 GMT
    Content-Type: text/html
    Content-Length: 176
    Location: http://localhost:1984/foo/bar
    Connection: keep-alive
    
    <html>
    <head><title>302 Found</title></head>
    <body bgcolor="white">
    <center><h1>302 Found</h1></center>
    <hr><center>nginx/0.8.41 (without pool)</center>
    </body>
    </html>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 2019-09-19
      • 2018-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多