T17 — Noções básicas de NodeJS Express
Resumo Conciso
O que é o Express.js
O Express é um framework popular que roda em Node.js para escrever servidores HTTP que lidam com solicitações de clientes de aplicativos web. Oferece suporte a diversas maneiras de ler parâmetros enviados por HTTP.
Script inicial do servidor
$ mkdir myserver && cd myserver/ && npm initconst express = require('express')const app = express()const host = "myserver"const port = 8080app.get('/', (req, res) => { res.send('Request received')})app.listen(port, host, () => { console.log(`Server ready at http://${host}:${port}`)})| Elemento | Função |
|---|---|
express | Módulo Express incluído |
app | Instância do Express que executa a aplicação |
host | Nome do servidor (localhost por omissão) |
port | Porta de comunicação (obrigatória) |
app.get() | Responde a solicitações HTTP GET |
app.listen() | Ativa o servidor com host e porta |
Iniciar o servidor:
$ node index.jsTestar com curl:
$ curl http://myserver:8080 -vRotas
Uma rota especifica um método HTTP e define um caminho (URI). Componentes de uma rota:
| Componente | Exemplo |
|---|---|
| Método HTTP | get, post, delete |
| Caminho | /, /echo, /ip |
| Função handler | (req, res) => { ... } |
Método POST
Para enviar dados ao servidor, usa-se o método HTTP POST:
$ curl http://myserver:8080/echo --data message="This is the POST request body"Para processar dados POST, necessário incluir:
app.use(express.urlencoded({ extended: true }))Depois os dados estão acessíveis via req.body.message:
app.post('/', (req, res) => { res.send(req.body.message)})Passar dados via HTTP GET
| Método | Propriedade | Exemplo |
|---|---|---|
| Query string | req.query | ?message=hello |
| Parâmetros de rota | req.params | /echo/:message |
| Cabeçalhos | req.headers | req.headers['user-agent'] |
| IP do cliente | req.ip | req.ip |
// Query stringapp.get('/echo', (req, res) => { res.send(req.query.message)})// Parâmetro de rotaapp.get('/echo/:message', (req, res) => { res.send(req.params.message)})// IP do clienteapp.get('/ip', (req, res) => { res.send(req.ip)})Ajustes à resposta
// Definir tipo de conteúdores.type('text/plain')// Enviar respostares.send('texto')// Enviar JSONres.json(objeto)// Enviar estado HTTPres.sendStatus(204)Cookies
$ npm install cookie-parserconst cookieParser = require('cookie-parser')app.use(cookieParser())| Método | Função |
|---|---|
req.cookies.known | Lê um cookie da solicitação |
res.cookie('known', '1') | Cria/envia um cookie ao cliente |
app.get('/', (req, res) => { res.type('text/plain') if ( req.cookies.known === undefined ){ res.cookie('known', '1') res.send('Welcome, new visitor!') } else res.send('Welcome back, visitor')})Testar cookies com curl:
$ curl http://myserver:8080/ -c cookies.txt -b cookies.txt -v| Opção curl | Função |
|---|---|
-c cookies.txt | Armazena cookies recebidos |
-b cookies.txt | Envia cookies armazenados |
Segurança dos cookies
- XSS (Cross-Site Scripting): Inserção de código JavaScript malicioso em páginas
- CSRF (Cross-Site Request Forgery): Roubo de cookies para personificar clientes
- Usar middleware especializados:
express-sessionoucookie-session
Arquivos estáticos
$ mkdir server && cd server/ && npm init && npm install expressapp.use(express.static('public'))- O parâmetro
publicindica o diretório dos ficheiros estáticos - O cliente solicita apenas o nome do ficheiro (sem incluir
public) - Exemplo: para
public/layout.css, o cliente pede/layout.css
Saída formatada — JSON
// Resposta JSONres.json(user_entries)- JSON: formato de texto simples com chaves e valores
- Útil para comunicação entre programas
- Rejeitar solicitações sem
application/jsonno cabeçalhoaccept
Modelos EJS (Embedded JavaScript)
$ npm install ejsapp.set('view engine', 'ejs')res.render('index', {title: "My messages", messages: user_entries})Tags EJS:
| Tag | Função |
|---|---|
<% … %> | Fluxo de controlo (loops, condições) — sem inserção de conteúdo |
<%= … %> | Insere conteúdo escapado da variável (previne XSS) |
<%# … %> | Comentário (ignorado pelo parser) |
<%- … %> | Insere conteúdo sem escape da variável |
Exemplo de modelo views/index.ejs:
<!DOCTYPE html><html lang="en"><head> <title><%= title %></title> <link rel="stylesheet" href="/layout.css"></head><body> <form action="/" method="post"> <input type="text" name="message"> <input type="submit" value="Submit"> </form> <ul> <% messages.forEach( (message) => { %> <li><%= message %></li> <% }) %> </ul></body></html>Configuração do diretório de views:
app.set('views', './templates')Resumo de funcionalidades Express
| Funcionalidade | Método/Configuração |
|---|---|
| Rotas GET | app.get(path, handler) |
| Rotas POST | app.post(path, handler) |
| Corpo da solicitação POST | req.body (requer express.urlencoded) |
| Query string | req.query |
| Parâmetros de rota | req.params |
| Arquivos estáticos | app.use(express.static('public')) |
| Cookies | req.cookies, res.cookie() |
| Resposta JSON | res.json() |
| Modelos EJS | res.render('template', data) |
| Resposta de texto | res.send() |
🧭 Exercícios Guiados (resolvidos)
Exercício Guiado 1 — Ler campo de query string
Enunciado: Como o conteúdo do campo comment, enviado dentro de uma string de consulta do método HTTP GET, pode ser lido em uma função de manipulação?
Solução passo a passo:
- O campo
commenté enviado na URL como?comment=texto - O Express disponibiliza automaticamente os campos da query string no objeto
req.query - O campo está acessível na propriedade
req.query.comment
Exercício Guiado 2 — Rota para user-agent
Enunciado: Escreva uma rota que use o método HTTP GET e o caminho /agent para enviar de volta ao cliente o conteúdo do cabeçalho user-agent.
Solução passo a passo:
app.get('/agent', (req, res) => { res.send(req.headers['user-agent'])})- Define-se a rota com
app.get('/agent', ...) - O cabeçalho
user-agentestá acessível emreq.headers['user-agent'] - Usa-se
res.send()para devolver o conteúdo ao cliente
Exercício Guiado 3 — Parâmetro de rota
Enunciado: O Express.js tem um recurso chamado parâmetros de rota, onde um caminho como /user/:name pode ser usado para receber o parâmetro name enviado pelo cliente. Como o parâmetro name pode ser acessado de dentro da função de manipulação da rota?
Solução passo a passo:
- O parâmetro
nameestá acessível na propriedadereq.params.name
Exercício Guiado 4 — Rota para formulário HTML
Enunciado: Se o nome de host de um servidor é myserver, qual rota do Express receberia o envio do formulário <form action="/contact/feedback" method="post">?
Solução passo a passo:
app.post('/contact/feedback', (req, res) => { ...})- O atributo
action="/contact/feedback"define o caminho - O atributo
method="post"define o método HTTP - Cria-se uma rota com
app.post('/contact/feedback', handler)
Exercício Guiado 5 — Modelo EJS condicional
Enunciado: Use tags de modelo EJS para escrever uma tag HTML <h2></h2> com o conteúdo da variável JavaScript h2. Essa tag deve ser renderizada somente se a variável h2 não estiver vazia.
Solução passo a passo:
<% if ( h2 != "" ) { %> <h2><%= h2 %></h2><% } %>- Usa-se
<% if (...) { %>para controlo de fluxo - Usa-se
<%= h2 %>para inserir o conteúdo escapado - Fecha-se com
<% } %>
🔬 Exercícios Exploratórios (prática no terminal)
- Enunciado: Durante o desenvolvimento do servidor, o programador não consegue ler a propriedade
req.body, mesmo depois de verificar se o cliente está a enviar o conteúdo corretamente através do método HTTP POST. Qual é a causa provável desse problema?
O programador não incluiu o módulo express.urlencoded. É necessário adicionar antes das definições de rota:
app.use(express.urlencoded({ extended: true }))Explicação: Sem este middleware, o Express não consegue extrair e parsear o corpo das solicitações POST no formato application/x-www-form-urlencoded.
- Enunciado: O que acontece quando o servidor tem uma rota definida para o caminho
/user/:namee o cliente faz uma solicitação para/user/?
O servidor emite uma resposta 404 Not Found, porque a rota requer que o parâmetro :name seja fornecido pelo cliente.
$ curl http://myserver:8080/user/# Resposta: 404 Not FoundExplicação: O parâmetro de rota :name é obrigatório; sem ele, a rota não corresponde.
- Enunciado: Por padrão, os ficheiros de modelo do Express ficam no diretório
views. Como essa configuração pode ser modificada para que os ficheiros de modelo sejam armazenados emtemplates?
app.set('views', './templates')Explicação: A configuração views do Express define o diretório onde os modelos EJS são procurados.
- Enunciado: Suponha que um cliente recebe uma resposta em HTML sem título (
<title></title>). Depois de verificar o modelo EJS, o desenvolvedor encontra a tag<title><% title %></title>na seção head do ficheiro. Qual é a causa provável do problema?
A tag correta deve ser <%= title %> e não <% title %>. A tag <% %> é para controlo de fluxo e não insere conteúdo. A tag <%= %> é que insere o conteúdo escapado da variável.
<!-- Correto --><title><%= title %></title><!-- Incorreto --><title><% title %></title>Explicação: <% %> apenas executa JavaScript sem produzir saída HTML; <%= %> renderiza o valor da variável no HTML.
- Enunciado: Como o
express.staticdeve ser configurado para que os clientes possam solicitar ficheiros no diretórioassets?
app.use(express.static('assets'))Explicação: Basta adicionar a chamada app.use(express.static('assets')) no script do servidor. Os clientes poderão solicitar ficheiros desse diretório diretamente pelo nome.