Guía de desarrollo de guías

Prácticas de aplicaciones web de alto rendimiento.

introducir

fibjs es un marco de servidor de aplicaciones de alto rendimiento diseñado principalmente para el desarrollo web backend. Está construido sobre el motor JavaScript de Google v8 y elige una solución de concurrencia diferente a las devoluciones de llamada tradicionales. fibjs utiliza fibras para aislar la complejidad empresarial causada por llamadas asincrónicas en la capa de marco, lo que reduce en gran medida la dificultad de desarrollo y los problemas de rendimiento causados ​​por el procesamiento asincrónico frecuente en el espacio del usuario.

El diseño de fibjs presta gran atención al rendimiento. Los módulos de E/S de red integrados y HTTP adoptan un modelo de E/S sin bloqueo basado en eventos, para que los desarrolladores puedan implementar fácilmente aplicaciones de servidor de alta confiabilidad. Y debido a que la capa inferior está implementada en C++, fibjs tiene un rendimiento muy superior y puede hacer frente fácilmente a un alto acceso concurrente y proporcionar servicios extremadamente estables y confiables.

Al mismo tiempo, fibjs también admite WebSocket, que es un protocolo de comunicación full-duplex basado en el protocolo TCP, que establece una conexión ininterrumpida entre el navegador y el servidor, permite la transmisión de datos bidireccional en tiempo real y puede admitir datos. en cualquier formato transmisión. WebSocket se puede utilizar para implementar fácilmente aplicaciones de comunicación en tiempo real con mejores efectos de comunicación.

En resumen, fibjs no solo enfatiza el alto rendimiento y la alta confiabilidad, sino que también proporciona funciones de comunicación en tiempo real como WebSocket, un marco muy adecuado para desarrollar aplicaciones web de alta velocidad.

Configuración del entorno de desarrollo

Antes de comenzar el desarrollo de fibjs, debemos preparar el entorno de desarrollo. Este capítulo presentará cómo instalar fibjs, cómo usar la herramienta fibjs para inicializar el proyecto y cómo usar el entorno de desarrollo integrado IDE.

Instalar fibjs

Para diferentes sistemas operativos, los métodos para instalar fibjs son ligeramente diferentes.

Para usuarios de Linux y macOS, fibjs se puede instalar usando el siguiente comando:

1
curl -s https://fibjs.org/download/installer.sh | sh

Si está utilizando macOS y utiliza el administrador de paquetes Homebrew, también puede instalarlo usando el siguiente comando:

1
brew install fibjs

Para los usuarios de Windows, deben descargar el instalador del sitio web oficial de fibjs y luego seguir las instrucciones para instalarlo.

Crea un nuevo proyecto usando fibjs –init

Después de instalar fibjs, puede utilizar la herramienta fibjs para crear rápidamente nuevos proyectos. Utilice el siguiente comando para crear una plantilla de proyecto básica:

1
fibjs --init

Este comando creará una nueva estructura de proyecto en el directorio actual, incluido package.json, que se utiliza para almacenar información básica del proyecto e información de dependencia.

Escribir aplicaciones web

El desarrollo de aplicaciones web es actualmente el escenario de aplicación más utilizado de fibjs. fibjs proporciona una serie de herramientas y módulos para ayudarnos a crear aplicaciones web más rápidamente.

Escribir un servidor HTTP

  • Primero importe el módulo http;
  • Cree una instancia de http.Server y escuche las solicitudes.
  • El servidor se inicia a través de la función de inicio.
1 2 3 4 5 6
const http = require('http'); const server = new http.Server(8080, (req) => { req.response.write('Hello World!'); }); server.start();

Analizar los parámetros de URL y el cuerpo de la solicitud

El análisis de los parámetros de URL y los cuerpos de solicitud es muy importante y se utiliza en varias aplicaciones del lado del servidor. En fibjs, los parámetros de la URL entrante se pueden analizar directamente a través de req.query y el cuerpo de la solicitud se puede leer a través de req.body.

1 2 3 4 5 6 7 8
const 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 control de acceso a la interfaz

Restringir el acceso de los usuarios a través de interfaces es un escenario muy común. A continuación se muestra un ejemplo sencillo.

1 2 3 4 5 6 7 8 9 10
const 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();

Agregar procesamiento de enrutamiento

El enrutamiento es uno de los conceptos más importantes en una aplicación web y se refiere a la distribución de las solicitudes recibidas a los procesadores de acuerdo con ciertas reglas. En fibjs, puede escribir su propio módulo de enrutamiento y vincularlo al servidor http, y luego realizar la coincidencia de URL y el procesamiento correspondiente mediante un análisis de ruta personalizado.

