035.2 Μάθημα 1
Πιστοποιητικό: |
Web Development Essentials |
---|---|
Έκδοση: |
1.0 |
Θέμα: |
035 Προγραμματισμός NodeJS Server |
Σκοπός: |
035.2 Βασικά Στοιχεία NodeJS Express |
Μάθημα: |
1 απο 2 |
Εισαγωγή
Το Express.js, ή απλά Express, είναι ένα δημοφιλές framework που τρέχει στο Node.js και χρησιμοποιείται για τη δημιουργία HTTP servers που χειρίζονται requests από clients web εφαρμογών. Το Express υποστηρίζει πολλούς τρόπους ανάγνωσης παραμέτρων που αποστέλλονται μέσω HTTP.
Αρχικό Server Script
Για να δείξουμε τις βασικές δυνατότητες του Express για λήψη και χειρισμό requests, ας προσομοιώσουμε μια εφαρμογή που ζητά ορισμένες πληροφορίες από τον server. Συγκεκριμένα, το παράδειγμα server:
-
Παρέχει ένα
echo
function, το οποίο απλώς επιστρέφει το μήνυμα που έστειλε ο client. -
Λέει στον client τη διεύθυνση IP του κατόπιν request.
-
Χρησιμοποιεί cookies για την αναγνώριση γνωστών clients.
Το πρώτο βήμα είναι να δημιουργήσετε το αρχείο JavaScript που θα λειτουργεί ως server. Χρησιμοποιώντας npm
, δημιουργήστε ένα folder που ονομάζεται myserver
με το αρχείο JavaScript:
$ mkdir myserver $ cd myserver/ $ npm init
Για το σημείο εισόδου, μπορεί να χρησιμοποιηθεί οποιοδήποτε όνομα αρχείου. Εδώ θα χρησιμοποιήσουμε το προεπιλεγμένο όνομα αρχείου: index.js
. Η ακόλουθη παράθεση εμφανίζει ένα βασικό αρχείο index.js
που θα χρησιμοποιηθεί ως σημείο εισόδου για τον server μας:
const express = require('express')
const app = express()
const host = "myserver"
const port = 8080
app.get('/', (req, res) => {
res.send('Request received')
})
app.listen(port, host, () => {
console.log(`Server ready at http://${host}:${port}`)
})
Ορισμένες σημαντικές σταθερές για τη διαμόρφωση του server ορίζονται στις πρώτες γραμμές του script. Οι δύο πρώτες, express
και app
, αντιστοιχούν στη συμπεριλαμβανόμενη express
module και σε ένα instance αυτού του module που εκτελεί την εφαρμογή μας. Θα προσθέσουμε τις ενέργειες που θα εκτελεστούν από τον server στο object app
.
Οι άλλες δύο σταθερές, host
και port
, ορίζουν τον host και το port επικοινωνίας που σχετίζονται με τον server.
Εάν έχετε έναν host προσβάσιμο απο το internet, χρησιμοποιήστε το όνομά του αντί για myserver
ως τιμή του host
. Εάν δεν παρέχετε το όνομα του host, το Express θα χρησιμοποιήσει το localhost
απο προεπιλογή, τον υπολογιστή στον οποίο εκτελείται η εφαρμογή. Σε αυτήν την περίπτωση, κανένας εξωτερικός client δεν θα μπορεί να τρέξει το πρόγραμμα, το οποίο μπορεί να είναι καλό για δοκιμή, αλλά προσφέρει μικρή αξία στο production.
Πρέπει να παρασχεθεί το port, διαφορετικά ο server δεν θα ξεκινήσει.
Tο script συνδέει μόνο δύο διαδικασίες στο object app
: την ενέργεια app.get()
που απαντά σε requests που υποβάλλονται από clients μέσω HTTP GET
και την κλήση app.listen()
, η οποία απαιτείται για την ενεργοποίηση του server και του εκχωρεί ένα host και ένα port.
Για να ξεκινήσετε τον server, απλώς εκτελέστε την εντολή node
, παρέχοντας το όνομα του script ως argument:
$ node index.js
Μόλις εμφανιστεί το μήνυμα Server ready at http://myserver:8080
, ο server είναι έτοιμος να λάβει requests από έναν HTTP client. Τα requests μπορούν να γίνουν από ένα πρόγραμμα περιήγησης που τρέχει στον ίδιο υπολογιστή όπου εκτελείται ο server ή από άλλο μηχάνημα που μπορεί να έχει πρόσβαση στον server.
Όλες οι λεπτομέρειες της επικοινωνίας που θα δούμε εδώ εμφανίζονται στο πρόγραμμα περιήγησης εάν ανοίξετε ένα παράθυρο για την κονσόλα προγραμματιστή. Εναλλακτικά, η εντολή curl
μπορεί να χρησιμοποιηθεί για HTTP επικοινωνία και σας επιτρέπει να επιθεωρείτε πιο εύκολα τις λεπτομέρειες της σύνδεσης. Εάν δεν είστε εξοικειωμένοι με τη γραμμή εντολών του shell, μπορείτε να δημιουργήσετε μια φόρμα HTML για να υποβάλετε requests σε έναν server.
Το ακόλουθο παράδειγμα δείχνει πώς να χρησιμοποιήσετε την εντολή curl
στη γραμμή εντολών για να κάνετε ένα HTTP request στον πρόσφατα δημιουργημένο server:
$ curl http://myserver:8080 -v * Trying 192.168.1.225:8080... * TCP_NODELAY set * Connected to myserver (192.168.1.225) port 8080 (#0) > GET / HTTP/1.1 > Host: myserver:8080 > User-Agent: curl/7.68.0 >Accept: / > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < X-Powered-By: Express < Content-Type: text/html; charset=utf-8 < Content-Length: 16 < ETag: W/"10-1WVvDtVyAF0vX9evlsFlfiJTT5c" < Date: Fri, 02 Jul 2021 14:35:11 GMT < Connection: keep-alive < * Connection #0 to host myserver left intact Request received
Η επιλογή -v
της εντολής curl
εμφανίζει όλα τα headers των request και των response, καθώς και άλλες πληροφορίες εντοπισμού σφαλμάτων. Οι γραμμές που ξεκινούν με >
υποδεικνύουν τα headers των request που αποστέλλονται από τον client και οι γραμμές που ξεκινούν με <
υποδεικνύουν τα headers των response που αποστέλλονται από τον server. Οι γραμμές που ξεκινούν με *
είναι πληροφορίες που δημιουργούνται από το ίδιο το curl
. Το περιεχόμενο του response εμφανίζεται μόνο στο τέλος, που σε αυτήν την περίπτωση είναι η γραμμή Request received
.
Η διεύθυνση URL της υπηρεσίας, η οποία σε αυτήν την περίπτωση περιέχει το hostname και το port του server (http://myserver:8080
), δόθηκαν ως arguments στην εντολή curl
. Επειδή δεν δίνεται φάκελος ή όνομα αρχείου, αυτά, βρίσκονται στο root φάκελο /
απο προεπιλογή. Η κάθετος εμφανίζεται ως το αρχείο του request στη γραμμή > GET / HTTP/1.1
, η οποία ακολουθείται στο output από το hostname και το port.
Εκτός από την εμφάνιση headers της HTTP σύνδεσης, η εντολή curl
βοηθά την ανάπτυξη εφαρμογών επιτρέποντάς σας να στέλνετε δεδομένα στον server χρησιμοποιώντας διαφορετικές μεθόδους HTTP και σε διαφορετικές μορφές. Αυτή η ευελιξία διευκολύνει τον εντοπισμό σφαλμάτων τυχόν προβλημάτων και την εφαρμογή νέων δυνατοτήτων στον server.
Routes
Τα request που μπορεί να κάνει ο client στον server εξαρτώνται από τα routes [δρομολόγια] που έχουν οριστεί στο αρχείο index.js
. Ένα route καθορίζει μια μέθοδο HTTP και ορίζει ένα path (ακριβέστερα, ένα URI) που μπορεί να ζητηθεί από τον client.
Μέχρι στιγμής, ο server έχει διαμορφωμένο μόνο ένα route:
app.get('/', (req, res) => {
res.send('Request received')
})
Παρόλο που είναι ένα πολύ απλό route, απλώς επιστρέφει ένα απλό μήνυμα κειμένου στον client, αρκεί για να προσδιορίσετε τα πιο σημαντικά στοιχεία που χρησιμοποιούνται για τη δομή των περισσότερων routes:
-
Η μέθοδος HTTP που εξυπηρετείται από το route. Στο παράδειγμα, η μέθοδος HTTP
GET
υποδεικνύεται από την ιδιότηταget
του objectapp
. -
Το path που εξυπηρετεί το route. Όταν ο client δεν καθορίζει ένα path για το request, ο server χρησιμοποιεί τον root φάκελο, ο οποίος είναι ο βασικός φάκελος που έχει οριστεί για χρήση από τον web server. Ένα άλλο παράδειγμα αργότερα σε αυτό το κεφάλαιο, χρησιμοποιεί το path
/echo
, το οποίο αντιστοιχεί σε ένα request που υποβλήθηκε στοmyserver:8080/echo
. -
Το function που εκτελείται όταν ο server λαμβάνει ένα request σε αυτό το route, που συνήθως γράφεται σε συντομογραφία ως arrow function επειδή η σύνταξη
=>
δείχνει τον ορισμό του ανώνυμου function. Η παράμετροςreq
(συντομογραφία για το “request”) και η παράμετροςres
(συντομογραφία για το “response”) παρέχουν λεπτομέρειες σχετικά με τη σύνδεση, που μεταβιβάστηκε στο function από την ίδια το instance της εφαρμογής.
Μέθοδος POST
Για να επεκτείνουμε τη λειτουργικότητα του δοκιμαστικού server μας, ας δούμε πώς να ορίσουμε ένα route για τη μέθοδο HTTP POST
. Χρησιμοποιείται από clients όταν χρειάζεται να στείλουν επιπλέον δεδομένα στον server πέρα από αυτά που περιλαμβάνονται στο request header. Η επιλογή --data
της εντολής curl
καλεί αυτόματα τη μέθοδο POST
και περιλαμβάνει περιεχόμενο που θα σταλεί στον server μέσω του POST
. Η γραμμή POST / HTTP/1.1
στο ακόλουθο output δείχνει ότι χρησιμοποιήθηκε η μέθοδος POST
. Ωστόσο, ο server μας όρισε μόνο μια μέθοδο GET
, επομένως προκύπτει ένα σφάλμα όταν χρησιμοποιούμε το curl
για να στείλουμε ένα request μέσω POST
:
$ curl http://myserver:8080/echo --data message="This is the POST request body" * Trying 192.168.1.225:8080... * TCP_NODELAY set * Connected to myserver (192.168.1.225) port 8080 (#0) > POST / HTTP/1.1 > Host: myserver:8080 > User-Agent: curl/7.68.0 >Accept: / > Content-Length: 37 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 37 out of 37 bytes * Mark bundle as not supporting multiuse < HTTP/1.1 404 Not Found < X-Powered-By: Express < Content-Security-Policy: default-src 'none' < X-Content-Type-Options: nosniff < Content-Type: text/html; charset=utf-8 < Content-Length: 140 < Date: Sat, 03 Jul 2021 02:22:45 GMT < Connection: keep-alive < <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Error</title> </head> <body> <pre>Cannot POST /</pre> </body> </html> * Connection #0 to host myserver left intact
Στο προηγούμενο παράδειγμα, η εκτέλεση του curl
με την παράμετρο --data message="This is the POST request body"
ισοδυναμεί με την υποβολή μιας φόρμας που περιέχει το πεδίο κειμένου με το όνομα message
, και κείμενο This is the POST request body
.
Επειδή ο server έχει ρυθμιστεί με ένα μόνο route για το path /
και αυτό το route ανταποκρίνεται μόνο στη μέθοδο HTTP GET
, το response header επομένως έχει τη γραμμή HTTP/1.1 404 Not Found
. Επιπλέον, το Express δημιούργησε αυτόματα ένα σύντομο HTML response με την προειδοποίηση Cannot POST
.
Έχοντας δει πώς δημιουργείται ένα POST
request μέσω του curl
, ας γράψουμε ένα πρόγραμμα Express που μπορεί να χειριστεί με επιτυχία το request.
Αρχικά, σημειώστε ότι το πεδίο Content-Type
στο request header λέει ότι τα δεδομένα που αποστέλλονται από τον client είναι στη μορφή application/x-www-form-urlencoded
. Η Express δεν αναγνωρίζει αυτή τη μορφή από προεπιλογή, επομένως πρέπει να χρησιμοποιήσουμε το module express.urlencoded
. Όταν περιλαμβάνουμε αυτό το module, το object req
--που μεταβιβάζεται ως παράμετρος στο handler function—έχει την ιδιότητα req.body.message
ρυθμισμένη, η οποία αντιστοιχεί στο πεδίο message
που αποστέλλεται από τον client. Το module φορτώνεται με app.use
, το οποίο θα πρέπει να τοποθετηθεί πριν από τη δήλωση των routes:
const express = require('express')
const app = express()
const host = "myserver"
const port = 8080
app.use(express.urlencoded({ extended: true }))
Μόλις γίνει αυτό, θα αρκούσε να αλλάξετε το app.get
σε app.post
στο υπάρχον route για να εκπληρώσετε requests που έγιναν μέσω του POST
και να ανακτήσετε το σώμα του request:
app.post('/', (req, res) => {
res.send(req.body.message)
})
Αντί να αντικαταστήσετε το route, μια άλλη δυνατότητα θα ήταν απλώς να προσθέσετε αυτό το νέο route, επειδή το Express προσδιορίζει τη μέθοδο HTTP στο request header και χρησιμοποιεί το κατάλληλο route. Επειδή μας ενδιαφέρει να προσθέσουμε περισσότερες από μία λειτουργίες σε αυτόν τον server, είναι βολικό να διαχωρίζουμε τη καθεμία με το δική της path, όπως /echo
και /ip
.
Path και Function Handler
Έχοντας ορίσει ποια μέθοδο HTTP θα ανταποκριθεί στο request, τώρα πρέπει να ορίσουμε ένα συγκεκριμένο path για το resource και ένα function που επεξεργάζεται και δημιουργεί ένα response στον client.
Για να επεκτείνουμε τη λειτουργία echo
του server, μπορούμε να ορίσουμε ένα route χρησιμοποιώντας τη μέθοδο POST
με το path /echo
:
app.post('/echo', (req, res) => {
res.send(req.body.message)
})
Η παράμετρος req
του handler function περιέχει όλες τις λεπτομέρειες του request αποθηκευμένες ως ιδιότητες. Το περιεχόμενο του πεδίου message
στο σώμα του request είναι διαθέσιμο στην ιδιότητα req.body.message
. Το παράδειγμα απλώς στέλνει αυτό το πεδίο που αποστέλλεται πίσω στον client μέσω της κλήσης res.send(req.body.message)
.
Θυμηθείτε ότι οι αλλαγές που κάνετε ισχύουν μόνο μετά την επανεκκίνηση του server. Επειδή εκτελείτε τον server από ένα παράθυρο ενός terminal κατά τη διάρκεια των παραδειγμάτων σε αυτό το κεφάλαιο, μπορείτε να τερματίσετε τη λειτουργία του server πατώντας kbd:[Ctrl+C] σε αυτό το terminal. Στη συνέχεια, εκτελέστε ξανά τον server μέσω της εντολής node index.js
. Το response που έλαβε ο client στο curl
request που δείξαμε πριν είναι πλέον επιτυχής:
$ curl http://myserver:8080/echo --data message="This is the POST request body" This is the POST request body
Άλλοι Τρόποι Μεταβίβασης και Επιστροφής Πληροφοριών σε ένα GET Request
Μπορεί να είναι υπερβολική η χρήση της μεθόδου HTTP POST
εάν πρόκειται να σταλούν μόνο σύντομα μηνύματα κειμένου όπως αυτό που χρησιμοποιείται στο παράδειγμα. Σε τέτοιες περιπτώσεις, τα δεδομένα μπορούν να σταλούν σε ένα query string που ξεκινά με ένα ερωτηματικό. Έτσι, το string ?message=This+is+the+message
θα μπορούσε να συμπεριληφθεί στο request path της μεθόδου HTTP GET
. Τα πεδία που χρησιμοποιούνται στο query string είναι διαθέσιμα στον server, στην ιδιότητα req.query
. Επομένως, ένα πεδίο με το όνομα message
είναι διαθέσιμο στην ιδιότητα req.query.message
.
Ένας άλλος τρόπος αποστολής δεδομένων μέσω της μεθόδου HTTP GET
είναι να χρησιμοποιήσετε τις route parameters [παραμέτρους διαδρομής] του Express:
app.get('/echo/:message', (req, res) => {
res.send(req.params.message)
})
Το route σε αυτό το παράδειγμα ταιριάζει με requests που έγιναν με τη μέθοδο GET
χρησιμοποιώντας το route /echo/:message
, όπου το :message
είναι ένα placeholder [σύμβολο υποκατάστασης] για οποιονδήποτε όρο αποστέλλεται με αυτήν την ετικέτα από τον client. Αυτές οι παράμετροι είναι προσβάσιμες στην ιδιότητα req.params
. Με αυτό το νέο route, το echo
function του server μπορεί να ζητηθεί πιο συνοπτικά από τον client:
$ curl http://myserver:8080/echo/hello hello
Σε άλλες περιπτώσεις, οι πληροφορίες που χρειάζεται ο server για την επεξεργασία του request δεν χρειάζεται να παρέχονται ρητά από τον client. Για παράδειγμα, ο server έχει έναν άλλο τρόπο για να ανακτήσει τη δημόσια IP διεύθυνση του client. Αυτές οι πληροφορίες υπάρχουν στο object req
από προεπιλογή, στην ιδιότητα req.ip
:
app.get('/ip', (req, res) => {
res.send(req.ip)
})
Τώρα ο πελάτης μπορεί να ζητήσει το path /ip
με τη μέθοδο GET
για να βρει τη δική του δημόσια IP διεύθυνση:
$ curl http://myserver:8080/ip 187.34.178.12
Άλλες ιδιότητες του object req
μπορούν να τροποποιηθούν από τον client, ειδικά τα request headers που είναι διαθέσιμα στο req.headers
. Η ιδιότητα req.headers.user-agent
, για παράδειγμα, προσδιορίζει ποιο πρόγραμμα υποβάλλει το request. Αν και δεν είναι κοινή πρακτική, ο client μπορεί να αλλάξει τα περιεχόμενα αυτού του πεδίου, επομένως ο server δεν θα πρέπει να το χρησιμοποιεί για την αξιόπιστη αναγνώριση ενός συγκεκριμένου client. Είναι ακόμη πιο σημαντικό να επικυρώνονται τα δεδομένα που παρέχονται ρητά από τον client, για να αποφευχθούν ασυνέπειες στα όρια και τις μορφές που θα μπορούσαν να επηρεάσουν αρνητικά την εφαρμογή.
Προσαρμογές στο Response
Όπως είδαμε σε προηγούμενα παραδείγματα, η παράμετρος res
είναι υπεύθυνη για την επιστροφή ενός response στον client. Επιπλέον, το object res
μπορεί να αλλάξει άλλες πτυχές του response. Ίσως έχετε παρατηρήσει ότι, αν και τα responses που έχουμε εφαρμόσει μέχρι στιγμής είναι απλώς σύντομα μηνύματα απλού κειμένου, το header Content-Type
των responses χρησιμοποιεί text/html; charset=utf-8
. Αν και αυτό δεν εμποδίζει την αποδοχή ενός response απλού κειμένου, θα είναι πιο σωστό αν επαναπροσδιορίσουμε αυτό το πεδίο στο header του response σε text/plain
με τη ρύθμιση res.type('text/plain')
.
Άλλοι τύποι response προσαρμογών περιλαμβάνουν τη χρήση cookies, τα οποία επιτρέπουν στον server να αναγνωρίσει έναν client που έχει υποβάλει στο παρελθόν ένα request. Τα cookies είναι σημαντικά για προηγμένες λειτουργίες, όπως η δημιουργία ιδιωτικών sessions που συσχετίζουν requests με έναν συγκεκριμένο χρήστη, αλλά εδώ θα δούμε απλώς ένα απλό παράδειγμα του τρόπου χρήσης ενός cookie για τον προσδιορισμό ενός client που είχε προηγουμένως πρόσβαση στον server.
Δεδομένης της αρθρωτής σχεδίασης του Express, η διαχείριση cookie πρέπει να εγκατασταθεί με την εντολή npm
πριν χρησιμοποιηθεί στο script:
$ npm install cookie-parser
Μετά την εγκατάσταση, η διαχείριση cookie πρέπει να περιλαμβάνεται στο script του server. Ο ακόλουθος ορισμός πρέπει να συμπεριληφθεί κοντά στην αρχή του αρχείου:
const cookieParser = require('cookie-parser')
app.use(cookieParser())
Για να δείξουμε τη χρήση των cookies, ας τροποποιήσουμε το handler function του route με το root path /
που υπάρχει ήδη στο script. Το object req
έχει μια ιδιότητα req.cookies
, όπου διατηρούνται τα cookies που αποστέλλονται στο request header. Το object res
, από την άλλη πλευρά, έχει μια μέθοδο res.cookie()
που δημιουργεί ένα νέο cookie που θα σταλεί στον client. Το handler function στο ακόλουθο παράδειγμα ελέγχει εάν υπάρχει ένα cookie με το όνομα known
στο request. Εάν δεν υπάρχει τέτοιο cookie, ο server υποθέτει ότι είναι επισκέπτης για πρώτη φορά και του στέλνει ένα cookie με αυτό το όνομα μέσω της κλήσης res.cookie('known', '1')
. Εκχωρούμε αυθαίρετα την τιμή 1
στο cookie επειδή υποτίθεται ότι έχει κάποιο περιεχόμενο, αλλά ο server δεν συμβουλεύεται αυτήν την τιμή. Αυτή η εφαρμογή απλώς υποθέτει ότι η απλή παρουσία του cookie υποδηλώνει ότι ο client έχει ήδη ζητήσει αυτό το route στο παρελθόν:
app.get('/', (req, res) => {
res.type('text/plain')
if ( req.cookies.known === undefined ){
res.cookie('known', '1')
res.send('Welcome, new visitor!')
}
else
res.send('Welcome back, visitor');
})
Από προεπιλογή, το curl
δεν χρησιμοποιεί cookies στις συναλλαγές. Αλλά έχει επιλογές αποθήκευσης (-c cookies.txt
) και αποστολής αποθηκευμένων cookies (-b cookies.txt
):
$ curl http://myserver:8080/ -c cookies.txt -b cookies.txt -v * Trying 192.168.1.225:8080... * TCP_NODELAY set * Connected to myserver (192.168.1.225) port 8080 (#0) > GET / HTTP/1.1 > Host: myserver:8080 > User-Agent: curl/7.68.0 >Accept: / > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < X-Powered-By: Express < Content-Type: text/plain; charset=utf-8 * Added cookie known="1" for domain myserver, path /, expire 0 < Set-Cookie: known=1; Path=/ < Content-Length: 21 < ETag: W/"15-l7qrxcqicl4xv6EfA5fZFWCFrgY" < Date: Sat, 03 Jul 2021 23:45:03 GMT < Connection: keep-alive < * Connection #0 to host myserver left intact Welcome, new visitor!
Επειδή αυτή η εντολή ήταν η πρώτη πρόσβαση από τότε που εφαρμόστηκαν τα cookies στον server, ο client δεν είχε cookies για να συμπεριλάβει στο request. Όπως ήταν αναμενόμενο, ο server δεν αναγνώρισε το cookie στο request και επομένως συμπεριέλαβε το cookie στα response headers, όπως υποδεικνύεται στο Set-Cookie: known=1; Path=/
γραμμή της εξόδου. Εφόσον έχουμε ενεργοποιήσει τα cookie στο curl
, ένα νέο request θα περιλαμβάνει το cookie known=1
στα request headers, επιτρέποντας στον server να αναγνωρίσει την παρουσία του cookie:
$ curl http://myserver:8080/ -c cookies.txt -b cookies.txt -v * Trying 192.168.1.225:8080... * TCP_NODELAY set * Connected to myserver (192.168.1.225) port 8080 (#0) > GET / HTTP/1.1 > Host: myserver:8080 > User-Agent: curl/7.68.0 >Accept: / > Cookie: known=1 > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < X-Powered-By: Express < Content-Type: text/plain; charset=utf-8 < Content-Length: 21 < ETag: W/"15-ATq2flQYtLMYIUpJwwpb5SjV9Ww" < Date: Sat, 03 Jul 2021 23:45:47 GMT < Connection: keep-alive < * Connection #0 to host myserver left intact Welcome back, visitor
Ασφάλεια Cookie
Ο προγραμματιστής θα πρέπει να γνωρίζει πιθανές ευπάθειες όταν χρησιμοποιεί cookies για τον εντοπισμό clients που υποβάλλουν requests. Οι εισβολείς μπορούν να χρησιμοποιήσουν τεχνικές όπως cross-site scripting (XSS) και cross-site request forgery (CSRF) για να κλέψουν cookies από έναν client και, ως εκ τούτου, να τα πλαστοπροσωπήσουν όταν υποβάλλουν ένα request στον server. Σε γενικές γραμμές, αυτοί οι τύποι επιθέσεων χρησιμοποιούν μη επικυρωμένα πεδία σχολίων ή σχολαστικά κατασκευασμένες διευθύνσεις URL για την εισαγωγή κακόβουλου κώδικα JavaScript στη σελίδα. Όταν εκτελείται από έναν αυθεντικό client, αυτός ο κώδικας μπορεί να αντιγράψει έγκυρα cookies και να τα αποθηκεύσει ή να τα προωθήσει σε άλλο προορισμό.
Επομένως, ειδικά σε επαγγελματικές εφαρμογές, είναι σημαντικό να εγκαταστήσετε και να χρησιμοποιήσετε πιο εξειδικευμένες λειτουργίες Express, γνωστές ως middleware. Το module express-session
ή cookie-session
παρέχει πληρέστερο και ασφαλέστερο έλεγχο στη διαχείριση session και cookie. Αυτά τα στοιχεία επιτρέπουν επιπλέον ελέγχους για την αποτροπή εκτροπής των cookies από τον αρχικό τους εκδότη.
Καθοδηγούμενες Ασκήσεις
-
Πώς μπορεί να διαβαστεί το περιεχόμενο του πεδίου
comment
, που αποστέλλεται μέσα σε ένα query string της μεθόδου HTTPGET
, σε ένα handler function; -
Γράψτε ένα route που χρησιμοποιεί τη μέθοδο HTTP
GET
και το path/agent
για να στείλει πίσω στον client τα περιεχόμενα του headeruser-agent
. -
Το Express.js έχει μια δυνατότητα που ονομάζεται route parameters, όπου ένα route όπως το
/user/:name
μπορεί να χρησιμοποιηθεί για τη λήψη της παραμέτρουname
που αποστέλλεται από τον client. Πώς μπορεί να γίνει πρόσβαση στην παράμετροname
στο handler function του route;
Ασκήσεις Εξερεύνησης
-
Εάν το hostname ενός server είναι
myserver
, ποιό Express route θα λάβει την υποβολή στην παρακάτω φόρμα;<form action="/contact/feedback" method="post"> ... </form>
-
Κατά την ανάπτυξη λογισμικού server, ο προγραμματιστής δεν μπορεί να διαβάσει την ιδιότητα
req.body
, ακόμη και αφού επαληθεύσει ότι ο client στέλνει σωστά το περιεχόμενο μέσω της μεθόδου HTTPPOST
. Ποια είναι η πιθανή αιτία για αυτό το πρόβλημα; -
Τι συμβαίνει όταν ο server έχει ορίσει ένα route στο path
/user/:name
και ο client κάνει ένα request στο/user/
;
Σύνοψη
Αυτό το μάθημα εξηγεί πώς να γράφετε Express scripts για να λαμβάνετε και να χειρίζεστε HTTP requests. Η Express χρησιμοποιεί την έννοια των routes [διαδρομών] για να ορίσει τους πόρους που είναι διαθέσιμοι στους clients, γεγονός που σας δίνει μεγάλη ευελιξία για τη δημιουργία servers για κάθε είδους web εφαρμογή. Αυτό το μάθημα περιλαμβάνει τις ακόλουθες έννοιες και διαδικασίες:
-
Routes που χρησιμοποιούν τις μεθόδους HTTP
GET
και HTTPPOST
. -
Πώς αποθηκεύονται τα δεδομένα φόρμας στο object
request
. -
Πώς να χρησιμοποιήσετε τα route parameters.
-
Προσαρμογή response headers.
-
Βασική διαχείριση cookie.
Απαντήσεις στις Καθοδηγούμενες Ασκήσεις
-
Πώς μπορεί να διαβαστεί το περιεχόμενο του πεδίου
comment
, που αποστέλλεται μέσα σε ένα query string της μεθόδου HTTPGET
, σε ένα handler function;Το πεδίο
comment
είναι διαθέσιμο στην ιδιότηταreq.query.comment
. -
Γράψτε ένα route που χρησιμοποιεί τη μέθοδο HTTP
GET
και το path/agent
για να στείλει πίσω στον client τα περιεχόμενα του headeruser-agent
.app.get('/agent', (req, res) => { res.send(req.headers.user-agent) })
-
Το Express.js έχει μια δυνατότητα που ονομάζεται route parameters, όπου ένα route όπως το
/user/:name
μπορεί να χρησιμοποιηθεί για τη λήψη της παραμέτρουname
που αποστέλλεται από τον client. Πώς μπορεί να γίνει πρόσβαση στην παράμετροname
στο handler function του route;Η παράμετρος
name
είναι προσβάσιμη στην ιδιότηταreq.params.name
.
Απαντήσεις στις Ασκήσεις Εξερεύνησης
-
Εάν το hostname ενός server είναι
myserver
, ποιό Express route θα λάβει την υποβολή στην παρακάτω φόρμα;<form action="/contact/feedback" method="post"> ... </form>
app.post('/contact/feedback', (req, res) => { ... })
-
Κατά την ανάπτυξη λογισμικού server, ο προγραμματιστής δεν μπορεί να διαβάσει την ιδιότητα
req.body
, ακόμη και αφού επαληθεύσει ότι ο client στέλνει σωστά το περιεχόμενο μέσω της μεθόδου HTTPPOST
. Ποια είναι η πιθανή αιτία για αυτό το πρόβλημα;Ο προγραμματιστής δεν συμπεριέλαβε το module
express.urlencoded
, το οποίο επιτρέπει στο Express να εξάγει το σώμα ενός request. -
Τι συμβαίνει όταν ο server έχει ορίσει ένα route στο path
/user/:name
και ο client κάνει ένα request στο/user/
;Ο server θα εκδώσει ένα '404 Not Found' response, επειδή το route απαιτεί την παράμετρο
:name
να παρέχεται από τον client.