Proxy Nginx dengan Metode Permintaan

17

Apakah mungkin / bagaimana saya bisa mengkonfigurasi blok lokasi Nginx ke proxy ke backend yang berbeda tergantung pada metode permintaan (mis. GET / POST)?

Alasannya adalah, saya saat ini menangani 2 metode di 2 URL yang berbeda (satu melalui proksi http dan lainnya melalui fcgi) dan saya mencoba membuatnya lebih "REST", jadi, idealnya akan MENDAPATKAN sumber daya untuk mengembalikan daftar. , sementara POSTing ke sumber yang sama harus ditambahkan ke daftar.

Brenton Alker
sumber

Jawaban:

27

Saya tidak menggunakan konfigurasi ini, tetapi berdasarkan pada contoh di sini :

location /service  {
  if ($request_method = POST ) {
    fastcgi_pass 127.0.0.1:1234;
  }

  if ($request_method = GET ) {
     alias /path/to/files;
  }
}

Jika Anda menulis aplikasi Anda sendiri, Anda juga dapat mempertimbangkan untuk memeriksa GET / POST di dalamnya, dan mengirim header X-Accel-Redirect untuk menyerahkan transportasi file ke nginx.

Jason
sumber
Blok GET adalah proxy_pass dalam kasus saya, tetapi jika tidak berfungsi. Saat ini saya tidak menggunakan blok if kedua, nginx tampaknya menghentikan "pemrosesan" ketika direktif fastcgi_pass tercapai (mis. Tidak melewati dan menjalankan proxy pass juga) karena saya ingin selain POST untuk mengembalikan ke proxy.
Brenton Alker
2
Perhatikan bahwa ifumumnya berkecil hati dengan dokumentasi Nginx: nginx.com/resources/wiki/start/topics/depth/ifisevil
vog
1
Jadi apa alternatifnya?
WM
1
@WM Lihat jawaban saya: serverfault.com/a/823053/175421
vog
@vog, Menarik. Cara yang cukup cerdas untuk melakukannya. Terima kasih telah berbagi.
WM
23

Meskipun Anda bisa mencapai ini if, ini umumnya tidak disarankan oleh dokumentasi Nginx , karena iftidak cocok dengan arahan lain. Misalnya, anggap GET harus terbuka untuk semua orang, sementara POST hanya untuk pengguna yang diautentikasi, menggunakan HTTP Basic Auth. Itu perlu ifdikombinasikan dengan auth_basic, yang tidak berfungsi dengan baik.

Berikut adalah alternatif yang berfungsi tanpa if. Caranya adalah dengan menggunakan "GET" dan "POST" sebagai bagian dari nama hulu, sehingga ini dapat diatasi dengan substitusi variabel:

http {
  upstream other_GET {
    server ...;
  }
  upstream other_POST {
    server ...;
  }
  server {
    location /service {
      proxy_pass http://other_$request_method;
    }
  }
}

Untuk menggabungkan ini dengan HTTP Basic Auth untuk segalanya kecuali GET, cukup tambahkan satu limit_exceptblok:

  ...
    location /service {
      proxy_pass http://other_$request_method;
      limit_except GET {
        auth_basic ...;
      }
    }
  ...
vog
sumber
Masalah dengan pendekatan ini adalah sekarang kami akan kembali 502 gateway errorkarena no resolver defined to resolve other_HEAD(atau apa pun hulu Anda yang hilang). Akan lebih semantik untuk mengembalikan sesuatu seperti 405 method not allowed. Apakah ada cara untuk menyelesaikan ini?
James
1
@ James: Ini mungkin bisa diutarakan sebagai pertanyaan baru, merujuk pada yang ini. Saya tidak punya jawaban untuk perincian ini, tapi mungkin yang lain juga.
vog
0

Inilah yang saya lakukan untuk membuat semuanya bekerja untuk saya

add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
    proxy_pass http://back-end;
}
Mansur Ali
sumber
Hoe persis apakah itu beralih antara dua titik akhir berdasarkan metode permintaan?
Dasar
0

Sedikit perubahan pada jawaban vog untuk menyertakan penangan default untuk metode lain seperti PILIHAN, PUT, dll.

    upstream webdav_default {
            server example.com;
    }
    upstream webdav_upload {
            server example.com:8081;
    }
    upstream webdav_download {
            server example.com:8082;
    }
    server {
            map upstream_location $request_method {
                    GET     webdav_download;
                    HEAD    webdav_download;
                    PUT     webdav_upload;
                    LOCK    webdav_upload;
                    default webdav_default;
            }
            location / {
                    proxy_pass https://$upstream_location;
            }
    }
timmmmmy
sumber
0

Saya tidak bisa mendapatkan jawaban dari @timmmmmy untuk bekerja, tetapi itu mengarahkan saya ke dokumentasi peta dan ini berhasil bagi saya:

map $request_method $upstream_location {
   PUT     example.com:8081;
   POST    example.com:8081;
   PATCH   example.com:8081;
   default example.com:8082;
}
server {
   location / {
      proxy_pass https://$upstream_location;
   }
}
rik harris
sumber