Làm cách nào để chuyển tiếp các tham số chuỗi truy vấn thông qua proxy_pass với nginx?


114
upstream apache {
   server 127.0.0.1:8080;
}
server{
   location ~* ^/service/(.*)$ {
      proxy_pass http://apache/$1;
      proxy_redirect off;
   }
 }

Đoạn mã trên sẽ chuyển hướng các yêu cầu trong đó url bao gồm chuỗi "dịch vụ" đến một máy chủ khác, nhưng nó không bao gồm các tham số truy vấn.

Câu trả lời:


163

Từ tài liệu proxy_pass :

Một trường hợp đặc biệt đang sử dụng các biến trong câu lệnh proxy_pass: URL được yêu cầu không được sử dụng và bạn hoàn toàn chịu trách nhiệm tự tạo URL đích.

Vì bạn đang sử dụng $ 1 trong mục tiêu, nên nginx dựa vào bạn để cho nó biết chính xác những gì cần vượt qua. Bạn có thể sửa lỗi này theo hai cách. Đầu tiên, việc loại bỏ phần đầu của uri bằng proxy_pass là không cần thiết:

location /service/ {
  # Note the trailing slash on the proxy_pass.
  # It tells nginx to replace /service/ with / when passing the request.
  proxy_pass http://apache/;
}

Hoặc nếu bạn muốn sử dụng vị trí regex, chỉ cần bao gồm các args:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}

1
Tôi không tin bạn có thể làm được điều sau. Tôi đã thử và nginx phàn nàn với tôi.
duma

3
Khiếu nại như thế nào? Tôi vừa thử nghiệm nó trên nginx 1.3.4 và nó hoạt động tốt đối với tôi.
kolbyjack

Humm .. Tôi không thể nhớ lại bây giờ :( Nhưng tôi cảm thấy như nó có thể liên quan đến "~ *". Tuy nhiên, tôi vừa kiểm tra và tôi có nginx 1.2.3 (thông qua homebrew). Có lẽ vậy?
duma

"mặc định proxy_redirect" có thể không được sử dụng với "proxy_pass" chỉ thị với biến
Jean-Philippe Caruana

1
phải sử dụng viết lại location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Andrew Arnautov

27

Tôi sử dụng phiên bản sửa đổi một chút của cách tiếp cận thứ hai của kolbyjack với ~thay vì ~*.

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}

10

Tôi đã sửa đổi mã @kolbyjack để làm cho nó hoạt động

http://website1/service
http://website1/service/

với các thông số

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}

1
Hãy nhớ rằng điều này sẽ làm cho máy chủ trả lại phản hồi 301 cho máy khách trước khi chuyển hướng. Lệnh proxy_passtrên thực hiện chuyển hướng ở phía máy chủ.
Luke Peterson

1
Điều này sẽ phá vỡ nếu các tham số truy vấn của bạn chứa các ký tự được mã hóa URL (%). Hãy sử dụng câu trả lời của Andrew để thay thế.
David Weber

9

bạn phải sử dụng rewrite để chuyển params bằng proxy_pass, đây là ví dụ tôi đã làm để triển khai ứng dụng anglejs cho s3

S3 Lưu trữ Trang web Tĩnh Định tuyến Tất cả Đường dẫn đến Index.html

được chấp nhận theo nhu cầu của bạn sẽ giống như

location /service/ {
    rewrite ^\/service\/(.*) /$1 break;
    proxy_pass http://apache;
}

nếu bạn muốn kết thúc bằng http://127.0.0.1:8080/query/params/

nếu bạn muốn kết thúc bằng http://127.0.0.1:8080/service/query/params/, bạn sẽ cần một cái gì đó như

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}

1
Điều này có vẻ như nó xử lý tốt các tham số đường dẫn ( /path/params) nhưng không xử lý các tham số truy vấn ( ?query=params)?
Sẽ

À không, sai lầm của tôi, các tham số truy vấn sẽ được thêm tự động (chúng đang trong quá trình thử nghiệm của tôi).
Sẽ

2

github ý chính https://gist.github.com/anjia0532/da4a17f848468de5a374c860b17607e7

#set $token "?"; # deprecated

set $token ""; # declar token is ""(empty str) for original request without args,because $is_args concat any var will be `?`

if ($is_args) { # if the request has args update token to "&"
    set $token "&";
}

location /test {
    set $args "${args}${token}k1=v1&k2=v2"; # update original append custom params with $token
    # if no args $is_args is empty str,else it's "?"
    # http is scheme
    # service is upstream server
    #proxy_pass http://service/$uri$is_args$args; # deprecated remove `/`
    proxy_pass http://service$uri$is_args$args; # proxy pass
}

#http://localhost/test?foo=bar ==> http://service/test?foo=bar&k1=v1&k2=v2

#http://localhost/test/ ==> http://service/test?k1=v1&k2=v2

1

Để chuyển hướng Không có Chuỗi truy vấn, hãy thêm các dòng bên dưới trong Khối máy chủ dưới dòng cổng lắng nghe:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/;
}

Với Chuỗi truy vấn:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}

1
Tài liệu nginx rõ ràng nên tránh sử dụng ifkhi có thể. Trong trường hợp này, giải pháp có thể đúng bằng cách sử dụng locationnhư được hiển thị trong các câu trả lời khác.
Andrés Morales

2
nào một giải pháp nhiều hơn ngay cả khi nó có nhược điểm là tốt hơn
Dmitry Malugin

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.