Blogue ·
Um selo que punha um cookie em cada página
Uma imagem no rodapé custava vinte e dois pontos Lighthouse em todo o sítio. A correção não foi removê-la, e o interessante é o que um proxy tem de recusar.
Por Provibr
A pontuação de boas práticas do nosso sítio de marketing era 78 em todas as páginas. Não numa página, em todas: a página inicial, a de preços, a documentação, tudo, de forma uniforme. Pontuações uniformes são bom sinal, porque querem dizer que a causa está em algo que todas as páginas partilham.
Era uma etiqueta de imagem no rodapé. Um selo de listagem de lançamento, carregado diretamente da plataforma que o emite, porque é assim que um selo destes é suposto ser incorporado e porque o número que traz é suposto estar ao vivo.
O que uma etiqueta de imagem consegue fazer
O selo é servido a partir de um anfitrião de API que está atrás da Cloudflare, e a Cloudflare responde aos pedidos com o seu cookie de gestão de robôs: __cf_bm, SameSite=None, Secure, com âmbito no domínio de quem emite o selo. Isso não é uma decisão do sítio a quem o selo pertence. É o que uma CDN faz, sobre um SVG, em cada carregamento de página, para cada visitante.
Duas auditorias do Lighthouse reagem a isso. A auditoria de cookies de terceiros pesa cinco dos vinte e oito pesos da categoria, e um problema do inspetor pesa um. Seis pesos perdidos numa imagem. Ao longo das trinta e oito medições da ronda anterior, era essa a totalidade da distância entre 78 e 100.
A terceira consequência é a que nenhuma pontuação capta. O endereço IP de cada visitante ia para uma empresa com quem não tinha escolhido falar, em cada página, em troca de um número num rodapé.
Removê-lo também não é a resposta
Já tínhamos registado o compromisso, num comentário, meses antes: se algum dia quiser isto sem um aviso de consentimento, alojar o SVG por conta própria é o caminho. Com o contra-argumento agarrado, que é o de uma cópia alojada por nós ser uma fotografia. O selo existe para mostrar uma listagem ao vivo; congele os bytes e tem uma imagem de uma listagem.
Há um terceiro caminho, e só é evidente depois de separar duas coisas que um navegador faz ao mesmo tempo. O navegador vai buscar bytes, e o navegador estabelece uma ligação. Só a segunda é o problema.
O selo passa portanto a vir da nossa própria origem, num caminho da nossa própria API, e essa rota vai buscar a fonte no servidor. Os mesmos bytes. O navegador do visitante faz um pedido, a nós. Não há nada na linha em que pôr um cookie, porque não há terceiro nenhum na página do visitante. E o número continua ao vivo, porque continuamos a perguntar.
As boas práticas passaram de 78 para 100 em trinta e duas de trinta e seis medições. As quatro restantes são as páginas de artigo, que ficam em 96 por causa de um botão de terceiros completamente diferente, e isso é uma decisão à parte e não um resto.
O que um proxy deve a quem serve
Servir os bytes de outra pessoa a partir da sua própria origem muda o que eles são. Um SVG carregado por uma etiqueta de imagem não pode executar código; é uma garantia da especificação e é uma boa garantia. Mas a partir do momento em que esses bytes vêm do nosso domínio, o que está lá dentro é nosso.
A rota verifica portanto a resposta antes de a passar adiante. Essa verificação não é, deliberadamente, um saneador. Um saneador tenta tornar seguro conteúdo perigoso; esta recusa tudo o que não se pareça com o selo que já conhecemos, e a rota recai numa cópia congelada. O pior caso é um selo desta manhã em vez de um selo deste minuto, e é um preço que vale a pena pagar para nunca ter de raciocinar sobre o que a resposta de outra pessoa poderia conter.
Duas das recusas dizem respeito precisamente àquilo para que toda esta mudança serviu. Um SVG pode referenciar uma imagem externa, e pode referenciar um recurso externo a partir de uma declaração de estilo. Qualquer uma dessas alcançaria um terceiro uma camada mais funda do que a etiqueta que acabámos de remover, a partir de dentro de um ficheiro que estamos a servir como nosso. Uma verificação que só procurasse código teria deixado passar as duas.
Falhar para uma imagem, de propósito
Todos os caminhos de falha devolvem a cópia congelada com estado 200. Erro de rede, tempo esgotado, um estado que não é 200, um corpo em que a verificação não confia: todos eles, 200, com um selo lá dentro.
O raciocínio é sobre o aspeto da falha. Um 404 ou um 502 numa imagem no rodapé de todas as páginas é um ícone de imagem partida em todas as páginas, o que se lê como um sítio partido, por causa de um elemento decorativo. Um selo ligeiramente antigo não se lê como nada.
A compensação é que o caminho de falha leva um cabeçalho de cache curto enquanto o caminho de sucesso leva um longo. De outro modo, uma paragem de cinco minutos do outro lado fixaria a cópia congelada à frente de toda a gente durante a janela de cache inteira.
Há uma cópia congelada e ela deliberadamente não vive como ficheiro na pasta pública. Como ficheiro teria um segundo endereço público ao lado da rota, e uma ronda futura poderia razoavelmente largar uma etiqueta de imagem a apontar diretamente para ele, o que remove em silêncio o comportamento ao vivo que todo este arranjo existe para preservar. Guardada como constante, a única maneira de a servir é através da rota que também tenta a rede primeiro.
Duas caches, com trabalhos diferentes
Há aqui duas camadas de cache e confundi-las produz um sistema que ou martela a fonte ou mostra bytes velhos para sempre.
A cache de dados da framework guarda a resposta da fonte: com uma revalidação de seis horas, um visitante de seis em seis horas provoca um pedido para fora, independentemente do tráfego. O cabeçalho de cache HTTP guarda a nossa resposta, na CDN e no navegador. A fonte põe quatro horas na sua própria resposta; seis do nosso lado é um meio passo mais largo, deliberado, para que uma paragem do outro lado não nos deixe cair na cópia congelada ao ritmo de quatro horas.
Uma pequena armadilha, que custou uma compilação. O Next lê a configuração de segmento de rota estaticamente a partir do código, portanto a exportação de revalidação tem de ser um número literal. Escrevê-la como expressão, mesmo como uma constante declarada umas linhas abaixo no mesmo ficheiro, aborta a compilação com um erro de configuração de segmento inválida. A constante passa agora a ler da exportação em vez do contrário, de modo que continua a haver exatamente um número.
O 307 que era um sinalizador de arranque
A mesma ronda gastou tempo com uma coisa que parecia um erro de encaminhamento e não era, e vale a pena registá-la porque desperdiçou uma ronda anterior por completo.
A correr a compilação de produção localmente, todos os caminhos de marketing nus respondiam 307, a redirecionar para si próprios. Não os caminhos localizados, não as rotas de API: os nus. Isto tinha bloqueado a metade inglesa de todos os varrimentos locais de disposição durante semanas e tinha sido registado como um defeito por explicar.
É a ligação ao anfitrião. Arrancado com um endereço de loopback literal como nome de anfitrião, o Next deixa esse valor como está, enquanto um nome de anfitrião vazio ou com caráter universal é normalizado para localhost. O URL inicial e a origem que o intermediário calcula passam então a discordar, a reescrita fica absoluta, o encaminhador trata-a como externa e volta a entrar. Arrancado com o caráter universal, que é o valor que a produção usa, ou com localhost, tudo responde 200.
Não havia nada para reparar. O que havia a fazer era escrever a linha de arranque correta no script, e registar porquê, porque um defeito que é na verdade um sinalizador será de outro modo redescoberto pela pessoa seguinte com a mesma confiança.
A falha que escolhemos não reparar
Uma terceira coisa da mesma ronda é uma não reparação deliberada, e essas merecem ser registadas pelo menos com o mesmo cuidado que as correções.
Tínhamos visto 404 em fragmentos no terreno: HTML a referenciar ficheiros JavaScript que já não existem. A explicação acabou por ser um cabeçalho. A página inicial leva uma janela de stale-while-revalidate medida em um ano, portanto um nó de fronteira de CDN pode servir HTML de uma compilação mais antiga durante muito tempo, e os nomes dos fragmentos nesse HTML pertencem a essa compilação.
O botão está mesmo ali e deixámo-lo em paz, porque foi essa mesma cópia velha que manteve o sítio a responder durante um ciclo de falhas da base de dados quinze dias antes. Encurtar a janela troca um carregamento partido raro por uma paragem total ainda mais rara. É uma troca a sério, pertence a quem carrega o risco, e o trabalho da ronda era explicar o mecanismo e não tomar a decisão.
O que registaríamos
- Uma pontuação uniforme em todas as páginas aponta para algo que todas as páginas partilham. É a pista mais barata que vai ter.
- Uma etiqueta de imagem é uma ligação, não apenas bytes. Tudo o que uma CDN quer fazer num pedido, faz também nesse.
- Alojar por conta própria não é a única alternativa a incorporar. Ir buscar no servidor mantém o comportamento ao vivo e retira o terceiro da página do visitante.
- A partir do momento em que serve os bytes de outra pessoa, são seus. Verifique-os, e verifique em especial as referências que voltariam a abrir o buraco que acabou de fechar.
- Prefira uma imagem velha a uma imagem partida. Para decoração, uma falha visível custa mais do que uma desatualização invisível, desde que a janela de desatualização seja curta no caminho de falha.
- Não dê um endereço público à cópia congelada. Tudo o que é alcançável acaba por ser ligado, e o caminho ao vivo será contornado em silêncio.
- Saiba que cache guarda o quê. Uma guarda a resposta da fonte, outra guarda a sua, e as suas janelas respondem a perguntas diferentes.
- Algum vermelho é um sinalizador, não um erro. Reproduza o mecanismo antes de reparar o sintoma e, se se revelar o seu próprio comando de arranque, diga-o no script.
Para que fique claro o que isto é: a rota está em produção e as pontuações vêm de uma compilação de produção local ao longo de trinta e seis medições, não de dados de campo. A explicação dos 404 em fragmentos é derivada de cabeçalhos e não foi reproduzida, e a decisão sobre essa janela de cache pertence a quem carrega o risco de disponibilidade, não à ronda.
Do trabalho de plataforma na Provibr. Outra medição que ficou verde pela razão errada está em uma exceção de acessibilidade que se mede, e um campo que guardava uma intenção onde pertencia um facto está em uma data futura não é um calendário.