HTTP-сервер на Go

в 14:30, , рубрики: Go, http, wedev, Программирование

Привет! В этой статье я хочу рассказать, как легко написать полноценный 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

Источник

Поделиться новостью

* - обязательные к заполнению поля