Điểm:0

Sử dụng một phần của URI làm số cổng cho lệnh nginx proxy_pass

lá cờ cn

Đây là cấu hình nginx của tôi:

người phục vụ {
        nghe 443 ssl;
        server_name sub.example.fr ;
        vị trí ~ ^/ (123[0-9])$ { # công việc regex
                #rewrite ^/[0-9]{4}(.*)$ $1 cuối cùng; # không hoạt động, với lần cuối hoặc ngắt
                #proxy_pass http://localhost:$1/; # thêm dấu gạch chéo không cho phép
                proxy_pass http://localhost:$1;
        }
}

tôi muốn chuyển tiếp https://sub.example.fr/1234 đến http://localhost:1234, vì vậy tôi chỉ muốn trích xuất số cổng, xóa nó khỏi url và sử dụng nó vào proxy_pass.

Điểm:2
lá cờ gr

Trước hết, của bạn ^/(123[0-9])$ regex sẽ chỉ khớp /1234 URI (hoặc /1230, /1231, v.v.) nhưng không phải là /1234/một số/đường dẫn vì bạn đang sử dụng $ neo cuối chuỗi. Tôi cho rằng đó không phải là lỗi mà là giải pháp thiết kế. Nếu không, để phù hợp với cả hai /1234/1234/một số/đường dẫn (nhưng không giống như /12345), bạn có thể sử dụng cách thay thế: ^/(123[0-9])(?:/|$) (Tôi đang sử dụng một nhóm không chụp (?:...) ở đây, vì nó được coi là có hiệu suất tốt hơn một chút so với nhóm chụp).

Cấu hình của bạn có rất nhiều lỗi khác nhau. Hãy xem xét từng người một.

Sai lầm #1: Không chính xác viết lại ... cuối cùng; cách sử dụng.

Thật vậy, bạn không thể chỉ định một URI cho proxy_pass ngược dòng giống như bạn đang cố gắng thực hiện với dấu gạch chéo

proxy_pass http://localhost:$1/; # thêm dấu gạch chéo không cho phép

bên trong các vị trí khớp regex (cũng như bên trong các vị trí được đặt tên) và cách duy nhất để thay đổi URI sẽ được chuyển đến phần phụ trợ là sử dụng viết lại chỉ thị. Tuy nhiên, cách đúng để thay đổi URI bên trong địa điểm khối để xử lý nó sau trong cùng một vị trí là sử dụng viết lại... phá; từ viết lại ... cuối cùng; sẽ buộc nginx tìm kiếm một vị trí mới cho URI đã viết lại. Điều đó có nghĩa là chúng ta cần sử dụng nghỉ cờ cho viết lại chỉ thị:

viết lại ^/[0-9]{4}(.*)$ $1 break;

Hãy coi chừng! Không có chỉ thị từ ngx_http_rewrite_module sẽ được thực hiện sau viết lại... phá; (hoặc đơn giản nghỉ;) chỉ thị (cập nhật: sau một số thử nghiệm, ngược lại với những gì được nói trong tài liệu, hóa ra nó chỉ đúng với nghỉ chỉ đạo nhưng không phải là viết lại ... phá vỡ one, ít nhất là cho OpenResty 1.17.8.2 dựa trên lõi nginx 17.8).

Sai lầm #2: Bạn nên trích dẫn bất kỳ chuỗi nào chứa dấu ngoặc nhọn nếu không chúng sẽ được coi là khối cấu hình nginx.

Lệnh trước sẽ cho chúng tôi lỗi sau:

nginx: [emerg] chỉ thị "viết lại" không bị chấm dứt bởi ";"

Để loại bỏ lỗi này, chúng tôi cần mã hóa mẫu biểu thức chính quy của mình do việc sử dụng dấu ngoặc nhọn:

viết lại "^/[0-9]{4}(.*)$" $1 break;

Sai lầm #3: Các ảnh chụp được đánh số bị ghi đè bất cứ khi nào biểu thức chính quy được đánh giá.

Giả sử bạn có URI là /1234:

vị trí ~ ^/(123[0-9])$ {
    # Ở đây giá trị của biến '$1' là "1234"
    viết lại "^/[0-9]{4}(.*)$" $1 break;
    # Ở đây giá trị của biến '$1' là một chuỗi rỗng!
    proxy_pass http://localhost:$1; # Sẽ không có cổng cho chỉ thị 'proxy_pass'
}

Bạn có thể lưu nó $1 giá trị trước khi quy tắc viết lại đánh giá biểu thức chính quy của chính nó bằng cách sử dụng bộ chỉ thị:

vị trí ~ ^/(123[0-9])$ {
    đặt cổng $1;
    viết lại "^/[0-9]{4}(.*)$" $1 break;
    proxy_pass http://localhost:$port;
}

hoặc tốt hơn là sử dụng nhóm chụp có tên:

vị trí ~ ^/(?<port>123[0-9])$ {
    viết lại "^/[0-9]{4}(.*)$" $1 break;
    proxy_pass http://localhost:$port;
}

