Nginx 基於查詢字串重新導向

Nginx 基於查詢字串重新導向

我正在將舊網站連結遷移到新網站,它將使用相同的網域

這是一些舊連結。

舊連結 新連結
http://example.com/?p=contact /接觸
http://example.com/?p=static&id=career /職業
http://example.com/?p=static&id=about /關於
http://example.com/?p=catalog&action=images&cat_id=1 /產品類別/類別-slug-1
http://example.com/?p=catalog&action=images&cat_id=2 /產品類別/類別-slug-2
http://example.com/?p=catalog&action=viewimages&pid=1&cat_id=1 /產品/產品-slug-1
http://example.com/?p=catalog&action=viewimages&pid=2&cat_id=3 /產品/產品-slug-2

新的產品頁面的URL中沒有id,所以我手動列出了所有這些,總共只有5個類別和20個產品頁面。

這是我在知道不支援嵌套 if 之前嘗試過的方法。

location / {
    if ($arg_p = contact) { return 301 /contact; }
    if ($arg_p = static) { 
        if ($arg_id = career) { return 301 /career; }
        # other static pages redirect to /about
        return 301 /about;
    }

    if ($arg_p = catalog) {
        if ($arg_action = images) {
            if ($arg_cat_id = 1) { return 301 /product-category/category-slug-1; }
            if ($arg_cat_id = 2) { return 301 /product-category/category-slug-2; }
            # other unlisted categories should redirect to /product-categories
            return 301 /product-categories;
        }
        if ($arg_action = viewimages) {
            if ($arg_pid = 1) { return 301 /product/product-slug-1/; }
            if ($arg_pid = 2) { return 301 /product/product-slug-2/; }
        }
        # other unlisted links defaults to /products
        return 301 /products;
    }
}

配置應該是什麼?

答案1

你可以用幾個連結來做到這一點map塊。這是一個想法:

map $arg_p $url_p {
    contact    /contact;
    static     $url_id;
    catalog    $url_action;
    # default value will be an empty string
}

map $arg_id $url_id {
    career     /career;
    about      /about;
    # other static pages redirect to /about
    default    /about;
}

map $arg_action $url_action {
    images     $url_cat_id;
    viewimages $url_pid;
    # other unlisted actions defaults to /products
    default    /products;
}

map $arg_cat_id $url_cat_id {
    1          /product-category/category-slug-1;
    2          /product-category/category-slug-2;
    # other unlisted categories should redirect to /product-categories
    default    /product-categories;
}

map $arg_pid $url_pid {
    1          /product/product-slug-1;
    2          /product/product-slug-2;
    # other unlisted products defaults to /products
    default    /products;
}

server {
    listen ...
    server_name ...
    ...
    if ($url_p) { # if '$url_p' variable is not an empty string
        return 301 $url_p;
    }
    location / {
        ...
    }
    ...
}

有些map區塊可以縮短,例如,假設您有 3 個靜態頁面/career/clients「預設」頁面/about、5 個類別和 45 個產品:

map $arg_id $url_id {
    ~^(career|clients)$        /$1;
    default                    /about;
}

map $arg_cat_id $url_cat_id {
    ~^([1-5])$                 /product-category/category-slug-$1;
    default                    /product-categories;
}

map $arg_pid $url_pid {
    ~^([1-9]|[1-3]\d|4[0-5])$  /product/product-slug-$1;
    default                    /products;
}

更新

OP 聲明他不能使用map指令,因為他無權存取完整的 nginx 配置,而只能server阻止內容。雖然以前的解決方案要優雅得多(並且在性能方面應該更有效),但可以僅使用if區塊來執行相同的操作:

if ($arg_p = contact) { return 301 /contact; }

if ($arg_p = static) { set $page static_$arg_id; }
if ($page = static_career) { return 301 /career; }
if ($page) { return 301 /about; } # anything that is not 'career' redirected to '/about'

if ($arg_p = catalog) { set $action $arg_action; }

if ($action = images) { set $page category_$arg_cat_id; }
if ($page = category_1) { return 301 /product-category/category-a; }
if ($page = category_2) { return 301 /product-category/category-b; }
# ... other categories
if ($action = images) { return 301 /product-categories; } # unlisted category specified

if ($action = viewimages) { set $page product_$arg_pid; }
if ($page = product_1) { return 301 /product/product-a; }
if ($page = product_2) { return 301 /product/product-b; }
# ... other products
if ($action = viewimages) { return 301 /products; } # unlisted product specified

# if you want to process any unlisted action in some special way
# if ($action) { ... } # 'action' query argument neither 'images' nor 'viewimages'

該片段可以放置在serverlocation上下文中。

答案2

我最終得到了這個解決方案。

location / {
  if ($arg_p = contact) { return 301 /contact; }
  if ($args ~ p=static&id=career) { return 301 /career; }
  if ($arg_p = static) { return 301 /about; }
  if ($args ~ p=catalog&action=images&cat_id=1) { return 301 /product-category/category-a; }
  if ($args ~ p=catalog&action=images&cat_id=2) { return 301 /product-category/category-b; }
  # and other cat_id
  if ($args ~ p=catalog&action=viewimages&pid=1&cat_id=1) { return 301 /product/product-a; }
  if ($args ~ p=catalog&action=viewimages&pid=2&cat_id=1) { return 301 /product/product-b; }
  # and other pid
  if ($arg_p = catalog) { return 301 /products; } #other p=catalog defaults to /products
  try_files $uri $uri/ /index.php$is_args$args;
}

它可以工作,但它無法處理查詢參數順序未寫在下面的情況,例如/?id=career&p=static(id 和 p 互換)

另外cat_idin也p=catalog&action=viewimages沒有使用,但是當我cat_id從規則中刪除 時,p=catalog&action=viewimages&pid=10總是重定向到p=catalog&action=viewimages&pid=1,所以我不得不將cat_id.

如果有人有更好的想法來處理查詢參數的動態順序,請隨時發布作為答案。如果有效,我會將其標記為已接受。

編輯:有關動態訂單查詢參數和更清晰的 if,請參閱伊凡·沙茨基的回答

相關內容