Nginx重写规则以下划线替换查询字符串问号


16

为了将整个网站镜像为静态HTML,

我想将URL转换http://example.com/script.php?t=12http://example.com/script.php_t=12

注意?URL正在被转换为_

这将允许nginx或apache从磁盘上将这些文件作为我们从中获取并保存的原始HTML wget(每个URL一个文件)而不是PHP文件。

是否可以通过Nginx URL重写来做到这一点?


当然有可能,但是真的很奇怪。你要干嘛
Alexey 2015年

2
这种方法的一个问题是URL中的多个GET参数可以以任何顺序排列,并且在进行此转换时,将更改URL的语义。
Tero Kilkanen 2015年

它用于以静态html归档旧论坛,但是,http://example.com/script.php?a=1&t=3要进行此项工作,就需要采取一些超级幻想的重写措施
Sam Saffron

1
实际上,@ string始终是相同顺序的。因此,这不是一个问题。
杰夫·阿特伍德

1
@chx它是用于存档的旧论坛,所以参数可以比其他tfu等等
Arpit惹

Answers:


15

我使用try_files进行此工作:

location / {
    try_files "${uri}_${args}" 404.html;
}

这将尝试在磁盘上找到一个以您提供的“ _”(而不是“?”)模式命名的文件。

进一步的配置取决于如何保存静态文件(例如图像或样式表)。您可以添加一个后备尝试在没有查询字符串形式磁盘的情况下读取它们,如下所示:

location / {
    try_files "${uri}_${args}" $uri 404.html;
}

1
非常有趣的方法,这是否会导致潜在的磁盘读取和所有潜在URL上的“找不到文件”?
杰夫·阿特伍德

来自try_files:“按指定顺序检查文件是否存在,并使用找到的第一个文件进行请求处理”。因此,这不会导致对您的问题中的URL进行任何其他磁盘读取。
马提亚斯·拜耳

1
好吧,如果我们把它放进去就location ~ \.php$可以开始try_files工作,但是它不能工作location /
Jeff Atwood

+1例如使用花括号:)
Danila Vershinin

4

大致情况:

location ~ \.php$ {
  # only rewrite URL's with args
  if ($args != '') {
    rewrite .* "${uri}_${args}?" last;
  }
}

您忽略了?我使用的答案。
chx 2015年

您对?的回答是正确的,至于您的回答,我花了一些时间在真实的服务器上对其进行测试,因此直到我发布我的信息,我才看到您的答案。而且,即使不带参数“ _”的变体,您的URL也将全部重写,这可能是不希望的。
Max Gashkov

Matthias使用try_files的解决方案实际上对此更为可取。
Max Gashkov

当我们.*在第一个重写参数中指定一个更严格的子句时,就可以不用if了。这非常有帮助!
Jeff Atwood

@JeffAtwood我认为这是不可能的– nginx重写(以及位置)模式应仅在查询字符串之前应用于URL的一部分。
Max Gashkov

1

我认为您无法使用香草nginx做到这一点,但是如果您愿意为nginx安装Lua模块(http://wiki.nginx.org/HttpLuaModule),则可以做到。

server {
    server_name so.dev;
    listen 80;

    location / {

        root /tmp;

        rewrite_by_lua '
            local uri = ngx.var.uri
            local params = ngx.req.get_uri_args(0)

            for key, value in pairs(params) do
                uri = string.format("%s_%s=%s", uri, key, value)
            end

            ngx.req.set_uri(uri)
            ngx.req.set_uri_args({})
        ';

    }
}

在本地进行了测试,似乎可以满足您的需求。如果要使其他参数与号分隔,请将rewrite_by_lua块更改为

local uri = ngx.var.uri
local param_string = ""
local params = ngx.req.get_uri_args(0)
local separator = ""

for key, value in pairs(params) do
    param_string = param_string .. separator .. key .. "=" .. value
    separator = "&"
end

ngx.req.set_uri(uri .. "_" .. param_string)
ngx.req.set_uri_args({})

1

这适用于nginx / 1.6.2。

rewrite ^/.*\.php$ "${uri}_${args}";

但是个人而言,如果有的话,我将使用try_files具有原始URI的后备解决方案。

try_files $uri "${uri}_${args}";

例如,如果script.php磁盘上有磁盘,它将首先尝试使用它,然后,如果没有磁盘,则将继续使用script.php_t=12try_files需要最新版本的Nginx。

如果这还不够,您可以在内执行以下操作if

return 301 "${uri}_${args}";

我喜欢这样,但是我们无法使try_files位真正起作用,而重写确实起作用。(好吧,如果您?在重写的末尾添加a ,这样就不会在其中添加查询参数。)
Jeff Atwood

@JeffAtwood try_files将在$uri某个位置块或与其匹配的文件(没有get args的请求)相匹配的地方停下来-是这样吗?
AD7six

@JeffAtwood ?对静态文件没有可见的影响,您只会在访问日志中看到一个额外的查询;如果您在乎,请务必添加一个问号
sanmai 2015年

0

维基说:

如果指定?在重写结束时,Nginx将删除原始的$ args(参数)。

因此,然后rewrite ^ ${uri}_$args? last;应该工作。


nginx无法使用该规则集重新启动rewrite ^ $uri_$args? last;
Jeff Atwood

固定。$ -the-bleeds-the-variables感觉就像PHP,我知道您只是喜欢。
chx 2015年

即使使用修订版,nginx也无法重新启动
Jeff Atwood

0

上面建议的答案应该起作用。但是,您会看到URL变得多么敏感。因为nginx尝试首先检查文件名是否在服务器上,所以任何额外的参数都会将其丢弃。

http://example.com/script.php?t=12 // works 
http://example.com/script.php?t=12&_utm=twitter // not work

我的建议是保留URL不变,并使用php将其路由到正确的文件中。您可以访问该t参数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.