Nginx https viết lại biến POST thành GET


17

Máy chủ proxy của tôi chạy trên ip A và đây là cách mọi người truy cập dịch vụ web của tôi. Cấu hình nginx sẽ chuyển hướng đến một máy ảo trên ip B.

Đối với máy chủ proxy trên IP A, tôi có sẵn trong các trang web của mình

server {
        listen 443;
        ssl on;
        ssl_certificate nginx.pem;
        ssl_certificate_key nginx.key;

        client_max_body_size 200M;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;

        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;

                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

}

server {
        listen 80;
        rewrite     ^(.*)   https://$http_host$1 permanent;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;
        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

Cái proxy_redirectđược lấy từ làm thế nào để tôi có được nginx để chuyển tiếp các yêu cầu POST HTTP thông qua viết lại?

Tất cả mọi thứ đạt IP công cộng sẽ đạt 443 vì viết lại. Trong nội bộ, chúng tôi đang chuyển tiếp đến 80 trên máy ảo.

Nhưng khi tôi chạy một kịch bản python như đoạn dưới đây để kiểm tra cấu hình của chúng tôi

import requests

data = {'username': '....', 'password': '.....'}
url = 'http://IP_A/api/service/signup'

res  = requests.post(url, data=data, verify=False)
print res
print res.json
print res.status_code
print res.headers

Tôi đang nhận được một 405 Method Not Allowed. Trong nginx chúng tôi thấy rằng khi nó chạm vào máy chủ nội bộ, nginx nội bộ đã nhận được GETyêu cầu, mặc dù trong tiêu đề ban đầu chúng tôi đã thực hiện POST(điều này được hiển thị trong tập lệnh Python).

Vì vậy, có vẻ như viết lại có vấn đề. Bất kỳ ý tưởng làm thế nào để khắc phục điều này? Khi tôi nhận xét viết lại, nó chắc chắn đạt 80, và nó đã đi qua. Vì viết lại đã có thể nói chuyện với máy chủ nội bộ của chúng tôi, do đó, việc tự viết lại không có vấn đề gì. Nó chỉ là viết lại giảm POSTtới GET.

Cảm ơn bạn!

(Điều này cũng sẽ được hỏi trên diễn đàn Nginx vì đây là một công cụ chặn quan trọng ...)

Câu trả lời:


8

Đó không phải là Nginx, đó là trình duyệt của bạn.

Lưu ý từ RFC2616:

RFC 1945 và RFC 2068 chỉ định rằng máy khách không được phép thay đổi phương thức theo yêu cầu được chuyển hướng. Tuy nhiên, hầu hết các triển khai tác nhân người dùng hiện tại đều xử lý 302 như thể đó là phản hồi 303, thực hiện GET trên Vị trí [..]

Điều này đúng với tất cả các trình duyệt phổ biến và bạn không thể làm gì về nó.


@ c2h50h Tôi hiểu rằng thông số HTTP đã nêu một cái gì đó tương tự như thế. Nhưng tôi có thể làm gì ở Nginx? Ý tôi là đây là một thiết lập tầm thường nơi mọi người về phía trước 443 với một cổng nội bộ 80, nhưng họ vẫn có thể làm PUT, POST, DELETE, GET. Trong thiết lập trước đây của tôi, tôi đã không có proxy bổ sung này ở phía trước phục vụ đám đông. Tôi có cùng cấu hình trên cùng một máy chủ nội bộ (máy chủ thử nghiệm của chúng tôi). Điều đó làm việc tốt.
CppLearner

Không có gì. Đó là phía khách hàng 100%. Nếu một máy chủ web, bất kỳ máy chủ web nào, trả về chuyển hướng 301 hoặc 302 thì trình duyệt, ở phía máy khách, sẽ thay thế bất kỳ loại yêu cầu nào GET. Không có cấu hình phía máy chủ hoặc bất kỳ tiêu đề http nào được trả về sẽ không thay đổi điều đó. Nó giống như vậy vì những lý do lịch sử (các trình duyệt ban đầu hành xử theo cách đó do sự hiểu lầm và nó đã trở thành một tiêu chuẩn thực tế).
c2h5oh

Đối với một người, đây không thực sự là một trình duyệt. Chà, bạn có thể nói đó là trình duyệt vì nó sử dụng giao thức HTTP..okay .. không sao đâu. Nhưng một lần nữa, có vẻ như điều này chỉ xảy ra nếu tôi thực hiện cấu hình hai lớp này. Nếu tôi đặt cấu hình tương tự trực tiếp vào máy bên trong và chạy thử nghiệm ở đó, nó sẽ không phàn nàn. Nhưng một lần nữa, làm thế nào để mọi người làm điều đó trong sản xuất của họ? Tôi cho rằng một số người đang làm điều tương tự, đảo ngược 443 thành một số VM chỉ có thể chạy 80. Nếu có một thực hành tốt hơn, tôi muốn tìm hiểu và nghe về nó.
CppLearner

1
Theo trình duyệt, tôi có nghĩa là máy khách HTTP và với tất cả các máy khách phổ biến POSTsẽ trở thành GETnếu nó được chuyển hướng 301 hoặc 302. POST sẽ vẫn POST trên chuyển hướng proxy, nhưng không phải viết lại.
c2h5oh

1
RFC2616 một lần nữa: If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.Vì vậy, hầu hết các trình duyệt sẽ bật lên một thông báo cảnh báo, vì đối với các máy khách HTTP khác, tôi thậm chí không thể đoán được hành vi của chúng sẽ là gì.
c2h5oh

1

Tôi thấy POST /api/brandđang bị biến thành GET /api/brandvì ứng dụng web tôi đang sử dụng ( flask-restful) đang đưa ra yêu cầu "không hợp lệ". Nếu tôi sử dụng POST /api/brand/(chú ý dấu vết /), nó đã thành công.


Tôi đã sử dụng Postman để kiểm tra đăng nhập django rest-auth và đã thấy vấn đề tương tự được mô tả. Điều quan trọng là tôi đã bỏ qua dấu '/' trong yêu cầu POST.
Steve L
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.