A visualizar apenas posts da categoria Programação Web

Está na hora de actualizar um dos artigos mais lidos do blog sobre compressão, com novas ferramentas que se encontram agora disponíveis.

Quer tornar o seu site ainda mais rápido em Desktop e Mobile e melhorar o resultado do PageSpeed? Vamos a isso!

Funcionário empurra pessoas no comboio em Tóquio

Este artigo não se aplica a todos os developers, e o ideal será ter um pré-processador como o Gulp para automatizar estes processos de forma a aumentar a sua produtividade.

Irei basear-me na configuração de um servidor com Apache (CPanel) e no pré-processador Gulp.

Conteúdo estático CSS e JS

A maioria dos tutoriais na net vão indicar que se deve fazer a compressão destes ficheiros em tempo real pelo servidor. Essa é a forma mais fácil de o fazer mas trás várias desvantagens: aumento de carga, consumo de memória e tempo de compressão que pode ser contraproducente e demorar mais do que servir o elemento sem compressão, dependendo do servidor e tipo de compressão.

Com a utilização de pré-processadores para minificar CSS e JS, passar SASS para CSS e afins podemos adicionar mais 1 ou 2 passos e ter a melhor compressão possível sem carga alguma no servidor.

Vamos usar Gzip com o algoritmo Zopfli, desenvolvido pela Google, e um novo formato Brotli também desenvolvido pela Google especificamente para a web.

O primeiro passo é configurar o nosso servidor para enviar a codificação certa com a extensão com compressão e adicionar alguns headers para compatibilidade com proxys.

Este código pode ser adicionado a um ficheiro .htaccess ou semelhante, ou adicionado a nível geral no servidor. No caso de um servidor CPanel pode ser adicionado ao ficheiro post_virtualhost_global.conf em Apache Configuration > Include Editor.

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
# Ficheiros com compressão Brotli
<Files *.js.br>
    AddType "text/javascript" .br
    AddEncoding br .br
</Files>
<Files *.css.br>
    AddType "text/css" .br
    AddEncoding br .br
</Files>

# Ficheiros com compressão Gzip
<Files *.js.gz>
    AddType "text/javascript" .gz
    AddEncoding gzip .gz
</Files>
<Files *.css.gz>
    AddType "text/css" .gz
    AddEncoding gzip .gz
</Files>

# Headers para proxys
<Files *.br>
	Header set Content-Encoding: br
	Header set Vary: Accept-Encoding
</Files>
<Files *.gz>
	Header set Content-Encoding: gzip
	Header set Vary: Accept-Encoding
</Files>

Depois associado a cada domínio / vhost também num ficheiro .htaccess ou semelhante adicionamos uma regra para devolver o ficheiro em Brotli ou Gzip conforme o que for suportado pelo browser do utilizador.

1
2
3
4
5
6
7
8
9
10
11
12
# Necessário caso ainda não tenha sido iniciado anteriormente
RewriteEngine On

# Fornece ficheiro pré-comprimido em Brotli
RewriteCond %{HTTP:Accept-Encoding} br
RewriteCond %{REQUEST_FILENAME}.br -f
RewriteRule ^(.*)$ $1.br [L]

# Fornece ficheiro pré-comprimido em Gzip
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^(.*)$ $1.gz [L]

A configuração está feita, e agora como gerar os ficheiros? No artigo antigo sugeri usar o 7-Zip para criar os Gzip, mas agora existem ferramentas melhores. Se não usam um pré-processador podem usar o 7-Zip, assim como usar esta ferramenta para a compressão em Brotli, mas vão ter mais trabalho

Gerar ficheiros estáticos através do Gulp

Como uso Gulp para várias tarefas como passar SASS para CSS, minify e cache busting de CSS, JS e SVG faz todo o sentido adicionar estas tarefas de compressão ao meu processo que corro antes de enviar os ficheiros para produção.

