Puede estar de moda, pero hay una razón práctica para adoptar Node.js? Lee Boynton muestra cómo se puede usar para agregar un feed de noticias en tiempo real a su sitio PHP.

Este artículo tiene como objetivo mostrarle cómo puede comenzar a usar Node para agregar funciones en tiempo real a su sitio web basado en PHP. Primero, veremos un poco más qué hace que Node sea una buena opción para aplicaciones en tiempo real, antes de pasar a demostrar cómo construir un feed de noticias en tiempo real e incorporarlo a su sitio web PHP.

Basado en subprocesos vs basado en eventos

Tradicionalmente PHP se sirve con Apache y el módulo mod_php. Si ejecuta el comando’ top ‘ en su servidor web basado en Unix, probablemente verá un gran número de procesos Apache que sirven a clientes web. En esta configuración, cada solicitud de cliente normalmente genera un nuevo proceso de Apache hasta que se agote toda la RAM disponible. Recientemente, nginx y php-fpm han surgido como el método más eficiente de servir sitios web PHP, pero incluso en esta configuración, cada cliente es servido por un proceso PHP diferente. El punto clave aquí es que, de principio a fin, una solicitud de cliente está utilizando un proceso PHP durante toda la duración. Si se tarda mucho tiempo en procesar cada solicitud, los recursos del servidor se pueden agotar muy rápidamente.

En el nodo, un proceso de nodo único normalmente sirve a cada cliente en un bucle de eventos. Para procesos costosos y de larga duración, como el acceso al sistema de archivos, una base de datos o una API remota, se recomienda usar llamadas a métodos asíncronos en lugar de bloquearlas. Esto se logra mediante el uso de devoluciones de llamada que se activan cuando una acción como acceder al sistema de archivos ha finalizado. Esto significa que un proceso de un solo nodo puede continuar procesando nuevas solicitudes mientras la costosa operación se ejecuta en segundo plano. Cuando se completa la costosa operación, vuelve a la cola de bucle de eventos para ser procesada por el nodo.

En esencia, Node se puede ver como un entorno similar para crear aplicaciones como Twisted de Python o EventMachine en Ruby. Node también tiene un servidor HTTP listo para producción integrado, por lo que no necesita un servidor separado para ejecutarlo, como Apache o Nginx, lo que mejora aún más sus requisitos de recursos magros (salvo fugas de memoria).

var http = require('http');http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn');}).listen(1337, '127.0.0.1');console.log('Server running at http://127.0.0.1:1337/');

El ejemplo de código anterior muestra cómo puede escribir un servidor web obligatorio de «hola mundo» en solo unas pocas líneas de código. La primera línea muestra el uso del sistema de módulos conocido como CommonJS, que el nodo utiliza para incluir módulos separados. La función require está integrada y, en este caso, importa el módulo HTTP del nodo para su uso en la aplicación. La segunda línea crea un nuevo objeto de servidor web. Observe que el primer parámetro del método createServer es una función anónima. La mayoría de los métodos en el nodo aceptan una función de devolución de llamada como parámetro, y esta es la clave para crear aplicaciones basadas en eventos.

La siguiente línea de ejecución es la línea 5, que utiliza el encadenamiento de métodos para llamar al método listen sobre el valor devuelto del método createServer (el valor devuelto es la instancia del módulo HTTP). El método listen hace que el servidor comience a aceptar solicitudes HTTP en el puerto 1337 en localhost. La última línea escribe un mensaje en la consola para decir que el servidor se ha iniciado. Solo cuando se realiza una solicitud al servidor se llama a la función anónima, que establece el código de estado HTTP en 200 OK y establece el encabezado Content-Type. El mensaje’ Hola Mundo ‘ finalmente se escribe en el cuerpo de respuesta HTTP en la línea 4.

Por Qué Debería Usar Node.js Entonces?

El modelo basado en eventos de Node es especialmente adecuado para aplicaciones en tiempo real, como juegos, canales de noticias y aplicaciones de chat. Además, también le permite usar el mismo idioma en el frontend y el backend. JavaScript solo se está volviendo más popular a medida que se construyen aplicaciones más ricas del lado del cliente y los navegadores web se vuelven más rápidos en la ejecución de JavaScript. Tener que cambiar de idioma puede ser frustrante.

WordPress Spezial

