Prácticas de aplicacións web de alto rendemento
presentar
fibjs é un cadro de servidor de aplicacións de alto rendemento deseñado principalmente para o desenvolvemento de backend web. Está construído no motor JavaScript de Google v8 e escolle unha solución de simultaneidade diferente á das devolucións de chamada tradicionais. fibjs usa fibras para illar a complexidade empresarial causada polas chamadas asíncronas na capa de marco, reducindo moito a dificultade de desenvolvemento e reducindo os problemas de rendemento causados polo procesamento asíncrono frecuente no espazo do usuario.
O deseño de fibjs presta moita atención ao rendemento. Os módulos de E/S e HTTP de rede integrados adoptan un modelo de E/S sen bloqueo dirixido por eventos, polo que os desenvolvedores poden implementar facilmente aplicacións de servidor de alta fiabilidade. E debido a que a capa inferior está implementada en C++, fibjs ten un rendemento moi superior e pode xestionar facilmente un alto acceso simultaneo e proporcionar servizos extremadamente estables e fiables.
Ao mesmo tempo, fibjs tamén admite WebSocket, que é un protocolo de comunicación full-duplex baseado no protocolo TCP, que establece unha conexión ininterrompida entre o navegador e o servidor, permite a transmisión de datos bidireccional en tempo real e pode admitir datos. en calquera formato.transmisión. WebSocket pódese usar para implementar facilmente aplicacións de comunicación en tempo real con mellores efectos de comunicación.
En resumo, fibjs non só enfatiza o alto rendemento e a alta fiabilidade, senón que tamén ofrece funcións de comunicación en tempo real como WebSocket, un framework moi axeitado para desenvolver aplicacións web de alta velocidade.
Configuración do contorno de desenvolvemento
Antes de comezar o desenvolvemento de fibjs, necesitamos preparar o ambiente de desenvolvemento. Este capítulo presentará como instalar fibjs, como usar a ferramenta fibjs para inicializar o proxecto e como usar o ambiente de desenvolvemento integrado IDE.
Instalar fibjs
Para diferentes sistemas operativos, os métodos de instalación de fibjs son lixeiramente diferentes.
Para os usuarios de Linux e macOS, fibjs pódese instalar usando o seguinte comando:
1curl -s https://fibjs.org/download/installer.sh | sh
Se estás a usar macOS e o xestor de paquetes Homebrew, tamén podes instalalo usando o seguinte comando:
1brew install fibjs
Para os usuarios de Windows, debes descargar o instalador desde o sitio web oficial de fibjs e despois seguir as instrucións para instalalo.
Crea un novo proxecto usando fibjs –init
Despois de instalar fibjs, podes usar a ferramenta fibjs para crear novos proxectos rapidamente. Use o seguinte comando para crear un modelo básico de proxecto:
1fibjs --init
Este comando creará unha nova estrutura de proxecto no directorio actual, incluíndo package.json, que se usa para almacenar información básica do proxecto e información de dependencia.
Redacción de aplicacións web
O desenvolvemento de aplicacións web é actualmente o escenario de aplicacións máis utilizado de fibjs. fibjs ofrece unha serie de ferramentas e módulos para axudarnos a crear aplicacións web máis rapidamente.
Escribindo un servidor HTTP
- Primeiro importa o módulo http;
- Crea unha instancia de http.Server e escoita as solicitudes.
- O servidor iníciase mediante a función de inicio.
1
2
3
4
5
6const http = require('http');
const server = new http.Server(8080, (req) => {
req.response.write('Hello World!');
});
server.start();
Analiza os parámetros do URL e o corpo da solicitude
Analizar parámetros url e corpos de solicitude é moi importante e úsase en varias aplicacións do lado do servidor. En fibjs, os parámetros url entrantes pódense analizar directamente a través de req.query, e o corpo da solicitude lese a través de 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 o control de acceso á interface
Restringir o acceso dos usuarios a través de interfaces é un escenario moi común. A continuación móstrase un exemplo sinxelo.
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();
Engadir procesamento de enrutamento
O enrutamento é un dos conceptos máis importantes nunha aplicación Web. O enrutamento fai referencia a distribuír as solicitudes recibidas aos procesadores segundo determinadas regras. En fibjs, pode escribir o seu propio módulo de enrutamento e vinculalo ao servidor http e, a continuación, realizar a coincidencia de URL e o procesamento correspondente mediante unha análise de rutas personalizada.
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();
O exemplo anterior tamén se pode implementar cunha sintaxe máis sinxela:
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();
Manexo de erros e rexistro
En fibjs, pode capturar excepcións lóxicas a través de bloques try-catch e envialas a ficheiros de rexistro para depurar e gravar; se son excepcións mortais, pódense enviar directamente ao marco superior para procesalas.
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);
}
});
solicitude entre dominios
En fibjs, podemos usar o método enableCrossOrigin para permitir solicitudes entre dominios. Aquí tes un código de mostra de como crear un servidor http e permitir solicitudes entre dominios:
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();
No exemplo anterior, creamos un servidor http co porto 8080. O método enableCrossOrigin() permite solicitudes de orixe cruzada.
Ao usar enableCrossOrigin para permitir solicitudes entre dominios, pode especificar as cabeceiras entre dominios que se poden recibir pasando un parámetro allowHeaders. Por defecto, o valor allowHeaders é Content-Type.
O código de mostra é o seguinte:
1
2// enable "Content-Type" and "Authorization" headers in cross domain request
server.enableCrossOrigin("Content-Type, Authorization");
No código anterior, o valor de allowHeaders é "Content-Type, Authorization", o que significa que o servidor pode recibir os dous encabezados entre dominios "Content-Type" e "Authorization". Se a solicitude contén outras cabeceiras, será rexeitada polo servidor.
Cómpre ter en conta que cando usamos enableCrossOrigin para configurar a capacidade de recibir cabeceiras entre dominios, tamén necesitamos establecer a cabeceira de solicitude correspondente ao enviar solicitudes entre dominios, se non, tamén será rexeitada polo servidor.
WebSockets
O protocolo WebSocket é un protocolo de comunicación full-duplex baseado no protocolo TCP. Establece unha conexión ininterrompida entre o navegador e o servidor, pode realizar a transmisión de datos bidireccional en tempo real e pode soportar a transmisión de datos en calquera formato. En fibjs, o módulo de soporte de WebSocket proporciona as correspondentes interfaces API, que poden realizar o desenvolvemento do servidor e cliente WebSocket.
Use o módulo WebSocket nativo de fibjs para implementar o lado do servidor WebSocket
No lado do servidor, as solicitudes HTTP pódense converter en conexións WebSocket mediante a función de actualización. Ao crear un obxecto de servidor http, pode usar ws.upgrade(callback) e pasalo ao método http.start() para converter a solicitude http en 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();
No exemplo anterior, podemos supervisar o evento de mensaxe enviado polo cliente e o evento de peche de conexión entre o servidor e o cliente. Cando o servidor recibe a mensaxe do cliente, envía a mesma mensaxe de volta ao cliente. Neste punto implícase unha simple comunicación punto a punto WebSocket.
Implementar a interacción co almacenamento de datos
Cando se utiliza WebSocket para a comunicación, ademais de simplemente enviar e recibir mensaxes, tamén cómpre considerar operacións como o almacenamento persistente e a consulta de datos. Neste momento, cómpre usar a base de datos. Podes usar o módulo db integrado en fibjs para interactuar coa base de datos.
O código de mostra é o seguinte:
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();
No exemplo anterior, primeiro usamos o método openMySQL do módulo db para crear un obxecto de conexión de base de datos MySQL mysql, e despois de escoitar a mensaxe do cliente, usamos o método execute para executar directamente a consulta SQL e obter rexistros que cumprir as condicións. Finalmente, os resultados da consulta son enviados de volta ao cliente a través do protocolo WebSocket.
Cómpre sinalar que no desenvolvemento real, o manexo de excepcións e a seguridade dos datos deben facerse ben.
En resumo, a través do módulo db, podemos interactuar de xeito sinxelo e sinxelo coa base de datos, combinado co protocolo WebSocket, para implementar aplicacións Web en tempo real e de alto rendemento.
Implementar comunicación cliente-servidor WebSocket
No lado do cliente, pode conectarse a un servidor WebSocket creando unha instancia de WebSocket e especificando un URL e, a continuación, enviar mensaxes ao 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);
}
No código de cliente anterior, creamos unha instancia de WebSocket e especificamos o seu URL. Despois de establecer a conexión con éxito, podemos enviar mensaxes ao servidor. Cando o servidor recibe a mensaxe do cliente, envía a mesma mensaxe de volta ao cliente. Neste punto, implícase unha simple comunicación punto a punto WebSocket.
Vantaxes e escenarios de uso de WebSocket
O protocolo WebSocket ten un modelo de comunicación bidireccional típico, que permite ao servidor enviar datos activamente ao cliente.Adoita empregarse para implementar chat, xogos en liña e outras ocasións que requiren tempo real e alta inmediatez. En comparación con outros protocolos de transmisión, o protocolo WebSocket ten as seguintes vantaxes:
• Alto rendemento en tempo real, admite comunicación bidireccional • Especificación do protocolo simple, fácil de usar • Capaz de xestionar un gran número de conexións simultáneas • Admite conexións longas, reducindo o tempo de transmisión da rede
Os escenarios de uso máis comúns de WebSocket inclúen chat web, batallas de xogos, reprodución en liña e mensaxería instantánea.
En resumo, a través do módulo de soporte WebSocket, é moi sinxelo de implementar e os desenvolvedores poden construír rapidamente as súas propias aplicacións web.
proba unitaria
Marcos de proba e métodos de proba
No proceso de desenvolvemento de software, as probas son un vínculo moi importante e as probas unitarias son unha parte importante del. As probas unitarias poden verificar de forma efectiva se o código cumpre co deseño e os requisitos e evitar erros introducidos cando se modifica o código. En xeral, o principio das probas unitarias é probar cada función e método para garantir que a entrada e saída de cada función e método sexan correctas.
Un marco de proba é unha base de código que se usa para escribir, executar e verificar casos de proba. Ofrece funcións de xestión, execución e informes de casos de proba. En JavaScript e Node.js, os marcos de probas unitarias populares inclúen Mocha, Jest e Jasmine. En fibjs, tamén temos o noso propio marco de proba, o módulo de proba.
No proceso de proba unitaria, os métodos de proba de uso habitual inclúen a proba de caixa negra e a proba de caixa branca.
A proba da caixa negra é un método de proba que só considera a entrada e saída dunha función sen ter en conta os detalles de implementación dentro da función. As probas de caixa negra baséanse na análise de requisitos e especificacións de deseño. Mediante a análise e execución de casos de proba, determinan se o programa ten erros de lóxica, de límite, de seguridade, etc. A súa vantaxe é que o proceso de proba é sinxelo e os resultados da proba son fiables.A súa desvantaxe é que a proba non pode cubrir todas as rutas do programa.
As probas de caixa branca son un método de proba que considera os detalles internos de implementación dunha función, incluíndo instrucións condicionais, instrucións de bucle, recursión e cobertura de código. Estas probas poden identificar posibles problemas na interacción entre os datos compartidos e o código. A vantaxe das probas de caixa branca é que pode cubrir todas as rutas do programa.A desvantaxe é que o proceso de proba é máis complicado e os resultados das probas vense afectados polo ambiente e os métodos de implementación.
Escribe casos de proba usando o módulo de proba
En fibjs, podemos usar o módulo de proba para escribir casos de proba para o servidor web. Aquí tes un exemplo sinxelo:
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();
Neste exemplo, usamos as funcións describe e it para definir o módulo de proba e o caso de proba respectivamente, e usamos a función assert para a verificación de asercións.
Na función describe, podemos definir varias funcións para probar diferentes escenarios respectivamente. En cada función it, podemos usar a función http.get para simular unha solicitude HTTP GET, obter a resposta da solicitude e realizar a verificación de asercións como assertTrue e assertEqual.
Ao escribir casos de proba, pode probar eficazmente a corrección das funcións e dos módulos, garantir a calidade do produto e tamén mellorar a mantebilidade do código.
Actualización quente
A actualización en quente refírese á actualización do código do servidor sen deter o servizo. Durante o proceso de desenvolvemento do programa, para iterar rapidamente, moitas veces son necesarios axustes de código e novas funcións. Usando a actualización en quente, podes usar código novo para completar o traballo de iteración de forma máis eficiente sen deter o servizo.
En fibjs, podemos usar o módulo SandBox para conseguir actualizacións sen problemas. O módulo SandBox pode proporcionar un ambiente de execución seguro e simular variables globais e outras funcións. Para unha implementación específica, consulte os seguintes pasos:
- Carga os ficheiros de código que hai que actualizar (como web.js).
- A través de SandBox, crea un novo módulo de seguridade, carga web.js no módulo e xera o módulo de seguridade. Volve montar o controlador do servizo en execución a través do módulo de seguridade xerado.
- O servidor segue procesando solicitudes anteriores e as novas solicitudes montaranse no novo controlador.
O seguinte é un código de mostra que usa o módulo SandBox para implementar actualizacións sen problemas:
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.`);
});
Neste código, primeiro cargamos o código en web.js cando se inicia o programa, despois creamos unha instancia SandBox e cargamos o código na instancia. Despois diso, creamos un novo servidor HTTP e utilizamos os métodos do controlador para procesar a solicitude.
No código, usamos fs.watch para supervisar os cambios no ficheiro web.js. Unha vez que o ficheiro cambia, cargamos de novo o código e actualizamos a implementación no controlador.
Optimización do rendemento
Durante o proceso de desenvolvemento, moitas veces temos que afrontar problemas de rendemento. Optimizar o código e mellorar o rendemento son unha das habilidades esenciais dos desenvolvedores. En fibjs, podemos usar CPU Profiler para axudarnos a analizar o estado de execución do programa e optimizar o código.
En fibjs, só precisa usar o parámetro da liña de comandos --prof para iniciar fibjs para iniciar o CPU Profiler (o intervalo predeterminado é de 1000 ms). Se precisa unha análise de rexistro de maior precisión, pode utilizar o parámetro --prof-interval para establecer o intervalo de rexistro. Por exemplo:
1
2$ fibjs --prof test.js # 启动 CPU Profiler,默认以 1000ms 为间隔
$ fibjs --prof --prof-interval=10ms test.js # 启动 CPU Profiler,以 10000us(即 10ms)为间隔
Cando fibjs remate de executarse, xerarase un directorio de nomes de ficheiros de orixe no directorio actual. Este directorio contén un ficheiro de rexistro e algúns ficheiros auxiliares. O nome predeterminado do ficheiro de rexistro é fibjs-xxxx.log, onde xxxx é unha marca de tempo. Podes usar a opción --log para especificar o nome do ficheiro de rexistro. Neste punto, pode --prof-process
procesar os rexistros xerados usando:
1fibjs --prof-process fibjs-xxxx.log prof.svg
Despois de completar a operación, use o navegador para abrir prof.svg para ver o gráfico de chamas deste rexistro: pode facer clic para ver a imaxe a tamaño completo. Na imaxe a tamaño completo, pode usar o rato para ver máis detalles. información: prof. svg .
No gráfico de chama xerado, cada bloque de cores representa un punto de gravación. Canto máis longo sexa o bloque de cores, máis veces se rexistra; cada liña representa unha capa de pila de chamadas e cantas máis capas, máis capas se chaman; chamadas A pila colócase boca abaixo. Canto máis baixo sexa o bloque de cores, máis orixinal será a función.
Hai dous tipos de bloques de cores, un é vermello e outro azul. No perfilador fibjs, o vermello representa operacións JavaScript e o azul representa operacións io ou operacións nativas. Dependendo do problema que necesites resolver, as áreas nas que debes centrarte variarán. Por exemplo, se necesitas resolver o problema do uso elevado da CPU, debes prestar atención aos bloques de cor vermella.Se a túa aplicación ten un uso baixo da CPU pero unha resposta lenta, debes prestar atención aos bloques de cor azul. Canto maior sexa o bloque de cores preto da parte superior, máis atención e optimización precisa.
Podemos tentar axustar funcións que ocupan máis recursos da CPU, implementar IO, etc. de forma asíncrona ou optimizar o código ao escribir.
Implantación e en liña
Para que o noso proxecto se execute nun ambiente de produción, necesitamos compilalo e implementalo. Aquí presentamos como usar o ficheiro package.json para configurar a compilación e a implantación.
No proxecto, podemos usar package.json para xestionar as dependencias do proxecto, configurar a compilación e a implantación. Tome unha mostra sinxela package.json como exemplo:
1
2
3
4
5
6
7{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"fib-pool": "^1.0.0"
}
}
Cando necesitemos compilar e despregar o proxecto, só necesitamos introducir o directorio do proxecto no terminal e executar o seguinte comando:
1fibjs --install
Este comando instalará automaticamente os módulos dos que depende o proxecto. Despois, podemos iniciar o proxecto usando o seguinte comando:
1fibjs app.js