Com a integração com o PHPStorm com dois cliques em menos de 500ms tenho tudo pronto a enviar, ficheiros Gzip e Brotli incluídos.

Se não usam um pré-processador como o Gulp não sabem o que estão a perder.

Vamos precisar de dois módulos: gulp-zopfli e gulp-brotli. Podem ser facilmente instalados com estes dois comandos:

1
2
npm install gulp-zopfli --save-dev
npm install gulp-brotli --save-dev

Adiciona-se os require ao gulpfile.js

1
2
var zopfli = require('gulp-zopfli');
var brotli = require('gulp-brotli');

De seguida criamos duas novas tarefas, uma para a compressão Gzip com o algoritmo Zopfli e outra para Brotli. Para simplificar apenas adicionei como exemplo ficheiros CSS e JS mas pode ser aplicado a outras extensões como SVG. O mesmo para o caminho, estão aqui hardcoded para ser mais fácil a sua compreensão.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Compressão Gzip
gulp.task('zopfli', function(){
    return gulp.src('dist/*.{js,css}')
        .pipe(zopfli({ format: 'gzip' }))
        .pipe(gulp.dest('dist/'));
});

// Compressão Brotli
gulp.task('brotli', function(){
    return gulp.src('dist/*.{js,css}')
        .pipe(brotli.compress({
            extension: 'br',
            quality: 11
        }))
        .pipe(gulp.dest('dist/'));
});

E agora é uma simples questão de adicionar estas novas tarefas à tarefa existente que corro antes de enviar ficheiros estáticos para o servidor em produção.

1
2
3
4
5
gulp.task('build', gulp.series(
    'clean',
    gulp.parallel('styles', 'scripts'),
    gulp.parallel('zopfli', 'brotli')
));

Já usava o método antigo, vale a pena mudar?

O método antigo já é uma boa optimização. A compressão em Gzip com o 7-Zip já permitiam reduções superiores a 60% e se a diferença entre 7-Zip e Gzip com Zopfli é de apenas 1%, com Brotli temos uma diferença de 6%.

Aqui fica uma tabela com os resultados de um teste que efectuei num ficheiro Javascript.

MinifyGzip (7-Zip)Gzip (Zopfli)Brotli
Tamanho5,99 KB2,37 KB2,33 KB1,94 KB

Vale a pena mudar se for usado um pré-processador, ai apenas se gastam 30 minutos a adicionar estas configurações ao servidor e a adicionar duas novas tarefas ao processo já existente. No caso do Brotli as diferenças fazem especial sentido em mobile e já existe suporte em Android e browsers como o Chrome e Firefox. Até o Edge em Desktop suporta!

Conteúdo dinâmico

Usar Zopfli e Brotli em conteúdo dinâmico não faz sentido. O ponto forte destes novos algoritmos é que apesar de demorarem mais tempo no processo de compressão têm tempos de descompressão muito semelhantes ao Gzip normal. E é por isso que apenas devem ser usados em ficheiros estáticos, pré-comprimidos antes de os enviar para o servidor.

No caso de conteúdo dinâmico (páginas vindas de PHP, chamadas AJAX, etc) devemos continuar a usar o mod_deflate do Apache.

1
2
3
<IfModule mod_deflate.c>
  AddOutPutFilterByType DEFLATE text/html application/json
</IfModule>

Também pode ser adicionado conteúdo estático ao mod_deflate para simplificar as coisas em ambientes onde não existem pré-processadores ou que existem ficheiros CSS e JS gerados dinamicamente através de um CMS por exemplo.

Como testar se funcionou?

A ferramenta de Compressão HTTP foi actualizada para verificar não só a compressão com Gzip e Deflate mas também Brotli. Basta colocar o endereço do ficheiro CSS, JS ou outro e confirmar se a compressão funciona em Gzip e Brotli.

Devemos sempre fazer os nossos testes de performance quando testamos algo. Nem sempre o que se diz nos fóruns e em sites da especialidade se converte em melhorias caso dos nossos sites em especifico.