Entwickler Magazin Spezial Vol. 10: WordPressEntwickler Magazin Spezial Vol. 10: WordPress
Alles rund um WordPress im Entwickler Spezial Vol. 10-ab 18.11.2016 im Handel.
WordPress es el sistema de blogs más sencillo. In diesem Sonderheft beschäftigen sich zahlreiche Spezialisten mit allen wichtigen Fragen rund um das verbreitetste CMS im Web; und dabei geht es nicht nur um klassische Themen, sondern auch um Affiliate Marketing, E-Commerce u.v.m.

Segundo, tiene un buen soporte para WebSockets. Si bien es posible soportar WebSockets en PHP, la naturaleza asíncrona de Node y su servidor HTTP incorporado lo hacen un mejor ajuste. WebSockets son una forma de mantener una conexión persistente con el navegador para enviar datos al cliente rápidamente. En comparación con soluciones anteriores, como long polling o comet, los WebSockets implican una latencia mucho menor, ya que no hay sobrecarga de instanciar una conexión HTTP cada vez que se necesitan enviar algunos datos. La desventaja de WebSockets es que es una característica HTML5,y como tal no está tan bien soportada en los navegadores como el Ajax normal. Sin embargo, es posible recurrir a técnicas alternativas como el sondeo largo en navegadores que no admiten WebSockets.

En la Conferencia Internacional de PHP de este año, puede obtener más información sobre la integración de nodos.js con PHP!

La Conferencia Internacional de PHP es la primera conferencia de PHP del mundo y ha sido un hito para la experiencia pragmática de primer nivel en PHP y tecnologías web durante más de una década . En el IPC, expertos de renombre internacional de la industria de PHP se reúnen con usuarios y desarrolladores de PHP de grandes y pequeñas empresas. ¡Echa un vistazo a nuestros Precios de Reserva Anticipada para obtener grandes descuentos!

Aquí hay algunas sesiones destacadas de IPC:

  • Haciendo su Angular.aplicación js accesible
    Dirk Ginader (Google)
  • TypeScript – Haciendo que el desarrollo de JavaScript sea más Productivo y robusto
    Rainer Stropek (software architects gmbh)
  • Cómo prepararse para PHP 7
    Sebastian Bergmann (software architects gmbh) thePHP.cc)

Tenga en cuenta que Node es una plataforma inmadura en comparación con PHP. Creado originalmente en 2009, todavía está en su infancia y aún no ha alcanzado la versión 1.0, si eso le importa. Puede encontrar que las API que usa cambian en el futuro, o no puede encontrar un marco que tenga el mismo conjunto de características que su marco PHP favorito. De hecho, en mi experiencia, las bibliotecas y frameworks de terceros disponibles tienden a consistir en paquetes mucho más pequeños de funcionalidad que necesita juntar.

También hay un mayor riesgo de fugas de memoria que paralizan la aplicación. Los procesos de nodo normalmente se ejecutan continuamente, mientras que los procesos PHP tienden a reaparecer periódicamente para negar el efecto de las fugas de memoria.

La Parte de Integración

El feed de noticias se integrará con un sitio web PHP básico que maneja los inicios de sesión y las sesiones de los usuarios, utilizando una configuración común de php-fpm y nginx. Utilizaremos JavaScript para comunicarnos con una aplicación de nodo en el lado del servidor y actualizar dinámicamente el feed de noticias sin recargar la página. En primer lugar, sin embargo, un rápido aparte en las sesiones.

Si aún no lo está haciendo, debería usar un área de almacenamiento centralizada para sus sesiones (Figura 1). Memcached se puede usar fácilmente para esta tarea utilizando el controlador de guardado de sesiones integrado en la extensión PECL memcached. Si desea la capacidad de reiniciar el servidor para almacenar sus sesiones sin perder datos, Redis es una buena apuesta. De cualquier manera, un almacenamiento de sesiones centralizado le permite equilibrar la carga de su aplicación en varios servidores web. También le permite compartir datos de sesión con aplicaciones creadas con otros lenguajes de programación.

Figura 1: Arquitectura de sesión compartida.

Sin embargo, hay un pequeño problema al analizar los datos de la sesión. A continuación se muestra el formato de serialización predeterminado de una sesión PHP:

not|a:2:{i:0;s:4:"easy";i:1;a:1:{s:2:"to";s:5:"parse";}}

Puede parecer que puede usar la manipulación de cadenas para analizarla, pero puede haber casos extremos que son difíciles de resolver. Sería bueno que la sesión fuera serializada en el muy querido formato JSON:

{"this":{"is": "easier", "to": "parse"}}

