Bisakah nginx blok lokasi cocok dengan string kueri URL?

23

Bisakah nginx locationblok cocok dengan string kueri URL?

Misalnya, blok lokasi apa yang mungkin cocok dengan GETpermintaan HTTP

GET /git/sample-repository/info/refs?service=git-receive-pack HTTP/1.1
Derek Mahar
sumber
Saya kira "location / git / sample-repository / info / refs? Service = git-accept-pack" karena nginx hanya melakukan perbandingan string.
JosefScript
Perbandingan string seluruh URL atau hanya bagian sebelum tanda tanya ( ?)?
Derek Mahar
1
Beberapa klarifikasi terakhir ketika saya sendiri tersandung masalah ini: nginx.org/en/docs/http/request_processing.html dengan jelas menyatakan: "Perhatikan bahwa lokasi semua jenis menguji hanya bagian URI dari baris permintaan tanpa argumen. Ini dilakukan karena argumen dalam string kueri dapat diberikan dalam beberapa cara "
Thomas Urban

Jawaban:

37

Bisakah nginx blok lokasi cocok dengan string kueri URL?

Jawaban singkat : Tidak.

Jawaban panjang : Ada solusi jika kita hanya memiliki sedikit blok lokasi seperti itu.

Berikut ini contoh solusi untuk 3 blok lokasi yang harus cocok dengan string kueri tertentu:

server {
  #... common definitions such as server, root

  location / {
    error_page 418 = @queryone;
    error_page 419 = @querytwo;
    error_page 420 = @querythree;

    if ( $query_string = "service=git-receive-pack" ) { return 418; }
    if ( $args ~ "service=git-upload-pack" ) { return 419; }
    if ( $arg_somerandomfield = "somerandomvaluetomatch" ) { return 420; }

    # do the remaining stuff
    # ex: try_files $uri =404;

  }

  location @queryone {
    # do stuff when queryone matches
  }

  location @querytwo {
    # do stuff when querytwo matches
  }

  location @querythree {
    # do stuff when querythree matches
  }
}

Anda dapat menggunakan $ query_string, $ args atau $ arg_fieldname. Semua akan melakukan pekerjaan itu. Anda mungkin tahu lebih banyak tentang error_page di dokumen resmi .

Peringatan: Pastikan untuk tidak menggunakan kode HTTP standar .

Pothi Kalimuthu
sumber
1
Pendekatan yang menarik! Bolehkah saya merekomendasikan, $args ~ "service=git-send-pack"bukan $args = "service=git-send-pack"? Formulir ini mengakomodasi beberapa parameter kueri.
Derek Mahar
1
stackoverflow.com/a/40313590/107158 menggambarkan pendekatan yang saya ikuti untuk menangani argumen string kueri. Seperti jawaban Anda, milik saya menggunakan ifdan $arg_fieldname, tetapi menggunakan rewritealih-alih error_pagedan location @name. Perhatikan bahwa dalam contoh itu, upaya saya dalam menggunakan @nameuntuk parameter pengganti di rewritetidak berhasil.
Derek Mahar
1
By the way, itu harus $args ~dan $arg_somerandomfield =.
Derek Mahar
1
Anda juga dapat menggunakan mapfitur nginx untuk tujuan ini, yang lebih cepat.
Tero Kilkanen
1
@PothiKalimuthu, terima kasih telah menjelaskan ini. Sementara itu yang saya lakukan adalah mengganti queryparameter dengan jalur url yang seperti ini feedback/{auth_key}alih-alih /feedback?auth_key=abc. Dengan cara ini saya tidak perlu menggunakan if, saya dapat menentukan pola lokasi menggunakan regexdan hanya itu.
WM
4

Saya tahu pertanyaan ini sudah lebih dari setahun, tetapi saya telah menghabiskan beberapa hari terakhir menghancurkan otak saya karena masalah yang sama. Saya ingin berbagai otentikasi dan aturan penanganan untuk repo publik dan pribadi, termasuk mendorong dan menarik. Inilah yang akhirnya saya buat, jadi saya pikir saya akan berbagi. Saya tahu ifini adalah arahan yang rumit, tetapi ini tampaknya berhasil bagi saya:

# pattern for all repos, public or private, followed by username and reponame
location ~ ^(?:\/(private))?\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?$ {

    # if this is a pull request
    if ( $arg_service = "git-upload-pack" ) {

        # rewrite url with a prefix
        rewrite ^ /upload$uri;

    }

    # if this is a push request
    if ( $arg_service = "git-receive-pack" ) {

        # rewrite url with a prefix
        rewrite ^ /receive$uri;

    }

}

# for pulling public repos
location ~ ^\/upload(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}

# for pushing public repos
location ~ ^\/receive(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}

# for pulling private repos
location ~ ^\/upload\/private(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}

# for pushing private repos
location ~ ^\/receive\/private(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}
Jared Brandt
sumber