Können Nginx-Standortblöcke mit einer URL-Abfragezeichenfolge übereinstimmen?

23

Können Nginx- locationBlöcke mit einer URL- Abfragezeichenfolge übereinstimmen?

Zum Beispiel, welcher Standortblock mit einer HTTP- GETAnfrage übereinstimmen könnte

GET /git/sample-repository/info/refs?service=git-receive-pack HTTP/1.1
Derek Mahar
quelle
Ich würde "location / git / sample-repository / info / refs? Service = git-receive-pack" raten, da nginx nur einen Stringvergleich durchführt.
JosefScript
Stringvergleich der gesamten URL oder nur des Teils vor dem Fragezeichen ( ?)?
Derek Mahar
1
Einige letzte Klarstellungen, als ich selbst über dieses Problem stolperte: nginx.org/en/docs/http/request_processing.html besagt eindeutig: "Beachten Sie, dass Speicherorte aller Typen nur einen URI-Teil der Anforderungszeile ohne Argumente testen. Dies geschieht aufgrund von Argumenten in der Abfragezeichenfolge kann auf verschiedene Weise angegeben werden "
Thomas Urban

Antworten:

37

Können Nginx-Standortblöcke mit einer URL-Abfragezeichenfolge übereinstimmen?

Kurze Antwort : Nein.

Lange Antwort : Es gibt eine Problemumgehung, wenn wir nur eine Handvoll solcher Standortblöcke haben.

Hier ein Beispiel für eine Problemumgehung für 3 Standortblöcke, die bestimmten Abfragezeichenfolgen entsprechen müssen:

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
  }
}

Sie können $ query_string, $ args oder $ arg_fieldname verwenden. Alle werden den Job machen. Weitere Informationen zu error_page finden Sie in den offiziellen Dokumenten .

Warnung: Bitte achten Sie darauf, nicht die Standard-HTTP-Codes zu verwenden .

Pothi Kalimuthu
quelle
1
Interessanter Ansatz! Darf ich empfehlen $args ~ "service=git-send-pack"statt $args = "service=git-send-pack"? Dieses Formular enthält mehrere Abfrageparameter.
Derek Mahar
1
stackoverflow.com/a/40313590/107158 veranschaulicht den Ansatz, den ich bei der Verarbeitung von Argumenten für Abfragezeichenfolgen verfolgt habe. Wie Ihre Antwort verwendet meine ifund $arg_fieldname, aber verwendet rewriteanstelle von error_pageund location @name. Beachten Sie, dass in diesem Beispiel meine Versuche, @nameden Ersetzungsparameter in rewritezu verwenden, fehlgeschlagen sind.
Derek Mahar
1
Übrigens sollte es $args ~und sein $arg_somerandomfield =.
Derek Mahar
1
Zu mapdiesem Zweck kann man auch die Nginx- Funktion verwenden, die schneller ist.
Tero Kilkanen
1
@PothiKalimuthu, danke für die Klarstellung. Was ich in der Zwischenzeit geschehen ist , um die ersetzen queryParameter durch einen URL - Pfad ein , wie dies feedback/{auth_key}statt /feedback?auth_key=abc. Auf diese Weise brauche ich nicht zu verwenden if, ich kann Standortmuster mit definieren regexund das wars.
WM
4

Ich weiß, dass diese Frage über ein Jahr alt ist, aber ich habe die letzten Tage damit verbracht, mein Gehirn wegen eines ähnlichen Problems zu zerstören. Ich wollte unterschiedliche Authentifizierungs- und Handhabungsregeln für öffentliche und private Repos, einschließlich Push und Pull. Das ist es, was ich mir endlich ausgedacht habe, also dachte ich mir, ich würde es teilen. Ich weiß if, dass dies eine heikle Anweisung ist, aber das scheint für mich in Ordnung zu sein:

# 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
quelle