Mucho mejor. Es bastante fácil escribir su propio serializador de sesión que convertirá lo que almacene en format _SESSION a formato JSON, vea mi versión.

Alternativamente, es posible que desee considerar msgpack que se puede configurar para serializar sesiones, como en el código a continuación, que también muestra cómo usar memcached como controlador de guardado de sesiones.


Hay una biblioteca de terceros disponible para Node que puede ser serializada y deserializada msgpack, disponible en npm (Node Package Manager, contiene una gran cantidad de módulos que se pueden usar en su aplicación con una simple instalación de npm ). Ahora veremos cómo construir el feed de noticias usando Node e incorporándolo a una aplicación PHP.

Aplicación PHP

La aplicación PHP simplemente maneja los inicios de sesión y las sesiones de los usuarios. Las sesiones se almacenan en memcached, pero podrían almacenarse fácilmente en redis. El siguiente código muestra fragmentos de la aplicación simple de una página (para ver la fuente completa, vaya a github.com/lboynton/phphants-march-php).

// // <!]>

La primera línea del script incluye el archivo de carga automática de Composer, lo que significa que todas las dependencias se cargan automáticamente, obviando la necesidad de líneas de inclusión o de requerimiento separadas (Nota del editor: para más información sobre Composer, consulte Jefersson Nathan de O. Artículo de Chaves). En este caso, el manejador de guardar sesión es la única pieza de código externo que se requiere. Sin embargo, es muy fácil incluir cualquier paquete de terceros disponible en packagist o en otro lugar en una fecha posterior utilizando Composer, que también se agregará automáticamente a la carga automática. Las líneas 3 y 4 configuran una conexión a memcached, mientras que el manejador de guardar sesión se inicializa y registra con PHP en las líneas 5-14. Los usuarios inician sesión simplemente especificando el nombre de usuario como un parámetro GET, aunque en un sistema real esto debería reemplazarse por un sistema de autenticación más funcional.

En el lado de JavaScript, utilizamos algunas bibliotecas de terceros: jQuery, subrayado.js y la Socket.IO cliente, que es la parte del navegador del módulo de nodo que utilizaremos para enviar datos al navegador. La io.la llamada al método connect crea una conexión a la aplicación Node, que podría usar uno de varios transportes, como websockets o Ajax, dependiendo de la compatibilidad del navegador. Zócalo.el método on configura un controlador de eventos que renderizará una noticia en la página cada vez que el servidor active un evento de «noticias».

Nota: La aplicación utiliza Composer para instalar el controlador de guardado de sesiones y Bower, un administrador de paquetes para instalar activos del lado del cliente. Para instalar Bower, ejecute ‘npm-g install bower’. A continuación, para instalar los activos, haga ‘instalación de enramadas’. También puede actualizar las etiquetas de script y las hojas de estilo con versiones locales.

La aplicación se sirve con nginx. Aquí está el archivo de configuración de nginx:

