Изучаем Go - создание загрузчика (часть 2)
В прошлый раз мы опеределились с планом создания простого сервера на Go, который бы загружал удаленные файлы. В этот раз я бы уже хотел приступить к написанию настоящего кода. Я постараюсь документировать все, что помогло мне собрать программу вместе со всеми ссылками, которые я использовал. Я также пытался ясно и понятно именовать переменные. Например, используя ответ http.ResponseWriter , запросите *http.Request вместо w http.ResponseWriter, r *http.Request. Надеюсь на то, что любой человек с любым опытом сможет разобраться в коде.
Шаг первый
Наша первая задача - наконец то увидеть код на экране. Мы собираемся создать несколько пакетов приложения, один формата main и другой формата fmt , чтобы можно было выводить результат в стандартный вывод.
package main import "fmt"
Мы будем использовать объект JSON, с которым определились ранее, и создадим его структуру на сайте JSON-to-Go. Он позволяет удобно и просто работать с JSON, поэтому, если собираетесь работать с JSON в Go, рекомендую добавить его в закладки.
type download struct {
Title string `json:"title"`
Location string `json:"location"`
}
Для начала заставим программу при запуске выводить слово «Downloader» и сделаем это все в функции main . После этого создадим тестовую структуру, которую потом тоже выведем.
func main() {
fmt.Printf("Downloader")
download := download{
Title: "title-test",
Location: "location-test",
}
fmt.Printf("%v", download)
}
И при запуске мы увидим следующее:
$ go run downloader.go
Downloader
{title-test location-test}
Шаг второй
Первое, на что обратим внимание, это то, что теперь мы используем два новых импорта. Эти импорты: io/ioutil и net/http являются частью стандартной библиотеки Go и возьмут на себя некоторую функциональность. Стандартная библиотека предоставляет разработчику множество инструментов, необходимых для создания различных программ. Надо лишь научится использовать их друг с другом. А далее вы узнаете, что даже если стандартного библиотечного пакета для функции не существует, скорей всего кто то в сообществе уже подумал и исправил это.
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
type download struct {
Title string `json:"title"`
Location string `json:"location"`
}
Ну вот мы и подошли к первой новой функции - status (статусу). В настоящее время запрос «/» на сервер выдаст код ответа 200 с телом «Hello!». Вскоре мы поменяем ответ и будем возвращать информацию о сервере для проверки его работоспособности.
func status(response http.ResponseWriter, request *http.Request) {
fmt.Fprintf(response, "Hello!")
}
Новая функция handleDownloadRequest будет основной задачей серверной части нашей программы. Пока что она примет запрос «/ download», выведет тело запроса в консоль и слово «Download!». в браузер.
func handleDownloadRequeset(response http.ResponseWriter, request *http.Request) {
r, err := ioutil.ReadAll(request.Body)
if err != nil {
fmt.Println(err)
}
defer request.Body.Close()
fmt.Println(string(r))
fmt.Fprintf(response, "Download!")
}
Обновим функцию main, чтобы использовать новые функции для настройки обработчиков HTTP( HTTP handlers ). Наконец, мы запускаем сервер, прослушивающий порт 3000.
func main() {
fmt.Println("Downloader")
http.HandleFunc("/", status)
http.HandleFunc("/download", handleDownloadRequest)
http.ListenAndServe(":3000", nil)
}
Шаг третий
На этот раз большинство изменений происходят в функции handleDownloadRequest. Однако, если вы посмотрите внимательно, вы увидите, что я также добавил новые импорты encoding/json и log. Так как у нас серверное приложение, я хотел использовать встроенные функции логера и выводить их в консоль. Я пока не уверен, как поступить лучше, отправлять логи в файл или просто выводить в консоль.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type download struct {
Title string `json:"title"`
Location string `json:"location"`
}
func status(response http.ResponseWriter, request *http.Request) {
fmt.Fprintf(response, "Hello!")
}
А вот и сердце нашей программы. К тому же, здесь видны некоторые существенные изменения. Сначала, мы создаем структуру с именем downloadReqest для хранения нашего входящего заголовка и URL. Я так же улучшил обработку ошибок, добавил при необходимости возможность вывода реальных ошибок в браузере.
func handleDownloadRequest(response http.ResponseWriter, request *http.Request) {
var downloadRequest download
r, err := ioutil.ReadAll(request.Body)
if err != nil {
http.Error(response, "bad request", 400)
log.Println(err)
return
}
defer request.Body.Close()
Предполагая, что начальный запрос прошел мы можем прочитать тело и далее вставляем запрос JSON в нашу структуру. Вызов json.Unmarshal сделает всю грязную работу за нас. Если он не справится, мы можем вернуть ошибку в браузер. Вот как мы выводим сообщение об ошибке в json.Unmarshal
err = json.Unmarshal(r, &downloadRequest)
if err != nil {
http.Error(response, "bad request: "+err.Error(), 400)
log.Println(err)
return
}
log.Printf("%#v", downloadRequest)
fmt.Fprintf(response, "Download!")
}
func main() {
log.Println("Downloader")
http.HandleFunc("/", status)
http.HandleFunc("/download", handleDownloadRequest)
http.ListenAndServe(":3000", nil)
}
Мы с вами довольно много успели сделать! Быстро прошли путь от базового скелета до рабочего сервера. Теперь займемся изменением функции handleDownloadRequest, добавив к ней еще одну функцию getFile, которая нам понадобится для получения фактического файла.
Другие статьи из цикла:
- Изучаем Go - создание загрузчика (часть 1)
- Изучаем Go - создание загрузчика (часть 2)
- Изучаем Go - создание загрузчика (часть 3)
- Изучаем Go - создание загрузчика (часть 4)
- Изучаем Go - создание загрузчика (часть 5)
- Изучаем Go - Использование REST API
- Изучаем Go - Продолжаем работать с REST API
- Изучаем Go - Отправка REST-запросов
- Изучаем Go - Используем REST API в паре с шаблонами проектирования
- Изучаем Go - Повторная отправка электронной почты через API
Изучаем Go - Давайте станем модульными!скороИзучаем Go - Давайте станем модульными снова!скороИзучаем Go - Сборка DevLog Часть 01скороИзучаем Go - Сборка DevLog Часть 02скоро