Puncte:0

Utilizarea unei părți a URI ca număr de port pentru directiva nginx proxy_pass

drapel cn

Aceasta este configurația mea nginx:

Server {
        asculta 443 ssl;
        nume_server sub.example.fr ;
        locație ~ ^/ (123[0-9])$ { # lucru regex
                #rewrite ^/[0-9]{4}(.*)$ $1 ultimul; # nu funcționează, cu ultimul sau pauză
                #proxy_pass http://localhost:$1/; # adăugare bară oblică nu este permisă
                proxy_pass http://localhost:$1;
        }
}

vreau să înaintez https://sub.example.fr/1234 la http://localhost:1234, așa că vreau doar să extrag numărul portului, să îl elimin din url și să îl folosesc în proxy_pass.

Puncte:2
drapel gr

În primul rând, dvs ^/(123[0-9])$ regex se va potrivi numai /1234 URI (sau /1230, /1231, etc.) dar nu /1234/unele/cale din moment ce utilizați $ ancoră de capăt de sfoară. Presupun că nu este o eroare, ci o soluție de proiectare. Dacă nu este, să se potrivească pe ambele /1234 și /1234/unele/cale (dar nu ceva de genul /12345), puteți folosi o alternativă: ^/(123[0-9])(?:/|$) (Folosesc un grup fără captură (?:...) aici, deoarece se consideră că are performanțe puțin mai bune decât grupul de captură).

Configurația dvs. are o grămadă de greșeli diferite. Să ne uităm peste fiecare.

Greșeala nr. 1: incorectă rescrie... ultimul; utilizare.

Într-adevăr, nu puteți specifica un URI pentru proxy_pass în amonte, așa cum încercați să faceți cu un slash final

proxy_pass http://localhost:$1/; # adăugare bară oblică nu este permisă

în interiorul locațiilor de potrivire regex (precum și în interiorul locațiilor numite) și singura modalitate de a schimba URI-ul care va fi transmis backend-ului este să utilizați rescrie directivă. Cu toate acestea, modul corect de a schimba un URI în interiorul Locație bloc pentru a-l procesa mai târziu în aceeași locație este de utilizat rescrie... pauză; de cand rescrie... ultimul; va forța nginx să caute o nouă locație pentru URI-ul rescris. Asta înseamnă că trebuie să folosim pauză steag pentru rescrie directivă:

rescrie ^/[0-9]{4}(.*)$ $1 pauză;

Ai grijă! Fără directive de la ngx_http_rewrite_module va fi executat după rescrie... pauză; (sau pur și simplu pauză;) directiva (Actualizați: după unele teste, spre deosebire de ceea ce se spune în documentație, se dovedește că este adevărat numai pentru pauză directiva dar nu rescrie... pauză unul, cel puțin pentru OpenResty 1.17.8.2 bazat pe nucleul nginx 17.8).

Greșeala #2: Ar trebui să citați orice șir care conține paranteze sau acestea vor fi considerate ca bloc de configurare nginx.

Directiva anterioară ne va da următoarea eroare:

nginx: directiva [emerg] „rewrite” nu este terminată cu „;”

Pentru a scăpa de această eroare, trebuie să menționăm modelul nostru regex din cauza utilizării parantezelor:

rescrie „^/[0-9]{4}(.*)$” $1 pauză;

Greșeala #3: Capturile numerotate sunt suprascrise ori de câte ori se evaluează expresia regulată.

Să presupunem că aveți un URI de /1234:

locație ~ ^/(123[0-9])$ {
    # Aici valoarea variabilei „$1” este „1234”
    rescrie „^/[0-9]{4}(.*)$” $1 pauză;
    # Aici valoarea variabilei „$1” este un șir gol!
    proxy_pass http://localhost:$1; # Nu va exista niciun port pentru directiva „proxy_pass”.
}

Poți salva asta $1 valoare înainte ca regula de rescrire să-și evalueze propria expresie regulată folosind a stabilit directivă:

