Introdução
O evento Garden Night tem várias entradas web locais: credenciamento, mapa, página da equipe e informações sobre ingressos. Antes da abertura, os organizadores precisam de um resultado fiel para cada verificação atribuída. Uma entrada recusada ou lenta não pode desaparecer do relatório.
Você completará uma função de verificação em Go e salvará um relatório JSON real. É necessário conhecer funções, estruturas, slices, módulos e a sintaxe básica de canais Go, além de ter feito Building a Lost and Found API ou possuir experiência equivalente com HTTP. Erros do cliente HTTP, tempos de espera limitados e a responsabilidade pelos recursos da resposta são explicados antes do uso. Todos os destinos são serviços locais de teste controlados; esta é uma verificação pontual do evento, não um scanner da Internet ou serviço de monitoramento. Esta unidade independente não precisa de arquivos de outra VM. Reserve cerca de 55 minutos, incluindo leitura e erros comuns; essa é uma estimativa do autor.
Leia o resultado de uma verificação simples
Nesta etapa, execute um pequeno caso funcional e entenda o que um resultado identifica. Comece em Workspace. O código Go e o serviço local do evento já estão preparados. Todos os comandos abaixo são executados em Workspace.
cd seleciona o diretório. Go está em /usr/local/go/bin; export adiciona esse diretório antes do $PATH existente deste shell. Isso vale apenas para esta sessão do terminal. Repita as duas linhas ao abrir outro shell; não é necessário alterar arquivos globais de configuração.
cd /home/labex/project/site-checker
export PATH=/usr/local/go/bin:$PATH
cat lê arquivos sem editá-los. Leia as duas tarefas normais e as estruturas de dados Go:
cat normal.json types.go
Cada destino tem um id que identifica a tarefa, uma url a solicitar e want, o texto esperado no corpo da resposta. O resultado mantém id e url; kind é o resultado de negócio e status é o código HTTP recebido, ou zero se nenhum cabeçalho chegou. Uma tarefa é diferente de sua URL: duas pessoas podem pedir verificações separadas da mesma entrada.
go run . compila e executa o pacote Go deste diretório. O comando preparado aceita -input para uma lista JSON, -workers para o número máximo de verificações simultâneas e -timeout para o orçamento de tempo HTTP de cada destino. 200ms significa 200 milissegundos. Aqui, um worker verifica as duas entradas rápidas em sequência. O símbolo > do shell envia a saída padrão a um arquivo, substituindo-o se ele já existir; os erros continuam no terminal.
go run . -input normal.json -workers 1 -timeout 200ms > normal-report.json
Leia o resultado realmente salvo:
cat normal-report.json
As duas tarefas devem mostrar kind: "ok" e status: 200, com seus IDs e URLs originais. 200 significa que o servidor aceitou este GET; isso sozinho não prova que o conteúdo esperado está presente. A versão inicial só entende o caso fácil. A seguir, você dará significado aos resultados das demais entradas.
Se aparecer go: command not found, repita o export da sessão. Se um arquivo não for encontrado, repita cd e confira seu nome. Se Go apresentar depois um erro de compilação, use o nome do arquivo e o número da linha para localizar e corrigir essa pequena área. A próxima etapa ensina a editar, salvar e verificar suas alterações sem substituir o arquivo inteiro. Preserve main.go, types.go, todos os JSON de entrada e o serviço local preparado.
Diferencie respostas de requisições que falharam
Nesta etapa, edite a pequena função Check em Workspace, uma decisão por vez. Mantenha run.go sequencial para se concentrar no significado de um resultado para um único destino. Primeiro leia a versão inicial:
cat check.go
O resultado começa com o ID e a URL desta tarefa. client.Get retorna uma resposta e um erro. A ramificação de erro existente trata uma conexão que falhou; uma chamada bem-sucedida dá a esta função a responsabilidade de fechar o corpo da resposta. Mantenha defer response.Body.Close() imediatamente após essa ramificação de erro: defer executa quando a função retorna, incluindo um retorno antecipado. Mantenha também a atribuição do status recebido. Você ampliará esta versão, em vez de substituí-la por um programa pronto fornecido.
Edite e recupere-se localmente
Antes de editar, faça um backup do código-fonte. cp copia um arquivo; a extensão .bak importa porque outro arquivo .go seria compilado como parte deste pacote e poderia definir Check duas vezes.
cp check.go check.go.bak
Abra o arquivo existente no editor do terminal:
nano check.go
No nano, mova-se com as setas. Digite para inserir texto; Backspace e Delete removem caracteres. Ctrl+K recorta a linha atual, então use-o somente quando a linha inteira deva ser removida. Ctrl significa manter Control pressionado enquanto pressiona a outra tecla. Use Ctrl+W, digite func Check e pressione Enter para pesquisar; Ctrl+C cancela uma busca. Edite na posição do cursor. Para salvar, pressione Ctrl+O, confira se o nome do arquivo continua sendo check.go e pressione Enter. Pressione Ctrl+X para sair. Repita nano check.go sempre que precisar de outra edição. Se abriu o nome errado ou fez alterações indesejadas, pressione Ctrl+X e depois N quando for perguntado se deseja salvar. Em um prompt de nome de arquivo indesejado, Ctrl+C cancela o prompt. Execute pwd para ler seu diretório, use o cd da primeira etapa e abra o arquivo correto antes de tentar novamente.
Após cada edição, gofmt -w check.go formata o arquivo no próprio local. Uma chave ausente ou outro erro de sintaxe inclui o nome do arquivo e o número da linha: reabra esse arquivo, pesquise a instrução próxima e corrija essa área. Use cat check.go após salvar para examinar o que realmente está no disco. Mantenha as partes funcionais que já escreveu; um erro comum no código-fonte não exige reiniciar a VM nem sobrescrever a função inteira.
Decida se o servidor aceitou esta entrada
Uma resposta 403 é uma troca HTTP bem-sucedida, portanto Get não retorna automaticamente um erro Go para ela. Este evento espera exatamente o status 200; outros status recebidos significam http_error. Esta é a regra de negócio do evento, não uma afirmação de que qualquer outro status 2xx seja universalmente uma falha HTTP.
Em Check, após salvar response.StatusCode, escreva uma condição que o compare com http.StatusOK, a constante da biblioteca padrão para 200. Para um status diferente, defina o tipo do resultado como "http_error" e retorne esse resultado imediatamente. Mantenha por enquanto o resultado final "ok" existente. Retornar aqui fecha o corpo por meio do defer existente, sem esperar para ler um corpo de erro desnecessário.
Salve, saia do nano e formate:
gofmt -w check.go
Antes de executar, preveja o que as tarefas normais e da equipe devem informar. Você pode examinar todas as tarefas sem editá-las:
cat targets.json
go run . -input targets.json -workers 1 -timeout 200ms
Nesta fase, a tarefa da equipe deve ser http_error com 403, enquanto páginas 200 recebidas ainda são ok, mesmo quando seu conteúdo está errado. A verificação lenta de ingressos ainda é chamada de connection_error; você distinguirá timeouts abaixo. Esses erros que restam deliberadamente mostram o que suas próximas edições devem mudar. Cada ID de entrada, incluindo os dois IDs de credenciamento, ainda deve ter um resultado.
Verifique o conteúdo da página recebida
Para uma resposta 200, io.ReadAll(response.Body) retorna os bytes do corpo e um erro. Acrescente io e strings junto de net/http em um grupo de importações: import ( seguido de um nome de pacote entre aspas por linha e depois ). Importações nomeiam os pacotes usados pelo arquivo; importações não utilizadas são erros de compilação, então acrescente-as ao implementar suas chamadas.
Antes de classificar um corpo recebido com sucesso, leia-o em body e err. Se a leitura falhar, retorne por enquanto um resultado com "connection_error". Mantenha no resultado o status já recebido. Após uma leitura bem-sucedida, primeiro defina ou mantenha result.Kind = "ok". Depois, após essa atribuição e antes do retorno final, teste o marcador esperado. string(body) converte os bytes em texto, e strings.Contains(string(body), target.Want) responde se esse texto inclui o marcador. Quando a resposta for falsa, altere o tipo para "content_mismatch". Não atribua "ok" novamente após essa condição, pois isso sobrescreveria a divergência. Em Go, ! nega um booleano. Mantenha um retorno final para o corpo lido com sucesso.
Salve e saia; depois formate e repita as mesmas tarefas reais:
gofmt -w check.go
go run . -input targets.json -workers 1 -timeout 200ms
Agora o mapa errado deve ser content_mismatch com 200, enquanto as duas tarefas de credenciamento permanecem ok com 200 e o resultado da equipe continua http_error com 403. Um status recebido não prova que o marcador correspondeu. O timeout de ingressos ainda precisa de sua própria categoria.
Distinga uma espera limitada de outra falha
O orçamento do cliente HTTP inclui a leitura do corpo da resposta. Um timeout antes dos cabeçalhos deixa o status em zero; um timeout após cabeçalhos 200 deve manter o status 200. Acrescente net às importações. Um net.Error tem um método Timeout(). Este pequeno padrão Go verifica se um erro oferece essa interface antes de chamar seu método:
if networkError, ok := err.(net.Error); ok && networkError.Timeout() {
// The operation exceeded its time budget.
}
A asserção de tipo retorna um valor convertido e um booleano. && avalia o lado direito somente se o esquerdo for verdadeiro. Em ambas as ramificações de erro de requisição e de leitura do corpo, mantenha "connection_error" como padrão e depois altere-o para "timeout" quando esse teste protegido tiver sucesso. Mantenha o retorno de cada ramificação e a identidade original da tarefa. Salve, saia e formate:
gofmt -w check.go
O serviço existente também oferece dois casos controlados úteis: /garden/bodylate/check envia cabeçalhos 200 antes de sua demora finita de 600ms no corpo; /garden/deniedbody/check envia cabeçalhos 403 antes da mesma demora desnecessária no corpo. Crie uma entrada complementar para examinar esses casos, mantendo intactas todas as listas JSON preparadas:
nano body-probes.json
Digite este array JSON. JSON usa chaves e strings entre aspas duplas, vírgulas entre campos e objetos e colchetes ao redor da lista. Não há vírgula após o último campo ou objeto.
[
{"id": "body-200", "url": "http://127.0.0.1:8080/garden/bodylate/check", "want": "GARDEN OPEN"},
{"id": "body-403", "url": "http://127.0.0.1:8080/garden/deniedbody/check", "want": "GARDEN OPEN"}
]
Salve com Ctrl+O, confirme body-probes.json e Enter, depois saia com Ctrl+X. Leia o arquivo real antes de usá-lo:
cat body-probes.json
Preveja os dois resultados e depois faça as requisições com um orçamento de 200ms:
go run . -input body-probes.json -workers 1 -timeout 200ms
Espere que body-200 seja timeout com status 200 e que body-403 seja http_error com status 403. A recusa já é conhecida antes de ler o corpo, portanto a demora do corpo não deve transformá-la em timeout. O timeout do cliente interrompe a espera; o servidor pode concluir seu trabalho finito mais tarde. Não deduza a correção pelo tempo total decorrido.
Por fim, execute novamente a lista original completa de tarefas:
go run . -input targets.json -workers 1 -timeout 200ms
Relacione por ID, não pela posição da linha. Espere dois resultados ok, um http_error com 403, um content_mismatch com 200, um timeout com zero e um connection_error com zero. Falhas de negócio são valores normais do relatório, então o comando ainda termina com sucesso. Um erro de compilação ou de sintaxe JSON significa que o comando não conseguiu realizar o trabalho: use seu nome de arquivo e localização para corrigir sua edição local e depois repita esse comando. A verificação do curso exercita seu código-fonte original e o comportamento de fechamento do corpo em entradas independentes; não exige um editor específico nem o nome do arquivo complementar.
Salve e leia o relatório completo
Nesta etapa, salve um relatório útil sem perder nenhuma tarefa. Leia o laço sequencial preparado:
cat run.go
http.Client{Timeout: budget} define um orçamento finito para cada requisição. O laço chama Check uma vez por destino e acrescenta todos os resultados, inclusive erros. Não deve retornar na primeira entrada que falha nem reunir resultados em um map indexado por URL. O slice vazio inicializado também gera um array JSON vazio quando não há tarefas.
Salve agora o relatório completo. Apenas o arquivo de relatório será substituído intencionalmente; as tarefas de entrada continuam intactas.
go run . -input targets.json -workers 1 -timeout 200ms > report.json
Leia o arquivo que você realmente produziu:
cat report.json
Use os IDs para relacionar as duas tarefas de credenciamento à mesma URL. Cada uma deve aparecer exatamente uma vez. O resultado 403 informa que um servidor respondeu e recusou a requisição; não é uma falha de conexão. O marcador incorreto do mapa pede uma investigação do conteúdo apesar do status 200. Um timeout significa que esta verificação excedeu o orçamento, não que o serviço jamais responderá.
Por fim, use a lista vazia preparada. A saída padrão é exibida diretamente e não substitui seu relatório útil:
go run . -input empty.json -workers 1 -timeout 200ms
Espere [] e encerramento normal. Preserve report.json, seu check.go atualizado e todas as entradas originais. As verificações do curso leem o relatório e também executam seu código inalterado contra serviços locais independentes; linhas copiadas ou estáticas não substituem requisições reais.
Resumo
Você criou um resultado fiel para cada entrada local atribuída, distinguiu recusas HTTP de falhas de transporte, identificou conteúdo incorreto, aplicou orçamentos HTTP finitos e fechou todos os corpos recebidos. Salvou e leu um relatório JSON completo, preservando URLs repetidas como tarefas com IDs separados. A próxima unidade mantém essas decisões e altera como um grupo pequeno de workers compartilha o trabalho.