E no meu caso cheguei a essa conclusão ao efectuar alguns testes com o Memcached.

Disco SSD da Samsung

Quando desenvolvi o o meu próprio CMS um dos pontos onde me foquei foi na performance, essencialmente na cache e na redução de pedidos ao servidor. Isto permitiu-me reduzir custos e ter vários sites com um total superior a 250 mil visitas mensais a correr num servidor com apenas 2GB de Ram.

E não são sites estáticos, tal como o Mais Gasolina que tem várias actualizações diárias feitas pelos utilizadores, assim como outros sites onde existem API’s a serem consumidas por serviços externos. Mas com a cache é quase como se fossem.

Actualmente uso uma cache em filesystem, são ficheiros estáticos que são lidos pelo PHP que faz algumas verificações sobre os headers a enviar e devolve o conteúdo que já foi guardado com compressão.

Mas depois de muito ler e ver testes de performance onde o Memcached se mostrava superior até em sistemas com discos SSD decidi experimentar. A alteração de código era mínima, em vez de duas verificações para perceber se o ficheiro existia e abrir e ler o ficheiro, ligava-me ao Memcached e recebia os mesmos dados. Na teoria como estava em memória seria muito mais rápido.

Decidi então testar, primeiro com o sistema actual. Fiz vários acessos com browsers diferentes e fiz uma média do tempo de resposta do servidor através dos vários inspectores de cada browser. Depois com o Memcached fiz o mesmo teste.

Certamente depois de tudo o que li iria ser mais rápido mas constantemente os acessos eram mais lentos entre 1 a 2 ms. Ainda pensei, 2GB de Ram é pouco e pode estar a influenciar os meus testes. Graças à virtualização foi fácil colocar o servidor com 4GB de Ram, o dobro. Repeti os testes e o resultado foi o mesmo, mais 1 a 2 ms com Memcached.

Quer isto dizer que o Memcached é lento? Não! Mas eu podia ter-me guiado pela opinião de outras pessoas e pensar para mim próprio: instalei o Memcached, agora os sites estão mais rápidos. No meu caso em concreto o Memcached não compensa, até porque o sistema operativo não é parvo e acaba por colocar os ficheiros mais lidos em memória. O tempo adicional deve-se ao overhead da ligação ao serviço do Memcached, porque tanto os ficheiros estáticos como o conteúdo do Memcached já estavam em memória.

E antes de começarem a remover Memcached, Varnish ou Squid dos vossos servidores ou a enviarem-me emails a dizer que estou errado, percebam que estou a relatar o meu caso em concreto e o Memcached é uma óptima solução, mas não aqui.

Onde quero chegar com este artigo, ou TL;DR, antes de efectuarem alterações de performance testem e façam testes antes e depois de aplicarem essa alteração e comparem os valores. Não basta aceder uma vez, efectuar alterações, aceder novamente e comparar tempos de resposta. É preciso efectuar vários testes, obter uma média e comparar porque existem muitas variáveis em jogo.

Infelizmente ainda vejo developers e sysadmins a seguirem a lógica de aplicar a grande novidade do Github ou o que leram no Stackoverflow como uma verdade absoluta sem testarem se existem melhorias ou não, e isso tem que mudar para o beneficio de todos, mas especialmente dos utilizadores.

No meu percurso profissional já me passou imenso código mau pelos olhos. Desde sites que não fazem qualquer validação ao que um utilizador insere num formulário à construção de querys que inserem parâmetros vindos directamente da barra de endereços do browser. Um desastre à espera de acontecer.

Mas mesmo com código bem estruturado e com validações podem existir falhas, seja no código ou na configuração do servidor. Felizmente existem aplicações para testar este tipo de vulnerabilidades.

Porta de um cofre

