В этом блоге в основном рассказывается, как начать с нуля, использовать модуль Go для управления зависимостями и шаг за шагом создавать веб-сервер Go на основе Gin. И используйте Endless для плавного перезапуска сервера, и используйте Swagger для автоматического создания документации API.
Откройте GoLand, найдите Global GOPATH в настройках GoLand, установите для него значение$HOME/go.$HOMEКаталог — это пользовательский каталог вашего компьютера, если такого каталога нетgoЕсли нет необходимости создавать новый каталог, когда мы инициализируем модуль в следующей операции, он автоматически создаст новый каталог go в пользовательском каталоге.
Включить модуль GO
Опять же, найдите Go Modules (vgo) в настройках GoLand. Установите флажок перед интеграцией модулей Go (vgo), чтобы включить Go Moudle.
Создайте структуру проекта
новый каталог
Создайте новый каталог в своей обычной рабочей области.Если у вас есть проект github, вы можете клонировать его напрямую.
инициализировать модуль go
go mod init $MODULE_NAME
В корневом каталоге только что созданного проекта используйте приведенную выше команду для инициализации модуля go. Эта команда создаст новый файл go.mod в корневом каталоге проекта.
Если ваш проект клонирован с github,$MODULE_NAMEЭтот параметр не нужен. по умолчанию это будетgithub.com/$GITHUB_USER_NAME/$PROJECT_NAME.
Например, этот проектgithub.com/detectiveHLH/go-backend-starter; Если это новый проект локально, необходимо добавить последний параметр. В противном случае будет обнаружена следующая ошибка.
go: cannot determine module path for source directory /Users/hulunhao/Projects/go/test/src (outside GOPATH, no import comments)
после инициализацииgo.modСодержимое файла следующее.
module github.com/detectiveHLH/go-backend-starter
go 1.12
Новый main.go
Создайте новый main.go в корневом каталоге проекта. код показывает, как показано ниже.
использовать в корневом каталогеgo run main.go, если вы видите вывод командной строкиThis worksЭто означает, что основная структура была построена. Далее мы начинаем внедрять Gin во фреймворк.
Представьте Джин
GinЭто HTTP-веб-фреймворк, реализованный на Go, и мы используем Gin в качестве базовой фреймворка для начала.
Установить Джин
Установить напрямую через команду go get
go get github.com/gin-gonic/gin
После успешной установки мы видим, что содержимое в файле go.mod изменилось.
Более того, мы не видели только что установленных зависимостей под установленным GOPATH. На самом деле зависимости устанавливаются в $GOPATH/pkg/mod.
module github.com/detectiveHLH/go-backend-starter
go 1.12
require github.com/gin-gonic/gin v1.4.0 // indirect
При этом также создается файл go.sum. Содержание следующее.
Любой, кто использовал Node, знает, что после установки зависимостей генерируется файл package-lock.json для блокировки версии зависимостей. Чтобы предотвратить установку новой версии при последующей переустановке зависимостей, но она несовместима с существующим кодом, что приведет к некоторым ненужным ошибкам.
Но этот файл go.sum этого не делает. Мы видим, что в go.mod записана только одна зависимость Gin, а в go.sum их намного больше. Это связано с тем, что в go.mod записывается только верхний уровень, то есть зависимости, которые мы устанавливаем непосредственно с помощью командной строки. Но имейте в виду, что пакет с открытым исходным кодом обычно зависит от многих других зависимостей.
И go.sum — это файл, который записывает конкретную версию всех высокоуровневых и косвенно зависимых пакетов и генерирует конкретное хэш-значение для каждой зависимой версии, так что, когда проект включается в новой среде, он может зависеть от проект.100% реставрация. go.sum также хранит некоторую информацию о версиях, использовавшихся в прошлом.
В модуле go нет необходимости в каталоге поставщика для обеспечения воспроизводимых сборок, но нужен файл go.mod для точного управления версиями каждой зависимости в проекте.
Если в предыдущем проекте использовался вендор, переписывать его с помощью go.mod нецелесообразно. мы можем использоватьgo mod vendorКоманда копирует все зависимости предыдущего проекта в каталог vendor.Для обеспечения совместимости зависимости в каталоге vendor отличаются от go.mod. Каталог после копирования не содержит номер версии.
И из установки джина выше видно, что при нормальных обстоятельствах файл go.mod не нужно редактировать вручную, после того как мы выполним команду, go.mod также автоматически обновит соответствующие зависимости и номера версий.
Давайте взглянем на команды, связанные с go mod.
init инициализирует модуль go
загрузить Загрузите зависимости из go.mod в каталог локального кеша ($GOPATH/pkg/mod)
edit Отредактируйте go.mod, вручную обновите и получите зависимости через командную строку
поставщик копирует зависимости проекта поставщику
tidy устанавливает отсутствующие зависимости и отбрасывает бесполезные зависимости
graph печатает график зависимости модуля
проверить убедиться, что зависимости верны
Стоит упомянуть еще одну команду,go list -m allСписок сборки для текущего проекта может быть указан.
Изменить main.go
Код для изменения main.go выглядит следующим образом.
Приведенный выше код вводит маршрутизацию.Те, кто знаком с Node, должны заметить, что это очень похоже на использование koa-router.
запустить сервер
Выполните шаги, описанные выше, чтобы запустить main.go для запуска main.go. Вы можете увидеть следующий вывод в консоли.
This works.
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /hello --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
На данный момент сервер запущен на порту 8080. Затем посетите http://localhost:8080/hello в браузере, вы увидите нормальное возвращение сервера. При этом серверная сторона также распечатает соответствующий лог.
В этот файл экспортируется функция InitRouter, которая возвращает тип gin.Engine. Функция также определяет запрос GET, направляемый в /api/v1/hello.
Внедрить маршрутизацию в основную функцию
Измените код main.go на следующий.
package main
import (
"fmt"
"github.com/detectiveHLH/go-backend-starter/router"
)
func main() {
r := router.InitRouter()
r.Run()
}
Затем запустите main.go, после запуска посетитеhttp://localhost:8080/api/v1/hello, вы можете видеть, что результат доступа к маршруту /hello такой же, как и раньше.
Пока что у нас есть веб-сервер с простым функционалом. Тогда возникает проблема, такой открытый сервер, пока вы знаете адрес, ваш сервер будет открыт для других. Это принесет некоторые риски безопасности. Поэтому нам необходимо добавить аутентификацию в интерфейс, только вызывающий абонент, прошедший аутентификацию, имеет право вызывать интерфейс сервера. Итак, далее нам нужно представить JWT.
Внедрить JWT-аутентификацию
Установите зависимости jwt-go с помощью команды go get.
go get github.com/dgrijalva/jwt-go
Создайте новый файл аутентификации jwt
Создайте новый каталог промежуточного ПО/jwt в корневом каталоге и создайте новый файл jwt.go в каталоге jwt.Код выглядит следующим образом.
На этом этапе в коде будут ошибки, потому что мы не объявили пакет consts, а переменные SUCCESS, INVALID_PARAMS и ERROR_AUTH_CHECK_TOKEN_FAIL не определены. Функция GetMsg, которая получает информацию, возвращаемую сервером по коду, также не определена. Также не определены util.ParseToken(токен) и Claims.ExpiresAt. Итак, мы должны создать новый пакет consts. Мы создаем новый каталог consts в корневом каталоге и создаем новый code.go в каталоге consts, чтобы ввести некоторые определенные константы.Код выглядит следующим образом.
В приведенном выше утилите пакет настроек не определен, поэтому на этом этапе нам нужно определить пакет настроек.
Установите зависимости с помощью команды go get.
go get gopkg.in/ini.v1
Создайте новый каталог настроек в корневом каталоге проекта и создайте новый файл settings.go в каталоге настроек.Код выглядит следующим образом.
package setting
import (
"gopkg.in/ini.v1"
"log"
)
type App struct {
JwtSecret string
}
type Server struct {
Ip string
Port string
}
type Database struct {
Type string
User string
Password string
Host string
Name string
TablePrefix string
}
var AppSetting = &App{}
var ServerSetting = &Server{}
var DatabaseSetting = &Database{}
var config *ini.File
func Setup() {
var err error
config, err = ini.Load("config/app.ini")
if err != nil {
log.Fatal("Fail to parse 'config/app.ini': %v", err)
}
mapTo("app", AppSetting)
mapTo("server", ServerSetting)
mapTo("database", DatabaseSetting)
}
func mapTo(section string, v interface{}) {
err := config.Section(section).MapTo(v)
if err != nil {
log.Fatalf("Cfg.MapTo RedisSetting err: %v", err)
}
}
Новый файл конфигурации
Создайте новый каталог конфигурации в корневом каталоге проекта и создайте новый файл app.ini со следующим содержимым.
[app]
JwtSecret = 233
[server]
Ip : localhost
Port : 8000
Url : 127.0.0.1:27017
[database]
Type = mysql
User = $YOUR_USERNAME
Password = $YOUR_PASSWORD
Host = 127.0.0.1:3306
Name = golang_test
TablePrefix = golang_test_
Реализовать интерфейс входа
Добавлен интерфейс входа
На данный момент логика аутентификации через токен jwt завершена, а остальным необходимо реализовать интерфейс входа в систему, чтобы возвращать токен пользователю после того, как пользователь успешно войдет в систему.
В дополнение к возвращаемому классу в login.go есть ключевая логика аутентификации, которая еще не реализована. Создайте новый каталог service/authentication в корневом каталоге и создайте новый файл auth.go в этом каталоге.Код выглядит следующим образом.
Здесь вам необходимо реализовать проверку правильности вызова пользовательского интерфейса в соответствии с вашим бизнесом. Например, вы можете аутентифицироваться в базе данных на основе имени пользователя и пароля.
Как видите, мы добавили интерфейс /login в файл маршрутизации и использовали наше промежуточное ПО для аутентификации jwt. Пока это маршрут под v1, он войдет в jwt для аутентификации перед запросом и может продолжить выполнение после прохождения аутентификации.
запустить main.go
Пока что мы используемgo run main.goзапустить сервер, получить доступhttp://localhost:8080/api/v1/helloБудет обнаружена следующая ошибка.
{
"code": 400,
"data": null,
"msg": "请求参数错误"
}
Это связано с тем, что мы добавили аутентификацию. Любой интерфейс, требующий аутентификации, должен иметь токен параметра. Чтобы получить токен, вы должны сначала войти в систему. Предположим, что наше имя пользователя — Том, а пароль — 123. Таким образом вызывается интерфейс входа в систему.
Общий метод обработки заключается в том, что интерфейс получает токен, сохраняет его в постоянном хранилище, а затем записывает токен в заголовок для каждого последующего запроса и отправляет его на сервер. Серверная часть сначала проверяет действительность вызывающего интерфейса с помощью токена в заголовке, а затем выполняет вызов реального интерфейса после прохождения проверки.
И здесь я написал токен в параметре запроса, просто для примера.
Представьте чванство
После завершения базовой структуры мы начинаем вводить документацию swagger для интерфейса. Студенты, которые писали на Java, должны быть знакомы с swagger. Документация по API обычно пишется вручную. То есть каждый параметр каждого интерфейса нужно набирать вручную.
В отличие от swagger, swagger может автоматически генерировать для вас документы swagger, только добавляя в интерфейс несколько аннотаций (операций на Java). В го делаем по аннотации, а потом устанавливаемgin-swagger.
Установить зависимости
go get github.com/swaggo/gin-swagger
go get -u github.com/swaggo/gin-swagger/swaggerFiles
go get -u github.com/swaggo/swag/cmd/swag
go get github.com/ugorji/go/codec
go get github.com/alecthomas/template
Внедрить чванство в роутер
После введения зависимостей нам нужно внедрить swagger в router/router.go. добавить в импорт_ "github.com/detectiveHLH/go-backend-starter/docs".
И вrouter := gin.New()Затем добавьте следующий код.
Использовать в корневом каталоге проектаswag initКоманда для инициализации документации swagger. Эта команда создаст каталог docs в корневом каталоге проекта со следующим содержимым.
.
├── docs.go
├── swagger.json
└── swagger.yaml
Посмотреть документацию по чванству
Запустите main.go, а затем зайдите в браузереhttp://localhost:8080/swagger/index.htmlВы можете увидеть документацию API, автоматически сгенерированную swagger на основе аннотаций.
Представляем Бесконечный
Установить бесконечный
go get github.com/fvbock/endless
Изменить main.go
package main
import (
"fmt"
"github.com/detectiveHLH/go-backend-starter/router"
"github.com/fvbock/endless"
"log"
"syscall"
)
func main() {
r := router.InitRouter()
address := fmt.Sprintf("%s:%s", setting.ServerSetting.Ip, setting.ServerSetting.Port)
server := endless.NewServer(address, r)
server.BeforeBegin = func(add string) {
log.Printf("Actual pid is %d", syscall.Getpid())
}
err := server.ListenAndServe()
if err != nil {
log.Printf("Server err: %v", err)
}
}
написать на обороте
По сравнению с управлением зависимостями без модуля go текущий модуль go больше похож на package.json в Node.js и pom.xml в Java, единственное отличие состоит в том, что pom.xml нужно обновлять вручную.
Когда мы получаем проект с модулем go, нам не нужно беспокоиться о некоторых проблемах совместимости, которые могут быть вызваны проблемами версии, когда мы полагаемся на него. Непосредственно используйте команду в моде go для установки всех зависимостей указанной версии, эффект аналогичен тому, что в Node.jsnpm install.
Способ, которым модуль go находит модуль, аналогичен логике Node.js, ищущей зависимости: Node запускается из каталога, в котором выполняется текущая команда, а затем проверяет, есть ли эта зависимость в node_modules, пока не будет найдена. . Go, в свою очередь, ищет файл go.mod, чтобы найти модуль.
Я верю, что управление зависимостями после go будет становиться все лучше и лучше.