1 2 3 4 5 6 7 8 9
const 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();

El ejemplo anterior también se puede implementar con una sintaxis más sencilla:

1 2 3 4 5 6 7 8
const http = require('http'); var svr = new http.Server(8080, { '/hello/:name': function (req, name) { req.response.write('hello, ' + name); } }); svr.start();

Manejo de errores y registro

En fibjs, puede capturar excepciones lógicas a través de bloques try-catch y enviarlas a archivos de registro para depurar y registrar; si son excepciones fatales, se pueden enviar directamente al marco superior para su procesamiento.

1 2 3 4 5 6 7 8 9 10
const console = require('console'); const http = require('http'); const server = new http.Server(8080, (req) => { try { // ... } catch (e) { console.log(e.message, e.stack); } });

solicitud entre dominios

En fibjs, podemos usar el método enableCrossOrigin para permitir solicitudes entre dominios. Aquí hay un código de muestra sobre cómo crear un servidor http y permitir solicitudes entre dominios:

1 2 3 4 5 6 7 8
const http = require('http'); const server = new http.Server(8080, (req) => { req.response.write('Hello World!'); }); server.enableCrossOrigin(); // enable cross domain request server.start();

En el ejemplo anterior, creamos un servidor http con el puerto 8080. El método enableCrossOrigin() permite solicitudes de origen cruzado.

Al utilizar enableCrossOrigin para permitir solicitudes entre dominios, puede especificar los encabezados entre dominios que se pueden recibir pasando un parámetro enableHeaders. De forma predeterminada, el valor de enableHeaders es Tipo de contenido.

El código de muestra es el siguiente:

1 2
// enable "Content-Type" and "Authorization" headers in cross domain request server.enableCrossOrigin("Content-Type, Authorization");

En el código anterior, el valor de enableHeaders es "Tipo de contenido, Autorización", lo que significa que el servidor puede recibir los dos encabezados entre dominios "Tipo de contenido" y "Autorización". Si la solicitud contiene otros encabezados, será rechazada por el servidor.

Cabe señalar que cuando usamos enableCrossOrigin para configurar la capacidad de recibir encabezados entre dominios, también debemos configurar el encabezado de solicitud correspondiente al enviar solicitudes entre dominios; de lo contrario, el servidor también lo rechazará.

WebSockets

El protocolo WebSocket es un protocolo de comunicación full-duplex basado en el protocolo TCP, que establece una conexión ininterrumpida entre el navegador y el servidor, puede realizar una transmisión de datos bidireccional en tiempo real y puede admitir la transmisión de datos en cualquier formato. En fibjs, el módulo de soporte WebSocket proporciona las interfaces API correspondientes, que pueden realizar el desarrollo del servidor y cliente WebSocket.

Utilice el módulo WebSocket nativo de fibjs para implementar el lado del servidor WebSocket

En el lado del servidor, las solicitudes HTTP se pueden convertir en conexiones WebSocket mediante la función de actualización. Al crear un objeto de servidor http, puede usar ws.upgrade(callback) y pasarlo al método http.start() para convertir la solicitud 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 27
var 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();

En el ejemplo anterior, podemos monitorear el evento de mensaje enviado por el cliente y el evento de cierre de conexión entre el servidor y el cliente. Cuando el servidor recibe el mensaje del cliente, envía el mismo mensaje al cliente. En este punto, se implementa una comunicación simple punto a punto de WebSocket.

Implementar la interacción con el almacenamiento de datos.

Al utilizar WebSocket para la comunicación, además de simplemente enviar y recibir mensajes, también debe considerar operaciones como el almacenamiento persistente y la consulta de datos. En este momento, necesita usar la base de datos, puede usar el módulo db integrado en fibjs para interactuar con la base de datos.

El código de muestra es el siguiente:

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 33
var 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();

En el ejemplo anterior, primero usamos el método openMySQL del módulo db para crear un objeto de conexión de base de datos MySQL mysql, y luego, después de escuchar el mensaje del cliente, usamos el método de ejecución para ejecutar directamente la consulta SQL y obtener registros que cumplir las condiciones. Finalmente, los resultados de la consulta se envían al cliente a través del protocolo WebSocket.

Cabe señalar que en el desarrollo real, el manejo de excepciones y la seguridad de los datos deben realizarse bien.

En resumen, a través del módulo db, podemos interactuar fácil y fácilmente con la base de datos, combinada con el protocolo WebSocket, para implementar aplicaciones web de alto rendimiento en tiempo real.

Implementar la comunicación cliente-servidor WebSocket

En el lado del cliente, puede conectarse a un servidor WebSocket creando una instancia de WebSocket y especificando una URL, y luego enviar mensajes 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 24
var 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 código de cliente anterior, creamos una instancia de WebSocket y especificamos su URL. Una vez que la conexión se haya establecido correctamente, podemos enviar mensajes al servidor. Cuando el servidor recibe el mensaje del cliente, envía el mismo mensaje al cliente. En este punto, se implementa una comunicación simple punto a punto de WebSocket.

Ventajas y escenarios de uso de WebSocket

El protocolo WebSocket tiene un modelo de comunicación bidireccional típico, que permite que el servidor envíe datos activamente al cliente. A menudo se utiliza para implementar chat, juegos en línea y otras ocasiones que requieren tiempo real y alta inmediatez. En comparación con otros protocolos de transmisión, el protocolo WebSocket tiene las siguientes ventajas:

• Alto rendimiento en tiempo real, admite comunicación bidireccional • Especificación de protocolo simple, fácil de usar • Capaz de manejar una gran cantidad de conexiones simultáneas • Admite conexiones largas, lo que reduce el tiempo de transmisión de la red

Los escenarios de uso más comunes de WebSocket incluyen chat web, batallas de juegos, reproducción en línea y mensajería instantánea.

En resumen, a través del módulo de soporte WebSocket, es muy sencillo de implementar y los desarrolladores pueden crear rápidamente sus propias aplicaciones web.

prueba de unidad

Marcos de prueba y métodos de prueba.

En el proceso de desarrollo de software, las pruebas son un vínculo muy importante, y las pruebas unitarias son una parte importante de él. Las pruebas unitarias pueden verificar de manera efectiva si el código cumple con el diseño y los requisitos y evitar errores introducidos cuando se modifica el código. En términos generales, el principio de las pruebas unitarias es probar cada función y método para garantizar que la entrada y salida de cada función y método sean correctas.

Un marco de prueba es una base de código que se utiliza para escribir, ejecutar y verificar casos de prueba y proporciona funciones de gestión, ejecución y generación de informes de casos de prueba. En JavaScript y Node.js, los marcos de pruebas unitarias populares incluyen Mocha, Jest y Jasmine. En fibjs también tenemos nuestro propio marco de pruebas, el módulo de prueba.

En el proceso de prueba unitaria, los métodos de prueba comúnmente utilizados incluyen pruebas de caja negra y pruebas de caja blanca.

La prueba de caja negra es un método de prueba que solo considera la entrada y salida de una función sin considerar los detalles de implementación dentro de la función. Las pruebas de caja negra se basan en el análisis de requisitos y las especificaciones de diseño y, a través del análisis y la ejecución de casos de prueba, determinan si el programa tiene errores lógicos, errores de límites, problemas de seguridad, etc. Su ventaja es que el proceso de prueba es simple y los resultados de la prueba son confiables, su desventaja es que la prueba no puede cubrir todas las rutas del programa.

La prueba de caja blanca es un método de prueba que considera los detalles de implementación interna de una función, incluidas declaraciones condicionales, declaraciones de bucle, recursividad y cobertura de código. Estas pruebas pueden identificar posibles problemas en la interacción entre datos compartidos y código. La ventaja de las pruebas de caja blanca es que puede cubrir todas las rutas del programa, la desventaja es que el proceso de prueba es más complicado y los resultados de la prueba se ven afectados por el entorno y los métodos de implementación.

Escribir casos de prueba usando el módulo de prueba.

En fibjs, podemos usar el módulo de prueba para escribir casos de prueba para el servidor web. He aquí un ejemplo sencillo:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
var 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 este ejemplo, usamos las funciones describe e it para definir el módulo de prueba y el caso de prueba respectivamente, y usamos la función de afirmación para la verificación de aserciones.

En la función de descripción, podemos definir múltiples funciones para probar diferentes escenarios respectivamente. En cada función, podemos usar la función http.get para simular una solicitud HTTP GET, obtener la respuesta de la solicitud y realizar una verificación de aserción como afirmarTrue y afirmarEqual.

Al escribir casos de prueba, puede probar de manera efectiva la corrección de funciones y módulos, garantizar la calidad del producto y también mejorar la capacidad de mantenimiento del código.

Actualización en caliente

La actualización en caliente se refiere a la actualización del código del servidor sin detener el servicio. Durante el proceso de desarrollo del programa, para iterar rápidamente, a menudo se requieren ajustes de código y nuevas funciones. Con la actualización en caliente, puede utilizar código nuevo para completar el trabajo de iteración de manera más eficiente sin detener el servicio.

En fibjs, podemos usar el módulo SandBox para lograr actualizaciones en caliente sin problemas. El módulo SandBox puede proporcionar un entorno de ejecución seguro y simular variables globales y otras funciones. Para una implementación específica, consulte los siguientes pasos:

  • Cargue los archivos de código que deben actualizarse (como web.js).
  • A través de SandBox, cree un nuevo módulo de seguridad, cargue web.js en el módulo y genere el módulo de seguridad. Vuelva a montar el controlador del servicio en ejecución a través del módulo de seguridad generado.
  • El servidor continúa procesando solicitudes anteriores y las nuevas solicitudes se montarán en el nuevo controlador.

El siguiente es un código de muestra que utiliza el módulo SandBox para implementar actualizaciones en caliente sin problemas:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
const 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 este código, primero cargamos el código en web.js cuando se inicia el programa, luego creamos una instancia de SandBox y cargamos el código en la instancia. Después de eso, creamos un nuevo servidor HTTP y utilizamos los métodos del controlador para procesar la solicitud.

En el código, usamos fs.watch para monitorear los cambios en el archivo web.js. Una vez que el archivo cambia, recargamos el código y actualizamos la implementación en el controlador.

Optimización del rendimiento

Durante el proceso de desarrollo, a menudo tenemos que enfrentarnos a problemas de rendimiento. Optimizar el código y mejorar el rendimiento son una de las habilidades esenciales para los desarrolladores. En fibjs, podemos usar CPU Profiler para ayudarnos a analizar el estado de ejecución del programa y optimizar el código.

En fibjs, solo necesita usar el parámetro de línea de comando --prof para iniciar fibjs e iniciar CPU Profiler (el intervalo predeterminado es 1000 ms). Si necesita un análisis de registros de mayor precisión, puede utilizar el parámetro --prof-interval para establecer el intervalo de registro. Por ejemplo:

1 2
$ fibjs --prof test.js # 启动 CPU Profiler,默认以 1000ms 为间隔 $ fibjs --prof --prof-interval=10ms test.js # 启动 CPU Profiler,以 10000us(即 10ms)为间隔

Cuando fibjs termine de ejecutarse, se generará un directorio con el nombre del archivo fuente en el directorio actual, que contiene un archivo de registro y algunos archivos auxiliares. El nombre predeterminado del archivo de registro es fibjs-xxxx.log, donde xxxx es una marca de tiempo. Puede utilizar la opción --log para especificar el nombre del archivo de registro. En este punto, puede --prof-processprocesar los registros generados usando:

1
fibjs --prof-process fibjs-xxxx.log prof.svg

Una vez completada la operación, use el navegador para abrir prof.svg y ver el gráfico de llamas de este registro: profe puede hacer clic para ver la imagen en tamaño completo. En la imagen en tamaño completo, puede operar el mouse para ver más detalles. información: profesor svg .

En el gráfico de llama generado, cada bloque de color representa un punto de grabación. Cuanto más largo es el bloque de color, más veces se registra; cada línea representa una capa de la pila de llamadas, y cuantas más capas, más capas se llaman; llamadas La pila se coloca al revés: cuanto más bajo sea el bloque de color, más original será la función.

Hay dos tipos de bloques de color, uno es rojo y el otro es azul. En el generador de perfiles fibjs, el rojo representa operaciones de JavaScript y el azul representa operaciones io u operaciones nativas. Dependiendo del problema que necesites resolver, las áreas en las que deberás concentrarte variarán. Por ejemplo, si necesita resolver el problema del uso elevado de CPU, debe prestar atención a los bloques de color rojo. Si su aplicación tiene un uso bajo de CPU pero una respuesta lenta, debe prestar atención a los bloques de color azul. Cuanto más grande sea el bloque de color cerca de la parte superior, más atención y optimización necesitará.

Podemos intentar ajustar funciones que consumen más recursos de CPU, implementar IO, etc. de forma asincrónica u optimizar el código al escribir.

Implementación y en línea

Para que nuestro proyecto se ejecute en un entorno de producción, necesitamos compilarlo e implementarlo. Aquí presentamos cómo usar el archivo package.json para configurar la compilación y la implementación.

En el proyecto, podemos usar package.json para administrar las dependencias del proyecto, configurar la compilación y la implementación. Tome un paquete de muestra simple.json como ejemplo:

1 2 3 4 5 6 7
{ "name": "my-project", "version": "1.0.0", "dependencies": { "fib-pool": "^1.0.0" } }

Cuando necesitamos compilar e implementar el proyecto, solo necesitamos ingresar el directorio del proyecto en la terminal y ejecutar el siguiente comando:

1
fibjs --install

Este comando instalará automáticamente los módulos de los que depende el proyecto. Luego, podemos iniciar el proyecto usando el siguiente comando:

1
fibjs app.js

👉【Enrutamiento de nombres de dominio