Cách xóa đường dẫn bằng nginx proxy_pass


77

Tôi có một ứng dụng web đang chạy http://example.com/và muốn "gắn kết" một ứng dụng khác trên một máy chủ riêng biệt http://example.com/en. Máy chủ ngược dòng và proxy_passdường như hoạt động, nhưng vì một vấn đề:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

Khi mở example.com/en, ứng dụng ngược dòng của tôi trở lại 404 not found /en. Điều này có ý nghĩa, vì thượng nguồn không có đường dẫn /en.

proxy_pathgiải pháp đúng đắn? Tôi có nên viết lại "ngược dòng" để nó lắng nghe /enthay vào đó, vì nó là đường dẫn gốc? Hoặc có một lệnh nào cho phép tôi viết lại đường dẫn được truyền ngược lên không?

Câu trả lời:


133

Đây có thể là cách hiệu quả nhất để làm những gì bạn muốn mà không cần sử dụng bất kỳ biểu thức thông thường nào:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}

1
Theo như tôi biết, phần cuối cùng vẫn sẽ vượt qua "/ en" là đường dẫn đến proxy, phải không?
berkes 21/12/13

15
@berkes, không, nó sẽ không - dấu gạch chéo trong đó proxy_passlà điều làm nên sự khác biệt. Ngoài ra, câu trả lời này là hơn đúng so với cái bạn đã đưa ra, bởi vì nó cũng đảm bảo rằng proxy_redirectở yên default, vì vậy, bạn vẫn có thể sử dụng 302et al trong backend của bạn, và có nó hoạt động chính xác ở khắp mọi nơi.
cnst

4
À, tôi đã bỏ lỡ dấu gạch chéo :(
Vanuan

3
ÔNG! GIAO HÀNG TẬN NƠI!
barrymac

4
3 giờ tìm kiếm, và vâng ... Đó là dấu gạch chéo. Cảm ơn bạn đời!
Lucas P.

12

Tôi muốn giải quyết một câu trả lời dựa trên regex mới hơn đang được phổ biến.

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

Giải pháp thoạt nhìn có vẻ dễ thương hơn, nhưng nó sai vì nhiều lý do.

  • Regex ở trên sẽ phù hợp với yêu cầu của bạn /enjoy, chuyển hướng nó lên /joythượng nguồn. Đây thực sự là dự định?

  • Yêu cầu /ensẽ không dẫn đến bất kỳ chuyển hướng nào, trực tiếp phục vụ /từ thượng nguồn (gần như là một yêu cầu /en/được thực hiện thay thế, nhưng không hoàn toàn). Nếu bạn sử dụng các URI tương đối trong trang gốc của bạn ngược dòng (nếu không, tại sao bạn không có /en/tiền tố ngay trong URI ngược dòng?), Ví dụ src="style.css"(có thể tham chiếu một ngôn ngữ cụ thể theo ngôn ngữ url("menu.png")), thì trình duyệt sẽ yêu cầu như /style.cssthay vì /en/style.css. (Hoặc ngay cả khi bạn sử dụng URI tuyệt đối ở mọi nơi, điều gì sẽ xảy ra nếu ai đó tham chiếu tài nguyên bán tùy chọn tương đối khó hiểu?) Rất tiếc, trang web có thể không hoạt động, nhưng chỉ đôi khi hoặc trong các trường hợp cạnh.

  • Theo lời khuyên trước đây của tôi tại một câu hỏi khác đã được đề cập bởi câu trả lời của chính OP , việc sử dụng các biểu thức chính quy sẽ ngăn lệnh proxy_redirectnày có giá trị mặc định default, offthay vào đó thay thế. Điều này có nghĩa là nếu trả lời ngược dòng Location: http://127.0.0.1:8080/en/dir/khi yêu cầu /en/dirđược đưa ra, thì đó là những gì khách hàng sẽ thấy, rõ ràng là nó sẽ không hoạt động chính xác. (Điều này đặc biệt mỉa mai cho một /enyêu cầu nhắc nhở sử dụng regex ngay từ đầu, tuy nhiên việc triển khai cụ thể này thay vì gặp phải một vấn đề khác như đã đề cập ở trên.) Plus, nếu bạn đang sử dụngupstreamChỉ thị, sau đó có thể trở nên xấu hơn nếu bạn chỉ cố gắng đi với một tùy chỉnh, đặc biệt là nếu bạn có thể có nhiều hơn một máy chủ ngược dòng - làm thế nào để bạn có một riêng proxy_redirectcho từng máy chủ ? Bạn cũng có thể sử dụng các biểu thức chính quy bên trong proxy_redirect, thậm chí có thể để khớp với bất kỳ máy chủ nào, nhưng nếu bạn quyết định đưa ra một chuyển hướng tên miền chéo trong tương lai thì sao?

Để cố gắng giải quyết một số điểm trên với một vị trí dựa trên regex duy nhất, chúng tôi có thể làm như sau (lưu ý rằng proxy_passchúng tôi cũng phải bỏ tham chiếu đến máy chủ từ một upstreamchỉ thị dựa trên cơ sở, để proxy_redirectđơn giản hơn):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

Vì vậy, nếu bạn hỏi tôi, giải pháp ban đầu với hai vị trí cấp cao nhất của anh chị em vẫn sẽ là một ý tưởng tốt hơn là tự đào một cái hố thỏ bằng cách đi theo con đường regex thay thế.


Điều này gây ra một ngoại lệ:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan

1
@Athlan, đó là vì bạn không nên sử dụng nó ngay từ đầu! Nếu bạn vẫn muốn, bạn có thể đặt vị trí đó bên ngoài regrec.
cnst

đặt nội địa hóa = / en bên ngoài hoạt động thực sự tốt! cảm ơn
Sebastian Webber

7

Vì vậy, tôi tìm thấy câu trả lời trên stackoverflow :

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

Về cơ bản: chuyển regex vào vị trí và chuyển backref dọc theo url proxy_pass.


Tôi nghĩ rằng "proxy_pass ngon / $ ;" phải là "proxy_pass ngon lành / $ 2 "
Zafer

1
@Zafer đã đúng, câu trả lời ở trên đã gây ra lỗi cho tôi
franck

Tôi đã thay đổi câu trả lời, nhưng không có máy chủ trong tay, nơi tôi có thể thử cái này, ATM, vì vậy nó không được xác minh.
berkes

0

Kế toán tài liệu Nginx

Để chuyển yêu cầu đến máy chủ được ủy quyền HTTP, lệnh proxy_pass được chỉ định bên trong một vị trí. Ví dụ:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

Cấu hình ví dụ này dẫn đến việc chuyển tất cả các yêu cầu được xử lý ở vị trí này đến máy chủ được ủy quyền tại địa chỉ được chỉ định. Địa chỉ này có thể được chỉ định làm tên miền hoặc địa chỉ IP. Địa chỉ cũng có thể bao gồm một cổng:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

Lưu ý rằng trong ví dụ đầu tiên ở trên, địa chỉ của máy chủ proxy được theo sau bởi một URI, / link /. Nếu URI được chỉ định cùng với địa chỉ, nó sẽ thay thế một phần của URI yêu cầu khớp với tham số vị trí. Ví dụ: ở đây, yêu cầu với /some/path/page.html URI sẽ được ủy quyền cho http://www.example.com/link/page.html . Nếu địa chỉ được chỉ định mà không có URI hoặc không thể xác định phần URI được thay thế, URI yêu cầu đầy đủ được thông qua (có thể, đã sửa đổi).

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.