Node.js
Web-apps met Express
Zoeken…
Invoering
Express is een minimaal en flexibel Node.js webtoepassingskader, dat een robuuste set functies biedt voor het bouwen van webtoepassingen.
De officiële website van Express is expressjs.com . De bron is te vinden op GitHub .
Syntaxis
- app.get (pad [, middleware], callback [, callback ...])
- app.put (pad [, middleware], callback [, callback ...])
- app.post (pad [, middleware], callback [, callback ...])
- app ['delete'] (pad [, middleware], callback [, callback ...])
- app.use (pad [, middleware], callback [, callback ...])
- app.use (callback)
parameters
Parameter | Details |
---|---|
path | Hiermee geeft u het padgedeelte of de URL op die door de opgegeven callback wordt verwerkt. |
middleware | Een of meer functies die vóór het terugbellen worden opgeroepen. In wezen een keten van meerdere callback functies. Handig voor meer specifieke afhandeling, bijvoorbeeld autorisatie of foutafhandeling. |
callback | Een functie die wordt gebruikt om aanvragen voor het opgegeven path te handelen. Het zal worden genoemd als callback(request, response, next) , waar request , response en next hieronder worden beschreven. |
callback request | Een object dat details bevat over het HTTP-verzoek dat de callback moet afhandelen. |
response | Een object dat wordt gebruikt om aan te geven hoe de server op het verzoek moet reageren. |
next | Een terugbelactie die de besturing doorgeeft aan de volgende overeenkomende route. Het accepteert een optioneel foutobject. |
Ermee beginnen
U moet eerst een map maken, deze in uw shell openen en Express installeren met behulp van npm door npm install express --save
Maak een bestand en noem het app.js
en voeg de volgende code toe die een nieuwe Express-server maakt en er één eindpunt aan toevoegt ( /ping
) met de methode app.get
:
const express = require('express');
const app = express();
app.get('/ping', (request, response) => {
response.send('pong');
});
app.listen(8080, 'localhost');
Om uw script uit te voeren, gebruikt u de volgende opdracht in uw shell:
> node app.js
Uw toepassing accepteert verbindingen op localhost-poort 8080. Als het hostname-argument voor app.listen
wordt weggelaten, accepteert de server zowel verbindingen op het IP-adres van de machine als op localhost. Als de poortwaarde 0 is, wijst het besturingssysteem een beschikbare poort toe.
Zodra uw script actief is, kunt u het in een shell testen om te bevestigen dat u de verwachte reactie "pong" van de server krijgt:
> curl http://localhost:8080/ping
pong
U kunt ook een webbrowser openen, navigeren naar de URL http: // localhost: 8080 / ping om de uitvoer te bekijken
Basis routing
Maak eerst een express-app:
const express = require('express');
const app = express();
Vervolgens kunt u routes als volgt definiëren:
app.get('/someUri', function (req, res, next) {})
Die structuur werkt voor alle HTTP-methoden en verwacht een pad als het eerste argument, en een handler voor dat pad, die de aanvraag- en reactieobjecten ontvangt. Dus voor de basis HTTP-methoden zijn dit de routes
// GET www.domain.com/myPath
app.get('/myPath', function (req, res, next) {})
// POST www.domain.com/myPath
app.post('/myPath', function (req, res, next) {})
// PUT www.domain.com/myPath
app.put('/myPath', function (req, res, next) {})
// DELETE www.domain.com/myPath
app.delete('/myPath', function (req, res, next) {})
U kunt de volledige lijst van ondersteunde werkwoorden controleren hier . Als u hetzelfde gedrag voor een route en alle HTTP-methoden wilt definiëren, kunt u het volgende gebruiken:
app.all('/myPath', function (req, res, next) {})
of
app.use('/myPath', function (req, res, next) {})
of
app.use('*', function (req, res, next) {})
// * wildcard will route for all paths
U kunt uw routedefinities voor één pad koppelen
app.route('/myPath')
.get(function (req, res, next) {})
.post(function (req, res, next) {})
.put(function (req, res, next) {})
U kunt ook functies toevoegen aan elke HTTP-methode. Ze worden uitgevoerd vóór de laatste callback en nemen de parameters (req, res, next) als argumenten.
// GET www.domain.com/myPath
app.get('/myPath', myFunction, function (req, res, next) {})
Uw laatste callbacks kunnen worden opgeslagen in een extern bestand om te voorkomen dat u teveel code in één bestand plaatst:
// other.js
exports.doSomething = function(req, res, next) {/* do some stuff */};
En vervolgens in het bestand met uw routes:
const other = require('./other.js');
app.get('/someUri', myFunction, other.doSomething);
Dit maakt je code veel schoner.
Informatie krijgen van het verzoek
Om informatie te krijgen van de aanvragende url (merk op dat req
het aanvraagobject is in de handlerfunctie van routes). Beschouw deze /settings/32135?field=name
/settings/:user_id
en dit specifieke voorbeeld /settings/32135?field=name
// get the full path
req.originalUrl // => /settings/32135?field=name
// get the user_id param
req.params.user_id // => 32135
// get the query value of the field
req.query.field // => 'name'
U kunt ook koppen van het verzoek krijgen, zoals deze
req.get('Content-Type')
// "text/plain"
Om het verkrijgen van andere informatie te vereenvoudigen, kunt u middlewares gebruiken. Om bijvoorbeeld de body-info van het verzoek te krijgen, kunt u de body-parser middleware gebruiken, die de ruwe body van het verzoek in een bruikbaar formaat zal transformeren.
var app = require('express')();
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
Stel nu een verzoek als dit
PUT /settings/32135
{
"name": "Peter"
}
Je hebt op deze manier toegang tot de geposte naam
req.body.name
// "Peter"
Op dezelfde manier hebt u vanaf het verzoek toegang tot cookies, u hebt ook een middleware zoals cookie-parser nodig
req.cookies.name
Modulaire uitdrukkelijke toepassing
Om express webapplicaties modulair te gebruiken, gebruik je routerfabrieken:
module:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
router.get('/greet', (req, res, next) => {
res.end(options.greeting);
});
return router;
};
Toepassing:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
express()
.use('/api/v1/', greetMiddleware({ greeting:'Hello world' }))
.listen(8080);
Dit maakt uw applicatie modulair, aanpasbaar en uw code herbruikbaar.
Bij toegang tot http://<hostname>:8080/api/v1/greet
de uitvoer Hello world
Meer gecompliceerd voorbeeld
Voorbeeld met services die de voordelen van de middleware-fabriek laten zien.
module:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
// Get controller
const {service} = options;
router.get('/greet', (req, res, next) => {
res.end(
service.createGreeting(req.query.name || 'Stranger')
);
});
return router;
};
Toepassing:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
class GreetingService {
constructor(greeting = 'Hello') {
this.greeting = greeting;
}
createGreeting(name) {
return `${this.greeting}, ${name}!`;
}
}
express()
.use('/api/v1/service1', greetMiddleware({
service: new GreetingService('Hello'),
}))
.use('/api/v1/service2', greetMiddleware({
service: new GreetingService('Hi'),
}))
.listen(8080);
Bij toegang tot http://<hostname>:8080/api/v1/service1/greet?name=World
de uitvoer Hello, World
en toegang tot http://<hostname>:8080/api/v1/service2/greet?name=World
de uitvoer is Hi, World
.
Een Template Engine gebruiken
Een Template Engine gebruiken
De volgende code zal Jade instellen als sjabloon-engine. (Opmerking: Jade is vanaf december 2015 hernoemd in pug
.)
const express = require('express'); //Imports the express module
const app = express(); //Creates an instance of the express module
const PORT = 3000; //Randomly chosen port
app.set('view engine','jade'); //Sets jade as the View Engine / Template Engine
app.set('views','src/views'); //Sets the directory where all the views (.jade files) are stored.
//Creates a Root Route
app.get('/',function(req, res){
res.render('index'); //renders the index.jade file into html and returns as a response. The render function optionally takes the data to pass to the view.
});
//Starts the Express server with a callback
app.listen(PORT, function(err) {
if (!err) {
console.log('Server is running at port', PORT);
} else {
console.log(JSON.stringify(err));
}
});
Evenzo zouden andere sjabloon motoren ook worden gebruikt zoals Handlebars
( hbs
) of ejs
. Vergeet niet npm install
de Template Engine te npm install
. Voor sturen gebruiken we het hbs
pakket, voor Jade hebben we een jade
pakket en voor EJS hebben we een ejs
pakket.
EJS-sjabloonvoorbeeld
Met EJS (net als andere express-sjablonen) kunt u servercode uitvoeren en toegang krijgen tot uw servervariabelen vanuit uw HTML.
In EJS wordt het gedaan met " <%
" als start-tag en " %>
" als eind-tag, variabelen worden doorgegeven terwijl de render-params toegankelijk zijn met <%=var_name%>
Als u bijvoorbeeld een array met benodigdheden in uw servercode hebt
je kunt er een lus over gebruiken met
<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
<li>
<a href='supplies/<%= supplies[i] %>'>
<%= supplies[i] %>
</a>
</li>
<% } %>
Zoals je in het voorbeeld kunt zien, moet je elke keer dat je schakelt tussen server side code en HTML de huidige EJS-tag sluiten en later een nieuwe openen, hier wilden we li
in de opdracht for
dus moesten we onze EJS-tag sluiten aan het einde van de for
en maak een nieuwe tag alleen voor de accolades
een ander voorbeeld
als we input standaardversie als een variabele van de server willen instellen, gebruiken we <%=
bijvoorbeeld:
Message:<br>
<input type="text" value="<%= message %>" name="message" required>
Hier is de berichtvariabele die wordt doorgegeven vanaf uw serverzijde de standaardwaarde van uw invoer. Houd er rekening mee dat als u de berichtvariabele niet hebt doorgegeven vanaf uw serverzijde, EJS een uitzondering genereert. U kunt parameters doorgeven met behulp van res.render('index', {message: message});
(voor ejs-bestand index.ejs).
In de EJS-tags kunt u ook if
, while
of een andere javascript-opdracht gebruiken.
JSON API met ExpressJS
var express = require('express');
var cors = require('cors'); // Use cors module for enable Cross-origin resource sharing
var app = express();
app.use(cors()); // for all routes
var port = process.env.PORT || 8080;
app.get('/', function(req, res) {
var info = {
'string_value': 'StackOverflow',
'number_value': 8476
}
res.json(info);
// or
/* res.send(JSON.stringify({
string_value: 'StackOverflow',
number_value: 8476
})) */
//you can add a status code to the json response
/* res.status(200).json(info) */
})
app.listen(port, function() {
console.log('Node.js listening on port ' + port)
})
Op http://localhost:8080/
uitvoerobject
{
string_value: "StackOverflow",
number_value: 8476
}
Presenteren van statische bestanden
Bij het bouwen van een webserver met Express is het vaak nodig om een combinatie van dynamische inhoud en statische bestanden weer te geven.
Het is bijvoorbeeld mogelijk dat index.html en script.js statische bestanden in het bestandssysteem zijn.
Het is gebruikelijk om de map 'public' te gebruiken om statische bestanden te hebben. In dit geval kan de mappenstructuur er als volgt uitzien:
project root
├── server.js
├── package.json
└── public
├── index.html
└── script.js
Zo configureert u Express om statische bestanden weer te geven:
const express = require('express');
const app = express();
app.use(express.static('public'));
Opmerking: zodra de map is geconfigureerd, zijn index.html, script.js en alle bestanden in de map "public" beschikbaar in het rootpad (u moet niet /public/
opgeven in de url). Dit komt omdat Express zoekt naar de bestanden met betrekking tot de geconfigureerde statische map. U kunt een virtueel padvoorvoegsel opgeven zoals hieronder wordt weergegeven:
app.use('/static', express.static('public'));
stelt de bronnen beschikbaar onder het /static/
prefix.
Meerdere mappen
Het is mogelijk om meerdere mappen tegelijkertijd te definiëren:
app.use(express.static('public'));
app.use(express.static('images'));
app.use(express.static('files'));
Bij het bedienen van de middelen zal Express de map in de volgorde van de definitie onderzoeken. In het geval van bestanden met dezelfde naam, wordt die in de eerste overeenkomende map weergegeven.
Genoemde routes in Django-stijl
Een groot probleem is dat waardevolle benoemde routes niet direct door Express worden ondersteund. Oplossing is het installeren van een ondersteund pakket van derden, bijvoorbeeld express-reverse :
npm install express-reverse
Sluit het aan op uw project:
var app = require('express')();
require('express-reverse')(app);
Gebruik het dan als:
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
Het nadeel van deze aanpak is dat u de route
Express-module niet kunt gebruiken zoals weergegeven in Geavanceerd routergebruik . De oplossing is om uw app
als parameter door te geven aan uw routerfabriek:
require('./middlewares/routing')(app);
En gebruik het als:
module.exports = (app) => {
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
};
Je kunt er vanaf nu achter komen hoe je functies definieert om het samen te voegen met opgegeven aangepaste naamruimten en naar de juiste controllers te wijzen.
Foutafhandeling
Basisfoutafhandeling
Standaard zoekt Express naar een weergave 'fout' in de map /views
om te renderen. Maak eenvoudig de weergave 'Fout' en plaats deze in de map 'Weergaven' om fouten af te handelen. Fouten worden geschreven met het foutbericht, de status en de stacktracering, bijvoorbeeld:
views / error.pug
html
body
h1= message
h2= error.status
p= error.stack
Geavanceerde foutafhandeling
Definieer uw foutafhandeling middleware-functies helemaal aan het einde van de stapel middleware-functies. Deze hebben bijvoorbeeld vier argumenten in plaats van drie (err, req, res, next)
:
app.js
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
//pass error to the next matching route.
next(err);
});
// handle error, print stacktrace
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
U kunt verschillende foutafhandelingsmiddleware-functies definiëren, net als bij normale middleware-functies.
Middleware en de volgende callback gebruiken
Express geeft een next
callback door aan elke routehandler en middleware-functie die kan worden gebruikt om logica voor afzonderlijke routes over meerdere handlers te doorbreken. Het aanroepen van next()
zonder argumenten vertelt express om door te gaan naar de volgende overeenkomende middleware of route-handler. Als u next(err)
belt met een fout, wordt elke middleware voor de fouthandler geactiveerd. Als je next('route')
aanroept, wordt elke volgende middleware op de huidige route omzeild en spring je naar de volgende overeenkomende route. Hierdoor kan domeinlogica worden ontkoppeld in herbruikbare componenten die op zichzelf staan, eenvoudiger te testen zijn en gemakkelijker te onderhouden en te wijzigen zijn.
Meerdere bijpassende routes
Verzoeken aan /api/foo
of /api/bar
zullen de initiële handler uitvoeren om het lid op te zoeken en vervolgens de besturing doorgeven aan de feitelijke handler voor elke route.
app.get('/api', function(req, res, next) {
// Both /api/foo and /api/bar will run this
lookupMember(function(err, member) {
if (err) return next(err);
req.member = member;
next();
});
});
app.get('/api/foo', function(req, res, next) {
// Only /api/foo will run this
doSomethingWithMember(req.member);
});
app.get('/api/bar', function(req, res, next) {
// Only /api/bar will run this
doSomethingDifferentWithMember(req.member);
});
Foutafhandeling
Foutafhandelaars zijn middleware met de handtekeningfunctie function(err, req, res, next)
. Ze kunnen per route worden ingesteld (bijv. app.get('/foo', function(err, req, res, next)
) maar meestal volstaat een enkele foutafhandelaar die een foutpagina weergeeft.
app.get('/foo', function(req, res, next) {
doSomethingAsync(function(err, data) {
if (err) return next(err);
renderPage(data);
});
});
// In the case that doSomethingAsync return an error, this special
// error handler middleware will be called with the error as the
// first parameter.
app.use(function(err, req, res, next) {
renderErrorPage(err);
});
middleware
Elk van de bovenstaande functies is eigenlijk een middleware-functie die wordt uitgevoerd wanneer een aanvraag overeenkomt met de gedefinieerde route, maar een willekeurig aantal middleware-functies kan op een enkele route worden gedefinieerd. Hierdoor kan middleware in afzonderlijke bestanden worden gedefinieerd en kan gemeenschappelijke logica op meerdere routes worden hergebruikt.
app.get('/bananas', function(req, res, next) {
getMember(function(err, member) {
if (err) return next(err);
// If there's no member, don't try to look
// up data. Just go render the page now.
if (!member) return next('route');
// Otherwise, call the next middleware and fetch
// the member's data.
req.member = member;
next();
});
}, function(req, res, next) {
getMemberData(req.member, function(err, data) {
if (err) return next(err);
// If this member has no data, don't bother
// parsing it. Just go render the page now.
if (!data) return next('route');
// Otherwise, call the next middleware and parse
// the member's data. THEN render the page.
req.member.data = data;
next();
});
}, function(req, res, next) {
req.member.parsedData = parseMemberData(req.member.data);
next();
});
app.get('/bananas', function(req, res, next) {
renderBananas(req.member);
});
In dit voorbeeld bevindt elke middleware-functie zich in een eigen bestand of in een variabele elders in het bestand, zodat deze op andere routes kan worden hergebruikt.
Foutafhandeling
Basisdocumenten zijn hier te vinden
app.get('/path/:id(\\d+)', function (req, res, next) { // please note: "next" is passed
if (req.params.id == 0) // validate param
return next(new Error('Id is 0')); // go to first Error handler, see below
// Catch error on sync operation
var data;
try {
data = JSON.parse('/file.json');
} catch (err) {
return next(err);
}
// If some critical error then stop application
if (!data)
throw new Error('Smth wrong');
// If you need send extra info to Error handler
// then send custom error (see Appendix B)
if (smth)
next(new MyError('smth wrong', arg1, arg2))
// Finish request by res.render or res.end
res.status(200).end('OK');
});
// Be sure: order of app.use have matter
// Error handler
app.use(function(err, req, res, next)) {
if (smth-check, e.g. req.url != 'POST')
return next(err); // go-to Error handler 2.
console.log(req.url, err.message);
if (req.xhr) // if req via ajax then send json else render error-page
res.json(err);
else
res.render('error.html', {error: err.message});
});
// Error handler 2
app.use(function(err, req, res, next)) {
// do smth here e.g. check that error is MyError
if (err instanceof MyError) {
console.log(err.message, err.arg1, err.arg2);
}
...
res.end();
});
Bijlage A
// "In Express, 404 responses are not the result of an error,
// so the error-handler middleware will not capture them."
// You can change it.
app.use(function(req, res, next) {
next(new Error(404));
});
Bijlage B
// How to define custom error
var util = require('util');
...
function MyError(message, arg1, arg2) {
this.message = message;
this.arg1 = arg1;
this.arg2 = arg2;
Error.captureStackTrace(this, MyError);
}
util.inherits(MyError, Error);
MyError.prototype.name = 'MyError';
Hook: Hoe code uit te voeren vóór elke req en na een res
app.use()
en middleware kunnen worden gebruikt voor "voor" en een combinatie van de nauwe en afwerking gebeurtenissen kunnen worden gebruikt voor "na".
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterResponse);
res.removeListener('close', afterResponse);
// actions after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
next();
});
...
app.use(app.router);
Een voorbeeld hiervan is de logger- middleware, die standaard aan het logboek wordt toegevoegd na de reactie.
Zorg er alleen voor dat deze "middleware" wordt gebruikt vóór app.router
want de volgorde doet er toe.
Origineel bericht is hier
POST-aanvragen afhandelen
Net zoals u verzoeken om ontvangen in Express met de app.get-methode afhandelt, kunt u de app.post-methode gebruiken om postverzoeken af te handelen.
Maar voordat u POST-aanvragen kunt afhandelen, moet u de body-parser
middleware gebruiken. Het ontleedt eenvoudigweg de inhoud van POST
, PUT
, DELETE
en andere verzoeken.
Body-Parser
middleware ontleedt de body van het verzoek en maakt er een object van dat beschikbaar is in req.body
var bodyParser = require('body-parser');
const express = require('express');
const app = express();
// Parses the body for POST, PUT, DELETE, etc.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/post-data-here', function(req, res, next){
console.log(req.body); // req.body contains the parsed body of the request.
});
app.listen(8080, 'localhost');
Cookies instellen met cookie-parser
Het volgende is een voorbeeld voor het instellen en lezen van cookies met behulp van de cookie-parsermodule :
var express = require('express');
var cookieParser = require('cookie-parser'); // module for parsing cookies
var app = express();
app.use(cookieParser());
app.get('/setcookie', function(req, res){
// setting cookies
res.cookie('username', 'john doe', { maxAge: 900000, httpOnly: true });
return res.send('Cookie has been set');
});
app.get('/getcookie', function(req, res) {
var username = req.cookies['username'];
if (username) {
return res.send(username);
}
return res.send('No cookie found');
});
app.listen(3000);
Aangepaste middleware in Express
In Express kunt u middlewares definiëren die kunnen worden gebruikt voor het controleren van aanvragen of als reactie hierop enkele headers.
app.use(function(req, res, next){ }); // signature
Voorbeeld
De volgende code voegt de user
aan het aanvraagobject en geeft het besturingselement door aan de volgende overeenkomende route.
var express = require('express');
var app = express();
//each request will pass through it
app.use(function(req, res, next){
req.user = 'testuser';
next(); // it will pass the control to next matching route
});
app.get('/', function(req, res){
var user = req.user;
console.log(user); // testuser
return res.send(user);
});
app.listen(3000);
Foutafhandeling in Express
In Express kunt u een uniforme foutafhandelingsfunctie definiëren voor fouten in de toepassing. Definieer vervolgens handler aan het einde van alle routes en logische code.
Voorbeeld
var express = require('express');
var app = express();
//GET /names/john
app.get('/names/:name', function(req, res, next){
if (req.params.name == 'john'){
return res.send('Valid Name');
} else{
next(new Error('Not valid name')); //pass to error handler
}
});
//error handler
app.use(function(err, req, res, next){
console.log(err.stack); // e.g., Not valid name
return res.status(500).send('Internal Server Occured');
});
app.listen(3000);
Middleware toevoegen
Middleware-functies zijn functies die toegang hebben tot het aanvraagobject (req), het responsobject (res) en de volgende middleware-functie in de aanvraag-responscyclus van de toepassing.
Middleware functies kan een code uit te voeren, wijzigingen aanbrengen in res
en req
voorwerpen, end respons cyclus en bel de volgende middleware.
Veel voorkomend voorbeeld van middleware is de cors
module. Om CORS-ondersteuning toe te voegen, installeert u deze, vereist u deze en zet u deze regel:
app.use(cors());
vóór routers of routeringsfuncties.
Hallo Wereld
Hier maken we een eenvoudige hallo wereld-server met behulp van Express. routes:
- '/'
- '/ Wiki'
En voor de rest geeft "404", dat wil zeggen pagina niet gevonden.
'use strict';
const port = process.env.PORT || 3000;
var app = require('express')();
app.listen(port);
app.get('/',(req,res)=>res.send('HelloWorld!'));
app.get('/wiki',(req,res)=>res.send('This is wiki page.'));
app.use((req,res)=>res.send('404-PageNotFound'));
Opmerking: We hebben 404-route als de laatste route gezet, aangezien Express routes in volgorde stapelt en deze voor elke aanvraag opeenvolgend verwerkt.