Pratiche per applicazioni Web ad alte prestazioni
introdurre
fibjs è un framework per server di applicazioni ad alte prestazioni progettato principalmente per lo sviluppo di back-end Web. È costruito sulla base del motore JavaScript di Google v8 e sceglie una soluzione di concorrenza diversa dal tradizionale callback. fibjs utilizza le fibre per isolare la complessità aziendale causata dalle chiamate asincrone a livello di framework, riducendo notevolmente la difficoltà di sviluppo e riducendo i problemi di prestazioni causati dalla frequente elaborazione asincrona nello spazio utente.
Il design di fibjs presta grande attenzione alle prestazioni.I moduli IO e HTTP di rete integrati adottano un modello di I/O non bloccante basato sugli eventi e gli sviluppatori possono facilmente implementare applicazioni server ad alta affidabilità. E poiché il livello inferiore è implementato da C++, fibjs ha prestazioni eccellenti, può gestire facilmente accessi simultanei elevati e fornire servizi estremamente stabili e affidabili.
Allo stesso tempo, fibjs supporta anche WebSocket, che è un protocollo di comunicazione full duplex basato sul protocollo TCP, che stabilisce una connessione ininterrotta tra il browser e il server, che può realizzare la trasmissione di dati bidirezionale in tempo reale e può supportare i dati in qualsiasi formato di trasmissione. Le applicazioni di comunicazione in tempo reale con migliori effetti di comunicazione possono essere facilmente realizzate utilizzando WebSocket.
In breve, fibjs non solo enfatizza le alte prestazioni e l'elevata affidabilità, ma fornisce anche funzionalità di comunicazione in tempo reale come WebSocket, un framework molto adatto allo sviluppo di applicazioni Web ad alta velocità.
Crea l'ambiente di sviluppo
Prima di iniziare lo sviluppo di fibjs, dobbiamo prima preparare l'ambiente di sviluppo. Questo capitolo introdurrà come installare fibjs, come utilizzare lo strumento fibjs per inizializzare il progetto e come utilizzare l'ambiente di sviluppo integrato IDE.
Installa fibjs
Per diversi sistemi operativi, anche il modo di installare fibjs è leggermente diverso.
Per gli utenti Linux e macOS, fibjs può essere installato con il seguente comando:
1curl -s https://fibjs.org/download/installer.sh | sh
Se utilizzi macOS e utilizzi il gestore pacchetti Homebrew, puoi anche installarlo con:
1brew install fibjs
Per gli utenti Windows, è necessario scaricare il programma di installazione dal sito Web ufficiale di fibjs, quindi seguire le istruzioni per installarlo.
Crea un nuovo progetto con fibjs --init
Dopo aver installato fibjs, puoi utilizzare lo strumento fibjs per creare rapidamente nuovi progetti. Un modello di progetto di base può essere creato con il seguente comando:
1fibjs --init
Questo comando creerà una nuova struttura del progetto nella directory corrente, incluso package.json, utilizzato per archiviare le informazioni di base del progetto e le informazioni sulle dipendenze.
Scrivere un'applicazione web
Lo sviluppo di applicazioni Web è attualmente lo scenario applicativo più comunemente utilizzato per fibjs. fibjs fornisce una serie di strumenti e moduli per aiutarci a creare applicazioni Web più rapidamente.
Scrivi un server HTTP
- Per prima cosa importa il modulo http;
- Crea un'istanza di http.Server e ascolta le richieste.
- Il server viene avviato con la funzione start.
1
2
3
4
5
6const http = require('http');
const server = new http.Server(8080, (req) => {
req.response.write('Hello World!');
});
server.start();
Analizza i parametri dell'URL e il corpo della richiesta
L'analisi dei parametri dell'URL e del corpo della richiesta è molto importante e applicata a varie applicazioni server. In fibjs, i parametri dell'URL in entrata possono essere analizzati direttamente tramite req.query, mentre il corpo della richiesta viene letto tramite req.body.
1
2
3
4
5
6
7
8const http = require('http');
const server = new http.Server(8080, (req) => {
var name = req.query.get('name');
var msg = name ? `Hello ${name}!` : 'Hello world!';
req.response.write(msg);
});
server.start();
Implementare il controllo dell'accesso all'interfaccia
Limitare l'accesso degli utenti tramite le interfacce è uno scenario molto comune. Di seguito è riportato un semplice esempio.
1
2
3
4
5
6
7
8
9
10const http = require('http');
const server = new http.Server(8080, (req) => {
if (req.headers.get('auth') === 'ok') {
req.response.write('Hello World!');
} else {
req.response.write('Access Denied!');
}
});
server.start();
Aggiungi l'elaborazione del routing
Il routing è uno dei concetti più importanti in un'applicazione Web. Il routing si riferisce alla distribuzione delle richieste ricevute ai processori in base a determinate regole. In fibjs, puoi scrivere il tuo modulo di routing e associarlo al server http, quindi eseguire la corrispondenza degli URL e l'elaborazione corrispondente tramite l'analisi del routing personalizzata.
1
2
3
4
5
6
7
8
9const http = require('http');
const { Router } = require('mq');
var router = new Router();
router.get('/hello/:name', function (req, name) {
req.response.write('hello, ' + name);
});
var svr = new http.Server(8080, router);
svr.start();
L'esempio precedente può anche essere implementato con una sintassi più semplice:
1
2
3
4
5
6
7
8const http = require('http');
var svr = new http.Server(8080, {
'/hello/:name': function (req, name) {
req.response.write('hello, ' + name);
}
});
svr.start();
Gestione e registrazione degli errori
In fibjs, puoi rilevare le eccezioni logiche tramite il blocco try-catch e inviarle al file di registro per il debug del record; se si tratta di un'eccezione fatale, puoi inviarla direttamente al framework superiore per l'elaborazione.
1
2
3
4
5
6
7
8
9
10const console = require('console');
const http = require('http');
const server = new http.Server(8080, (req) => {
try {
// ...
} catch (e) {
console.log(e.message, e.stack);
}
});
richiesta interdominio
In fibjs, possiamo usare il metodo enableCrossOrigin per consentire richieste cross-origin. Di seguito è riportato un codice di esempio su come creare un server http e consentire richieste cross-origin:
1
2
3
4
5
6
7
8const http = require('http');
const server = new http.Server(8080, (req) => {
req.response.write('Hello World!');
});
server.enableCrossOrigin(); // enable cross domain request
server.start();
Nell'esempio sopra, abbiamo creato un server http sulla porta 8080. Il metodo enableCrossOrigin() consente richieste cross-origin.
Quando si utilizza enableCrossOrigin per consentire le richieste cross-origin, è possibile passare un parametro allowHeaders per specificare le intestazioni cross-origin che possono essere ricevute. Per impostazione predefinita, il valore allowHeaders è Content-Type.
Il codice di esempio è il seguente:
1
2// enable "Content-Type" and "Authorization" headers in cross domain request
server.enableCrossOrigin("Content-Type, Authorization");
Nel codice precedente, il valore di allowHeaders è "Content-Type, Authorization", a indicare che il server consente di ricevere le due intestazioni cross-domain di "Content-Type" e "Authorization". Se la richiesta contiene altre intestazioni, verrà rifiutata dal server.
Va notato che quando utilizziamo l'impostazione enableCrossOrigin per consentire la ricezione di intestazioni tra domini, dobbiamo anche impostare l'intestazione della richiesta corrispondente quando inviamo richieste tra domini, altrimenti verrà rifiutata anche dal server.
WebSocket
Il protocollo WebSocket è un protocollo di comunicazione full duplex basato sul protocollo TCP che stabilisce una connessione ininterrotta tra il browser e il server, può realizzare la trasmissione di dati bidirezionale in tempo reale e può supportare la trasmissione di dati in qualsiasi formato. In fibjs, il modulo di supporto WebSocket fornisce l'interfaccia API corrispondente, che può realizzare lo sviluppo di server e client WebSocket.
Usa il modulo WebSocket nativo di fibjs per implementare il lato server WebSocket
Sul lato server, le richieste HTTP possono essere convertite in connessioni WebSocket tramite la funzione di aggiornamento. Quando si crea un oggetto server http, è possibile utilizzare ws.upgrade(callback) e passarlo al metodo http.start() per convertire la richiesta http in WebSocket.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27var ws = require('ws');
var http = require('http');
var server = new http.Server(8080, {
'/ws': ws.upgrade(function(conn, req) {
console.log('a client connected.');
// listening for message events
conn.onmessage = function(evt) {
console.log('received message: ', evt.data);
// echo the message back to client
conn.send('Server: ' + evt.data);
};
// listening for close events
conn.onclose = function(code, reason) {
console.log('closed.');
};
// listening for error events
conn.onerror = function(err) {
console.log(err);
};
})
});
server.start();
Nell'esempio sopra, possiamo monitorare l'evento del messaggio inviato dal client e l'evento di chiusura della connessione tra il server e il client. Quando il server riceve un messaggio client, invia lo stesso messaggio al client. A questo punto, si realizza una semplice comunicazione punto-punto WebSocket.
Implementazione dell'interazione con i datastore
Quando si utilizza WebSocket per la comunicazione, oltre al semplice invio e ricezione di messaggi, è necessario considerare anche operazioni come l'archiviazione persistente e l'interrogazione dei dati. In questo momento, è necessario utilizzare il database e puoi utilizzare il modulo db integrato di fibjs per interagire con il database.
Il codice di esempio è il seguente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33var ws = require("ws");
var http = require("http");
var db = require("db");
// open a mysql connection
var mysql = db.openMySQL("mysql://root:password@localhost/dbname");
var server = new http.Server(8080, {
"/ws": ws.upgrade(function(conn, req) {
console.log("a client connected.");
// listening for message events
conn.onmessage = function(evt) {
console.log("received message: ", evt.data);
// use execute to query the data
var rs = mysql.execute("SELECT * FROM user WHERE name=?", evt.data.toString());
conn.send(JSON.stringify(rs));
};
// listening for close events
conn.onclose = function(code, reason) {
console.log("closed.");
};
// listening for error events
conn.onerror = function(err) {
console.log(err);
};
})
});
server.start();
Nell'esempio precedente, utilizziamo prima il metodo openMySQL del modulo db per creare un oggetto di connessione al database MySQL mysql, quindi utilizziamo il metodo execute per eseguire direttamente le query SQL dopo aver ascoltato i messaggi dal client per ottenere i record che soddisfano le condizioni. Infine, i risultati della query vengono inviati al client tramite il protocollo WebSocket.
Va notato che nello sviluppo effettivo, la gestione delle eccezioni e la sicurezza dei dati devono essere eseguite correttamente.
In sintesi, attraverso il modulo db, possiamo facilmente interagire con il database, combinato con il protocollo WebSocket, per realizzare applicazioni Web ad alte prestazioni in tempo reale.
Implementa la comunicazione client-server WebSocket
Sul lato client, puoi connetterti a un server WebSocket creando un'istanza WebSocket e specificando un URL, quindi inviando messaggi al server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24var ws = require('ws');
// create a WebSocket object and connect to ws://localhost:8080/ws
var conn = new ws.Socket('ws://localhost:8080/ws');
// listening for open events
conn.onopen = function() {
conn.send('hello');
}
// listening for message events
conn.onmessage = function(evt) {
console.log('received message:', evt.data);
}
// listening for close events
conn.onclose = function(code, reason) {
console.log('closed.');
}
// listening for error events
conn.onerror = function(err) {
console.log(err);
}
Nel codice client sopra, creiamo un'istanza WebSocket e specifichiamo il suo URL.Dopo che la connessione è stata stabilita con successo, possiamo inviare messaggi al server. Quando il server riceve un messaggio client, invia lo stesso messaggio al client. A questo punto, si realizza una semplice comunicazione punto-punto WebSocket.
Vantaggi e scenari di utilizzo di WebSocket
Il protocollo WebSocket ha un tipico modello di comunicazione bidirezionale, che consente al server di inviare attivamente i dati al client e viene spesso utilizzato per implementare chat, giochi online e altre occasioni che richiedono tempo reale e alta immediatezza. Rispetto ad altri protocolli di trasporto, il protocollo WebSocket presenta i seguenti vantaggi:
• Elevate prestazioni in tempo reale, supporto della comunicazione bidirezionale • Specifica del protocollo semplice, facile da usare • In grado di gestire un gran numero di connessioni simultanee • Supporta connessioni lunghe, riducendo il consumo di tempo della trasmissione di rete
Gli scenari di utilizzo più comuni di WebSocket includono chat Web, battaglia di gioco, gioco online e messaggistica istantanea, ecc.
Per riassumere, con il modulo di supporto WebSocket, è molto semplice da implementare e gli sviluppatori possono creare rapidamente le proprie applicazioni Web.
prova unitaria
Quadro di prova e metodo di prova
Nel processo di sviluppo del software, il test è un collegamento molto importante e il test unitario ne è una parte importante.Il test unitario può verificare efficacemente se il codice soddisfa il design e i requisiti ed evitare errori introdotti quando il codice viene modificato. In generale, il principio del test unitario è testare ogni funzione e metodo per garantire che l'input e l'output di ogni funzione e metodo siano corretti.
Un framework di test è una base di codice per la scrittura, l'esecuzione e la verifica dei casi di test, che fornisce funzioni come la gestione dei casi di test, l'esecuzione e il reporting. In JavaScript e Node.js, i framework di unit test più diffusi includono Mocha, Jest e Jasmine, tra gli altri. In fibjs, abbiamo anche il nostro framework di test, il modulo di test.
Nel processo di test unitario, i metodi di test generalmente utilizzati includono test black-box e test white-box.
Il test black-box è un metodo di test che considera solo l'input e l'output di una funzione senza considerare i dettagli di implementazione all'interno della funzione. Il test black-box si basa sull'analisi dei requisiti e sulle specifiche di progettazione, attraverso l'analisi e l'esecuzione dei casi di test, per determinare se nel programma sono presenti errori logici, errori di confine e problemi di sicurezza. Il suo vantaggio è che il processo di test è semplice ei risultati del test sono affidabili, ma lo svantaggio è che il test non può coprire tutti i percorsi del programma.
Il test della scatola bianca è un metodo di test che considera i dettagli di implementazione interna delle funzioni, comprese le istruzioni condizionali, le istruzioni di ciclo, la ricorsione e la copertura del codice. Attraverso questi test, puoi trovare possibili problemi nell'interazione tra dati condivisi e codice. Il vantaggio del test white-box è che può coprire tutti i percorsi del programma, lo svantaggio è che il processo di test è più complicato ei risultati del test sono influenzati dall'ambiente e dai metodi di implementazione.
Scrivere casi di test utilizzando il modulo di test
In fibjs, possiamo usare il modulo di test per scrivere casi di test per il server web. Qui c'è un semplice esempio:
1
2
3
4
5
6
7
8
9
10
11
12
13
14var test = require('test');
test.setup();
var http = require('http');
describe('Web server test', () => {
it('should return hello world', () => {
var r = http.get('http://localhost:8080/hello');
assert.equal(r.statusCode, 200);
assert.equal(r.data.toString(), 'Hello World');
});
});
test.run();
In questo esempio, utilizziamo le funzioni describe e it per definire rispettivamente il modulo di test e i casi di test e utilizziamo la funzione assert per la verifica dell'asserzione.
Nella funzione describe, possiamo definire più funzioni it per testare rispettivamente diversi scenari. In ogni funzione it, possiamo utilizzare la funzione http.get per simulare una richiesta HTTP GET, ottenere la risposta alla richiesta ed eseguire la verifica di asserzioni come assertTrue e assertEqual.
Scrivendo casi di test, puoi testare in modo efficace la correttezza di funzioni e moduli, garantire la qualità del prodotto e migliorare la manutenibilità del codice.
aggiornamento a caldo
L'aggiornamento a caldo si riferisce all'aggiornamento del codice del server senza interrompere il servizio. Nel processo di sviluppo del programma, per iterare velocemente, è spesso necessario aggiustare il codice e aggiungere nuove funzioni. L'uso dell'aggiornamento a caldo può utilizzare il nuovo codice per completare il lavoro di iterazione in modo più efficiente senza interrompere il servizio.
In fibjs, possiamo utilizzare il modulo SandBox per ottenere aggiornamenti a caldo fluidi. Il modulo SandBox può fornire un ambiente di esecuzione sicuro, simulare variabili globali e altre funzioni. Per l'implementazione specifica, fare riferimento ai seguenti passaggi:
- Carica i file di codice che devono essere aggiornati (come web.js).
- Tramite SandBox, crea un nuovo modulo di sicurezza, carica web.js in questo modulo e genera un modulo di sicurezza. Rimontare il gestore del servizio in esecuzione tramite il modulo di sicurezza generato.
- Il server continua a elaborare le richieste precedenti e le nuove richieste verranno montate sul nuovo gestore.
Ecco un codice di esempio per aggiornamenti a caldo fluidi utilizzando il modulo SandBox:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const fs = require('fs');
const http = require('http');
const { SandBox } = require('vm');
let FILE_PATH = './web.js';
let handler = new SandBox().require(FILE_PATH).handler;
const server = new http.Server(8080, handler);
server.start();
fs.watch(FILE_PATH, (event, filename) => {
handler = new SandBox().require(FILE_PATH).handler;
server.handler = handler;
console.log(`[${new Date().toLocaleString()}] server reloaded.`);
});
In questo codice, per prima cosa carichiamo il codice in web.js una volta all'avvio del programma, quindi creiamo un'istanza SandBox e carichiamo il codice nell'istanza. Successivamente, abbiamo creato un nuovo server HTTP e utilizzato il metodo in handler per elaborare la richiesta.
Nel codice, usiamo fs.watch per monitorare le modifiche del file web.js. Una volta che il file cambia, ricarichiamo il codice e aggiorniamo l'implementazione nel gestore.
ottimizzazione delle prestazioni
Nel processo di sviluppo, spesso dobbiamo affrontare problemi di prestazioni. Ottimizzare il codice e migliorare le prestazioni è una delle competenze necessarie per gli sviluppatori. In fibjs, possiamo utilizzare CPU Profiler per aiutarci ad analizzare lo stato di esecuzione del programma e ottimizzare il codice.
In fibjs, devi solo utilizzare il parametro della riga di comando --prof per avviare fibjs, ovvero puoi avviare CPU Profiler (l'intervallo predefinito è 1000 ms). Se hai bisogno di log di analisi più precisi, puoi utilizzare il parametro --prof-interval per impostare l'intervallo di log. Per esempio:
1
2$ fibjs --prof test.js # 启动 CPU Profiler,默认以 1000ms 为间隔
$ fibjs --prof --prof-interval=10ms test.js # 启动 CPU Profiler,以 10000us(即 10ms)为间隔
Al termine dell'esecuzione di fibjs, nella directory corrente verrà generata una directory del nome del file di origine, che contiene un file di registro e alcuni file ausiliari. Il nome predefinito del file di registro è fibjs-xxxx.log, dove xxxx è un timestamp. Il nome del file di registro può essere specificato con l'opzione --log. A questo punto, puoi --prof-process
elaborare :
1fibjs --prof-process fibjs-xxxx.log prof.svg
Dopo l'esecuzione, apri prof.svg con un browser per visualizzare il grafico a fiamma di questo registro:
puoi fare clic per visualizzare l'immagine a grandezza naturale e nell'immagine a grandezza naturale puoi utilizzare il mouse per visualizzare informazioni più dettagliate: prof .svg .
Nel diagramma di fiamma generato, ogni blocco di colore rappresenta un punto di registrazione. Più lungo è il blocco di colore, più volte è stato registrato; ogni linea rappresenta uno strato di stack di chiamate, e più strati, più strati di chiamate; La disposizione della pila è invertita, più basso è il blocco colore, maggiore è la funzione originale.
Esistono due tipi di blocchi di colore, uno è rosso e l'altro è blu. Nel profiler di fibjs, il rosso rappresenta le operazioni JavaScript e il blu rappresenta le operazioni io o le operazioni native. A seconda del problema che devi risolvere, le aree su cui devi concentrarti varieranno. Ad esempio, se devi risolvere il problema dell'elevato utilizzo della CPU, devi prestare attenzione al blocco di colore rosso in questo momento; e se la tua applicazione ha un basso utilizzo della CPU ma una risposta lenta, devi prestare attenzione al colore blu bloccare. Più grande è il blocco di colore nella parte superiore, maggiore è l'attenzione e l'ottimizzazione necessarie.
Possiamo provare a regolare le funzioni che occupano più risorse della CPU, implementare l'IO tramite metodi asincroni o ottimizzare il codice durante la scrittura.
distribuzione in linea
Affinché il nostro progetto possa essere eseguito in produzione, dobbiamo compilarlo e distribuirlo. Qui viene introdotto come usare il file package.json per configurare la compilazione e la distribuzione.
Nel progetto, possiamo utilizzare package.json per gestire le dipendenze del progetto, configurare la compilazione e la distribuzione. Prendi un semplice esempio package.json come esempio:
1
2
3
4
5
6
7{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"fib-pool": "^1.0.0"
}
}
Quando dobbiamo compilare e distribuire il progetto, dobbiamo solo inserire la directory del progetto nel terminale, quindi eseguire il seguente comando:
1fibjs --install
Questo comando installerà automaticamente i moduli da cui dipende il progetto. Successivamente, possiamo avviare il progetto con il seguente comando:
1fibjs app.js