Pràctiques d'aplicacions web d'alt rendiment
introduir
fibjs és un marc de servidor d'aplicacions d'alt rendiment dissenyat principalment per al desenvolupament de backend web. Es basa en el motor JavaScript de Google v8 i tria una solució de concurrència diferent de les devolucions de trucada tradicionals. fibjs utilitza fibres per aïllar la complexitat empresarial causada per trucades asíncrones a la capa de marc, reduint en gran mesura la dificultat de desenvolupament i reduint els problemes de rendiment causats pel processament asíncron freqüent a l'espai de l'usuari.
El disseny de fibjs presta molta atenció al rendiment. Els mòduls d'E/S i HTTP de xarxa integrats adopten un model d'E/S sense bloqueig basat en esdeveniments, de manera que els desenvolupadors poden implementar fàcilment aplicacions de servidor d'alta fiabilitat. I com que la capa inferior s'implementa en C++, fibjs té un rendiment molt superior i pot fer front fàcilment a un alt accés simultani i proporcionar serveis extremadament estables i fiables.
Al mateix temps, fibjs també admet WebSocket, que és un protocol de comunicació full-duplex basat en el protocol TCP, que estableix una connexió ininterrompuda entre el navegador i el servidor, permet la transmissió de dades bidireccional en temps real i pot suportar dades. en qualsevol format.transmissió. WebSocket es pot utilitzar per implementar fàcilment aplicacions de comunicació en temps real amb millors efectes de comunicació.
En resum, fibjs no només posa èmfasi en l'alt rendiment i l'alta fiabilitat, sinó que també ofereix funcions de comunicació en temps real com WebSocket, un framework molt adequat per desenvolupar aplicacions web d'alta velocitat.
Configuració de l'entorn de desenvolupament
Abans de començar el desenvolupament de fibjs, hem de preparar l'entorn de desenvolupament. Aquest capítol presentarà com instal·lar fibjs, com utilitzar l'eina fibjs per inicialitzar el projecte i com utilitzar l'entorn de desenvolupament integrat IDE.
Instal·leu fibjs
Per a diferents sistemes operatius, els mètodes d'instal·lació de fibjs són lleugerament diferents.
Per als usuaris de Linux i macOS, fibjs es pot instal·lar mitjançant l'ordre següent:
1curl -s https://fibjs.org/download/installer.sh | sh
Si utilitzeu macOS i utilitzeu el gestor de paquets Homebrew, també podeu instal·lar-lo mitjançant l'ordre següent:
1brew install fibjs
Per als usuaris de Windows, heu de descarregar l'instal·lador des del lloc web oficial de fibjs i, a continuació, seguir les instruccions per instal·lar-lo.
Creeu un projecte nou amb fibjs –init
Després d'instal·lar fibjs, podeu utilitzar l'eina fibjs per crear nous projectes ràpidament. Utilitzeu l'ordre següent per crear una plantilla de projecte bàsica:
1fibjs --init
Aquesta ordre crearà una nova estructura de projecte al directori actual, inclòs package.json, que s'utilitza per emmagatzemar informació bàsica del projecte i informació de dependència.
Redacció d'aplicacions web
El desenvolupament d'aplicacions web és actualment l'escenari d'aplicació més utilitzat de fibjs. fibjs ofereix una sèrie d'eines i mòduls per ajudar-nos a crear aplicacions web més ràpidament.
Escriure un servidor HTTP
- Primer importeu el mòdul http;
- Crea una instancia de http.Server i escolta les sol·licituds.
- El servidor s'inicia mitjançant la funció d'inici.
1
2
3
4
5
6const http = require('http');
const server = new http.Server(8080, (req) => {
req.response.write('Hello World!');
});
server.start();
Analitzeu els paràmetres de l'URL i el cos de la sol·licitud
L'anàlisi dels paràmetres d'URL i dels cossos de sol·licitud és molt important i s'utilitza en diverses aplicacions del costat del servidor. En fibjs, els paràmetres d'URL entrants es poden analitzar directament mitjançant req.query, i el cos de la sol·licitud es llegeix mitjançant 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();
Implementar el control d'accés a la interfície
Restringir l'accés dels usuaris a través d'interfícies és un escenari molt comú. A continuació es mostra un exemple senzill.
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();
Afegeix el processament d'encaminament
L'encaminament és un dels conceptes més importants d'una aplicació Web. L'encaminament es refereix a distribuir les peticions rebudes als processadors d'acord amb determinades regles. A fibjs, podeu escriure el vostre propi mòdul d'encaminament i vincular-lo al servidor http, i després realitzar la concordança d'URL i el processament corresponent mitjançant l'anàlisi de rutes personalitzada.
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'exemple anterior també es pot implementar amb una sintaxi més senzilla:
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();
Gestió i registre d'errors
En fibjs, podeu capturar excepcions lògiques mitjançant blocs try-catch i enviar-les a fitxers de registre per a la depuració i l'enregistrament; si són excepcions fatals, es poden llançar directament al marc superior per processar-les.
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);
}
});
sol·licitud entre dominis
En fibjs, podem utilitzar el mètode enableCrossOrigin per permetre sol·licituds entre dominis. Aquí teniu un codi de mostra de com crear un servidor http i permetre sol·licituds entre dominis:
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();
A l'exemple anterior, hem creat un servidor http amb el port 8080. El mètode enableCrossOrigin() permet sol·licituds entre orígens.
Quan utilitzeu enableCrossOrigin per permetre sol·licituds entre dominis, podeu especificar les capçaleres entre dominis que es poden rebre passant un paràmetre allowHeaders. De manera predeterminada, el valor allowHeaders és Content-Type.
El codi de mostra és el següent:
1
2// enable "Content-Type" and "Authorization" headers in cross domain request
server.enableCrossOrigin("Content-Type, Authorization");
Al codi anterior, el valor de allowHeaders és "Content-Type, Authorization", el que significa que el servidor pot rebre les dues capçaleres entre dominis "Content-Type" i "Authorization". Si la sol·licitud conté altres capçaleres, el servidor la rebutjarà.
Cal tenir en compte que quan fem servir enableCrossOrigin per configurar la possibilitat de rebre capçaleres entre dominis, també hem d'establir la capçalera de sol·licitud corresponent quan enviem sol·licituds entre dominis, en cas contrari també serà rebutjada pel servidor.
WebSockets
El protocol WebSocket és un protocol de comunicació full-duplex basat en el protocol TCP que estableix una connexió ininterrompuda entre el navegador i el servidor, pot realitzar transmissió de dades bidireccional en temps real i pot suportar la transmissió de dades en qualsevol format. En fibjs, el mòdul de suport de WebSocket proporciona les interfícies API corresponents, que poden realitzar el desenvolupament del servidor i client WebSocket.
Utilitzeu el mòdul WebSocket natiu de fibjs per implementar el costat del servidor WebSocket
Al costat del servidor, les sol·licituds HTTP es poden convertir en connexions WebSocket mitjançant la funció d'actualització. Quan creeu un objecte de servidor http, podeu utilitzar ws.upgrade(callback) i passar-lo al mètode http.start() per convertir la sol·licitud http a 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();
A l'exemple anterior, podem controlar l'esdeveniment de missatge enviat pel client i l'esdeveniment de tancament de connexió entre el servidor i el client. Quan el servidor rep el missatge del client, envia el mateix missatge de nou al client. En aquest punt, s'implementa una comunicació punt a punt senzilla de WebSocket.
Implementar la interacció amb l'emmagatzematge de dades
Quan utilitzeu WebSocket per a la comunicació, a més de simplement enviar i rebre missatges, també heu de tenir en compte operacions com l'emmagatzematge persistent i la consulta de dades. En aquest moment, heu d'utilitzar la base de dades. Podeu utilitzar el mòdul db integrat a fibjs per interactuar amb la base de dades.
El codi de mostra és el següent:
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();
A l'exemple anterior, primer vam utilitzar el mètode openMySQL del mòdul db per crear un objecte de connexió de base de dades MySQL mysql, i després d'escoltar el missatge del client, vam utilitzar el mètode execute per executar directament la consulta SQL i obtenir registres que complir les condicions. Finalment, els resultats de la consulta s'envien al client mitjançant el protocol WebSocket.
Cal tenir en compte que en el desenvolupament real, el maneig d'excepcions i la seguretat de les dades s'han de fer bé.
En resum, mitjançant el mòdul db, podem interactuar de manera fàcil i senzilla amb la base de dades, combinat amb el protocol WebSocket, per implementar aplicacions web d'alt rendiment en temps real.
Implementar la comunicació client-servidor WebSocket
Al costat del client, podeu connectar-vos a un servidor WebSocket creant una instància WebSocket i especificant un URL i, a continuació, enviar missatges al servidor.
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);
}
En el codi de client anterior, creem una instància de WebSocket i especifiquem la seva URL. Un cop establerta la connexió correctament, podem enviar missatges al servidor. Quan el servidor rep el missatge del client, envia el mateix missatge de nou al client. En aquest punt, s'implementa una comunicació punt a punt senzilla de WebSocket.
Avantatges i escenaris d'ús de WebSocket
El protocol WebSocket té un model de comunicació bidireccional típic, que permet al servidor enviar dades activament al client. Sovint s'utilitza per implementar xat, jocs en línia i altres ocasions que requereixen temps real i alta immediatesa. En comparació amb altres protocols de transmissió, el protocol WebSocket té els següents avantatges:
• Alt rendiment en temps real, admet comunicacions bidireccionals • Especificació de protocol senzilla, fàcil d'utilitzar • Capaç de gestionar un gran nombre de connexions concurrents • Admet connexions llargues, reduint el temps de transmissió de la xarxa
Els escenaris d'ús més habituals de WebSocket inclouen xat web, batalles de jocs, reproducció en línia i missatgeria instantània.
En resum, mitjançant el mòdul de suport WebSocket, és molt senzill d'implementar i els desenvolupadors poden crear ràpidament les seves pròpies aplicacions web.
prova unitària
Marcs de prova i mètodes de prova
En el procés de desenvolupament de programari, les proves són un enllaç molt important i les proves unitàries en són una part important. Les proves unitàries poden verificar eficaçment si el codi compleix el disseny i els requisits, i evitar errors introduïts quan es modifica el codi. En termes generals, el principi de les proves unitàries és provar cada funció i mètode per assegurar-se que l'entrada i la sortida de cada funció i mètode són correctes.
Un marc de prova és una base de codi que s'utilitza per escriure, executar i verificar casos de prova. Proporciona funcions de gestió, execució i informes de casos de prova. A JavaScript i Node.js, els marcs de prova d'unitats populars inclouen Mocha, Jest i Jasmine. A fibjs, també tenim el nostre propi marc de prova, el mòdul de prova.
En el procés de prova d'unitat, els mètodes de prova utilitzats habitualment inclouen proves de caixa negra i proves de caixa blanca.
La prova de caixa negra és un mètode de prova que només considera l'entrada i la sortida d'una funció sense tenir en compte els detalls d'implementació dins de la funció. Les proves de caixa negra es basen en l'anàlisi de requisits i les especificacions de disseny. Mitjançant l'anàlisi i l'execució de casos de prova, determina si el programa té errors lògics, errors de límit, problemes de seguretat, etc. El seu avantatge és que el procés de prova és senzill i els resultats de la prova són fiables. El seu desavantatge és que la prova no pot cobrir totes les rutes del programa.
La prova de caixa blanca és un mètode de prova que té en compte els detalls d'implementació interna d'una funció, incloses les declaracions condicionals, les declaracions de bucle, la recursivitat i la cobertura del codi. Aquestes proves poden identificar possibles problemes en la interacció entre les dades compartides i el codi. L'avantatge de les proves de caixa blanca és que poden cobrir totes les rutes del programa. El desavantatge és que el procés de prova és més complicat i els resultats de les proves es veuen afectats per l'entorn i els mètodes d'implementació.
Escriu casos de prova utilitzant el mòdul de prova
En fibjs, podem utilitzar el mòdul de prova per escriure casos de prova per al servidor web. Aquí teniu un exemple senzill:
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();
En aquest exemple, fem servir les funcions describe i it per definir el mòdul de prova i el cas de prova, respectivament, i utilitzem la funció assert per a la verificació de l'asserció.
A la funció de descripció, podem definir múltiples funcions per provar diferents escenaris respectivament. En cada funció it, podem utilitzar la funció http.get per simular una sol·licitud HTTP GET, obtenir la resposta de la sol·licitud i realitzar una verificació d'assercions com assertTrue i assertEqual.
Mitjançant l'escriptura de casos de prova, podeu provar eficaçment la correcció de les funcions i els mòduls, garantir la qualitat del producte i també millorar el manteniment del codi.
Actualització calenta
L'actualització calenta fa referència a l'actualització del codi del servidor sense aturar el servei. Durant el procés de desenvolupament del programa, per tal d'iterar ràpidament, sovint es requereixen ajustaments de codi i noves funcions. Amb l'actualització activa, podeu utilitzar el codi nou per completar el treball d'iteració de manera més eficient sense aturar el servei.
En fibjs, podem utilitzar el mòdul SandBox per aconseguir actualitzacions ràpides sense problemes. El mòdul SandBox pot proporcionar un entorn d'execució segur i simular variables globals i altres funcions. Per a una implementació específica, consulteu els passos següents:
- Carregueu els fitxers de codi que cal actualitzar (com ara web.js).
- Mitjançant SandBox, creeu un mòdul de seguretat nou, carregueu web.js al mòdul i genereu el mòdul de seguretat. Torneu a muntar el controlador del servei en execució mitjançant el mòdul de seguretat generat.
- El servidor continua processant les sol·licituds anteriors i les noves es muntaran al nou gestor.
El següent és un codi de mostra que utilitza el mòdul SandBox per implementar actualitzacions ràpides sense problemes:
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.`);
});
En aquest codi, primer carreguem el codi a web.js quan s'inicia el programa, després creem una instància SandBox i carreguem el codi a la instància. Després d'això, vam crear un nou servidor HTTP i vam utilitzar els mètodes del controlador per processar la sol·licitud.
Al codi, fem servir fs.watch per supervisar els canvis al fitxer web.js. Un cop el fitxer canvia, tornem a carregar el codi i actualitzem la implementació al controlador.
Optimització del rendiment
Durant el procés de desenvolupament, sovint hem d'afrontar problemes de rendiment. L'optimització del codi i la millora del rendiment són una de les habilitats essencials dels desenvolupadors. A fibjs, podem utilitzar CPU Profiler per ajudar-nos a analitzar l'estat d'execució del programa i optimitzar el codi.
En fibjs, només heu d'utilitzar el paràmetre de línia d'ordres --prof per iniciar fibjs per iniciar el CPU Profiler (l'interval predeterminat és de 1000 ms). Si necessiteu una anàlisi de registre de major precisió, podeu utilitzar el paràmetre --prof-interval per establir l'interval de registre. Per exemple:
1
2$ fibjs --prof test.js # 启动 CPU Profiler,默认以 1000ms 为间隔
$ fibjs --prof --prof-interval=10ms test.js # 启动 CPU Profiler,以 10000us(即 10ms)为间隔
Quan fibjs s'hagi acabat d'executar, es generarà un directori de nom de fitxer font al directori actual. Aquest directori conté un fitxer de registre i alguns fitxers auxiliars. El nom predeterminat del fitxer de registre és fibjs-xxxx.log, on xxxx és una marca de temps. Podeu utilitzar l'opció --log per especificar el nom del fitxer de registre. En aquest punt, podeu --prof-process
processar els registres generats mitjançant:
1fibjs --prof-process fibjs-xxxx.log prof.svg
Un cop finalitzada l'operació, utilitzeu el navegador per obrir prof.svg per veure el gràfic de flama d'aquest registre: podeu fer clic per veure la imatge a mida completa. A la imatge a mida completa, podeu fer servir el ratolí per veure'n més detalls. informació: prof. svg .
Al gràfic de flama generat, cada bloc de color representa un punt d'enregistrament. Com més llarg sigui el bloc de color, més vegades s'enregistra; cada línia representa una capa de pila de trucades i com més capes, més capes es diuen; trucades La pila es col·loca cap per avall. Com més baix sigui el bloc de color, més original serà la funció.
Hi ha dos tipus de blocs de color, un és vermell i l'altre és blau. Al perfilador fibjs, el vermell representa les operacions de JavaScript i el blau representa les operacions io o les operacions natives. Segons el problema que hàgiu de resoldre, les àrees en què us heu de centrar variaran. Per exemple, si necessiteu resoldre el problema de l'ús elevat de la CPU, heu de parar atenció als blocs de color vermell. Si la vostra aplicació té un ús baix de la CPU però una resposta lenta, haureu de parar atenció als blocs de color blau. Com més gran sigui el bloc de color a prop de la part superior, més atenció i optimització necessitarà.
Podem intentar ajustar funcions que ocupen més recursos de la CPU, implementar IO, etc. de manera asíncrona, o optimitzar el codi en escriure.
Desplegament i en línia
Perquè el nostre projecte s'executi en un entorn de producció, hem de compilar-lo i desplegar-lo. Aquí us presentem com utilitzar el fitxer package.json per configurar la compilació i el desplegament.
Al projecte, podem utilitzar package.json per gestionar les dependències del projecte, configurar la compilació i el desplegament. Preneu un exemple simple package.json com a exemple:
1
2
3
4
5
6
7{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"fib-pool": "^1.0.0"
}
}
Quan necessitem compilar i desplegar el projecte, només hem d'introduir el directori del projecte al terminal i executar la següent comanda:
1fibjs --install
Aquesta ordre instal·larà automàticament els mòduls dels quals depèn el projecte. Després, podem iniciar el projecte amb l'ordre següent:
1fibjs app.js