Académique Documents
Professionnel Documents
Culture Documents
Node.js
8/4/2015
UntutorialdeNode.jspor:Manuel
Kiessling&HermanA.Junge
Sobre el Tutorial
El objetivo de este documento es ayudarte a
empezar con el desarrollo de aplicaciones para
Node.js, ensendote todo lo que necesites saber
acerca de JavaScript "avanzado" sobre la marcha.
Este tutorial va mucho ms all del tpico manual
"Hola Mundo".
Status
Ests leyendo la versin final de este libro, es decir,
las actualizaciones solo sern hechas para corregir
errores o para reflejar cambiar en nuevas versiones
de Node.js.
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font-
1/78
8/4/2015
Audiencia Objetivo
Este documento probablemente ser mejor
entendido por los lectores que tengan un trasfondo
similar al mo: Programadores experimentados en
al menos un lenguaje orientado al objeto, como
Ruby, Python, PHP o Java; poca experiencia con
JavaScript, y ninguna experiencia en Node.js.
El que este documento est orientado a
desarrolladores que ya tienen experiencia con otros
lenguajes de programacin significa que no vamos a
cubrir temas realmente bsicos como tipos de datos,
variables, estructuras de control y similares. Debes
saber acerca de estos tpicos para entender este
documento.
Sin embargo, dado que las funciones y objetos en
JavaScript son diferentes de sus contrapartes en la
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font-
2/78
8/4/2015
3/78
8/4/2015
Tabla de Contenidos
JavaScript y Node.js
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font-
4/78
8/4/2015
JavaScript y T
Antes que hablemos de toda la parte tcnica,
tommonos un minuto y hablemos acerca de ti y tu
relacin con JavaScript. Este captulo est aqu para
permitirte estimar si tiene sentido el que sigas o no
leyendo este documento.
Si eres como yo, empezaste con el "desarrollo"
HTML hace bastante tiempo, escribiendo
documentos HTML. Te encontraste en el camino
con esta cosa simptica llamada JavaScript, pero
solo la usabas en una forma muy bsica, agregando
interactividad a tus pginas de cuando en cuando.
Lo que realmente quisiste era "la cosa real", queras
saber cmo construir sitios web complejos Aprendiste un lenguaje de programacin como
PHP, Ruby, Java, y empezaste a escribir cdigo
"backend".
No obstante, mantuviste un ojo en JavaScript, y te
diste cuenta que con la introduccin de jQuery,
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font-
5/78
8/4/2015
6/78
8/4/2015
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font-
7/78
8/4/2015
Una Advertencia
Hay algunas personas realmente excelente en
JavaScript. No soy una de ellas.
Yo soy realmente el tipo del que te he hablado en los
prrafos previos. S un par de cosas acerca de
desarrollar aplicaciones backend, pero an soy
nuevo al JavaScript "real" y an ms nuevo a
Node.js. He aprendido solo recientemente alguno de
los aspectos avanzados de JavaScript. No soy
experimentado.
Por lo que este no es un libro "desde novicio hasta
experto". Este es ms bien un libro "desde novicio a
novicio avanzado".
Si no fallo, entonces este ser el tipo de documento
que deseo hubiese tenido cuando empec con
Node.js.
8/78
8/4/2015
Servidor
Las primeras encarnaciones de JavaScript vivan en
los browsers. Pero esto es slo el contexto. Define lo
que puedes hacer con el lenguaje, pero no dice
mucho acerca de lo que el lenguaje mismo puede
hacer. JavaScript es un lenguaje "completo": Lo
puedes usar en muchos contextos y alcanzar con
ste, todo lo que puedes alcanzar con cualquier otro
lenguaje "completo".
Node.js realmente es slo otro contexto: te permite
correr cdigo JavaScript en el backend, fuera del
browser.
Para ejecutar el cdigo JavaScript que tu pretendes
correr en el backend, este necesita ser interpretado
y, bueno, ejecutado, Esto es lo que Node.js realiza,
haciendo uso de la Maquina Virtual V8 de Google, el
mismo entorno de ejecucin para JavaScript que
Google Chrome utiliza.
Adems, Node.js viene con muchos mdulos tiles,
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font-
9/78
8/4/2015
"Hola Mundo"
Ok. Saltemos entonces al agua fra y escribamos
nuestra primera aplicacin Node.js: "Hola Mundo".
Abre tu editor favorito y crea un archivo
llamado holamundo.js. Nosotros queremos escribir
"Hola Mundo" a STDOUT, y aqu est el cdigo
necesario para hacer esto:
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
10/78
8/4/2015
console.log("Hola Mundo");
11/78
8/4/2015
La Pila de Aplicaciones
Hagamos un desglose a nuestra aplicacin. Qu
partes necesitan ser implementadas para poder
satisfacer nuestros casos de uso?
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
12/78
8/4/2015
13/78
8/4/2015
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
14/78
8/4/2015
Construyendo la Pila de
Aplicaciones
Un Servidor HTTP Bsico
Cuando llegu al punto donde quera empezar con
mi primera aplicacin Node.js "real", me pregunt
no solo como la iba a programar, sino que tambin,
como organizar mi cdigo.
Necesitar tenerlo todo en un archivo? Muchos
tutoriales en la Web que te ensean cmo escribir
un servidor HTTP bsico en Node.js tienen toda la
lgica en un solo lugar. Qu pasa si yo quiero
asegurarme que mi cdigo se mantenga leble a
medida que le vaya agregando ms cosas?
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
15/78
8/4/2015
16/78
8/4/2015
Ahora,
abre
tu
browser
y
apntalo
ahttp://localhost:8888/. Esto debera desplegar
una pgina web que diga "Hola Mundo".
Interesante, no? Qu tal si hablamos de que est
pasando aqu y dejamos la pregunta de 'cmo
organizar nuestro proyecto' para despus? Prometo
que volveremos a esto.
17/78
8/4/2015
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
18/78
8/4/2015
19/78
8/4/2015
20/78
8/4/2015
21/78
8/4/2015
De Qu manera el pasar
funciones hace que nuestro
servidor HTTP funcione
Con este conocimiento, Volvamos a nuestro servidor
HTTP minimalista:
var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
response.write("Hola Mundo");
response.end();
}).listen(8888);
22/78
8/4/2015
23/78
8/4/2015
24/78
8/4/2015
25/78
8/4/2015
26/78
8/4/2015
console.log("Servidor Iniciado.");
27/78
8/4/2015
28/78
8/4/2015
29/78
8/4/2015
30/78
8/4/2015
nuestro
31/78
8/4/2015
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado.");
exports.iniciar = iniciar;
32/78
8/4/2015
33/78
8/4/2015
34/78
8/4/2015
35/78
8/4/2015
Podemos,
por
supuesto,
tambin
utilizar querystring para parsear el cuerpo de una
peticin POST en busca de parmetros, como
veremos ms tarde.
Agreguemos ahora a nuestra funcin onRequest() la
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
36/78
8/4/2015
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado.");
exports.iniciar = iniciar;
37/78
8/4/2015
38/78
8/4/2015
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado.");
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
39/78
8/4/2015
exports.iniciar = iniciar;
40/78
8/4/2015
41/78
8/4/2015
42/78
8/4/2015
43/78
8/4/2015
44/78
8/4/2015
45/78
8/4/2015
46/78
8/4/2015
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
47/78
8/4/2015
48/78
8/4/2015
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado.");
exports.iniciar = iniciar;
49/78
8/4/2015
50/78
8/4/2015
archivo server.js.
"Manipular Peticiones" no significa otra cosa que
"Responder a las Peticiones" despus de todo, as
que
necesitamos
empoderar
a
nuestros
manipuladores de peticiones para hablar con el
browser
de la
misma
manera
que la
funcin onRequest lo hace.
51/78
8/4/2015
52/78
8/4/2015
exports.route = route;
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado.");
exports.iniciar = iniciar;
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
53/78
8/4/2015
Si nosotros arrancamos nuestra aplicacin reescrita, todo va a funcionar a las mil maravillas:
hacerle
una
peticin
ahttp://localhost:8888/iniciarresulta en "Hola
Iniciar" siendo desplegado en el browser, hacerle
una peticin ahttp://localhost:8888/subir nos da
"Hola
Subir",
y
la
peticin
ahttp://localhost:8888/foo produce "404 No
Encontrado".
OK, entonces Por qu esto es un problema? La
respuesta corta es: debido a que si uno de los
manipuladores de peticin quisiera hacer uso de
una operacin no-bloqueante (non-blocking) en el
futuro, entonces esta configuracin, como la
tenemos, sera problemtica.
Tommosnos algn tiempo para la respuesta larga.
Bloqueante y No-Bloqueante
Como se dijo, los problemas van a surgir cuando
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
54/78
8/4/2015
55/78
8/4/2015
// atasca la cpu
while (new Date().getTime() < startTime + milliSeconds);
sleep(10000);
return "Hola Iniciar";
function subir() {
console.log("Manipulador de peticion 'subir' fue llamado.");
return "Hola Subir";
}
exports.iniciar = iniciar;
exports.subir = subir;
56/78
8/4/2015
57/78
8/4/2015
58/78
8/4/2015
URL /inicio.
Lo que el cdigo hace es claro: crea una nueva
variable content() (con el valor incial de "vacio"),
ejecuta "ls -lah", llena la variable con el resultado, y
lo retorna.
Como siempre, arrancaremos nuestra aplicacin y
visitaremoshttp://localhost:8888/iniciar.
Lo que carga una bella pgina que despliega el
string "vacio". Qu es lo que est incorrecto ac?
Bueno, como ya habrn adivinado,exec() hace su
magia de una manera no-bloqueante. Buena cosa
esto, porque de esta manera podemos ejecutar
operaciones de shell muy caras en ejecucin (como,
por ejemplo, copiar archivos enormes o cosas
similares) sin tener que forzar a nuestra aplicacin a
detenerse como lo hizo la operacin sleep.
(Si quieres probar esto, reemplaza "ls -lah" con una
operacin ms cara como "find /").
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
59/78
8/4/2015
60/78
8/4/2015
61/78
8/4/2015
62/78
8/4/2015
63/78
8/4/2015
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado.");
exports.iniciar = iniciar;
64/78
8/4/2015
function subir(response) {
console.log("Manipulador de peticin 'subir' fue llamado.");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("Hola Subir");
response.end();
}
exports.iniciar = iniciar;
exports.subir = subir;
65/78
8/4/2015
66/78
8/4/2015
}
function subir(response) {
console.log("Manipulador de peticin 'subir' fue llamado.");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("Hola Subir");
response.end();
}
exports.iniciar = iniciar;
exports.subir = subir;
Esto
har
que
las
peticiones
HTTP
ahttp://localhost:8888/iniciartomen al menos 10
segundos,
pero,
las
peticiones
ahttp://localhost:8888/subir sean respondidas
inmediatamente, incluso si /iniciar todava est en
proceso.
67/78
8/4/2015
68/78
8/4/2015
ejercitarlo.
Segundo, manejar las subidas de archivos (i.e.
peticiones POST multiparte) no es simple con
Node.js, consecuentemente est ms all del alcance
de este tutorial, pero el aprender a usar un modulo
externo es una leccin en s misma que tiene sentido
de ser includa en un tutorial de principiantes.
69/78
8/4/2015
function iniciar(response) {
console.log("Manipulador de peticiones 'iniciar' fue llamado.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/subir" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Enviar texto" />'+
'</form>'+
'</body>'+
'</html>';
function subir(response) {
console.log("Manipulador de peticiones 'subir' fue llamado.");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("Hola Subir");
response.end();
}
exports.iniciar = iniciar;
exports.subir = subir;
70/78
8/4/2015
71/78
8/4/2015
72/78
8/4/2015
request.addListener("end", function() {
// funcion llamada cuando todos los trozos (chunks)
// de informacion (data) han sido recibidos.
});
73/78
8/4/2015
});
request.addListener("data", function(trozoPosteado) {
dataPosteada += trozoPosteado;
console.log("Recibido trozo POST '" + trozoPosteado + "'.");
request.addListener("end", function() {
route(handle, pathname, response, dataPosteada);
});
}
http.createServer(onRequest).listen(8888);
console.log("Servidor Iniciado");
exports.iniciar = iniciar;
74/78
8/4/2015
75/78
8/4/2015
exports.route = route;
76/78
8/4/2015
77/78
8/4/2015
exports.iniciar = iniciar;
exports.subir = subir;
data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font
78/78