Vô hiệu hóa giải mã URL trong proxy nginx


21

Khi tôi duyệt đến URL này: http://localhost:8080/foo/%5B-%5Dserver ( nc -l 8080) sẽ nhận được nó như hiện tại:

GET /foo/%5B-%5D HTTP/1.1

Tuy nhiên khi tôi ủy quyền ứng dụng này qua nginx (1.1.19):

location /foo {
        proxy_pass    http://localhost:8080/foo;
}

Yêu cầu tương tự được chuyển qua cổng nginx được chuyển tiếp với đường dẫn được giải mã:

GET /foo/[-] HTTP/1.1

Dấu ngoặc vuông được giải mã trong đường dẫn GET đang gây ra lỗi trong máy chủ đích ( Trạng thái HTTP 400 - Ký tự không hợp lệ trong đường dẫn ... ) khi chúng đến không thoát.

Có cách nào để vô hiệu hóa giải mã URL hoặc mã hóa lại để máy chủ mục tiêu có cùng đường dẫn chính xác khi được định tuyến qua nginx không? Một số quy tắc viết lại URL thông minh?


Câu trả lời:


19

Trích dẫn Valentin V. Bartenev (người sẽ nhận được tín dụng đầy đủ cho câu trả lời này):

Một trích dẫn từ tài liệu :

  • Nếu proxy_pass được chỉ định bằng URI , khi chuyển yêu cầu đến máy chủ, một phần của URI yêu cầu được chuẩn hóa khớp với vị trí được thay thế bằng URI được chỉ định trong lệnh

  • Nếu proxy_passđược chỉ định mà không có URI , URI yêu cầu được chuyển đến máy chủ ở dạng tương tự như được gửi bởi máy khách khi xử lý yêu cầu ban đầu

Cấu hình chính xác trong trường hợp của bạn sẽ là:

location /foo {
   proxy_pass http://localhost:8080;
}

8
Tôi đã phải thay đổi http://localhost:8080/để http://localhost:8080đề phòng bất cứ ai có cùng hoàn cảnh như tôi.
herrtim

4
Tại sao Nginx giải mã URI trước khi chuyển nó đến máy chủ phụ trợ? Nó sẽ không có ý nghĩa hơn nếu nó giữ cho URI không bị ảnh hưởng?
thú mỏ vịt

@platypus, nó được giữ nguyên, cho đến khi bạn rõ ràng bắt đầu thực hiện thay thế
cnst

2

Lưu ý rằng giải mã URL, thường được gọi là $uri"chuẩn hóa" trong tài liệu của nginx, xảy ra trước IFF phụ trợ:

  • hoặc bất kỳ URI nào được chỉ định trong proxy_passchính nó, ngay cả khi chỉ dấu gạch chéo tự nó,

  • hoặc, URI được thay đổi trong quá trình xử lý, ví dụ: thông qua rewrite.


Cả hai điều kiện đều được ghi lại rõ ràng tại http://nginx.org/r/proxy_pass (nhấn mạnh của tôi):

  • Nếu lệnh proxy_passđược chỉ định bằng URI , thì khi yêu cầu được chuyển đến máy chủ, một phần của URI yêu cầu được chuẩn hóa khớp với vị trí được thay thế bằng URI được chỉ định trong lệnh

  • Nếu proxy_passđược chỉ định mà không có URI , URI yêu cầu được chuyển đến máy chủ ở dạng tương tự như được gửi bởi máy khách khi yêu cầu ban đầu được xử lý hoặc URI yêu cầu chuẩn hóa đầy đủ được chuyển khi xử lý URI đã thay đổi


Giải pháp là bỏ qua URI như trong trường hợp OP, hoặc, thực sự, sử dụng một rewritequy tắc thông minh :

# map `/foo` to `/foo`:
location /foo {
    proxy_pass  http://localhost:8080;  # no URI -- not even just a slash
}

# map `/foo` to `/bar`:
location /foo {
    rewrite  ^  $request_uri;            # get original URI
    rewrite  ^/foo(/.*)  /bar$1  break;  # drop /foo, put /bar
    return 400;   # if the second rewrite won't match
    proxy_pass    http://localhost:8080$uri;
}

Bạn có thể thấy nó sống trong một câu trả lời Stack Overflow liên quan , bao gồm cả nhóm điều khiển.


Các tài liệu gây nhầm lẫn ở đây. Cả hai hình thức đều chứa một URI. Nó là thành phần đường dẫn có mặt trong cái này và cái kia bị thiếu.
Michael Hampton

@MichaelHampton, tôi không đồng ý - PATH thường được gọi là URI, vì vậy, cái không có đường dẫn, không chứa URI.
cnst

Tất nhiên, một đường dẫn tương đối cũng có thể là một URL hợp lệ. Vấn đề là, phần còn lại cũng là một URI hợp lệ (ví dụ http://localhost:8080). Nếu bạn không đồng ý, bạn có thể đưa nó lên với các tác giả của RFC 3986.
Michael Hampton

@MichaelHampton Thật không may, có vẻ như sơ đồ và đường dẫn bắt buộc phải là một URI, quyền hạn, đối số, đoạn là tùy chọn
Norman Xu
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.