locație ~ ^/(123[0-9])$ {
    setează $port $1;
    rescrie „^/[0-9]{4}(.*)$” $1 pauză;
    proxy_pass http://localhost:$port;
}

sau mai bine folosiți numit grup de captură:

locație ~ ^/(?<port>123[0-9])$ {
    rescrie „^/[0-9]{4}(.*)$” $1 pauză;
    proxy_pass http://localhost:$port;
}

Uneori nu poate exista altă soluție decât să folosești capturi cu nume, un exemplu excelent al unei astfel de situații este dat la acest fir.

Greșeala #4: URI-ul rescris nu poate fi un șir gol.

Din nou, să presupunem că aveți un URI de /1234. După regula de rescriere, un nginx intern $uri variabila va avea o valoare goală. Acest lucru ar duce la o eroare HTTP 500 Internal Server, iar în jurnalul de erori nginx veți vedea următorul mesaj de eroare:

URI-ul rescris are o lungime zero

Pentru a rezolva această eroare, trebuie doar să rescrieți orice URI în /:

locație ~ ^/(?<port>123[0-9])$ {
    rescrie ^ / break;
    proxy_pass http://localhost:$port;
}

Dacă ar trebui să serviți vreunul /<port_number>/some/path cerere ca mai sus, ar trebui să utilizați următorul bloc de locație pentru a vă asigura că URI-ul rescris începe cu o bară oblică:

locație ~ ^/(?<port>123[0-9])(?:/|$) {
    rescrie "^/\d{4}(?:/(.*))?" /$1 pauză;
    proxy_pass http://localhost:$port;
}

Greșeala #5: Trebuie să specificați un resolver atunci când utilizați variabile cu proxy_pass directivă.

Configurația de mai sus este aproape de soluția de lucru. Cu toate acestea, este încă nefuncțional, dându-vă o eroare HTTP 502 Bad Gateway. Trebuie să specificați a rezolutor atunci când utilizați variabile cu proxy_pass directivă și în amonte este specificată de numele domeniului și nu de adresa IP, altfel veți primi următoarea eroare în jurnalul de erori nginx:

nici un rezolutor definit pentru a rezolva localhost

În general, ar trebui să folosești ceva de genul

rezolutor 8.8.8.8;
locație ~ ^/(?<port>123[0-9])$ {
    rescrie ^ / break;
    proxy_pass http://localhost:$port;
}

dar din moment ce dvs. în amonte este gazdă locală, puteți specifica adresa sa IP în loc de numele domeniului, astfel nu veți avea nevoie de asta rezolutor directivă la toate:

locație ~ ^/(?<port>123[0-9])$ {
    rescrie ^ / break;
    proxy_pass http://127.0.0.1:$port;
}

Această configurație ar trebui să fie pe deplin funcțională (în sfârșit). Și încă o dată, dacă ar trebui să serviți vreunul /<port_number>/some/path cerere ca mai sus, ar trebui să utilizați în schimb următorul bloc de locație:

locație ~ ^/(?<port>123[0-9])(?:/|$) {
    rescrie "^/\d{4}(?:/(.*))?" /$1 pauză;
    proxy_pass http://127.0.0.1:$port;
}
themadmax avatar
drapel cn
Vă mulțumesc foarte mult, răspunsul dvs. este cu adevărat impresionant și foarte instructiv, sper că va ajuta alți oameni!
Ivan Shatsky avatar
drapel gr
Am făcut câteva actualizări (utile, sper) răspunsului. Da, răspunsul s-a dovedit a fi destul de detaliat (nu merită să votați? :) ), așa că pentru a ajuta alte persoane să găsească aceste informații, puteți redenumi întrebarea dvs. la ceva mai comun, cum ar fi _Folosirea unei părți a URI ca un număr de port pentru directiva nginx proxy_pass_ sau chiar mai frecvent _Folosirea unei părți a URI cu directiva nginx proxy_pass_.
drapel us
De asemenea, se pot captura toate elementele din directiva `locație` și să omite `rescrierea`.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.