Prévia do material em texto
5ºAula
HTTP Server
Objetivos de aprendizagem
Ao término desta aula, vocês serão capazes de:
• construir um web server;
• retornar arquivos externos pelo servidor;
• manipular os dados de um formulário;
• fazer upload de arquivos para o servidor;
• enviar e-mail pelo servidor.
Olá,
Bem-vindos(as) à aula 5 da disciplina de Desenvolvimento
Web II. Na aula anterior, o gerenciador de pacotes do Node.js foi
apresentado, além disso indicamos alguns módulos de terceiros com
funcionalidades importantes, tais como manipulação de string, cores e
data, criação de pequeno banco de dados JSON, além de um módulo
de execução automática.
Nesta aula, será demonstrado todo o potencial do JavaScript no
lado do servidor, criando um web server.
Leiam atentamente esta aula e se tiverem alguma dúvida, usem os
recursos que estão na sua área do aluno.
Boa aula!
Bons estudos!
Desenvolvimento Voltado a Web III 38
1 – Módulo HTTP
2 – Módulo URL
3 – Módulo Sistema de Arquivos
4 – Módulo Formulário
5 – Módulo E-mail
1 - Módulo HTTP
Na aula anterior, instalamos diversos módulos de
terceiros, com as mais diversas funcionalidades. O Node.js
nativamente já possui alguns módulos que permitem trabalhar
com diversos protocolos, tais como: HTTP, HTTPS, FTP,
SSH, DNS, UDP e WebSockets. Nesta seção usaremos o
módulo nativo HTTP para desenvolver um sistema web,
tratando do roteamento e carregamento da página.
Pereira (2014) explica que as aplicações web necessitam
que o servidor disponibilize seus recursos e, para esse
caso, define que programando-o no Node.js “desenvolve
uma aplicação middleware, ou seja, além de programar as
funcionalidades da sua aplicação, você também programa
códigos de configuração de sua infraestrutura”.
O módulo nativo HTTP do Node.js é suficiente para o
desenvolvimento de pequenos servidores HTTP, conforme
o tamanho da aplicação é indicada a utilização de um
framework que implementa funções e configurações que
facilitem o desenvolvimento, tal como o framework Express.
O interessante da utilização de frameworks é que eles facilitam
a construção, já que disponibilizam uma estrutura mínima
funcional para o que se precisa.
Antes de utilizar um framework é importante entender
todo o conceito do HTTP, portanto, utilizaremos o modulo
nativo do Node.js.
HTTP
HTTP é o protocolo de aplicação mais importante sobre o TCP/IP,
que é o conjunto de protocolos que fazem a internet funcionar. Esse
protocolo permite que browsers (cliente-side) se comuniquem com
servidores remotos (server-side) (COPES, 2019).
Para que essa comunicação seja possível, o HTTP transfere arquivos
HiperTexto pela internet. Esse arquivo será retornado quando o lado
do cliente solicitar ao protocolo através de um link, que pode ser um
endereço ip ou um nome de domínio (http:/unigran.br).
O protocolo trabalha com request e response: o lado do cliente faz
uma solicitação (request) e o servidor responde (response).
O request pode ser feito por GET, POST, HEAD, PUT, DELETE, OPTIONS
e TRACE.
Assim como todos os módulos já vistos, o HTTP precisa
ser carregado para poder ser utilizado. Criamos, então, uma
constante http que vai carregar esse módulo.
const http =
require(‘http’);
Com a constante definida utilizamos, então, um método
Seções de estudo
para a criação do servidor e outro para definir em qual porta
o servidor estará escutando as solicitações, createServer() e
listen(), respectivamente. O primeiro recebe por parâmetro
uma função que possui request e response também como
parâmetro, enquanto o segundo recebe o número da porta
pela qual o servidor deverá aguardar as solicitações.
const server = http.
createServer((request,response)=>{
c o n s o l e . l o g ( ‘ S o l i c i t a ç ã o
realizada!’);
});
server.listen(3000);
Podemos, então, colocar o nosso servidor para rodar no
prompt; fazemos uma chamada a node, passando o nome
do arquivo do servidor. Para realizar essa chamada pode-se
utilizar o navegador, através da url http://localhost:3000.
Nesse caso, estamos solicitando a um servidor local, na porta
3000, que responda nossa requisição.
Figura 1 – Servidor rodando.
Fonte: Acervo pessoal.
Ao colocar o servidor para rodar não irá aparecer nada
no console do prompt, já que o nosso código só apresenta
na tela a string ‘Solicitação realizada!’, quando o navegador
faz efetivamente uma request. Cada vez que fizermos uma
solicitação no navegado aparecerá no console a string que
passamos. Como nosso servidor ainda não envia uma
resposta, o navegador vai retornar o erro “ERR_EMPTY_
RESPONSE” já que nosso servidor não enviou nenhum
dado de volta.
Para resolver esse problema vamos enviar uma resposta
para o nosso navegador, através do método response.write(),
que irá enviar para o navegador uma string que for passada por
parâmetro a ele. Devemos ainda enviar um cabeçalho que irá
informar o código de status da resposta response.writeHead()
e finalizar o envio com response.end(). Se não colocar o end,
o navegador não vai entender que é o fim da resposta e não
irá parar de carregar.
const http = require(‘http’);
const server = http.
createServer((request,response)=>{
res.writeHead(200, {‘Content-
Type’:‘text-html’});
res.write(‘<h1>Hello World!</
h1>’);
res.end();
39
});
server.listen(3000);
Figura 2 – Hello World.
Fonte: Acervo pessoal.
Como vimos, na criação do servidor, dois parâmetros são
passados para nossa função, o request e o response, enquanto
o segundo é usado para ir construindo a nossa página, como já
foi visto, o primeiro retorna algumas informações relevantes
para entender de onde está vindo a requisição e o quais suas
propriedades.
Através do console.log(request) podemos observar o
conteúdo desse objeto. Duas propriedades importantes que
podemos acessar diretamente é o caminho do endereço
acessado (request.url) e o método da solicitação (request.
method). Para facilitar a visualização é possível utilizar o
módulo colors estudado na aula 04.
const http = require(‘http’);
const colors = require(‘colors’);
const server = http.
createServer((request,response)=>{
console.log(‘request.method=’.
yellow,request.method);
console.log(‘request.url=’.
yellow,request.url);
});
server.listen(3000);
No código acima, quando o servidor receber uma
requisição ele irá apresentar no console o método que o
request foi feito e também qual a url que foi chamada. Se a url
digitada no navegador for http://localhost:3000/, o resultado
pode ser visto na Figura 3, e se for http://localhost:3000/
index.html, o resultado pode ser visto na Figura 4.
Figura 3 – Propriedades request.
Fonte: Acervo pessoal.
Figura 4 – Propriedades request.
Fonte: Acervo pessoal.
Outra propriedade importante que pode ser obtida
através do request é o headers, que pode ser acessado
diretamente, como feito com o method e url. Ele retorna
informações sobre a conexão como user-agent e cookie.
Figura 5 – Propriedades headers.
Fonte: Acervo pessoal.
Um servidor pode também se comportar com uma API,
que retorna uma informação no formato JSON. A escolha
pelo envio desse método pode ser feita se na url que fez a
chamada tiver a palavra json “http://localhost:3000/json”.
const http = require(‘http’);
const server = http.
createServer((request,response)=>{
if(request.url == “/json”)
{
r e s p o n s e .
setHeader(‘Content-type’,’application/json’);
var carro = {
“modelo”: “Argo”,
“marca”: “Fiat”,
“ano”: 2019,
“revisoes”:
[“2018-05-10”,”2018-08-25”]
};
r e s p o n s e . e n d ( J S O N .
stringify(carro));
}
});
server.listen(3000);
Desenvolvimento Voltado a Web III 40
Figura 5 – Resultado JSON.
Fonte: Acervo pessoal.
Para visualizar melhor a estrutura de resposta no formato
JSON é interessante instalar uma extensão no seu navegador,
que te crie a estrutura em árvore, que representa o JSON.
Para o Chrome, usado no desenvolvimento deste guia de
estudos, a extensão pode ser encontrada na loja de extensõesdo Chrome com o nome de JSONView. Você pode escolher
a extensão que melhor se encaixe para o que você precisa.
2 - Módulo URL
A construção da URL é importante, pois ela irá informar
ao servidor o que o lado cliente está querendo ver. No
exemplo anterior, a URL fazia uma chamada simplesmente
acrescentando a palavra json no final da URL. E se for preciso
passar mais informações ao mesmo tempo para o servidor?
Para isso utilizamos o módulo url, que consegue quebrar
o endereço web em várias partes. Por exemplo, temos a url
“http://localhost:3000/index.html?ano=2019&mes=maio”,
que está no formato mais comum encontrado na internet,
passando informações por GET, o módulo em questão irá
então separar toda a URL em host, pathname e search.
var url = require(‘url’);
var colors =
require(‘colors’);
var webadr = ‘http://
localhost:3000’+
‘ /
index.html?’+
‘ano=2019&mes=maio’;
var q = url.parse(webadr,
true);
console.log(‘host = ‘.red,q.
host);
console.log(‘pathname =
‘.red,q.pathname);
console.log(‘search =
‘.red,q.search);
var mes = q.query.mes;
var ano = q.query.ano;
console.log(‘data =
‘.green,mes+’/’+ano);
Figura 6 – Módulo URL.
Fonte: Acervo pessoal.
3 - Módulo Sistema de Arquivos
Até esse momento inseríamos o conteúdo HTML que
o nosso servidor responde dentro do próprio servidor, mas
uma boa prática é separar o que é HTML do JavaScript. O
módulo nativo fs pode ser usado para manipular arquivos
e diretórios. Com o módulo fs podemos ler um arquivo
do sistema operacional utilizando as funções .readFile() ou
.readFileSync(). A diferença entre elas é que uma das funções
é síncrona e a outra assíncrona.
Pereira (2014) esclarece que o .readFile() faz uma leitura
assíncrona e “depois que o arquivo foi carregado, é invocada
uma função call-back para fazer os tratamentos finais, seja de
erro ou de retorno, do arquivo.” já o fs.readFileSync faz uma
leitura síncrona “bloqueando a aplicação até terminar sua
leitura e retornar o arquivo”.
Antes de demonstrarmos o código do servidor com
o módulo fs, precisamos criar o arquivo HTML, que será
retornado quando alguma chamada for feita ao servidor.
Daremos a esse arquivo o nome de index.html, com o
seguinte conteúdo.
<!DOCTYPE html>
<html>
<head>
<title>Exemplo modulo fs</
title>
</head>
<body>
<h1>Este arquivo foi
chamado pelo modulo fs</h1>
</body>
</html>
Primeiramente o módulo fs tem de ser carregado
juntamente do http. E quando o cliente fizer uma solicitação
ao servidor dentro do createServer() o arquivo será lido pela
função readFile() e o resultado da abertura do arquivo será
retornado para o cliente.
const http = require(‘http’);
41
const fs = require(‘fs’);
const server = http.
createServer((request,response)=>{
var diretorio = __dirname; //
retorna o diretório da aplicacao
fs.readFile(diretorio+’/index.
html’,(erro,html)=>{
r e s p o n s e .
writeHeader(200,{‘Content-Type’:’text/
html’});
response.write(html);
response.end();
});
});
server.listen(3000);
Figura 7 – Módulo FS.
Fonte: Acervo pessoal.
Podemos usar os módulos url e fs para criar diversas
rotas que darão em múltiplas páginas. O arquivo solicitado
só retorna quando ele existe. Quando ele não for encontrado,
volta o erro 404.
const http = require(‘http’);
const fs = require(‘fs’);
const url = require(‘url’);
const server = http.
createServer((request,response)=>{
var diretorio = __dirname;
var q = url.parse(request.url,
true);
f s . r e a d F i l e ( d i r e t o r i o + q .
pathname,(erro,html)=>{
if(erro){
r e s p o n s e .
writeHeader(404,{‘Content-Type’:’text/
html’});
r e s p o n s e .
write(“Pagina invalida”);
response.end();
}else{
r e s p o n s e .
writeHeader(200,{‘Content-Type’:’text/
html’});
r e s p o n s e .
write(html);
response.end();
}
});
});
server.listen(3000);
Se a url estiver vazia quando for passada para o
servidor, nenhum arquivo será encontrado, então, o servidor
retorna “Página inválida” Figura 8. Quando a url ”http://
localhost:3000/index.html” possui o arquivo e este é valido,
o servidor então retorna o conteúdo do arquivo, Figura 9.
Quem vai determinar qual rota deve seguir no caso do código
acima é se a tentativa de ler o arquivo ocasionou erro ou não.
Figura 8 – Arquivo não encontrado.
Fonte: Acervo pessoal.
Figura 9 – Arquivo encontrado.
Fonte: Acervo pessoal.
4 - Módulo Formulário
Todo sistema web possui pelo menos um formulário, seja
para cadastro de e-mail para receber notícias, ou formulários
complexos para cadastro de produtos em um estoque. Para
que o servidor receba as informações de um formulário, o
primeiro passo é construí-lo em HTML e identificar as tags
que serão preenchidas com a propriedade nome a que elas
são relacionadas.
Todos os elementos de um formulário estarão dispostos
entre as tags de abertura e fechamento form <form></form>.
Na tag de abertura duas propriedades devem ser setadas: a
action, que será passada para o servidor no pathname, e o
método, que colocaremos POST para que os dados sejam
enviados sem que apareçam na url. Criaremos uma página
externa chamada login.html que terá um formulário com dois
campos de texto para serem digitados, um e-mail e uma senha.
Desenvolvimento Voltado a Web III 42
<!DOCTYPE html>
<html>
<head>
<title>Exemplo modulo
formidable</title>
</head>
<body>
<h1>Login</h1>
<form action=”login”
method=”post” enctype=”multipart/form-data”>
<input type=”text”
name=”login”>
< i n p u t
type=”password” name=”senha”>
< i n p u t
type=”submit”>
</form>
</body>
</html>
Figura 10 – Página de Login.
Fonte: Acervo pessoal.
Antes de desenvolvermos o servidor, precisamos instalar
o módulo que auxilia na manipulação dos formulários, o
formidable. Fazemos isso através do npm.
npm install formidable --save
Iremos utilizar o servidor criado na seção anterior para
dar continuidade ao exemplo. Apenas criaremos uma rota
diferente dentro do nosso código, para quando a reuqest
receber na url o mesmo nome que foi colocado na propriedade
action da tag form. As linhas acrescentadas estarão com o
fundo amarelo.
const http = require(‘http’);
const fs = require(‘fs’);
const url = require(‘url’);
var formidable = require(‘formidable’);
const server = http.
createServer((request,response)=>{
if(request.url == “/login”){
var form = new formidable.
IncomingForm();
f o r m .
parse(request,(err,fields,files)=>{
i f ( f i e l d s .
login==”felipe”&&fields.senha==”felipe”){
r e s p o n s e .
writeHeader(200,{‘Content-Type’:’text/
html’});
r e s p o n s e .
write(fields.login+’ - ‘+fields.senha);
r e s p o n s e .
end();
}else{
r e s p o n s e .
writeHeader(200,{‘Content-Type’:’text/
html’});
r e s p o n s e .
write(“Usuario ou senha incorretos!”);
r e s p o n s e .
end();
}
});
}else{
var diretorio = __dirname;
var q = url.parse(request.
url, true);
fs.readFile(diretorio+q.
pathname,(erro,html)=>{
if(erro){
r e s p o n s e .
writeHeader(404,{‘Content-Type’:’text/
html’});
r e s p o n s e .
write(“Pagina invalida”);
r e s p o n s e .
end();
}else{
r e s p o n s e .
writeHeader(200,{‘Content-Type’:’text/
html’});
r e s p o n s e .
write(html);
r e s p o n s e .
end();
}
});
}
});
server.listen(3000);
Figura 11 – Formulário preenchido.
Fonte: Acervo pessoal.
43
Figura 12 – Usuário ou senha incorretos.
Fonte: Acervo pessoal.
Figura 13 – Usuário e senha corretos.
Fonte: Acervo pessoal.
As alterações feitas possibilitam nosso servidor retornar
mais duas possíveis rotas, quando o login e senha estão
corretos e quando o login e senha estão incorretos. O módulo
formidable, além de tratar dos formulários que enviam textos,
ainda facilita manipulação de formulários mais complexos
como o upload de arquivos para o servidor.
5 - Módulo E-mail
Quando um usuário novo se cadastra em um site de
compras, o site normalmente retorna um emailpara esse
novo cliente com algumas informações relevantes para sua
utilização. Esse e-mail é enviado pelo lado do servidor. O
módulo nodemailer facilita o envio de e-mails a partir do
servidor Node.js.
Este também não é um módulo nativo e necessita da
instalação via npm.
npm install nodemailer --save
Antes de iniciar a configuração do módulo em nosso
Node.js precisamos descobrir se o nosso e-mail está habilitado
para que envie e-mails externamente. No Gmail você pode
configurar a sua conta para permitir acesso a apps com baixa
segurança, https://www.google.com/settings/security/
lesssecureapps.
Vamos então ao código do nodemailer. O primeiro passo
é carregar o módulo, seguido da criação do transportador, que
irá conter as informações para acessar a conta que enviará os
e-mails.
var nodemailer = require(‘nodemailer’);
var transportador = nodemailer.
createTransport({
service: ‘gmail’,
auth: {
user: ‘seuemail@gmail.com’,
pass: ‘suasenha’
}
});
Em seguida é possível montar a mensagem criando
um objeto que terá valores atribuídos para as propriedades,
from, to, subject e text que, traduzindo: de, para, assunto e
conteúdo, respectivamente.
var email = {
from: ‘seuemail@gmail.com’,
to: ‘destinatario@yahoo.com’,
subject: ‘Enviando e-mail usando o
Node.js’,
text: ‘Exemplo de envio de e-mail
utilizando o módulo nodemailer’
};
Para efetivar o envio é necessário que a função
.sendMail() contendo o objeto email seja executada a partir do
transportador que foi criado.
transportador.sendMail(mailOptions,
(error,info)=>{
if (error) {
console.log(error);
} else {
console.log(‘Email enviado: ‘ +
info.response);
}
});
Essa função é amplamente utilizada, e no exemplo do
servidor poderíamos criar uma nova rota, para que quando
um usuário realizasse o cadastro através de um formulário,
recebesse um link por e-mail para confirmá-lo.
Retomando a aula
Chegamos ao final da quinta aula. Vamos recordar?
1 – Módulo HTTP
Na primeira seção foi feita uma contextualização sobre
o protocolo HTTP e como criar um servidor em Node.js,
que responda a solicitações que possam ser feitas pelo lado
do cliente.
2 – Módulo URL
Na segunda seção, o módulo url foi detalhado. Ele é
responsável por determinar o que queremos ver do web
Desenvolvimento Voltado a Web III 44
server ou por enviar dados do lado do cliente para o lado do
servidor.
3 – Módulo Sistema de Arquivos
Em seguida, o módulo de sistema de arquivos
incorporado no servidor em conjunto com o módulo url
permitem a criação de diversas rotas dentro do servidor,
além de separar o HTML do JavaScript, já que as páginas
são criadas externamente e só serão retornadas pelo servidor
quando algum usuário no lado do cliente fizer essa solicitação.
4 – Módulo Formulário
O módulo formidable foi apresentado na quarta seção.
Ele é responsável por gerenciar o que o servidor recebe
quando um formulário é enviado. Pode trabalhar com
entradas de texto e também com o envio de arquivos.
5 – Módulo Email
Na última seção foi descrito o módulo nodemailer, que
é capaz de enviar e-mails no lado do servidor. É muito útil
na construção de funções de recuperação de senha, novos
cadastros com confirmação por e-mail, entre muitos outros.
LECHETA, R R. Node Essencial, Novatec, 2012.
PEREIRA, C R. Aplicações web real-time com Node. js.
Editora Casa do Código, 2014.
RUBENS, J. Primeiros passos com Node.js. Editora Casa
do Código, 2017.
Vale a pena ler
COPES, F. In: The Node. js Handbook, 2019.
Disponível em: <https://flaviocopes.com/page/
ebooks/>. Acesso em: 20 mai. 2019.
DELBONO, E. In: Node.js Succinctly, 2016.
Disponível em: <https://www.syncfusion.com/ebooks/
nodejs>. Acesso em: 20 mai. 2019.
NODE. In: Node.js Tutorial, 2019. Disponivel em:
<https://www.w3schools.com/nodejs/default.asp>.
Acesso em: 02 jun. 2019
Vale a pena acessar
Vale a pena
Minhas anotações