Đôi khi không thể có giải pháp nào khác ngoài việc sử dụng các ảnh chụp được đặt tên, một ví dụ tuyệt vời về tình huống như vậy được đưa ra tại cái này chủ đề.

Sai lầm #4: URI viết lại không thể là một chuỗi rỗng.

Một lần nữa, giả sử bạn có URI là /1234. Sau quy tắc viết lại, một nginx nội bộ $uri biến sẽ có giá trị rỗng. Điều đó sẽ dẫn đến lỗi Máy chủ nội bộ HTTP 500 và trong nhật ký lỗi nginx, bạn sẽ thấy thông báo lỗi sau:

URI được viết lại có độ dài bằng không

Để giải quyết lỗi đó, chỉ cần viết lại bất kỳ URI nào vào /:

vị trí ~ ^/(?<port>123[0-9])$ {
    viết lại ^ / ngắt;
    proxy_pass http://localhost:$port;
}

Nếu bạn muốn phục vụ bất kỳ /<số_cổng>/một số/đường dẫn yêu cầu như trên, bạn nên sử dụng khối vị trí sau để đảm bảo URI được viết lại của bạn bắt đầu bằng dấu gạch chéo:

vị trí ~ ^/(?<port>123[0-9])(?:/|$) {
    viết lại "^/\d{4}(?:/(.*))?" /$1 phá vỡ;
    proxy_pass http://localhost:$port;
}

Sai lầm #5: Bạn cần chỉ định trình phân giải khi sử dụng các biến với proxy_pass chỉ thị.

Cấu hình trên gần với giải pháp làm việc. Tuy nhiên, nó vẫn không hoạt động được, gây ra lỗi HTTP 502 Bad Gateway. Bạn cần chỉ định một người giải quyết khi bạn đang sử dụng các biến với proxy_pass và ngược dòng của bạn được chỉ định bởi tên miền chứ không phải địa chỉ IP, nếu không, bạn sẽ gặp lỗi sau trong nhật ký lỗi nginx của mình:

không có trình phân giải nào được xác định để giải quyết localhost

Nói chung, bạn phải sử dụng một cái gì đó như

bộ giải quyết 8.8.8.8;
vị trí ~ ^/(?<port>123[0-9])$ {
    viết lại ^ / ngắt;
    proxy_pass http://localhost:$port;
}

nhưng vì thượng nguồn của bạn là máy chủ cục bộ, bạn có thể chỉ định địa chỉ IP của nó thay vì tên miền, theo cách này bạn sẽ không cần điều đó người giải quyết chỉ thị ở tất cả:

vị trí ~ ^/(?<port>123[0-9])$ {
    viết lại ^ / ngắt;
    proxy_pass http://127.0.0.1:$port;
}

Cấu hình này phải hoàn toàn khả thi (cuối cùng). Và một lần nữa, nếu bạn cần phục vụ bất kỳ /<số_cổng>/một số/đường dẫn yêu cầu như trên, thay vào đó, bạn nên sử dụng khối vị trí sau:

vị trí ~ ^/(?<port>123[0-9])(?:/|$) {
    viết lại "^/\d{4}(?:/(.*))?" /$1 phá vỡ;
    proxy_pass http://127.0.0.1:$port;
}
themadmax avatar
lá cờ cn
Cảm ơn bạn rất nhiều, câu trả lời của bạn thực sự ấn tượng và rất hữu ích, tôi hy vọng nó sẽ giúp ích cho những người khác!
Ivan Shatsky avatar
lá cờ gr
Tôi đã thực hiện một số cập nhật (hữu ích, tôi hy vọng) cho câu trả lời. Vâng, câu trả lời hóa ra khá chi tiết (không đáng để bỏ phiếu sao? :)), vì vậy để giúp người khác tìm thấy thông tin này, bạn có thể đổi tên câu hỏi của mình thành một tên phổ biến hơn, chẳng hạn như _Using a part of the URI as số cổng cho chỉ thị nginx proxy_pass_ hoặc thậm chí phổ biến hơn _Sử dụng một phần của URI với chỉ thị nginx proxy_pass_.
lá cờ us
Người ta cũng có thể nắm bắt tất cả các thành phần trong chỉ thị `location` và bỏ qua `viết lại`.

Đăng câu trả lời

Hầu hết mọi người không hiểu rằng việc đặt nhiều câu hỏi sẽ mở ra cơ hội học hỏi và cải thiện mối quan hệ giữa các cá nhân. Ví dụ, trong các nghiên cứu của Alison, mặc dù mọi người có thể nhớ chính xác có bao nhiêu câu hỏi đã được đặt ra trong các cuộc trò chuyện của họ, nhưng họ không trực giác nhận ra mối liên hệ giữa câu hỏi và sự yêu thích. Qua bốn nghiên cứu, trong đó những người tham gia tự tham gia vào các cuộc trò chuyện hoặc đọc bản ghi lại các cuộc trò chuyện của người khác, mọi người có xu hướng không nhận ra rằng việc đặt câu hỏi sẽ ảnh hưởng—hoặc đã ảnh hưởng—mức độ thân thiện giữa những người đối thoại.