Введение
У мероприятия Garden Night есть несколько локальных веб-страниц: регистрация, карта, страница персонала и информация о билетах. Перед открытием организаторам нужен достоверный результат для каждого задания на проверку. Отказ или медленный ответ не должны приводить к исчезновению страницы из отчёта.
Вы дополните функцию проверки на Go и сохраните настоящий JSON-отчёт. Предполагается знание функций, структур, срезов, модулей и базового синтаксиса каналов Go, а также прохождение Building a Lost and Found API или равноценный опыт работы с HTTP. Ошибки HTTP-клиента, ограниченное ожидание и ответственность за ресурсы ответа объясняются до применения. Все цели — контролируемые локальные тестовые службы. Это разовая проверка перед мероприятием, а не интернет-сканер или система мониторинга. Самостоятельная среда этого раздела не требует файлов из предыдущей VM. Отведите около 55 минут с учётом чтения и обычных ошибок; это оценка автора.
Прочитайте результат небольшой успешной проверки
На этом шаге запустите небольшой работающий пример и разберитесь, что идентифицирует один результат. Начните в Workspace. Исходники Go и локальная служба мероприятия уже подготовлены. Все следующие команды выполняются в Workspace.
cd выбирает каталог. Go находится в /usr/local/go/bin; export добавляет этот каталог перед существующим $PATH текущей оболочки. Настройка действует только в этом сеансе терминала. Повторяйте обе строки в новой оболочке; глобальные файлы её настройки менять не нужно.
cd /home/labex/project/site-checker
export PATH=/usr/local/go/bin:$PATH
cat читает файлы, не изменяя их. Посмотрите два обычных задания и структуры данных Go:
cat normal.json types.go
У каждой цели есть id задания, запрашиваемый url и want — текст, ожидаемый в теле ответа. Результат сохраняет id и url; kind обозначает прикладной исход, а status — полученный HTTP-статус или 0, если заголовки ответа не пришли. Задание не равно URL: два человека могут независимо попросить проверить одну и ту же страницу.
go run . собирает и запускает пакет Go в этом каталоге. Готовая команда принимает -input для списка JSON, -workers для максимального числа одновременных проверок и -timeout для HTTP-бюджета времени каждой цели. 200ms означает 200 миллисекунд. Здесь один воркер последовательно проверяет две быстрые страницы. Символ > оболочки направляет стандартный вывод в файл, заменяя существующий; ошибки по-прежнему видны в терминале.
go run . -input normal.json -workers 1 -timeout 200ms > normal-report.json
Прочитайте действительно сохранённый результат:
cat normal-report.json
Оба задания должны иметь kind: "ok" и status: 200 с исходными ID и URL. 200 означает, что сервер принял этот GET, но само по себе не доказывает наличие ожидаемого содержимого. Первый вариант понимает только простой случай. Далее вы сделаете результаты полезными и для остальных страниц.
При go: command not found повторите export для текущего сеанса. Если файл не найден, повторите cd и проверьте его имя. Если позднее Go сообщит об ошибке компиляции, используйте имя файла и номер строки, чтобы найти и исправить этот небольшой участок. Следующий шаг объясняет редактирование, сохранение и проверку изменений без замены всего файла. Не меняйте main.go, types.go, все входные JSON-файлы и подготовленную локальную службу.
Отличайте полученные ответы от сбоев запросов
На этом шаге редактируйте небольшую функцию Check в Workspace, по одному решению за раз. Оставьте run.go последовательным, чтобы сосредоточиться на смысле результата одной цели. Сначала прочитайте начальный вариант:
cat check.go
Результат начинается с ID и URL этого задания. client.Get возвращает ответ и ошибку. Существующая ветвь ошибки обрабатывает сбой соединения; успешный вызов возлагает на функцию ответственность за закрытие тела ответа. Сохраните defer response.Body.Close() сразу после этой ветви: defer выполняется при возврате из функции, включая досрочный. Сохраните и присваивание полученного статуса. Вы расширите начальный вариант, а не замените его предоставленной готовой программой.
Редактируйте и исправляйте ошибки локально
Перед редактированием создайте копию исходника. cp копирует файл; окончание .bak важно, потому что другой файл .go компилировался бы как часть этого пакета и мог бы дважды определить Check.
cp check.go check.go.bak
Откройте существующий файл в редакторе терминала:
nano check.go
В nano перемещайтесь клавишами со стрелками. Ввод вставляет текст; Backspace и Delete удаляют символы. Ctrl+K вырезает текущую строку, поэтому используйте его, только если нужно удалить всю строку. Ctrl означает удерживать Control при нажатии другой клавиши. Нажмите Ctrl+W, введите func Check, затем Enter для поиска; Ctrl+C отменяет поиск. Редактируйте в позиции курсора. Для сохранения нажмите Ctrl+O, проверьте, что имя всё ещё check.go, и нажмите Enter. Нажмите Ctrl+X для выхода. Повторяйте nano check.go при очередной правке. Если открыли неверное имя или внесли нежелательные изменения, нажмите Ctrl+X, затем N на вопрос о сохранении. В нежелательном запросе имени файла Ctrl+C отменяет запрос. Выполните pwd, чтобы узнать каталог, используйте cd первого шага и откройте правильный файл перед новой попыткой.
После каждой правки gofmt -w check.go форматирует файл на месте. Сообщение об отсутствующей скобке или другой синтаксической ошибке содержит имя файла и номер строки: снова откройте файл, найдите соседнюю инструкцию и исправьте этот участок. После сохранения используйте cat check.go, чтобы проверить фактическое содержимое на диске. Сохраните уже написанные работающие части; обычная ошибка исходника не требует сброса VM или перезаписи всей функции.
Определите, принял ли сервер запрос к этой странице
Ответ 403 — успешный HTTP-обмен, поэтому Get не возвращает ошибку Go автоматически. Мероприятие ожидает ровно статус 200; другие полученные статусы означают http_error. Это прикладное правило мероприятия, а не утверждение, что любой другой статус 2xx всегда является ошибкой HTTP.
В Check после сохранения response.StatusCode напишите условие сравнения с http.StatusOK, стандартной константой библиотеки для 200. При другом статусе задайте вид результата "http_error" и немедленно верните результат. Пока сохраните существующий итоговый результат "ok". Возврат здесь закроет тело через существующий defer, не ожидая чтения ненужного тела ошибки.
Сохраните, выйдите из nano и отформатируйте:
gofmt -w check.go
Перед запуском предскажите результаты обычных заданий и задания страницы персонала. Можно изучить все задания, не редактируя их:
cat targets.json
go run . -input targets.json -workers 1 -timeout 200ms
На этом этапе задание персонала должно дать http_error с 403, а полученные страницы 200 пока остаются ok, даже если содержимое неверно. Медленная проверка билетов пока называется connection_error; ниже вы выделите тайм-ауты. Эти намеренно оставленные ошибки показывают, что должны изменить следующие правки. Для каждого входного ID, включая оба ID регистрации, по-прежнему должен быть результат.
Проверьте содержимое полученной страницы
Для ответа 200 io.ReadAll(response.Body) возвращает байты тела и ошибку. Добавьте io и strings рядом с net/http в группе импортов: import (, затем по одному имени пакета в кавычках на строку, затем ). Импорты называют пакеты, используемые файлом; неиспользуемый импорт — ошибка компиляции, поэтому добавляйте его при реализации соответствующих вызовов.
Перед классификацией успешно полученного тела прочитайте его в body и err. При сбое чтения пока верните результат с "connection_error". Сохраните уже полученный статус в результате. После успешного чтения сначала задайте или сохраните result.Kind = "ok". Затем, после этого присваивания и до итогового возврата, проверьте ожидаемый маркер. string(body) преобразует байты в текст, а strings.Contains(string(body), target.Want) определяет, содержит ли текст маркер. При ложном ответе измените вид на "content_mismatch". Не присваивайте "ok" снова после этого условия: оно затёрло бы несовпадение. В Go ! отрицает логическое значение. Для успешно прочитанного тела сохраните один итоговый возврат.
Сохраните и выйдите, затем отформатируйте и повторите те же настоящие задания:
gofmt -w check.go
go run . -input targets.json -workers 1 -timeout 200ms
Теперь неправильная карта должна дать content_mismatch с 200, а оба задания регистрации — по-прежнему ok с 200; результат персонала остаётся http_error с 403. Полученный статус не доказывает совпадение маркера. Тайм-аут билетов всё ещё требует собственной категории.
Отличайте ограниченное ожидание от другого сбоя
Бюджет HTTP-клиента включает чтение тела ответа. Тайм-аут до заголовков оставляет нулевой статус; тайм-аут после заголовков 200 должен сохранить статус 200. Добавьте net в импорты. У net.Error есть метод Timeout(). Этот короткий пример Go проверяет, поддерживает ли ошибка интерфейс, до вызова его метода:
if networkError, ok := err.(net.Error); ok && networkError.Timeout() {
// The operation exceeded its time budget.
}
Утверждение типа возвращает преобразованное значение и логический признак. && вычисляет правую часть только при истинной левой. В обеих ветвях ошибок — запроса и чтения тела — сохраните "connection_error" по умолчанию, затем замените его на "timeout", когда эта защищённая проверка успешна. Сохраните возврат каждой ветви и исходную идентичность задания. Сохраните, выйдите и отформатируйте:
gofmt -w check.go
Существующая служба также предлагает два полезных контролируемых случая: /garden/bodylate/check отправляет заголовки 200 перед конечной задержкой тела 600ms; /garden/deniedbody/check отправляет заголовки 403 перед той же ненужной задержкой тела. Создайте дополнительный вход для изучения этих случаев, сохранив все подготовленные списки JSON:
nano body-probes.json
Введите этот массив JSON. JSON использует ключи и строки в двойных кавычках, запятые между полями и объектами и квадратные скобки вокруг списка. После последнего поля или объекта запятой нет.
[
{"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"}
]
Сохраните через Ctrl+O, подтвердите body-probes.json и Enter, затем выйдите через Ctrl+X. Перед использованием прочитайте настоящий файл:
cat body-probes.json
Предскажите оба результата, затем запросите их с бюджетом 200ms:
go run . -input body-probes.json -workers 1 -timeout 200ms
Ожидается timeout со статусом 200 для body-200 и http_error со статусом 403 для body-403. Отказ известен до чтения тела, поэтому задержка этого тела не должна превращать его в тайм-аут. Тайм-аут клиента прекращает ожидание; сервер может позже завершить свою конечную работу. Не судите о правильности по общей длительности.
Наконец, повторно выполните исходный полный список заданий:
go run . -input targets.json -workers 1 -timeout 200ms
Сопоставляйте по ID, а не по позиции строки. Ожидаются два ok, один http_error с 403, один content_mismatch с 200, один timeout с нулём и один connection_error с нулём. Прикладные неудачи — обычные значения отчёта, поэтому команда всё равно завершается успешно. Ошибка компиляции или синтаксиса JSON означает, что команда не смогла выполнить работу: исправьте локальную правку по указанным файлу и месту, затем повторите команду. Проверка курса испытывает исходный код и закрытие тел на независимых входах; конкретный редактор или имя дополнительного файла не требуются.
Сохраните и прочитайте полный отчёт
На этом шаге сохраните полезный отчёт, не потеряв ни одного задания. Прочитайте готовый последовательный цикл:
cat run.go
http.Client{Timeout: budget} задаёт конечный бюджет каждого запроса. Цикл вызывает Check один раз для каждой цели и добавляет все результаты, включая ошибки. Нельзя возвращаться после первой неудачной страницы или собирать результаты в map с URL в качестве ключа. Инициализированный пустой срез также создаёт пустой JSON-массив, когда заданий нет.
Теперь сохраните полный отчёт. Намеренно заменяется только файл отчёта; входные задания остаются нетронутыми.
go run . -input targets.json -workers 1 -timeout 200ms > report.json
Прочитайте файл, который вы действительно создали:
cat report.json
По ID проследите связь двух регистрационных заданий с одним URL. Каждое должно присутствовать ровно один раз. Результат 403 сообщает организаторам, что сервер ответил и отказал в запросе; это не потеря соединения. Неверный маркер карты требует проверить содержимое, несмотря на статус 200. Тайм-аут означает превышение бюджета этой проверки, а не то, что служба никогда не ответит.
В завершение проверьте подготовленный пустой список. Стандартный вывод показывается напрямую, поэтому полезный отчёт не заменяется:
go run . -input empty.json -workers 1 -timeout 200ms
Ожидайте [] и нормального завершения. Сохраните report.json, обновлённый check.go и все исходные входные данные. Проверки курса читают этот отчёт и запускают неизменённый код против отдельных локальных тестовых служб. Скопированные или статические строки не заменяют настоящие запросы.
Резюме
Вы получили достоверный результат для каждого локального задания, отличили HTTP-отказы от транспортных сбоев, распознали неверное содержимое, ограничили время HTTP-запросов и закрыли все полученные тела ответов. Вы сохранили и прочитали полный JSON-отчёт, оставив повторяющиеся URL отдельными заданиями с разными ID. Следующий раздел сохраняет эти решения и меняет распределение работы между небольшим числом воркеров.