Testei 3 aplicações contra um ambiente de testes criado para o efeito, com uma instalação CPanel e um site com dois formulários de contacto (um deles com Javascript), um formulário de pesquisa, um formulário de login e de registo de utilizador. Foram ainda criadas algumas páginas com conteúdo para permitir passar parâmetros pelo URL e chamadas por AJAX para obter conteúdo adicional.

Não incluí aqui o já conhecido Scan My Server por me parecer estar já desactualizado em relação às novas ofertas do mercado.

Detectify (Pago)

Resultados do Detectify

O Detectify funciona via web e existem servidores próprios para testar as vulnerabilidades nos nossos sites. Este foi de todos o mais completo, verificando até por falhas de segurança na configuração do CPanel e Apache.

Foi também o único que verificou que exista uma firewall instalada que bloqueou o acesso e deu um alerta com os IP’s que devem ser permitidos em whitelist.

O preço à data do artigo é de 30 Eur por mês por cada site sem qualquer limite de número de testes. Para testar existe um trial de 21 dias.

Endereço: https://detectify.com

Tinfoil (Pago)

Resultados do Tinfoil

Tal como o Detectify, o Tinfoil também funciona via web. Aqui os testes não são tão exaustivos, mas foi o melhor a verificar vulnerabilidades nos formulários de email, conseguindo mesmo dar a volta ao formulário onde a submissão era feita apenas por Javascript.

Os resultados dos testes não são tão compreensivos, mas a equipa de suporte é fantástica.

O preço é mais alto, 59 USD para apenas um site com análises mensais e um limite de 500 páginas. O trial é no entanto mais longo, 30 dias.

Endereço: https://www.tinfoilsecurity.com

OWASP Zed Attack Proxy (Grátis)

Resultados do Tinfoil

Gratis mas mais limitado, o ZAP é uma aplicação em Java que corre localmente no nosso computador para testar falhas de segurança da lista da OWASP.

A aplicação não é fácil de usar e ao adicionar o endereço a análise falhava de imediato. O User Agent curiosamente termina com ponto e virgula, estando a ser bloqueado no servidor com o ModSecurity usando regras da Atomicorp já com 2 anos.

Endereço: https://owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project

Conclusão

Estas ferramentas são interessantes para encontrar e mitigar algumas falhas de segurança. O Detectify é para mim o que tem os testes mais exaustivos e o ZAP parece-me ser inferior ao já antigo Scan My Server, que também é gratuito, mas ainda assim é melhor que nada.

Para empresas que desenvolvem aplicações para a web ou mesmo para particulares com sites simples estas ferramentas são uma mais valia e permitem detectar possíveis pontos de entrada antes que estes sejam explorados por hackers.

Mas atenção, não é para levar à letra e corrigir todos os avisos que aparecem. Fica este aviso porque trabalhei com alguns gestores de projecto que, por falta de conhecimento, corrigiam tudo o que estes testes online diziam.

Em todas as aplicações testadas existem avisos que podem não fazer sentido. Por exemplo não vamos colocar o header X-Frame-Options como deny se o site é usado dentro de uma frame noutro domínio.

Outras questões como o ficheiro robots.txt, não o removam porque o scanner diz que pode ter informação fidedigna. A ideia é dar a perceber que se existe dentro do robots.txt o caminho /admin para não ser indexado, é fácil saber que existe a pasta /admin para a gestão do site. A acção correcta é remover o endereço do ficheiro e colocar uma meta tag no ficheiro inicial da pasta /admin para não ser indexado.

Está na hora de encriptar o seu blog em WordPress. Já tem um certificado, está pronto a avançar, mas infelizmente mudar um blog WordPress de HTTP para HTTPS não é uma tarefa fácil.

Siga estes passos para o fazer sem grandes dificuldades.

Ligar a Wi-Fi no aeroporto

