Привет! В этой статье я хочу рассказать, как легко написать полноценный HTTP сервер на Go, дабы у читателей не возникло проблем с поиском необходимого функционала в библиотеках. Использовать будем только функционал стандартных библиотек и оригинальный компилятор.
Сервер не будет обрабатывать множество ошибок — он создан исключительно для того, чтобы объяснить, как его вообще реализовать.
1. main()
Начнём с написания главной функции. Она будет предельно проста.
package main
// Импортируем всё, что нам может понадобиться
import (
"fmt"
"net/http"
"io/ioutil"
"os"
)
// Наша главная функция
func main() {
// При получени запроса к "/*", если не задано других обработчиков для данного
// запроса, вызываем функцию "handler".
http.HandleFunc("/", handler)
// Ну а как-же без этого?)
fmt.Println("Запускаемся. Слушаем порт 8080")
// Сканируем запросы к порту 8080. При наличии таковых - отвечаем так, как
// указано выше
http.ListenAndServe(":8080", nil)
}
2. handler()
Главная функция готова, но без обработчика она не будет работать.
// Обработчик запросов. Принимает поток вывода от пакета "net/http",
// а также информацию о запроса
func handler(iWrt http.ResponseWriter, iReq *http.Request) {
// Отправляет "Привет, мир" в ответ на запрос
fmt.Fprintln(iWrt, "Привет, мир")
}
На данном этапе сервер уже прекрасно запускается и отвечает на любой запрос фразой "Привет, мир"
3. Чтение файлов
Ни один полноценный веб-сервер не может обойтись без чтения файлов. И наш тоже.
// Считыватель файлов. Принимает имя файла и выдаёт его содержимое
func readFile(iFileName string) string {
// Считываем файл
lData, err := ioutil.ReadFile(iFileName)
var lOut string // Объявляем строчную переменную
// Если файл существует - записываем его в переменную lOut
if !os.IsNotExist(err) {
lOut = string(lData)
} else { // Иначе - отправляем стандартный текст
lOut = "404"
}
return lOut // Возвращаем полученную информацию
}
Теперь правим функцию handler(), дабы дать ей возможность считывать файлы
// Обработчик запросов. Принимает поток вывода от пакета "net/http",
// а также информацию о запроса
func handler(iWrt http.ResponseWriter, iReq *http.Request) {
var lGet = iReq.URL.Path[1:] // Упростим напсание кода
if lGet == "" || lGet == "/" { // Дабы разрешить "/" запросы
lGet = "index.html"
}
lData := readFile(lGet) // Считываем файл
// Отправляет "Привет, мир" в ответ на запрос
fmt.Fprintln(iWrt, lData)
}
4. И напоследок
Да, сервер не умеет обрабатывать ошибку 404 так, как положено.
Да, он не умеет много чего ещё.
И да, он не умеет использовать HTTPS, хотя небольшая правка функци main это способна исправить.
Однако он уже запускается и способен выдавать файлы из своей же папки. Мало того, он защищён — не позволит обращаться к файлам выше своей директории.
Написал я эту статью (повторяюсь) просто для того, чтобы тем, кто это будет читать, не пришлось разрывать документацию в поисках одной единственной функции, как это пришлось делать мне.
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
// Наша главная функция
func main() {
// При получени запроса к "/*", если не задано других обработчиков для данного
// запроса, вызываем функцию "handler".
http.HandleFunc("/", handler)
// Ну а как-же без этого?)
fmt.Println("Запускаемся. Слушаем порт 8080")
// Сканируем запросы к порту 8080. При наличии таковых - отвечаем так, как
// указано выше
http.ListenAndServe(":8080", nil)
}
// Обработчик запросов. Принимает поток вывода от пакета "net/http",
// а также информацию о запроса
func handler(iWrt http.ResponseWriter, iReq *http.Request) {
var lGet = iReq.URL.Path[1:] // Упростим напсание кода
if lGet == "" || lGet == "/" { // Дабы разрешить "/" запросы
lGet = "index.html"
}
lData := readFile(lGet)
// Отправляет "Привет, мир" в ответ на запрос
fmt.Fprintln(iWrt, lData)
}
func readFile(iFileName string) string {
// Считываем файл
lData, err := ioutil.ReadFile(iFileName)
var lOut string // Объявляем строчную переменную
// Если файл существует - записываем его в переменную lOut
if !os.IsNotExist(err) {
lOut = string(lData)
} else { // Иначе - отправляем стандартный текст
lOut = "404"
}
return lOut // Возвращаем полученную информацию
}
Автор: handicraftsman