将查询字符串重写为路径参数

时间:2014-09-10 16:34:42

标签: nginx

我有以下配置的nginx来托管我的图像服务:

    upstream thumbor {
        server localhost:8888;
    }

    server {
        listen       80;
        server_name  my.imageserver.com;
        client_max_body_size 10M;
        rewrite_log on;
        location ~ /images { 
            if ($arg_width="10"){
                rewrite ^/images(/.*)$ /unsafe/$1 last;
            }
            rewrite ^/images(/.*)$ /unsafe/$1 last;
        }
        location ~ /unsafe {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header HOST $http_host;
            proxy_set_header X-NginX-Proxy true;

            proxy_pass http://thumbor;
            proxy_redirect off;
        }

        location = /favicon.ico {
            return 204;
            access_log     off;
            log_not_found  off;
        }
    }

我正在尝试重写以下网址:

http://my.imageserver.com/images/Jenesis/EmbeddedImage/image/jpeg/jpeg/9f5d124d-068d-43a4-92c0-1c044584c54a.jpeg

http://my.imageserver.com/unsafe/Jenesis/EmbeddedImage/image/jpeg/jpeg/9f5d124d-068d-43a4-92c0-1c044584c54a.jpeg

这很容易,当我想允许查询字符串应该转到url的路径时,问题就开始了:

http://my.imageserver.com/images/Jenesis/EmbeddedImage/image/jpeg/jpeg/9f5d124d-068d-43a4-92c0-1c044584c54a.jpeg?width=150&height=200&mode=smart

http://my.imageserver.com/unsafe/150x200/smart/Jenesis/EmbeddedImage/image/jpeg/jpeg/9f5d124d-068d-43a4-92c0-1c044584c54a.jpeg

如果查询字符串的顺序无关紧要,也会更好。

我尝试过使用: $ arg_width但它似乎不起作用。

在ubuntu上使用nginx 1.6.1。

非常感谢帮助。

3 个答案:

答案 0 :(得分:4)

使用查询参数总是很难(Apache也是如此)。

但是在你的例子中:

location ~ /images { 
    if ($arg_width="10"){
        rewrite ^/images(/.*)$ /unsafe/$1 last;
    }
    rewrite ^/images(/.*)$ /unsafe/$1 last;
}

我没有看到2次重写之间有任何区别......所以这可能就是为什么它不起作用。

无论如何你可以尝试类似的东西(基于this thread):

location ^~ /images {
    # get there only if we have a query string
    if ($is_args) {
        set $width ""; 
        set $height "";
        if ($args ~* "(?:^|&)width=([^&]+)") { 
            set $width $1; 
        }
        if ($args ~* "(?:^|&)height=([^&]+)") { 
            set $height $1; 
        }

        # string concatenation using sort of bash syntax
        set $dim "${width}x${height}";
        # maybe we should add a control here on $dim !='x'...

        # the ? here prevent query string from being appended
        rewrite ^/images(/.*)$ /unsafe/$dim/$1? last;
    }
    rewrite ^/images(/.*)$ /unsafe/$1 last;
} 
location ~ /unsafe {
    (...)

答案 1 :(得分:1)

您可以使用arg_name参数,然后摆脱location阻止:

 rewrite ^/images/(.*)$ /unsafe/$1;
 # WARNING: Here we suppose that when we have a "mode" parameter, we have
 # width and height paremeters too
 if ($arg_mode) {
     rewrite ^/unsafe/(.*)$ /images/unsafe/smart/$arg_mode/${arg_width}x${arg_height}/$1 last;
 }

答案 2 :(得分:1)

您需要作为脚本选项来评估输入并构造重写URL。我使用第三方Nginx Lua Module来表示这种逻辑。

在您的计算机上安装Lua或最好LuaJit之后,您需要将模块编译到Nginx中。

或者,您可以安装Openresty Nginx与一些完全将Nginx转换为完整Web应用程序服务器的模块捆绑在一起。 Openresty将在安装过程中处理Lua / LuaJit依赖项。

如果你有这个,这应该为你做的工作:

upstream thumbor {
    server localhost:8888;
}
server {
    [...]
    location ~ ^/images { 
        rewrite_by_lua '
            -- Use local variables to limit their scope to this location block
            local i, j, key, val, args, dimension, modetype, tempheight, replacement

            -- We only go ahead if there are request arguments to start with
            if ngx.var.is_args then
                -- Get the request arguments
                -- These are loaded into a Lua table of the form, { a = 1, b = 2, c = 3 } 
                args = ngx.req.get_uri_args()
                -- Loop through the args table and build our replacement string
                for key, val in pairs(args) do
                    if key == "width" then
                        if tempheight then
                            dimension = val .. "x" .. tempheight
                        else
                            dimension = val 
                        end
                    elseif key == "height" then 
                        if dimension then
                            dimension = dimension .. "x" .. val
                        else
                            tempheight = val 
                        end
                    elseif key == "mode" then 
                        modetype = val 
                    end
                end

                -- Construct the replacement string. 
                replacement = "/unsafe/" .. dimension .. "/" .. modetype .. "/"

                -- Replace "/images/" in the request url with the replacement string. 
                local newuri, n, err = ngx.re.sub(ngx.unescape_uri(ngx.var.request_uri), "/images/", replacement, "io")

                -- If there is a new string, then redirect to the new URL
                if newuri then
                    return ngx.redirect(newuri, 301) 
                end
            end
        ';
    }
    location ~ /unsafe {
        [...]
        proxy_pass http://thumbor;
    }
    [...] 
}