A web está a mudar. Dantes apenas sites e-commerce e bancos usavam HTTPS, hoje em dia com o que sabemos sobre espionagem da NSA graças ao Snowden e com o acesso massificado por redes Wi-Fi pouco seguras passou a ser um dever fornecer sites por HTTPS, não apenas por questões de segurança mas também de privacidade.

No entanto não basta comprar um certificado SSL, instalar o mesmo e mudar o endereço do blog para HTTPS. É necessário mudar os links para os ficheiros Javascript e CSS caso não estejam a ser usados caminhos relativos e mudar os caminhos das imagens nos posts assim como outro conteúdo, caso contrário o browser vai apresentar um erro de conteúdo misto.

Se sabe o que está a fazer passe para o fim do artigo, senão continue a ler.

O WordPress guarda o caminho completo da imagem na base de dados

Ao enviar uma imagem pelo WordPress para o servidor ou ao incluir uma imagem da galeria ao criar um novo post o WordPress coloca o caminho completo da imagem na base de dados. Em vez de /imagens/foto.jpg guarda http://www.eduardomaio.net/imagens/foto.jpg.

Ao mudar o seu blog para HTTPS estes dados vão-se manter na base de dados como HTTP e vamos ter um aviso de conteúdo misto e as imagens podem não aparecer. O mesmo acontece com caminhos para vídeos do Youtube ou Vimeo que eram incluídos antigamente por HTTP apenas.

O que é o aviso de conteúdo misto e porque os dados são bloqueados?

A ideia do HTTPS é garantir que a página é enviada encriptada e sem alterações entre o servidor e o browser. Desta forma um browser não pode permitir a apresentação de conteúdo sem encriptação na mesma página, uma vez que não está garantida a integridade e segurança dos dados.

Assim é necessário alterar os endereços de todos os recursos que temos no blog de HTTP para HTTPS, isto falando de imagens, vídeos, CSS, JS e afins.

O WordPress não permite esta alteração de forma simples, é necessário correr queries para fazer a alteração.

Alterar os endereços na base de dados

Primeiro vamos fazer um backup da base de dados caso exista algum erro a efectuar a alteração.

Depois com o phpMyAdmin ou outra ferramenta de acesso ao MySQL / MariaDB vamos correr as seguintes querys, mudando o endereço para o do seu blog:

1
2
3
4
5
UPDATE wp_posts SET guid = REPLACE(guid, 'http://www.eduardo.pt','https://www.eduardo.pt');

UPDATE wp_posts SET post_content = replace(post_content, 'http://www.eduardo.pt', 'https://www.eduardo.pt');

UPDATE wp_postmeta SET meta_value = replace(meta_value, 'http://www.eduardo.pt', 'https://www.eduardo.pt');

Na maioria dos casos estes comandos bastam. No meu caso tenho ainda vídeos do Youtube que foram incluídos no blog em 2008, com o link directo com HTTP. Assim foi preciso correr a seguinte query:

1
UPDATE wp_posts SET post_content = replace(post_content, 'http://www.youtube.com', 'https://www.youtube.com');

Agora o seu blog irá ficar a funcionar sem problemas com HTTPS.

O jQuery é uma das biblioteca de Javascript mais utilizadas, mas será realmente necessária para novos websites?

Com os utilizadores a mudarem os seus hábitos de navegação com a preferência pelo telemóvel e a usarem browsers mais recentes nos computadores o jQuery deixa de ser necessário.

jQuery será necessário?

Estou a desenvolver um novo website e para fazer a validação de dois formulários por AJAX e mostrar uma animação no caso de um erro pensei no jQuery. Já o uso noutros websites e permite criar uma camada de abstracção e corrigir problemas que existiam com browsers mais antigos.

Como o website é novo não vai suportar o Internet Explorer 8, portanto iria optar pelo jQuery 2 que é mais leve. Descarrego o ficheiro, 82,4 Kb, é mais que a página inicial do site que, com todos os ficheiros CSS e ícones ocupa cerca de 70 Kb.

