javascript - Videregivelse af variabler til næste middleware ved brug af next() i Express.js


Jeg vil gerne sende en variabel fra den første middleware til en anden middleware, og jeg prøvede at gøre dette, men der var "req.somevariable gives som 'undefined'".


//app.js
..
app.get('/someurl/', middleware1, middleware2)
...

////middleware1
...
some conditions
...
res.somevariable = variable1;
next();
...

////middleware2
...
some conditions
...
variable = req.somevariable;
...

Svar #1

v4.x API-dokumentation

Dette er, hvad res.locals-objektet er til. At sætte variabler direkte på forespørgselsobjektet understøttes ikke og er ikke dokumenteret. res.locals er garanteret til at holde tilstanden gennem hele en forespørgsel.

Citater fra dokumentationen:

Brug denne egenskab til at indstille variabler, der er tilgængelige i skabeloner gengivet med res.render. De variabler, der er indstillet på res.locals, er tilgængelige inden for en enkelt forespørgsels-svar-cyklus og vil ikke blive delt mellem forespørgsler.

Det lokale objekt bruges af visningsmotorer til at gengive et svar. Objektnøglerne kan være særligt følsomme og bør ikke indeholde brugerstyret input, da det kan påvirke visningsmotorens funktion eller give adgang til cross-site scripting. Konsulter dokumentationen for den anvendte visningsmotor for yderligere overvejelser.

app.use(function(req, res, next) {
    res.locals.user = req.user;  
    res.locals.authenticated = !req.user.anonymous;
    next();
});

For at hente variablen i næste middleware:

app.use(function(req, res, next) {
    if (res.locals.authenticated) {
        console.log(res.locals.user.id);
    }
    next();
});

Svar #2

Vedhæft din variabel til res.locals-objektet, ikke req.

I stedet for

req.somevariable = variable1;

Have :

res.locals.somevariable = variable1;

Som andre har påpeget, er res.locals den anbefalede måde at sende data gennem middleware på.

Svar #3

Jeg tror ikke, at bedste praksis vil være at videregive en variabel som req.YOUR_VAR. Du vil måske overveje req.YOUR_APP_NAME.YOUR_VAR eller req.mw_params.YOUR_VAR.

Det vil hjælpe dig med at undgå at overskrive andre attributter.

Svar #4

Det mest almindelige mønster for at videregive variabler til anden middleware og endpoint-funktioner er at vedhæfte værdier til forespørgselsobjektet req.

I dit tilfælde ville det betyde at have mellemsoftware som disse:

app.use(function (req, res, next) {
  req.someVariable = 123;
  next();
});

app.use(function (req, res, next) {
  console.log("The variable is", req.someVariable);
  next();
});

Der er mange almindelige anvendelsestilfælde af dette mønster, og det er den standard måde at gøre det på i Express-fællesskabet. Se for eksempel:

  • express.json, som følger med express, var tidligere en del af body-parser, som følger det samme mønster for al forespørgselsparsing.
  • multer bruges til parsing af multipart-data
  • express-jwt
  • express-validator (se kode)
  • express-session
  • express-brugeragent
  • express-pino-logger
  • express-bunyan-logger

Det er værd at bemærke, at det i øjeblikket mest stemte svar forkert anbefaler at bruge res.locals til dette formål---hvilket tilsyneladende stammer fra en fejllæsning af dokumentationen. Af den grund vil jeg uddybe, hvorfor dette ikke er den sædvanlige tilgang til problemet (selvom det heller ikke er særligt skadeligt).

Dokumentationen

Som støttende bevis for, at res.locals-tilgangen er den passende for sagen, citeres den nu forældede dokumentation:

Et objekt, der indeholder svar-lokale variabler, som er begrænset til forespørgslen, og derfor kun er tilgængelige for de visninger, der gengives under den forespørgsel/svar-cyklus (hvis nogen). Ellers er denne egenskab identisk med app.locals.

Denne egenskab er nyttig til at give adgang til oplysninger på anmodningsniveau, såsom anmodningsstiens navn, autentificeret bruger, brugerindstillinger osv.

Bemærk indramningen her: res.locals er kun for variabler, der er tilgængelige "for de view(er), der rendes under den pågældende request" (fremhævning tilføjet).

Det er det, res.locals relaterer til. res.render gengiver en skabelonfil med nogle givne data samt adgang til locals. Dette var faktisk mere klart i v2-dokumentationen, og vi har nu opdateret den nuværende Express-dokumentation for at gøre det klarere:

Brug denne egenskab til at indstille variabler, der er tilgængelige i skabeloner gengivet med res.render. Variablerne, der er indstillet på res.locals, er tilgængelige inden for en enkelt forespørgsels-respons-cyklus og vil ikke blive delt mellem forespørgsler.

For at gemme lokale variabler til brug i skabelonrendering mellem forespørgsler, brug i stedet app.locals.

Denne egenskab er nyttig til at eksponere anmodningsspecifik information såsom anmodningssti, autentificeret bruger, brugerindstillinger og så videre til skabeloner, der gengives inden for applikationen.

(Fremhævning tilføjet.)

Guiden

Yderligere bevis for, at udvidelse af req er den standardmæssige tilgang, findes i vejledningen om Skrivning af Middleware, som angiver:

Dernæst vil vi oprette en middleware-funktion kaldet „requestTime“ og tilføje en egenskab kaldet requestTime til forespørgselsobjektet.

const requestTime = function (req, res, next) {
 req.requestTime = Date.now()
 next()
}

Da dette blev nævnt i diskussionen i svarene på dette spørgsmål her, svarede en bruger: "Sådan gjorde man, før de tilføjede res.locals, så det kan være gamle dokumenter. res.locals er et navneområde specifikt til dette."

Dette stemmer dog ikke overens med historien for kodebasen: locals har været til stede siden v2, hvilket er væsentligt før f.eks. express.json blev inkluderet i biblioteket, på hvilket tidspunkt det ville have givet mening at ændre adfærden, hvis det faktisk var korrekt at gemme værdier i res.locals.

Afsluttende bemærkninger

Shoutout til @real_ate, som skrev i kommentarerne, men blev overset.

Relaterede artikler