upstream node { server localhost:3000;}server { listen 8080; server_name php-node-demo.localhost; root /home/lee/public_html/php-node-demo; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ .php$ { include fastcgi_params; fastcgi_index index.php; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location ~ /socket.io { proxy_pass http://node; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }}

Las líneas 1-3 definen un servidor ascendente que ejecuta la aplicación Node. Cualquier petición que termine en .php se enviará a php-fpm (líneas 15-20), mientras que cualquier petición con /socket.io en la URL se pasará a la aplicación Node (líneas 22-27). Las líneas 25 y 26 le dicen a nginx que admita la conmutación de protocolos y habilite el proxy de websockets a Node. Esto significa que la aplicación PHP y la aplicación Node se ejecutan en el mismo puerto, en lo que respecta al cliente.Nodo

.Aplicación js

El Nodo.la aplicación js simplemente maneja cualquier solicitud de cliente para el feed de noticias. A continuación se muestran fragmentos de él (véase github.com/lboynton/phphants-march-node para la fuente completa).

io.set('authorization', function(handshake, callback) { var cookies = cookie.parse(handshake.headers.cookie); mcClient.get('sessions/' + cookies.PHPSESSID, function(error, result) { if (error) { callback(error, false); } else if (result) { handshake.session = JSON.parse(result); callback(null, true); } else { callback('Could not find session ID ' + cookies.PHPSESSID + ' in memcached', false); } });});io.sockets.on('connection', function(socket) { var session = socket.handshake.session; sockets = socket;);function getNews() { redis.blpop('news', 0, function(err, data) {news = JSON.parse(data);if (typeof news.to !== 'undefined') { if (typeof sockets !== 'undefined') {sockets.emit('news', news.content); }} else { io.sockets.emit('news', news.content);}process.nextTick(getNews); });}

Socket.io es una biblioteca que proporciona una única API para realizar la comunicación WebSocket entre el cliente y el servidor. También es compatible con el respaldo elegante cuando los WebSockets no están disponibles en el navegador, y otras características útiles en un protocolo de mensajería, como latidos de corazón, tiempos de espera y soporte de desconexión, que no se admite de forma inmediata con la API WebSocket HTML5.

El primer fragmento configura la autorización para solicitudes que Socket.io recibe. Cuando llega una nueva solicitud, analizará las cookies de la solicitud e intentará recuperar una clave memcached que corresponda al valor de la cookie PHPSESSID (el nombre predeterminado de la cookie de sesión PHP). Si se encuentra, almacenará el valor analizado de la clave memcached en data.sesión a la que se puede acceder más adelante.

El siguiente fragmento configura lo que debe suceder cuando Socket.io activa el evento «conexión». Este evento se activa durante la conexión inicial del cliente, una vez autorizada. Ahora se puede hacer referencia a los datos de sesión que se recuperaron previamente de memcached a través del socket.variable de apretón de manos. Cuando el cliente se conecta, la instancia de socket se asocia con el nombre de usuario del cliente para que se puedan enviar mensajes a usuarios individuales.

El último fragmento contiene una función para comprobar si hay nuevas noticias en una cola de redis. Utiliza el comando BLPOP en redis, lo que significa que si la cola está vacía, se bloqueará hasta que se agreguen algunos datos a la cola antes de activarla. Cuando algunos datos se pueden sacar de la cola, se analizan como JSON antes de determinar si el contenido se debe enviar a cada cliente conectado o a un solo usuario. El contenido de la noticia se envía al conector correcto llamando al método emit() en el conector que se asoció con el usuario previamente en el controlador de eventos de conexión.

Finalmente, el proceso del nodo.El método nextTick () se llama con la función getNews como argumento. Esto significa que la función getNews se llamará la próxima vez que se ejecute el bucle de eventos y continuará revisando los datos de la cola redis hasta que se detenga la aplicación.

Para instalar, utilice npm para descargar las dependencias necesarias. A continuación, ejecute la aplicación con la aplicación node.js.

Ahora debería poder abrir un navegador web y navegar a http://localhost:8080/?username=bob y ver la aplicación de noticias. Ahora abra una segunda pestaña o ventana del navegador con un nombre de usuario diferente, por ejemplo http://localhost:8080/?username=sally.

Actualizar el Feed

Actualizar el feed es simplemente un caso de empujar una nueva noticia a la cola. Conéctese a la interfaz de redis CLI mediante el comando redis-cli. Este es un shell interactivo para redis, que le permite enviar comandos al servidor directamente. El ejemplo de código a continuación muestra cómo empujar a la cola:

rpush news '{"content": "Testy test", "to": "bob"}'

En la ventana del navegador web que abrió para el usuario bob, debería ver la noticia deslizarse hacia abajo desde la parte superior de la página. Alternativamente, puede enviar noticias a bob, sally y a cualquier otro cliente conectado excluyendo el parámetro «to», de la siguiente manera:

rpush news '{"content": "Everyone should see this"}'

En una aplicación real, puede enviar datos a la cola desde PHP, utilizando por ejemplo la extensión php-redis o predis.

Conclusión

Este es solo un ejemplo sencillo para demostrar cómo se puede integrar Node con su aplicación PHP. Hay algunas limitaciones en la implementación. Por ejemplo, solo recordará una conexión de cada usuario. Por lo tanto, si un usuario tiene varias pestañas o ventanas abiertas en el feed de noticias, solo se actualizará una página. Esto se puede resolver almacenando una matriz de sockets por usuario y realizando un seguimiento de cada conexión y desconexión para agregar o eliminar los sockets de la matriz. Se deja al lector la tarea de implementar una mejor solución. También mostró herramientas como Composer y Bower, que recomiendo encarecidamente que considere usar en sus aplicaciones.

Lee Boynton es un desarrollador con sede en Hampshire, Reino Unido, con un interés particular en aplicaciones en tiempo real, como mensajería instantánea y flujos de actividad. Tiene conocimientos de desarrollo y administración del lado del servidor, así como de desarrollo de frontend. Trabaja en la empresa local Symbios Group y también es miembro de PHP Hampshire para quien ayuda a organizar eventos.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.