Se dantes desenvolvia sem jQuery porque não voltar a fazer o mesmo? Até porque nunca fui grande fã de bibliotecas Javascript.

Comecei a fazer umas pesquisas sobre alternativas para animações com recurso a CSS3 e encontrei o youmightnotneedjquery.com que fornece código alternativo ao jQuery de acordo com a versão do browser que pretendem suportar.

Assim, em vez de 82 Kb adicionei apenas 3 Kb a este novo website e tendo em conta que terá uma utilização em dispositivos móveis a rondar os 60% a 70% quanto menos tráfego melhor. Não faz realmente sentido incluir uma biblioteca como o jQuery para seleccionar alguns elementos, fazer pedidos por AJAX, obter uma resposta em JSON e mostrar umas animações.

Um sistema de cache é normalmente utilizado para tornar o acesso mais rápido a um site, mas pode também utilizado para reduzir custos com um servidor, diminuindo os recursos necessários e consumo energético.

Datacenter do Google

No início do mês lancei uma nova versão do Mais Gasolina, baseado no CMS que já tinha desenvolvido para o Site dos Provérbios.

O código foi refeito totalmente de raiz, tendo sido tudo desenvolvido a pensar em conteúdo estático com o pouco conteúdo que continua dinâmico a ser servido por AJAX, ficando este também em cache quando possível através do Local Storage do HTML5. Assim o acesso ao MySQL é extremamente reduzido, existindo apenas processamento mínimo por parte do Apache e PHP.

Até o widget do Mais Gasolina foi optimizado para reduzir o número de pedidos por HTTP ao máximo.

O resultado foi uma redução drástica na carga do processador e consumo de memória. Consegui assim reduzir os custos consideravelmente, passando de um servidor com múltiplos cores para um servidor virtual bastante modesto com apenas um core a 2.2GHz e 2GB de RAM.

Este servidor virtual nesta configuração permite receber 300 pedidos por segundo, menos 100 que o servidor anterior. Certamente com memcache ou nginx conseguiria receber mais pedidos por segundo, mas o CPanel não tem ainda forma de fazer esta configuração facilmente.

No entanto o número de pedidos HTTP ao website também reduziu, com o uso de sprites, caches prolongados de imagens, css e ficheiros js e a devolução de códigos 304 quando o conteúdo não foi alterado facilmente o servidor actual tem capacidade para receber um fluxo de visitas como o que aconteceu quando o site apareceu na televisão, embora num futuro próximo tal seja altamente improvável.

Finalmente passou a ser possível carregar de forma assíncrona o código do Google AdSense, tornando os nossos sites mais rápidos. E o melhor de tudo, é código válido com HTML5.

Google AdSense

O carregamento assíncrono de Javascript permite tornar um site mais rápido, carregando todo o conteúdo em HTML e só depois começa a fazer os pedidos e a processar os ficheiros em Javascript. Isto faz com que o site não fique “em branco” enquanto carrega todos os ficheiros Javascript.

O código do AdSense era assim, bloqueava o processamento da página até aparecerem os banners com publicidade. Agora, embora em versão Beta, passa a ser possível o carregamento assíncrono. Já apliquei o código ao Site dos Provérbios e as diferenças estão lá. Mas nem tudo é positivo.

Já é bom termos um código que é valido de acordo com as regras do W3C, o problema é que numa análise no Page Speed continuam a existir pontos que falham como o header “Vary: Accept-Encoding” que está em falta, o tempo de cache de apenas uma hora e alguns redireccionamentos.

Pelo menos para o utilizador o acesso ao site torna-se mais rápido. Podem obter mais informações na página do Google+ do Google AdSense

 
Copyright © 1985 - 2017 Eduardo Maio. Alguns direitos reservados.
eduardomaio.net - Às vezes mais valia ser Agricultor do que Programador
Ao navegar no blog eduardomaio.net está a concordar com os termos legais e de privacidade.