Hoogwaardige webapplicatiepraktijken
voorstellen
fibjs is een krachtig applicatieserverframework dat voornamelijk is ontworpen voor de ontwikkeling van webbackends. Het is gebouwd op de Google v8 JavaScript-engine en kiest een andere gelijktijdigheidsoplossing dan traditionele callbacks. fibjs gebruikt vezels om de bedrijfscomplexiteit te isoleren die wordt veroorzaakt door asynchrone oproepen op de raamwerklaag, waardoor de moeilijkheidsgraad van de ontwikkeling aanzienlijk wordt verminderd en de prestatieproblemen die worden veroorzaakt door frequente asynchrone verwerking in de gebruikersruimte worden verminderd.
Bij het ontwerp van fibjs wordt veel aandacht besteed aan prestaties. De ingebouwde netwerk-IO- en HTTP-modules gebruiken een gebeurtenisgestuurd, niet-blokkerend I/O-model, zodat ontwikkelaars eenvoudig zeer betrouwbare serverapplicaties kunnen implementeren. En omdat de onderste laag is geïmplementeerd in C++, levert fibjs zeer superieure prestaties en kan het gemakkelijk omgaan met hoge gelijktijdige toegang en extreem stabiele en betrouwbare diensten leveren.
Tegelijkertijd ondersteunt fibjs ook WebSocket, een full-duplex communicatieprotocol gebaseerd op het TCP-protocol. Het brengt een ononderbroken verbinding tot stand tussen de browser en de server, maakt real-time tweerichtingsgegevensoverdracht mogelijk en kan gegevensoverdracht ondersteunen. in elk formaat. WebSocket kan worden gebruikt om eenvoudig real-time communicatietoepassingen met betere communicatie-effecten te implementeren.
Kortom, fibjs legt niet alleen de nadruk op hoge prestaties en hoge betrouwbaarheid, maar biedt ook real-time communicatiefuncties zoals WebSocket, een raamwerk dat zeer geschikt is voor het ontwikkelen van snelle webapplicaties.
Inrichting ontwikkelomgeving
Voordat we met de ontwikkeling van fibjs beginnen, moeten we de ontwikkelomgeving voorbereiden. In dit hoofdstuk wordt geïntroduceerd hoe u fibjs installeert, hoe u de fibjs-tool gebruikt om het project te initialiseren en hoe u de geïntegreerde IDE-ontwikkelomgeving gebruikt.
Installeer fibjs
Voor verschillende besturingssystemen zijn de methoden voor het installeren van fibjs enigszins verschillend.
Voor Linux- en macOS-gebruikers kan fibjs worden geïnstalleerd met behulp van de volgende opdracht:
1curl -s https://fibjs.org/download/installer.sh | sh
Als u macOS gebruikt en de Homebrew-pakketbeheerder gebruikt, kunt u deze ook installeren met de volgende opdracht:
1brew install fibjs
Voor Windows-gebruikers moet u het installatieprogramma downloaden van de officiële website van fibjs en vervolgens de instructies volgen om het te installeren.
Maak een nieuw project met fibjs –init
Na het installeren van fibjs kunt u de fibjs-tool gebruiken om snel nieuwe projecten te maken. Gebruik de volgende opdracht om een basisprojectsjabloon te maken:
1fibjs --init
Met deze opdracht wordt een nieuwe projectstructuur in de huidige map gemaakt, inclusief package.json, die wordt gebruikt om basisinformatie over het project en afhankelijkheidsinformatie op te slaan.
Webapplicaties schrijven
De ontwikkeling van webapplicaties is momenteel het meest gebruikte applicatiescenario van fibjs. fibjs biedt een reeks tools en modules waarmee we sneller webapplicaties kunnen bouwen.
Een HTTP-server schrijven
- Importeer eerst de http-module;
- Instantieer http.Server en luister naar verzoeken.
- De server wordt gestart via de startfunctie.
1
2
3
4
5
6const http = require('http');
const server = new http.Server(8080, (req) => {
req.response.write('Hello World!');
});
server.start();
Parseer URL-parameters en verzoektekst
Het parseren van URL-parameters en verzoekteksten is erg belangrijk en wordt gebruikt in verschillende servertoepassingen. In fibjs kunnen de binnenkomende URL-parameters rechtstreeks worden geparseerd via req.query, en de hoofdtekst van het verzoek wordt gelezen via 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();
Implementeer interfacetoegangscontrole
Het beperken van gebruikerstoegang via interfaces is een veel voorkomend scenario. Hieronder ziet u een eenvoudig voorbeeld.
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();
Voeg routeringsverwerking toe
Routing is een van de belangrijkste concepten in een webapplicatie. Routing verwijst naar het distribueren van ontvangen verzoeken naar processors volgens bepaalde regels. In fibjs kunt u uw eigen routeringsmodule schrijven en deze aan de http-server binden, en vervolgens URL-matching en bijbehorende verwerking uitvoeren via aangepaste routeparsing.
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();
Het bovenstaande voorbeeld kan ook worden geïmplementeerd met een eenvoudigere syntaxis:
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();
Foutafhandeling en registratie
In fibjs kun je logische uitzonderingen vastleggen via try-catch-blokken en deze uitvoeren naar logbestanden voor foutopsporing en opname; als het fatale uitzonderingen zijn, kunnen ze rechtstreeks naar het bovenste raamwerk worden gegooid voor verwerking.
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);
}
});
cross-domein verzoek
In fibjs kunnen we de methode enableCrossOrigin gebruiken om aanvragen tussen domeinen toe te staan. Hier is een voorbeeldcode van hoe u een http-server kunt maken en verzoeken tussen domeinen kunt toestaan:
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();
In het bovenstaande voorbeeld hebben we een http-server met poort 8080 gemaakt. Met de methode enableCrossOrigin() zijn cross-origin-aanvragen mogelijk.
Wanneer u enableCrossOrigin gebruikt om verzoeken tussen domeinen toe te staan, kunt u de cross-domein headers opgeven die mogen worden ontvangen door een parameter allowHeaders door te geven. Standaard is de waarde allowHeaders Content-Type.
De voorbeeldcode is als volgt:
1
2// enable "Content-Type" and "Authorization" headers in cross domain request
server.enableCrossOrigin("Content-Type, Authorization");
In de bovenstaande code is de waarde van allowHeaders "Content-Type, Authorization", wat betekent dat de server de twee domeinoverschrijdende headers "Content-Type" en "Authorization" mag ontvangen. Als het verzoek andere headers bevat, wordt het door de server afgewezen.
Opgemerkt moet worden dat wanneer we enableCrossOrigin gebruiken om de mogelijkheid in te stellen om cross-domein headers te ontvangen, we ook de overeenkomstige verzoekheader moeten instellen bij het verzenden van cross-domein verzoeken, anders wordt deze ook afgewezen door de server.
WebSockets
Het WebSocket-protocol is een full-duplex communicatieprotocol gebaseerd op het TCP-protocol, dat een ononderbroken verbinding tot stand brengt tussen de browser en de server, real-time tweerichtingsdatatransmissie kan realiseren en datatransmissie in elk formaat ondersteunt. In fibjs biedt de WebSocket-ondersteuningsmodule overeenkomstige API-interfaces, die de ontwikkeling van WebSocket-server en -client kunnen realiseren.
Gebruik de native WebSocket-module van fibjs om de WebSocket-serverzijde te implementeren
Aan de serverzijde kunnen HTTP-verzoeken via de upgradefunctie worden omgezet in WebSocket-verbindingen. Wanneer u een http-serverobject maakt, kunt u ws.upgrade(callback) gebruiken en dit doorgeven aan de http.start() -methode om het http-verzoek naar WebSocket te converteren.
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();
In het bovenstaande voorbeeld kunnen we de door de client verzonden berichtgebeurtenis en de gebeurtenis voor het sluiten van de verbinding tussen de server en de client monitoren. Wanneer de server het clientbericht ontvangt, stuurt hij hetzelfde bericht terug naar de client. Op dit punt is eenvoudige WebSocket point-to-point-communicatie geïmplementeerd.
Implementeer interactie met dataopslag
Wanneer u WebSocket voor communicatie gebruikt, moet u naast het eenvoudig verzenden en ontvangen van berichten ook rekening houden met handelingen als permanente opslag en het opvragen van gegevens. Op dit moment moet u de database gebruiken. U kunt de in fibjs ingebouwde db-module gebruiken om met de database te communiceren.
De voorbeeldcode is als volgt:
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();
In het bovenstaande voorbeeld hebben we eerst de openMySQL-methode van de db-module gebruikt om een MySQL-databaseverbindingsobject mysql te maken, en nadat we naar het bericht van de client hadden geluisterd, gebruikten we de execute-methode om de SQL-query rechtstreeks uit te voeren en records te verkrijgen die voldoen aan de voorwaarden. Ten slotte worden de queryresultaten via het WebSocket-protocol teruggestuurd naar de client.
Opgemerkt moet worden dat bij de daadwerkelijke ontwikkeling de afhandeling van uitzonderingen en de gegevensbeveiliging goed moeten worden uitgevoerd.
Samenvattend kunnen we via de db-module eenvoudig en gemakkelijk communiceren met de database, gecombineerd met het WebSocket-protocol, om realtime, krachtige webapplicaties te implementeren.
Implementeer WebSocket-client-server-communicatie
Aan de clientzijde kunt u verbinding maken met een WebSocket-server door een WebSocket-instantie te maken en een URL op te geven, en vervolgens berichten naar de server te verzenden.
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);
}
In de bovenstaande clientcode maken we een WebSocket-instantie aan en specificeren we de URL. Nadat de verbinding tot stand is gebracht, kunnen we berichten naar de server sturen. Wanneer de server het clientbericht ontvangt, stuurt hij hetzelfde bericht terug naar de client. Op dit punt is eenvoudige WebSocket point-to-point-communicatie geïmplementeerd.
Voordelen en gebruiksscenario's van WebSocket
Het WebSocket-protocol heeft een typisch tweerichtingscommunicatiemodel, waardoor de server actief gegevens naar de client kan pushen. Het wordt vaak gebruikt om chat, online games en andere gelegenheden te implementeren die realtime en hoge onmiddellijkheid vereisen. Vergeleken met andere transmissieprotocollen heeft het WebSocket-protocol de volgende voordelen:
• Hoge real-time prestaties, ondersteunt tweerichtingscommunicatie • Eenvoudige protocolspecificatie, gemakkelijk te gebruiken • Kan een groot aantal gelijktijdige verbindingen verwerken • Ondersteunt lange verbindingen, waardoor de netwerktransmissietijd wordt verkort
De meest voorkomende gebruiksscenario's van WebSocket zijn onder meer webchat, gamegevechten, online afspelen en instant messaging.
Samenvattend: via de WebSocket-ondersteuningsmodule is het heel eenvoudig te implementeren en kunnen ontwikkelaars snel hun eigen webapplicaties bouwen.
hoofdstuk toets
Testkaders en testmethoden
In het softwareontwikkelingsproces is testen een zeer belangrijke schakel, en unit-testen is daar een belangrijk onderdeel van. Unit-testen kunnen effectief verifiëren of de code voldoet aan het ontwerp en de vereisten, en fouten vermijden die worden geïntroduceerd wanneer de code wordt gewijzigd. Over het algemeen is het principe van unit-testen het testen van elke functie en methode om ervoor te zorgen dat de invoer en uitvoer van elke functie en methode correct zijn.
Een testframework is een codebasis die wordt gebruikt voor het schrijven, uitvoeren en verifiëren van testcases en biedt functies voor het beheren, uitvoeren en rapporteren van testcases. In JavaScript en Node.js omvatten populaire unit-testframeworks Mocha, Jest en Jasmine. In fibjs hebben we ook ons eigen testframework, de testmodule.
Bij het unit-testproces omvatten de meest gebruikte testmethoden black box-testen en white box-testen.
Black box-testen is een testmethode die alleen rekening houdt met de invoer en uitvoer van een functie, zonder rekening te houden met de implementatiedetails binnen de functie. Black box-testen zijn gebaseerd op analyse van vereisten en ontwerpspecificaties. Door middel van analyse en uitvoering van testcases wordt bepaald of het programma logische fouten, grensfouten, beveiligingsproblemen, enz. bevat. Het voordeel is dat het testproces eenvoudig is en de testresultaten betrouwbaar zijn, het nadeel is dat de test niet alle programmapaden kan bestrijken.
White-box-testen is een testmethode waarbij rekening wordt gehouden met de interne implementatiedetails van een functie, inclusief voorwaardelijke instructies, lusinstructies, recursie en codedekking. Deze tests kunnen mogelijke problemen in de interactie tussen gedeelde data en code identificeren. Het voordeel van white-box-testen is dat het alle programmapaden kan bestrijken, het nadeel is dat het testproces ingewikkelder is en de testresultaten worden beïnvloed door de omgeving en implementatiemethoden.
Schrijf testgevallen met behulp van de testmodule
In fibjs kunnen we de testmodule gebruiken om testcases voor de webserver te schrijven. Hier is een eenvoudig voorbeeld:
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 dit voorbeeld gebruiken we de functies write en it om respectievelijk de testmodule en de testcase te definiëren, en gebruiken we de assert-functie voor de verificatie van beweringen.
In de functie beschrijven kunnen we meerdere it-functies definiëren om respectievelijk verschillende scenario's te testen. In elke it-functie kunnen we de functie http.get gebruiken om een HTTP GET-verzoek te simuleren, het verzoekantwoord te verkrijgen en beweringverificatie uit te voeren, zoals assertTrue en assertEqual.
Door testcases te schrijven, kunt u de juistheid van functies en modules effectief testen, de productkwaliteit waarborgen en ook de onderhoudbaarheid van de code verbeteren.
Hete update
Hot update verwijst naar het bijwerken van de servercode zonder de service te stoppen. Om snel te kunnen itereren zijn tijdens het programmaontwikkelingsproces vaak codeaanpassingen en nieuwe functies nodig. Met behulp van Hot Update kunt u nieuwe code gebruiken om iteratiewerk efficiënter te voltooien zonder de service te stoppen.
In fibjs kunnen we de SandBox-module gebruiken om soepele hot-updates te realiseren. De SandBox-module kan een veilige uitvoeringsomgeving bieden en globale variabelen en andere functies simuleren. Voor een specifieke implementatie verwijzen wij u naar de volgende stappen:
- Laad de codebestanden die moeten worden bijgewerkt (zoals web.js).
- Maak via SandBox een nieuwe beveiligingsmodule, laad web.js in de module en genereer de beveiligingsmodule. Monteer de handler van de actieve service opnieuw via de gegenereerde beveiligingsmodule.
- De server blijft eerdere verzoeken verwerken en nieuwe verzoeken worden aan de nieuwe handler gekoppeld.
Het volgende is een voorbeeldcode die de SandBox-module gebruikt om soepele hot updates te implementeren:
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 deze code laden we eerst de code in web.js wanneer het programma start, maken vervolgens een SandBox-instantie en laden de code in de instantie. Daarna hebben we een nieuwe HTTP-server gemaakt en de methoden in de handler gebruikt om het verzoek te verwerken.
In de code gebruiken we fs.watch om wijzigingen in het web.js-bestand te monitoren. Zodra het bestand verandert, laden we de code opnieuw en werken we de implementatie in de handler bij.
Prestatie-optimalisatie
Tijdens het ontwikkelingsproces worden we vaak geconfronteerd met prestatieproblemen. Het optimaliseren van code en het verbeteren van de prestaties zijn een van de essentiële vaardigheden voor ontwikkelaars. In fibjs kunnen we CPU Profiler gebruiken om ons te helpen de actieve status van het programma te analyseren en de code te optimaliseren.
In fibjs hoeft u alleen de opdrachtregelparameter --prof te gebruiken om fibjs te starten om de CPU Profiler te starten (het standaardinterval is 1000 ms). Als u loganalyse met een hogere precisie nodig heeft, kunt u de parameter --prof-interval gebruiken om het loginterval in te stellen. Bijvoorbeeld:
1
2$ fibjs --prof test.js # 启动 CPU Profiler,默认以 1000ms 为间隔
$ fibjs --prof --prof-interval=10ms test.js # 启动 CPU Profiler,以 10000us(即 10ms)为间隔
Wanneer fibjs klaar is met draaien, wordt er een bronbestandsnaammap gegenereerd in de huidige map. Deze map bevat een logbestand en enkele hulpbestanden. De standaardnaam van het logbestand is fibjs-xxxx.log, waarbij xxxx een tijdstempel is. U kunt de optie --log gebruiken om de naam van het logbestand op te geven. Op dit punt kunt u --prof-process
de gegenereerde logboeken verwerken met behulp van:
1fibjs --prof-process fibjs-xxxx.log prof.svg
Nadat de bewerking is voltooid, gebruikt u de browser om prof.svg te openen om de vlamgrafiek van dit logboek te bekijken: u kunt klikken om de afbeelding op volledige grootte te bekijken. In de afbeelding op volledige grootte kunt u de muis gebruiken om meer details te bekijken informatie: prof. svg .
In de gegenereerde vlamgrafiek vertegenwoordigt elk kleurblok een opnamepunt. Hoe langer het kleurblok, hoe vaker het wordt opgenomen; elke lijn vertegenwoordigt een laag van de oproepstapel, en hoe meer lagen, hoe meer lagen worden aangeroepen; roept de stapel op wordt ondersteboven geplaatst. Hoe lager het kleurblok, hoe origineler de functie.
Er zijn twee soorten kleurblokken: de ene is rood en de andere is blauw. In de fibjs-profiler staat rood voor JavaScript-bewerkingen en blauw voor io-bewerkingen of native bewerkingen. Afhankelijk van het probleem dat u moet oplossen, zullen de gebieden waarop u zich moet concentreren variëren. Als u bijvoorbeeld het probleem van een hoog CPU-gebruik wilt oplossen, moet u op de rode kleurblokken letten. Als uw toepassing een laag CPU-gebruik maar een trage respons heeft, moet u op de blauwe kleurblokken letten. Hoe groter het kleurblok bovenaan, hoe meer aandacht en optimalisatie het nodig heeft.
We kunnen proberen functies aan te passen die meer CPU-bronnen in beslag nemen, IO etc. asynchroon implementeren, of de code optimaliseren tijdens het schrijven.
Implementatie en online
Om ons project in een productieomgeving te laten draaien, moeten we het compileren en implementeren. Hier laten we zien hoe u het bestand package.json kunt gebruiken om compilatie en implementatie te configureren.
In het project kunnen we package.json gebruiken om projectafhankelijkheden te beheren, compilatie en implementatie te configureren. Neem een eenvoudig voorbeeld package.json als voorbeeld:
1
2
3
4
5
6
7{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"fib-pool": "^1.0.0"
}
}
Wanneer we het project moeten compileren en implementeren, hoeven we alleen de projectmap in de terminal in te voeren en de volgende opdracht uit te voeren:
1fibjs --install
Met deze opdracht worden automatisch de modules geïnstalleerd waarvan het project afhankelijk is. Daarna kunnen we het project starten met behulp van het volgende commando:
1fibjs app.js