Nginx viết lại quy tắc để thay thế dấu hỏi chuỗi truy vấn bằng dấu gạch dưới


16

Để phản ánh toàn bộ trang web dưới dạng HTML tĩnh,

Tôi muốn chuyển đổi URL như http://example.com/script.php?t=12để http://example.com/script.php_t=12.

Thông báo ?trong URL đang được chuyển đổi thành _.

Điều này sẽ cho phép nginx hoặc apache phục vụ các tệp này từ đĩa dưới dạng HTML thô mà chúng tôi thu được và lưu từ wget- một tệp cho mỗi URL - thay vì dưới dạng tệp PHP.

Có thể làm như vậy thông qua việc viết lại URL Nginx?


Nó chắc chắn có thể, nhưng thực sự kỳ lạ. Bạn muốn nó để làm gì?
Alexey Ten

2
Một vấn đề với cách tiếp cận này là nhiều tham số GET trong một URL có thể theo bất kỳ thứ tự nào và khi bạn thực hiện chuyển đổi này, bạn sẽ thay đổi ngữ nghĩa của URL.
Tero Kilkanen 10/03/2015

Nó để lưu trữ một diễn đàn cũ trong html tĩnh, nhưng vâng, có công việc http://example.com/script.php?a=1&t=3này sẽ cần một số hành động viết lại siêu lạ mắt
Sam Saffron

1
@tero các URL chuỗi truy vấn, trên thực tế, luôn theo cùng một thứ tự. Vì vậy, đây là một vấn đề không.
Jeff Atwood

1
@chx nó để lưu trữ một diễn đàn cũ, vì vậy đối số có thể khác hơn tnhư f, uvv
Arpit Jalan

Câu trả lời:


15

Tôi đã làm việc này bằng cách sử dụng try_files:

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

Điều này sẽ cố gắng tìm một tệp trên đĩa được đặt tên theo mẫu bạn đã cung cấp với "_" thay vì "?".

Cấu hình hơn nữa phụ thuộc vào cách bạn lưu các tệp tĩnh như hình ảnh hoặc biểu định kiểu. Bạn có thể thêm một dự phòng cố gắng đọc chúng mà không cần đĩa dạng chuỗi truy vấn như vậy:

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

1
Cách tiếp cận rất thú vị, liệu điều này có gây ra một ổ đĩa tiềm năng đọc và "không tìm thấy tệp" trên tất cả các URL tiềm năng không?
Jeff Atwood

Từ try_files : "Kiểm tra sự tồn tại của các tệp theo thứ tự được chỉ định và sử dụng tệp tìm thấy đầu tiên để xử lý yêu cầu". Vì vậy, điều này sẽ không gây ra bất kỳ lần đọc đĩa bổ sung nào cho các URL trong câu hỏi của bạn.
Matthias Bayer

1
ok, nếu chúng ta đặt nó vào, location ~ \.php$chúng ta có thể try_fileslàm việc, nhưng nó không hoạt độnglocation /
Jeff Atwood

+1 ví dụ về sử dụng dấu ngoặc nhọn :)
Danila Vershinin

4

Một cái gì đó dọc theo dòng:

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

Bạn để lại ?câu trả lời của tôi được sử dụng.
chx

Bạn có đúng về vấn đề này không? Và của bạn sẽ viết lại tất cả các URL ngay cả khi không có đối số thành biến thể với "_" những gì có thể không mong muốn.
Max Gashkov

Giải pháp từ Matthias với try_files thực sự thích hợp hơn với điều này.
Max Gashkov

chúng ta có thể làm điều đó mà không cần if, khi chúng ta chỉ định một .*mệnh đề chặt chẽ hơn trong param viết lại đầu tiên. Điều này là rất hữu ích!
Jeff Atwood

@JeffAtwood Tôi không nghĩ rằng các mẫu có thể viết lại (cũng như vị trí) có thể áp dụng cho một phần của URL trước khi chỉ có chuỗi truy vấn.
Max Gashkov

1

Tôi không nghĩ bạn sẽ có thể làm điều này với vanilla nginx nhưng nếu bạn sẵn sàng cài đặt mô-đun Lua cho nginx ( http://wiki.nginx.org/HttpLuaModule ), bạn có thể làm điều đó.

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({})
        ';

    }
}

Đã thử nghiệm nó tại địa phương và dường như làm những gì bạn đang tìm kiếm. Nếu bạn muốn giữ các thông số khác được phân tách bằng ký hiệu, hãy thay đổi khối Rewrite_by_lua thành

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

Điều này hoạt động trên nginx / 1.6.2.

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

Nhưng cá nhân tôi sẽ sử dụng try_filesgiải pháp với dự phòng cho một URI gốc nếu có .

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

Ví dụ: nếu bạn có script.phptrên đĩa, nó sẽ thử trước, và sau đó, nếu không có, nó sẽ hoạt động script.php_t=12. try_filescần một phiên bản nginx đủ gần đây.

Và nếu điều này là không đủ, bạn có thể làm như thế này trong một if:

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

Tôi thích điều này, nhưng chúng ta không thể làm cho bit try_files thực sự hoạt động, trong khi việc viết lại không hoạt động. (tốt, nếu bạn thêm một ?phần cuối vào phần viết lại của mình ở đó để các thông số truy vấn không được thêm vào nó ..)
Jeff Atwood

@JeffAtwood try_filessẽ dừng lại $urinếu có khối vị trí khớp với tệp đó hoặc tệp cho nó (yêu cầu không có đối số) - có phải vậy không?
AD7six

@JeffAtwood ?không có hiệu ứng rõ ràng trên các tệp tĩnh, bạn sẽ chỉ thấy một truy vấn bổ sung trong nhật ký truy cập của mình; nếu bạn quan tâm đến nó, chắc chắn thêm một dấu hỏi
sanmai 13/03/2015

0

Các wiki nói

Nếu bạn chỉ định một? khi kết thúc việc viết lại, Nginx sẽ bỏ $ args (đối số) ban đầu.

Vì vậy, sau đó rewrite ^ ${uri}_$args? last;nên làm việc.


nginx không khởi động lại được với bộ quy tắc đó -rewrite ^ $uri_$args? last;
Jeff Atwood

Đã sửa. Các biến-$ -ble-over-the-biến có cảm giác giống như PHP mà tôi biết bạn chỉ yêu thích.
chx

ngay cả với phiên bản sửa đổi, nginx không khởi động lại
Jeff Atwood

0

Các câu trả lời được đề xuất ở trên nên hoạt động. Tuy nhiên, bạn thấy URL của bạn trở nên nhạy cảm như thế nào. Bởi vì nginx cố gắng kiểm tra xem tên tệp có tồn tại trên máy chủ không, bất kỳ tham số bổ sung nào cũng sẽ loại bỏ nó.

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

Đề nghị của tôi là để nguyên URL và định tuyến nó đến tệp đúng với php. Bạn có quyền truy cập vào ttham số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.